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 {
49*278f0de6SJung-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++) {
158*278f0de6SJung-uk Kim if (!strncmp(match->sig, "FADT", ACPI_NAMESEG_SIZE))
1592be4e471SJung-uk Kim hdr = &fadt;
160*278f0de6SJung-uk Kim else if (!strncmp(match->sig, ACPI_SIG_DSDT, ACPI_NAMESEG_SIZE))
1612be4e471SJung-uk Kim hdr = &dsdt;
162*278f0de6SJung-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