xref: /dflybsd-src/sys/dev/acpica/acpi_quirk.c (revision c1776041a2158922a67a1e8cab23c87d637a0572)
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