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