xref: /freebsd/sys/dev/acpica/acpi_quirk.c (revision 1bf4426682b3a9a83f4056ec9e2d8c7f36e567c5)
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  * $FreeBSD$
271bf44266SNate Lawson  */
281bf44266SNate Lawson 
291bf44266SNate Lawson #include <sys/param.h>
301bf44266SNate Lawson #include <sys/bus.h>
311bf44266SNate Lawson 
321bf44266SNate Lawson #include "acpi.h"
331bf44266SNate Lawson #include <dev/acpica/acpivar.h>
341bf44266SNate Lawson 
351bf44266SNate Lawson enum ops_t {
361bf44266SNate Lawson 	OP_NONE,
371bf44266SNate Lawson 	OP_LEQ,
381bf44266SNate Lawson 	OP_GEQ,
391bf44266SNate Lawson 	OP_EQL,
401bf44266SNate Lawson };
411bf44266SNate Lawson 
421bf44266SNate Lawson enum val_t {
431bf44266SNate Lawson 	OEM,
441bf44266SNate Lawson 	OEM_REV,
451bf44266SNate Lawson 	CREATOR,
461bf44266SNate Lawson 	CREATOR_REV,
471bf44266SNate Lawson };
481bf44266SNate Lawson 
491bf44266SNate Lawson #define ACPI_TABLE_END		(ACPI_TABLE_MAX + 1)
501bf44266SNate Lawson 
511bf44266SNate Lawson struct acpi_q_rule {
521bf44266SNate Lawson     int 	sig;		/* Table signature to match */
531bf44266SNate Lawson     enum val_t	val;
541bf44266SNate Lawson     union {
551bf44266SNate Lawson 	char	*id;
561bf44266SNate Lawson 	enum ops_t op;
571bf44266SNate Lawson     } x;
581bf44266SNate Lawson     union {
591bf44266SNate Lawson 	char	*tid;
601bf44266SNate Lawson 	int	rev;
611bf44266SNate Lawson     } y;
621bf44266SNate Lawson };
631bf44266SNate Lawson 
641bf44266SNate Lawson struct acpi_q_entry {
651bf44266SNate Lawson     const struct acpi_q_rule *match;
661bf44266SNate Lawson     int		quirks;
671bf44266SNate Lawson };
681bf44266SNate Lawson 
691bf44266SNate Lawson #include "acpi_quirks.h"
701bf44266SNate Lawson 
711bf44266SNate Lawson static int	aq_revcmp(int revision, enum ops_t op, int value);
721bf44266SNate Lawson static int	aq_strcmp(char *actual, char *possible);
731bf44266SNate Lawson static int	aq_match_header(ACPI_TABLE_HEADER *hdr,
741bf44266SNate Lawson 		    const struct acpi_q_rule *match);
751bf44266SNate Lawson 
761bf44266SNate Lawson static int
771bf44266SNate Lawson aq_revcmp(int revision, enum ops_t op, int value)
781bf44266SNate Lawson {
791bf44266SNate Lawson     switch (op) {
801bf44266SNate Lawson     case OP_LEQ:
811bf44266SNate Lawson 	if (revision <= value)
821bf44266SNate Lawson 	    return (TRUE);
831bf44266SNate Lawson 	break;
841bf44266SNate Lawson     case OP_GEQ:
851bf44266SNate Lawson 	if (revision >= value)
861bf44266SNate Lawson 	    return (TRUE);
871bf44266SNate Lawson 	break;
881bf44266SNate Lawson     case OP_EQL:
891bf44266SNate Lawson 	if (revision == value)
901bf44266SNate Lawson 	    return (TRUE);
911bf44266SNate Lawson 	break;
921bf44266SNate Lawson     case OP_NONE:
931bf44266SNate Lawson 	return (TRUE);
941bf44266SNate Lawson     default:
951bf44266SNate Lawson 	panic("aq_revcmp: invalid op %d", op);
961bf44266SNate Lawson     }
971bf44266SNate Lawson 
981bf44266SNate Lawson     return (FALSE);
991bf44266SNate Lawson }
1001bf44266SNate Lawson 
1011bf44266SNate Lawson static int
1021bf44266SNate Lawson aq_strcmp(char *actual, char *possible)
1031bf44266SNate Lawson {
1041bf44266SNate Lawson     if (actual == NULL || possible == NULL)
1051bf44266SNate Lawson 	return (TRUE);
1061bf44266SNate Lawson     return (strncmp(actual, possible, strlen(possible)) == 0);
1071bf44266SNate Lawson }
1081bf44266SNate Lawson 
1091bf44266SNate Lawson static int
1101bf44266SNate Lawson aq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match)
1111bf44266SNate Lawson {
1121bf44266SNate Lawson     int result;
1131bf44266SNate Lawson 
1141bf44266SNate Lawson     result = FALSE;
1151bf44266SNate Lawson     switch (match->val) {
1161bf44266SNate Lawson     case OEM:
1171bf44266SNate Lawson 	if (aq_strcmp(hdr->OemId, match->x.id) &&
1181bf44266SNate Lawson 	    aq_strcmp(hdr->OemTableId, match->y.tid))
1191bf44266SNate Lawson 	    result = TRUE;
1201bf44266SNate Lawson 	break;
1211bf44266SNate Lawson     case CREATOR:
1221bf44266SNate Lawson 	if (aq_strcmp(hdr->AslCompilerId, match->x.id))
1231bf44266SNate Lawson 	    result = TRUE;
1241bf44266SNate Lawson 	break;
1251bf44266SNate Lawson     case OEM_REV:
1261bf44266SNate Lawson 	if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev))
1271bf44266SNate Lawson 	    result = TRUE;
1281bf44266SNate Lawson 	break;
1291bf44266SNate Lawson     case CREATOR_REV:
1301bf44266SNate Lawson 	if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev))
1311bf44266SNate Lawson 	    result = TRUE;
1321bf44266SNate Lawson 	break;
1331bf44266SNate Lawson     }
1341bf44266SNate Lawson 
1351bf44266SNate Lawson     return (result);
1361bf44266SNate Lawson }
1371bf44266SNate Lawson 
1381bf44266SNate Lawson int
1391bf44266SNate Lawson acpi_table_quirks(int *quirks)
1401bf44266SNate Lawson {
1411bf44266SNate Lawson     const struct acpi_q_entry *entry;
1421bf44266SNate Lawson     const struct acpi_q_rule *match;
1431bf44266SNate Lawson     ACPI_TABLE_HEADER *hdr;
1441bf44266SNate Lawson     int done;
1451bf44266SNate Lawson 
1461bf44266SNate Lawson     /* First, allow the machdep system to set its idea of quirks. */
1471bf44266SNate Lawson     KASSERT(quirks != NULL, ("acpi quirks ptr is NULL"));
1481bf44266SNate Lawson     acpi_machdep_quirks(quirks);
1491bf44266SNate Lawson 
1501bf44266SNate Lawson     /* Then, override the quirks with any matched from table signatures. */
1511bf44266SNate Lawson     for (entry = acpi_quirks_table; entry->match; entry++) {
1521bf44266SNate Lawson 	done = TRUE;
1531bf44266SNate Lawson 	for (match = entry->match; match->sig != ACPI_TABLE_END; match++) {
1541bf44266SNate Lawson 	    switch (match->sig) {
1551bf44266SNate Lawson 	    case ACPI_TABLE_FADT:
1561bf44266SNate Lawson 		hdr = (ACPI_TABLE_HEADER *)AcpiGbl_FADT;
1571bf44266SNate Lawson 		break;
1581bf44266SNate Lawson 	    case ACPI_TABLE_DSDT:
1591bf44266SNate Lawson 		hdr = (ACPI_TABLE_HEADER *)AcpiGbl_DSDT;
1601bf44266SNate Lawson 		break;
1611bf44266SNate Lawson 	    case ACPI_TABLE_XSDT:
1621bf44266SNate Lawson 		hdr = (ACPI_TABLE_HEADER *)AcpiGbl_XSDT;
1631bf44266SNate Lawson 		break;
1641bf44266SNate Lawson 	    default:
1651bf44266SNate Lawson 		panic("invalid quirk header\n");
1661bf44266SNate Lawson 	    }
1671bf44266SNate Lawson 
1681bf44266SNate Lawson 	    /* If we don't match any, skip to the next entry. */
1691bf44266SNate Lawson 	    if (!aq_match_header(hdr, match)) {
1701bf44266SNate Lawson 		done = FALSE;
1711bf44266SNate Lawson 		break;
1721bf44266SNate Lawson 	    }
1731bf44266SNate Lawson 	}
1741bf44266SNate Lawson 
1751bf44266SNate Lawson 	/* If all entries matched, update the quirks and return. */
1761bf44266SNate Lawson 	if (done) {
1771bf44266SNate Lawson 	    *quirks = entry->quirks;
1781bf44266SNate Lawson 	    break;
1791bf44266SNate Lawson 	}
1801bf44266SNate Lawson     }
1811bf44266SNate Lawson 
1821bf44266SNate Lawson     return (0);
1831bf44266SNate Lawson }
184