xref: /freebsd/sys/dev/acpica/acpi_quirk.c (revision 2be4e4713aac95323b389243f0f7fa00f6a6112a)
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 
27a3ab9d1eSNate Lawson #include <sys/cdefs.h>
28a3ab9d1eSNate Lawson __FBSDID("$FreeBSD$");
29a3ab9d1eSNate Lawson 
301bf44266SNate Lawson #include <sys/param.h>
311bf44266SNate Lawson #include <sys/bus.h>
321bf44266SNate Lawson 
332a191126SDavid E. O'Brien #include <contrib/dev/acpica/acpi.h>
341bf44266SNate Lawson #include <dev/acpica/acpivar.h>
351bf44266SNate Lawson 
361bf44266SNate Lawson enum ops_t {
371bf44266SNate Lawson 	OP_NONE,
381bf44266SNate Lawson 	OP_LEQ,
391bf44266SNate Lawson 	OP_GEQ,
401bf44266SNate Lawson 	OP_EQL,
411bf44266SNate Lawson };
421bf44266SNate Lawson 
431bf44266SNate Lawson enum val_t {
441bf44266SNate Lawson 	OEM,
451bf44266SNate Lawson 	OEM_REV,
461bf44266SNate Lawson 	CREATOR,
471bf44266SNate Lawson 	CREATOR_REV,
481bf44266SNate Lawson };
491bf44266SNate Lawson 
501bf44266SNate Lawson struct acpi_q_rule {
512be4e471SJung-uk Kim     char	sig[ACPI_NAME_SIZE];	/* Table signature to match */
521bf44266SNate Lawson     enum val_t	val;
531bf44266SNate Lawson     union {
541bf44266SNate Lawson 	char	*id;
551bf44266SNate Lawson 	enum ops_t op;
561bf44266SNate Lawson     } x;
571bf44266SNate Lawson     union {
581bf44266SNate Lawson 	char	*tid;
591bf44266SNate Lawson 	int	rev;
601bf44266SNate Lawson     } y;
611bf44266SNate Lawson };
621bf44266SNate Lawson 
631bf44266SNate Lawson struct acpi_q_entry {
641bf44266SNate Lawson     const struct acpi_q_rule *match;
651bf44266SNate Lawson     int		quirks;
661bf44266SNate Lawson };
671bf44266SNate Lawson 
681bf44266SNate Lawson #include "acpi_quirks.h"
691bf44266SNate Lawson 
701bf44266SNate Lawson static int	aq_revcmp(int revision, enum ops_t op, int value);
711bf44266SNate Lawson static int	aq_strcmp(char *actual, char *possible);
721bf44266SNate Lawson static int	aq_match_header(ACPI_TABLE_HEADER *hdr,
731bf44266SNate Lawson 		    const struct acpi_q_rule *match);
741bf44266SNate Lawson 
751bf44266SNate Lawson static int
761bf44266SNate Lawson aq_revcmp(int revision, enum ops_t op, int value)
771bf44266SNate Lawson {
781bf44266SNate Lawson     switch (op) {
791bf44266SNate Lawson     case OP_LEQ:
801bf44266SNate Lawson 	if (revision <= value)
811bf44266SNate Lawson 	    return (TRUE);
821bf44266SNate Lawson 	break;
831bf44266SNate Lawson     case OP_GEQ:
841bf44266SNate Lawson 	if (revision >= value)
851bf44266SNate Lawson 	    return (TRUE);
861bf44266SNate Lawson 	break;
871bf44266SNate Lawson     case OP_EQL:
881bf44266SNate Lawson 	if (revision == value)
891bf44266SNate Lawson 	    return (TRUE);
901bf44266SNate Lawson 	break;
911bf44266SNate Lawson     case OP_NONE:
921bf44266SNate Lawson 	return (TRUE);
931bf44266SNate Lawson     default:
941bf44266SNate Lawson 	panic("aq_revcmp: invalid op %d", op);
951bf44266SNate Lawson     }
961bf44266SNate Lawson 
971bf44266SNate Lawson     return (FALSE);
981bf44266SNate Lawson }
991bf44266SNate Lawson 
1001bf44266SNate Lawson static int
1011bf44266SNate Lawson aq_strcmp(char *actual, char *possible)
1021bf44266SNate Lawson {
1031bf44266SNate Lawson     if (actual == NULL || possible == NULL)
1041bf44266SNate Lawson 	return (TRUE);
1051bf44266SNate Lawson     return (strncmp(actual, possible, strlen(possible)) == 0);
1061bf44266SNate Lawson }
1071bf44266SNate Lawson 
1081bf44266SNate Lawson static int
1091bf44266SNate Lawson aq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match)
1101bf44266SNate Lawson {
1111bf44266SNate Lawson     int result;
1121bf44266SNate Lawson 
1131bf44266SNate Lawson     result = FALSE;
1141bf44266SNate Lawson     switch (match->val) {
1151bf44266SNate Lawson     case OEM:
1161bf44266SNate Lawson 	if (aq_strcmp(hdr->OemId, match->x.id) &&
1171bf44266SNate Lawson 	    aq_strcmp(hdr->OemTableId, match->y.tid))
1181bf44266SNate Lawson 	    result = TRUE;
1191bf44266SNate Lawson 	break;
1201bf44266SNate Lawson     case CREATOR:
1211bf44266SNate Lawson 	if (aq_strcmp(hdr->AslCompilerId, match->x.id))
1221bf44266SNate Lawson 	    result = TRUE;
1231bf44266SNate Lawson 	break;
1241bf44266SNate Lawson     case OEM_REV:
1251bf44266SNate Lawson 	if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev))
1261bf44266SNate Lawson 	    result = TRUE;
1271bf44266SNate Lawson 	break;
1281bf44266SNate Lawson     case CREATOR_REV:
1291bf44266SNate Lawson 	if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev))
1301bf44266SNate Lawson 	    result = TRUE;
1311bf44266SNate Lawson 	break;
1321bf44266SNate Lawson     }
1331bf44266SNate Lawson 
1341bf44266SNate Lawson     return (result);
1351bf44266SNate Lawson }
1361bf44266SNate Lawson 
1371bf44266SNate Lawson int
1381bf44266SNate Lawson acpi_table_quirks(int *quirks)
1391bf44266SNate Lawson {
1401bf44266SNate Lawson     const struct acpi_q_entry *entry;
1411bf44266SNate Lawson     const struct acpi_q_rule *match;
1422be4e471SJung-uk Kim     ACPI_TABLE_HEADER fadt, dsdt, xsdt, *hdr;
1431bf44266SNate Lawson     int done;
1441bf44266SNate Lawson 
1451bf44266SNate Lawson     /* First, allow the machdep system to set its idea of quirks. */
1461bf44266SNate Lawson     KASSERT(quirks != NULL, ("acpi quirks ptr is NULL"));
1471bf44266SNate Lawson     acpi_machdep_quirks(quirks);
1481bf44266SNate Lawson 
1492be4e471SJung-uk Kim     if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_FADT, 0, &fadt)))
1502be4e471SJung-uk Kim 	bzero(&fadt, sizeof(fadt));
1512be4e471SJung-uk Kim     if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &dsdt)))
1522be4e471SJung-uk Kim 	bzero(&fadt, sizeof(dsdt));
1532be4e471SJung-uk Kim     if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_XSDT, 0, &xsdt)))
1542be4e471SJung-uk Kim 	bzero(&fadt, sizeof(xsdt));
1552be4e471SJung-uk Kim 
1561bf44266SNate Lawson     /* Then, override the quirks with any matched from table signatures. */
1571bf44266SNate Lawson     for (entry = acpi_quirks_table; entry->match; entry++) {
1581bf44266SNate Lawson 	done = TRUE;
1592be4e471SJung-uk Kim 	for (match = entry->match; match->sig[0] != '\0'; match++) {
1602be4e471SJung-uk Kim 	    if (!strncmp(match->sig, "FADT", ACPI_NAME_SIZE))
1612be4e471SJung-uk Kim 		hdr = &fadt;
1622be4e471SJung-uk Kim 	    else if (!strncmp(match->sig, ACPI_SIG_DSDT, ACPI_NAME_SIZE))
1632be4e471SJung-uk Kim 		hdr = &dsdt;
1642be4e471SJung-uk Kim 	    else if (!strncmp(match->sig, ACPI_SIG_XSDT, ACPI_NAME_SIZE))
1652be4e471SJung-uk Kim 		hdr = &xsdt;
1662be4e471SJung-uk Kim 	    else
1671bf44266SNate Lawson 		panic("invalid quirk header\n");
1681bf44266SNate Lawson 
1691bf44266SNate Lawson 	    /* If we don't match any, skip to the next entry. */
1702be4e471SJung-uk Kim 	    if (aq_match_header(hdr, match) == FALSE) {
1711bf44266SNate Lawson 		done = FALSE;
1721bf44266SNate Lawson 		break;
1731bf44266SNate Lawson 	    }
1741bf44266SNate Lawson 	}
1751bf44266SNate Lawson 
1761bf44266SNate Lawson 	/* If all entries matched, update the quirks and return. */
1771bf44266SNate Lawson 	if (done) {
1781bf44266SNate Lawson 	    *quirks = entry->quirks;
1791bf44266SNate Lawson 	    break;
1801bf44266SNate Lawson 	}
1811bf44266SNate Lawson     }
1821bf44266SNate Lawson 
1831bf44266SNate Lawson     return (0);
1841bf44266SNate Lawson }
185