1d2fa5f95SSascha Wildner /*-
2d2fa5f95SSascha Wildner * Copyright (c) 2004 Nate Lawson (SDG)
3d2fa5f95SSascha Wildner * All rights reserved.
4d2fa5f95SSascha Wildner *
5d2fa5f95SSascha Wildner * Redistribution and use in source and binary forms, with or without
6d2fa5f95SSascha Wildner * modification, are permitted provided that the following conditions
7d2fa5f95SSascha Wildner * are met:
8d2fa5f95SSascha Wildner * 1. Redistributions of source code must retain the above copyright
9d2fa5f95SSascha Wildner * notice, this list of conditions and the following disclaimer.
10d2fa5f95SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
11d2fa5f95SSascha Wildner * notice, this list of conditions and the following disclaimer in the
12d2fa5f95SSascha Wildner * documentation and/or other materials provided with the distribution.
13d2fa5f95SSascha Wildner *
14d2fa5f95SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15d2fa5f95SSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16d2fa5f95SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17d2fa5f95SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18d2fa5f95SSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19d2fa5f95SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20d2fa5f95SSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21d2fa5f95SSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22d2fa5f95SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23d2fa5f95SSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24d2fa5f95SSascha Wildner * SUCH DAMAGE.
25d2fa5f95SSascha Wildner *
26d2fa5f95SSascha Wildner * $FreeBSD: head/sys/dev/acpica/acpi_quirk.c 193530 2009-06-05 18:44:36Z jkim $
27d2fa5f95SSascha Wildner */
28d2fa5f95SSascha Wildner
29d2fa5f95SSascha Wildner #include <sys/param.h>
30d2fa5f95SSascha Wildner #include <sys/bus.h>
31d2fa5f95SSascha Wildner
32d2fa5f95SSascha Wildner #include <contrib/dev/acpica/source/include/acpi.h>
33d2fa5f95SSascha Wildner
34d2fa5f95SSascha Wildner #include <dev/acpica/acpivar.h>
35d2fa5f95SSascha Wildner
36d2fa5f95SSascha Wildner enum ops_t {
37d2fa5f95SSascha Wildner OP_NONE,
38d2fa5f95SSascha Wildner OP_LEQ,
39d2fa5f95SSascha Wildner OP_GEQ,
40d2fa5f95SSascha Wildner OP_EQL,
41d2fa5f95SSascha Wildner };
42d2fa5f95SSascha Wildner
43d2fa5f95SSascha Wildner enum val_t {
44d2fa5f95SSascha Wildner OEM,
45d2fa5f95SSascha Wildner OEM_REV,
46d2fa5f95SSascha Wildner CREATOR,
47d2fa5f95SSascha Wildner CREATOR_REV,
48d2fa5f95SSascha Wildner };
49d2fa5f95SSascha Wildner
50d2fa5f95SSascha Wildner struct acpi_q_rule {
51*c1776041SSascha Wildner char sig[ACPI_NAMESEG_SIZE]; /* Table signature to match */
52d2fa5f95SSascha Wildner enum val_t val;
53d2fa5f95SSascha Wildner union {
54d2fa5f95SSascha Wildner char *id;
55d2fa5f95SSascha Wildner enum ops_t op;
56d2fa5f95SSascha Wildner } x;
57d2fa5f95SSascha Wildner union {
58d2fa5f95SSascha Wildner char *tid;
59d2fa5f95SSascha Wildner int rev;
60d2fa5f95SSascha Wildner } y;
61d2fa5f95SSascha Wildner };
62d2fa5f95SSascha Wildner
63d2fa5f95SSascha Wildner struct acpi_q_entry {
64d2fa5f95SSascha Wildner const struct acpi_q_rule *match;
65d2fa5f95SSascha Wildner int quirks;
66d2fa5f95SSascha Wildner };
67d2fa5f95SSascha Wildner
68d2fa5f95SSascha Wildner #include "acpi_quirks.h"
69d2fa5f95SSascha Wildner
70d2fa5f95SSascha Wildner static int aq_revcmp(int revision, enum ops_t op, int value);
71d2fa5f95SSascha Wildner static int aq_strcmp(char *actual, char *possible);
72d2fa5f95SSascha Wildner static int aq_match_header(ACPI_TABLE_HEADER *hdr,
73d2fa5f95SSascha Wildner const struct acpi_q_rule *match);
74d2fa5f95SSascha Wildner
75d2fa5f95SSascha Wildner static int
aq_revcmp(int revision,enum ops_t op,int value)76d2fa5f95SSascha Wildner aq_revcmp(int revision, enum ops_t op, int value)
77d2fa5f95SSascha Wildner {
78d2fa5f95SSascha Wildner switch (op) {
79d2fa5f95SSascha Wildner case OP_LEQ:
80d2fa5f95SSascha Wildner if (revision <= value)
81d2fa5f95SSascha Wildner return (TRUE);
82d2fa5f95SSascha Wildner break;
83d2fa5f95SSascha Wildner case OP_GEQ:
84d2fa5f95SSascha Wildner if (revision >= value)
85d2fa5f95SSascha Wildner return (TRUE);
86d2fa5f95SSascha Wildner break;
87d2fa5f95SSascha Wildner case OP_EQL:
88d2fa5f95SSascha Wildner if (revision == value)
89d2fa5f95SSascha Wildner return (TRUE);
90d2fa5f95SSascha Wildner break;
91d2fa5f95SSascha Wildner case OP_NONE:
92d2fa5f95SSascha Wildner return (TRUE);
93d2fa5f95SSascha Wildner default:
94d2fa5f95SSascha Wildner panic("aq_revcmp: invalid op %d", op);
95d2fa5f95SSascha Wildner }
96d2fa5f95SSascha Wildner
97d2fa5f95SSascha Wildner return (FALSE);
98d2fa5f95SSascha Wildner }
99d2fa5f95SSascha Wildner
100d2fa5f95SSascha Wildner static int
aq_strcmp(char * actual,char * possible)101d2fa5f95SSascha Wildner aq_strcmp(char *actual, char *possible)
102d2fa5f95SSascha Wildner {
103d2fa5f95SSascha Wildner if (actual == NULL || possible == NULL)
104d2fa5f95SSascha Wildner return (TRUE);
105d2fa5f95SSascha Wildner return (strncmp(actual, possible, strlen(possible)) == 0);
106d2fa5f95SSascha Wildner }
107d2fa5f95SSascha Wildner
108d2fa5f95SSascha Wildner static int
aq_match_header(ACPI_TABLE_HEADER * hdr,const struct acpi_q_rule * match)109d2fa5f95SSascha Wildner aq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match)
110d2fa5f95SSascha Wildner {
111d2fa5f95SSascha Wildner int result;
112d2fa5f95SSascha Wildner
113d2fa5f95SSascha Wildner result = FALSE;
114d2fa5f95SSascha Wildner switch (match->val) {
115d2fa5f95SSascha Wildner case OEM:
116d2fa5f95SSascha Wildner if (aq_strcmp(hdr->OemId, match->x.id) &&
117d2fa5f95SSascha Wildner aq_strcmp(hdr->OemTableId, match->y.tid))
118d2fa5f95SSascha Wildner result = TRUE;
119d2fa5f95SSascha Wildner break;
120d2fa5f95SSascha Wildner case CREATOR:
121d2fa5f95SSascha Wildner if (aq_strcmp(hdr->AslCompilerId, match->x.id))
122d2fa5f95SSascha Wildner result = TRUE;
123d2fa5f95SSascha Wildner break;
124d2fa5f95SSascha Wildner case OEM_REV:
125d2fa5f95SSascha Wildner if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev))
126d2fa5f95SSascha Wildner result = TRUE;
127d2fa5f95SSascha Wildner break;
128d2fa5f95SSascha Wildner case CREATOR_REV:
129d2fa5f95SSascha Wildner if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev))
130d2fa5f95SSascha Wildner result = TRUE;
131d2fa5f95SSascha Wildner break;
132d2fa5f95SSascha Wildner }
133d2fa5f95SSascha Wildner
134d2fa5f95SSascha Wildner return (result);
135d2fa5f95SSascha Wildner }
136d2fa5f95SSascha Wildner
137d2fa5f95SSascha Wildner int
acpi_table_quirks(int * quirks)138d2fa5f95SSascha Wildner acpi_table_quirks(int *quirks)
139d2fa5f95SSascha Wildner {
140d2fa5f95SSascha Wildner const struct acpi_q_entry *entry;
141d2fa5f95SSascha Wildner const struct acpi_q_rule *match;
142d2fa5f95SSascha Wildner ACPI_TABLE_HEADER fadt, dsdt, xsdt, *hdr;
143d2fa5f95SSascha Wildner int done;
144d2fa5f95SSascha Wildner
145d2fa5f95SSascha Wildner /* First, allow the machdep system to set its idea of quirks. */
146d2fa5f95SSascha Wildner KASSERT(quirks != NULL, ("acpi quirks ptr is NULL"));
147d2fa5f95SSascha Wildner acpi_machdep_quirks(quirks);
148d2fa5f95SSascha Wildner
149d2fa5f95SSascha Wildner if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_FADT, 0, &fadt)))
150d2fa5f95SSascha Wildner bzero(&fadt, sizeof(fadt));
151d2fa5f95SSascha Wildner if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &dsdt)))
152d2fa5f95SSascha Wildner bzero(&dsdt, sizeof(dsdt));
153d2fa5f95SSascha Wildner if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_XSDT, 0, &xsdt)))
154d2fa5f95SSascha Wildner bzero(&xsdt, sizeof(xsdt));
155d2fa5f95SSascha Wildner
156d2fa5f95SSascha Wildner /* Then, override the quirks with any matched from table signatures. */
157d2fa5f95SSascha Wildner for (entry = acpi_quirks_table; entry->match; entry++) {
158d2fa5f95SSascha Wildner done = TRUE;
159d2fa5f95SSascha Wildner for (match = entry->match; match->sig[0] != '\0'; match++) {
160*c1776041SSascha Wildner if (ACPI_COMPARE_NAMESEG(match->sig, "FADT"))
161d2fa5f95SSascha Wildner hdr = &fadt;
162*c1776041SSascha Wildner else if (ACPI_COMPARE_NAMESEG(match->sig, ACPI_SIG_DSDT))
163d2fa5f95SSascha Wildner hdr = &dsdt;
164*c1776041SSascha Wildner else if (ACPI_COMPARE_NAMESEG(match->sig, ACPI_SIG_XSDT))
165d2fa5f95SSascha Wildner hdr = &xsdt;
166d2fa5f95SSascha Wildner else
167d2fa5f95SSascha Wildner panic("invalid quirk header\n");
168d2fa5f95SSascha Wildner
169d2fa5f95SSascha Wildner /* If we don't match any, skip to the next entry. */
170d2fa5f95SSascha Wildner if (aq_match_header(hdr, match) == FALSE) {
171d2fa5f95SSascha Wildner done = FALSE;
172d2fa5f95SSascha Wildner break;
173d2fa5f95SSascha Wildner }
174d2fa5f95SSascha Wildner }
175d2fa5f95SSascha Wildner
176d2fa5f95SSascha Wildner /* If all entries matched, update the quirks and return. */
177d2fa5f95SSascha Wildner if (done) {
178d2fa5f95SSascha Wildner *quirks = entry->quirks;
179d2fa5f95SSascha Wildner break;
180d2fa5f95SSascha Wildner }
181d2fa5f95SSascha Wildner }
182d2fa5f95SSascha Wildner
183d2fa5f95SSascha Wildner return (0);
184d2fa5f95SSascha Wildner }
185