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