acpi_quirk.c revision 183190
1131313Snjl/*-
2131313Snjl * Copyright (c) 2004 Nate Lawson (SDG)
3131313Snjl * All rights reserved.
4131313Snjl *
5131313Snjl * Redistribution and use in source and binary forms, with or without
6131313Snjl * modification, are permitted provided that the following conditions
7131313Snjl * are met:
8131313Snjl * 1. Redistributions of source code must retain the above copyright
9131313Snjl *    notice, this list of conditions and the following disclaimer.
10131313Snjl * 2. Redistributions in binary form must reproduce the above copyright
11131313Snjl *    notice, this list of conditions and the following disclaimer in the
12131313Snjl *    documentation and/or other materials provided with the distribution.
13131313Snjl *
14131313Snjl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15131313Snjl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16131313Snjl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17131313Snjl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18131313Snjl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19131313Snjl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20131313Snjl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21131313Snjl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22131313Snjl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23131313Snjl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24131313Snjl * SUCH DAMAGE.
25131313Snjl */
26131313Snjl
27148318Snjl#include <sys/cdefs.h>
28148318Snjl__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_quirk.c 183190 2008-09-19 15:25:13Z jkim $");
29148318Snjl
30131313Snjl#include <sys/param.h>
31131313Snjl#include <sys/bus.h>
32131313Snjl
33150003Sobrien#include <contrib/dev/acpica/acpi.h>
34131313Snjl#include <dev/acpica/acpivar.h>
35131313Snjl
36131313Snjlenum ops_t {
37131313Snjl	OP_NONE,
38131313Snjl	OP_LEQ,
39131313Snjl	OP_GEQ,
40131313Snjl	OP_EQL,
41131313Snjl};
42131313Snjl
43131313Snjlenum val_t {
44131313Snjl	OEM,
45131313Snjl	OEM_REV,
46131313Snjl	CREATOR,
47131313Snjl	CREATOR_REV,
48131313Snjl};
49131313Snjl
50131313Snjlstruct acpi_q_rule {
51167814Sjkim    char	sig[ACPI_NAME_SIZE];	/* Table signature to match */
52131313Snjl    enum val_t	val;
53131313Snjl    union {
54131313Snjl	char	*id;
55131313Snjl	enum ops_t op;
56131313Snjl    } x;
57131313Snjl    union {
58131313Snjl	char	*tid;
59131313Snjl	int	rev;
60131313Snjl    } y;
61131313Snjl};
62131313Snjl
63131313Snjlstruct acpi_q_entry {
64131313Snjl    const struct acpi_q_rule *match;
65131313Snjl    int		quirks;
66131313Snjl};
67131313Snjl
68131313Snjl#include "acpi_quirks.h"
69131313Snjl
70131313Snjlstatic int	aq_revcmp(int revision, enum ops_t op, int value);
71131313Snjlstatic int	aq_strcmp(char *actual, char *possible);
72131313Snjlstatic int	aq_match_header(ACPI_TABLE_HEADER *hdr,
73131313Snjl		    const struct acpi_q_rule *match);
74131313Snjl
75131313Snjlstatic int
76131313Snjlaq_revcmp(int revision, enum ops_t op, int value)
77131313Snjl{
78131313Snjl    switch (op) {
79131313Snjl    case OP_LEQ:
80131313Snjl	if (revision <= value)
81131313Snjl	    return (TRUE);
82131313Snjl	break;
83131313Snjl    case OP_GEQ:
84131313Snjl	if (revision >= value)
85131313Snjl	    return (TRUE);
86131313Snjl	break;
87131313Snjl    case OP_EQL:
88131313Snjl	if (revision == value)
89131313Snjl	    return (TRUE);
90131313Snjl	break;
91131313Snjl    case OP_NONE:
92131313Snjl	return (TRUE);
93131313Snjl    default:
94131313Snjl	panic("aq_revcmp: invalid op %d", op);
95131313Snjl    }
96131313Snjl
97131313Snjl    return (FALSE);
98131313Snjl}
99131313Snjl
100131313Snjlstatic int
101131313Snjlaq_strcmp(char *actual, char *possible)
102131313Snjl{
103131313Snjl    if (actual == NULL || possible == NULL)
104131313Snjl	return (TRUE);
105131313Snjl    return (strncmp(actual, possible, strlen(possible)) == 0);
106131313Snjl}
107131313Snjl
108131313Snjlstatic int
109131313Snjlaq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match)
110131313Snjl{
111131313Snjl    int result;
112131313Snjl
113131313Snjl    result = FALSE;
114131313Snjl    switch (match->val) {
115131313Snjl    case OEM:
116131313Snjl	if (aq_strcmp(hdr->OemId, match->x.id) &&
117131313Snjl	    aq_strcmp(hdr->OemTableId, match->y.tid))
118131313Snjl	    result = TRUE;
119131313Snjl	break;
120131313Snjl    case CREATOR:
121131313Snjl	if (aq_strcmp(hdr->AslCompilerId, match->x.id))
122131313Snjl	    result = TRUE;
123131313Snjl	break;
124131313Snjl    case OEM_REV:
125131313Snjl	if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev))
126131313Snjl	    result = TRUE;
127131313Snjl	break;
128131313Snjl    case CREATOR_REV:
129131313Snjl	if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev))
130131313Snjl	    result = TRUE;
131131313Snjl	break;
132131313Snjl    }
133131313Snjl
134131313Snjl    return (result);
135131313Snjl}
136131313Snjl
137131313Snjlint
138131313Snjlacpi_table_quirks(int *quirks)
139131313Snjl{
140131313Snjl    const struct acpi_q_entry *entry;
141131313Snjl    const struct acpi_q_rule *match;
142167814Sjkim    ACPI_TABLE_HEADER fadt, dsdt, xsdt, *hdr;
143131313Snjl    int done;
144131313Snjl
145131313Snjl    /* First, allow the machdep system to set its idea of quirks. */
146131313Snjl    KASSERT(quirks != NULL, ("acpi quirks ptr is NULL"));
147131313Snjl    acpi_machdep_quirks(quirks);
148131313Snjl
149167814Sjkim    if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_FADT, 0, &fadt)))
150167814Sjkim	bzero(&fadt, sizeof(fadt));
151167814Sjkim    if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &dsdt)))
152183190Sjkim	bzero(&dsdt, sizeof(dsdt));
153167814Sjkim    if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_XSDT, 0, &xsdt)))
154183190Sjkim	bzero(&xsdt, sizeof(xsdt));
155167814Sjkim
156131313Snjl    /* Then, override the quirks with any matched from table signatures. */
157131313Snjl    for (entry = acpi_quirks_table; entry->match; entry++) {
158131313Snjl	done = TRUE;
159167814Sjkim	for (match = entry->match; match->sig[0] != '\0'; match++) {
160167814Sjkim	    if (!strncmp(match->sig, "FADT", ACPI_NAME_SIZE))
161167814Sjkim		hdr = &fadt;
162167814Sjkim	    else if (!strncmp(match->sig, ACPI_SIG_DSDT, ACPI_NAME_SIZE))
163167814Sjkim		hdr = &dsdt;
164167814Sjkim	    else if (!strncmp(match->sig, ACPI_SIG_XSDT, ACPI_NAME_SIZE))
165167814Sjkim		hdr = &xsdt;
166167814Sjkim	    else
167131313Snjl		panic("invalid quirk header\n");
168131313Snjl
169131313Snjl	    /* If we don't match any, skip to the next entry. */
170167814Sjkim	    if (aq_match_header(hdr, match) == FALSE) {
171131313Snjl		done = FALSE;
172131313Snjl		break;
173131313Snjl	    }
174131313Snjl	}
175131313Snjl
176131313Snjl	/* If all entries matched, update the quirks and return. */
177131313Snjl	if (done) {
178131313Snjl	    *quirks = entry->quirks;
179131313Snjl	    break;
180131313Snjl	}
181131313Snjl    }
182131313Snjl
183131313Snjl    return (0);
184131313Snjl}
185