xref: /freebsd/sys/dev/acpica/acpi_quirk.c (revision fdafd315)
11bf44266SNate Lawson /*-
21bf44266SNate Lawson  * Copyright (c) 2004 Nate Lawson (SDG)
31bf44266SNate Lawson  * All rights reserved.
41bf44266SNate Lawson  *
51bf44266SNate Lawson  * Redistribution and use in source and binary forms, with or without
61bf44266SNate Lawson  * modification, are permitted provided that the following conditions
71bf44266SNate Lawson  * are met:
81bf44266SNate Lawson  * 1. Redistributions of source code must retain the above copyright
91bf44266SNate Lawson  *    notice, this list of conditions and the following disclaimer.
101bf44266SNate Lawson  * 2. Redistributions in binary form must reproduce the above copyright
111bf44266SNate Lawson  *    notice, this list of conditions and the following disclaimer in the
121bf44266SNate Lawson  *    documentation and/or other materials provided with the distribution.
131bf44266SNate Lawson  *
141bf44266SNate Lawson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151bf44266SNate Lawson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161bf44266SNate Lawson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171bf44266SNate Lawson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181bf44266SNate Lawson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191bf44266SNate Lawson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201bf44266SNate Lawson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211bf44266SNate Lawson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221bf44266SNate Lawson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231bf44266SNate Lawson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241bf44266SNate Lawson  * SUCH DAMAGE.
251bf44266SNate Lawson  */
261bf44266SNate Lawson 
271bf44266SNate Lawson #include <sys/param.h>
281bf44266SNate Lawson #include <sys/bus.h>
291bf44266SNate Lawson 
30129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
31129d3046SJung-uk Kim 
321bf44266SNate Lawson #include <dev/acpica/acpivar.h>
331bf44266SNate Lawson 
341bf44266SNate Lawson enum ops_t {
351bf44266SNate Lawson 	OP_NONE,
361bf44266SNate Lawson 	OP_LEQ,
371bf44266SNate Lawson 	OP_GEQ,
381bf44266SNate Lawson 	OP_EQL,
391bf44266SNate Lawson };
401bf44266SNate Lawson 
411bf44266SNate Lawson enum val_t {
421bf44266SNate Lawson 	OEM,
431bf44266SNate Lawson 	OEM_REV,
441bf44266SNate Lawson 	CREATOR,
451bf44266SNate Lawson 	CREATOR_REV,
461bf44266SNate Lawson };
471bf44266SNate Lawson 
481bf44266SNate Lawson struct acpi_q_rule {
49278f0de6SJung-uk Kim     char	sig[ACPI_NAMESEG_SIZE];	/* Table signature to match */
501bf44266SNate Lawson     enum val_t	val;
511bf44266SNate Lawson     union {
521bf44266SNate Lawson 	char	*id;
531bf44266SNate Lawson 	enum ops_t op;
541bf44266SNate Lawson     } x;
551bf44266SNate Lawson     union {
561bf44266SNate Lawson 	char	*tid;
571bf44266SNate Lawson 	int	rev;
581bf44266SNate Lawson     } y;
591bf44266SNate Lawson };
601bf44266SNate Lawson 
611bf44266SNate Lawson struct acpi_q_entry {
621bf44266SNate Lawson     const struct acpi_q_rule *match;
631bf44266SNate Lawson     int		quirks;
641bf44266SNate Lawson };
651bf44266SNate Lawson 
661bf44266SNate Lawson #include "acpi_quirks.h"
671bf44266SNate Lawson 
681bf44266SNate Lawson static int	aq_revcmp(int revision, enum ops_t op, int value);
691bf44266SNate Lawson static int	aq_strcmp(char *actual, char *possible);
701bf44266SNate Lawson static int	aq_match_header(ACPI_TABLE_HEADER *hdr,
711bf44266SNate Lawson 		    const struct acpi_q_rule *match);
721bf44266SNate Lawson 
731bf44266SNate Lawson static int
aq_revcmp(int revision,enum ops_t op,int value)741bf44266SNate Lawson aq_revcmp(int revision, enum ops_t op, int value)
751bf44266SNate Lawson {
761bf44266SNate Lawson     switch (op) {
771bf44266SNate Lawson     case OP_LEQ:
781bf44266SNate Lawson 	if (revision <= value)
791bf44266SNate Lawson 	    return (TRUE);
801bf44266SNate Lawson 	break;
811bf44266SNate Lawson     case OP_GEQ:
821bf44266SNate Lawson 	if (revision >= value)
831bf44266SNate Lawson 	    return (TRUE);
841bf44266SNate Lawson 	break;
851bf44266SNate Lawson     case OP_EQL:
861bf44266SNate Lawson 	if (revision == value)
871bf44266SNate Lawson 	    return (TRUE);
881bf44266SNate Lawson 	break;
891bf44266SNate Lawson     case OP_NONE:
901bf44266SNate Lawson 	return (TRUE);
911bf44266SNate Lawson     default:
921bf44266SNate Lawson 	panic("aq_revcmp: invalid op %d", op);
931bf44266SNate Lawson     }
941bf44266SNate Lawson 
951bf44266SNate Lawson     return (FALSE);
961bf44266SNate Lawson }
971bf44266SNate Lawson 
981bf44266SNate Lawson static int
aq_strcmp(char * actual,char * possible)991bf44266SNate Lawson aq_strcmp(char *actual, char *possible)
1001bf44266SNate Lawson {
1011bf44266SNate Lawson     if (actual == NULL || possible == NULL)
1021bf44266SNate Lawson 	return (TRUE);
1031bf44266SNate Lawson     return (strncmp(actual, possible, strlen(possible)) == 0);
1041bf44266SNate Lawson }
1051bf44266SNate Lawson 
1061bf44266SNate Lawson static int
aq_match_header(ACPI_TABLE_HEADER * hdr,const struct acpi_q_rule * match)1071bf44266SNate Lawson aq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match)
1081bf44266SNate Lawson {
1091bf44266SNate Lawson     int result;
1101bf44266SNate Lawson 
1111bf44266SNate Lawson     result = FALSE;
1121bf44266SNate Lawson     switch (match->val) {
1131bf44266SNate Lawson     case OEM:
1141bf44266SNate Lawson 	if (aq_strcmp(hdr->OemId, match->x.id) &&
1151bf44266SNate Lawson 	    aq_strcmp(hdr->OemTableId, match->y.tid))
1161bf44266SNate Lawson 	    result = TRUE;
1171bf44266SNate Lawson 	break;
1181bf44266SNate Lawson     case CREATOR:
1191bf44266SNate Lawson 	if (aq_strcmp(hdr->AslCompilerId, match->x.id))
1201bf44266SNate Lawson 	    result = TRUE;
1211bf44266SNate Lawson 	break;
1221bf44266SNate Lawson     case OEM_REV:
1231bf44266SNate Lawson 	if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev))
1241bf44266SNate Lawson 	    result = TRUE;
1251bf44266SNate Lawson 	break;
1261bf44266SNate Lawson     case CREATOR_REV:
1271bf44266SNate Lawson 	if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev))
1281bf44266SNate Lawson 	    result = TRUE;
1291bf44266SNate Lawson 	break;
1301bf44266SNate Lawson     }
1311bf44266SNate Lawson 
1321bf44266SNate Lawson     return (result);
1331bf44266SNate Lawson }
1341bf44266SNate Lawson 
1351bf44266SNate Lawson int
acpi_table_quirks(int * quirks)1361bf44266SNate Lawson acpi_table_quirks(int *quirks)
1371bf44266SNate Lawson {
1381bf44266SNate Lawson     const struct acpi_q_entry *entry;
1391bf44266SNate Lawson     const struct acpi_q_rule *match;
1402be4e471SJung-uk Kim     ACPI_TABLE_HEADER fadt, dsdt, xsdt, *hdr;
1411bf44266SNate Lawson     int done;
1421bf44266SNate Lawson 
1431bf44266SNate Lawson     /* First, allow the machdep system to set its idea of quirks. */
1441bf44266SNate Lawson     KASSERT(quirks != NULL, ("acpi quirks ptr is NULL"));
1451bf44266SNate Lawson     acpi_machdep_quirks(quirks);
1461bf44266SNate Lawson 
1472be4e471SJung-uk Kim     if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_FADT, 0, &fadt)))
1482be4e471SJung-uk Kim 	bzero(&fadt, sizeof(fadt));
1492be4e471SJung-uk Kim     if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &dsdt)))
150d1dfacc2SJung-uk Kim 	bzero(&dsdt, sizeof(dsdt));
1512be4e471SJung-uk Kim     if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_XSDT, 0, &xsdt)))
152d1dfacc2SJung-uk Kim 	bzero(&xsdt, sizeof(xsdt));
1532be4e471SJung-uk Kim 
1541bf44266SNate Lawson     /* Then, override the quirks with any matched from table signatures. */
1551bf44266SNate Lawson     for (entry = acpi_quirks_table; entry->match; entry++) {
1561bf44266SNate Lawson 	done = TRUE;
1572be4e471SJung-uk Kim 	for (match = entry->match; match->sig[0] != '\0'; match++) {
158278f0de6SJung-uk Kim 	    if (!strncmp(match->sig, "FADT", ACPI_NAMESEG_SIZE))
1592be4e471SJung-uk Kim 		hdr = &fadt;
160278f0de6SJung-uk Kim 	    else if (!strncmp(match->sig, ACPI_SIG_DSDT, ACPI_NAMESEG_SIZE))
1612be4e471SJung-uk Kim 		hdr = &dsdt;
162278f0de6SJung-uk Kim 	    else if (!strncmp(match->sig, ACPI_SIG_XSDT, ACPI_NAMESEG_SIZE))
1632be4e471SJung-uk Kim 		hdr = &xsdt;
1642be4e471SJung-uk Kim 	    else
1651bf44266SNate Lawson 		panic("invalid quirk header\n");
1661bf44266SNate Lawson 
1671bf44266SNate Lawson 	    /* If we don't match any, skip to the next entry. */
1682be4e471SJung-uk Kim 	    if (aq_match_header(hdr, match) == FALSE) {
1691bf44266SNate Lawson 		done = FALSE;
1701bf44266SNate Lawson 		break;
1711bf44266SNate Lawson 	    }
1721bf44266SNate Lawson 	}
1731bf44266SNate Lawson 
1741bf44266SNate Lawson 	/* If all entries matched, update the quirks and return. */
1751bf44266SNate Lawson 	if (done) {
1761bf44266SNate Lawson 	    *quirks = entry->quirks;
1771bf44266SNate Lawson 	    break;
1781bf44266SNate Lawson 	}
1791bf44266SNate Lawson     }
1801bf44266SNate Lawson 
1811bf44266SNate Lawson     return (0);
1821bf44266SNate Lawson }
183