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