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