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$"); 29148318Snjl 30131313Snjl#include <sys/param.h> 31131313Snjl#include <sys/bus.h> 32131313Snjl 33193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 34193530Sjkim 35131313Snjl#include <dev/acpica/acpivar.h> 36131313Snjl 37131313Snjlenum ops_t { 38131313Snjl OP_NONE, 39131313Snjl OP_LEQ, 40131313Snjl OP_GEQ, 41131313Snjl OP_EQL, 42131313Snjl}; 43131313Snjl 44131313Snjlenum val_t { 45131313Snjl OEM, 46131313Snjl OEM_REV, 47131313Snjl CREATOR, 48131313Snjl CREATOR_REV, 49131313Snjl}; 50131313Snjl 51131313Snjlstruct acpi_q_rule { 52167814Sjkim char sig[ACPI_NAME_SIZE]; /* Table signature to match */ 53131313Snjl enum val_t val; 54131313Snjl union { 55131313Snjl char *id; 56131313Snjl enum ops_t op; 57131313Snjl } x; 58131313Snjl union { 59131313Snjl char *tid; 60131313Snjl int rev; 61131313Snjl } y; 62131313Snjl}; 63131313Snjl 64131313Snjlstruct acpi_q_entry { 65131313Snjl const struct acpi_q_rule *match; 66131313Snjl int quirks; 67131313Snjl}; 68131313Snjl 69131313Snjl#include "acpi_quirks.h" 70131313Snjl 71131313Snjlstatic int aq_revcmp(int revision, enum ops_t op, int value); 72131313Snjlstatic int aq_strcmp(char *actual, char *possible); 73131313Snjlstatic int aq_match_header(ACPI_TABLE_HEADER *hdr, 74131313Snjl const struct acpi_q_rule *match); 75131313Snjl 76131313Snjlstatic int 77131313Snjlaq_revcmp(int revision, enum ops_t op, int value) 78131313Snjl{ 79131313Snjl switch (op) { 80131313Snjl case OP_LEQ: 81131313Snjl if (revision <= value) 82131313Snjl return (TRUE); 83131313Snjl break; 84131313Snjl case OP_GEQ: 85131313Snjl if (revision >= value) 86131313Snjl return (TRUE); 87131313Snjl break; 88131313Snjl case OP_EQL: 89131313Snjl if (revision == value) 90131313Snjl return (TRUE); 91131313Snjl break; 92131313Snjl case OP_NONE: 93131313Snjl return (TRUE); 94131313Snjl default: 95131313Snjl panic("aq_revcmp: invalid op %d", op); 96131313Snjl } 97131313Snjl 98131313Snjl return (FALSE); 99131313Snjl} 100131313Snjl 101131313Snjlstatic int 102131313Snjlaq_strcmp(char *actual, char *possible) 103131313Snjl{ 104131313Snjl if (actual == NULL || possible == NULL) 105131313Snjl return (TRUE); 106131313Snjl return (strncmp(actual, possible, strlen(possible)) == 0); 107131313Snjl} 108131313Snjl 109131313Snjlstatic int 110131313Snjlaq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match) 111131313Snjl{ 112131313Snjl int result; 113131313Snjl 114131313Snjl result = FALSE; 115131313Snjl switch (match->val) { 116131313Snjl case OEM: 117131313Snjl if (aq_strcmp(hdr->OemId, match->x.id) && 118131313Snjl aq_strcmp(hdr->OemTableId, match->y.tid)) 119131313Snjl result = TRUE; 120131313Snjl break; 121131313Snjl case CREATOR: 122131313Snjl if (aq_strcmp(hdr->AslCompilerId, match->x.id)) 123131313Snjl result = TRUE; 124131313Snjl break; 125131313Snjl case OEM_REV: 126131313Snjl if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev)) 127131313Snjl result = TRUE; 128131313Snjl break; 129131313Snjl case CREATOR_REV: 130131313Snjl if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev)) 131131313Snjl result = TRUE; 132131313Snjl break; 133131313Snjl } 134131313Snjl 135131313Snjl return (result); 136131313Snjl} 137131313Snjl 138131313Snjlint 139131313Snjlacpi_table_quirks(int *quirks) 140131313Snjl{ 141131313Snjl const struct acpi_q_entry *entry; 142131313Snjl const struct acpi_q_rule *match; 143167814Sjkim ACPI_TABLE_HEADER fadt, dsdt, xsdt, *hdr; 144131313Snjl int done; 145131313Snjl 146131313Snjl /* First, allow the machdep system to set its idea of quirks. */ 147131313Snjl KASSERT(quirks != NULL, ("acpi quirks ptr is NULL")); 148131313Snjl acpi_machdep_quirks(quirks); 149131313Snjl 150167814Sjkim if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_FADT, 0, &fadt))) 151167814Sjkim bzero(&fadt, sizeof(fadt)); 152167814Sjkim if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &dsdt))) 153183190Sjkim bzero(&dsdt, sizeof(dsdt)); 154167814Sjkim if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_XSDT, 0, &xsdt))) 155183190Sjkim bzero(&xsdt, sizeof(xsdt)); 156167814Sjkim 157131313Snjl /* Then, override the quirks with any matched from table signatures. */ 158131313Snjl for (entry = acpi_quirks_table; entry->match; entry++) { 159131313Snjl done = TRUE; 160167814Sjkim for (match = entry->match; match->sig[0] != '\0'; match++) { 161167814Sjkim if (!strncmp(match->sig, "FADT", ACPI_NAME_SIZE)) 162167814Sjkim hdr = &fadt; 163167814Sjkim else if (!strncmp(match->sig, ACPI_SIG_DSDT, ACPI_NAME_SIZE)) 164167814Sjkim hdr = &dsdt; 165167814Sjkim else if (!strncmp(match->sig, ACPI_SIG_XSDT, ACPI_NAME_SIZE)) 166167814Sjkim hdr = &xsdt; 167167814Sjkim else 168131313Snjl panic("invalid quirk header\n"); 169131313Snjl 170131313Snjl /* If we don't match any, skip to the next entry. */ 171167814Sjkim if (aq_match_header(hdr, match) == FALSE) { 172131313Snjl done = FALSE; 173131313Snjl break; 174131313Snjl } 175131313Snjl } 176131313Snjl 177131313Snjl /* If all entries matched, update the quirks and return. */ 178131313Snjl if (done) { 179131313Snjl *quirks = entry->quirks; 180131313Snjl break; 181131313Snjl } 182131313Snjl } 183131313Snjl 184131313Snjl return (0); 185131313Snjl} 186