From 909278c8d9fabad18a78379bd4fbf1d8d3a4bbc3 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Tue, 13 May 2014 04:44:18 +0200
Subject: [PATCH 2/2] WIP ACPI quirks from FreeBSD.

---
 sys/conf/files                          |   6 +
 sys/conf/kmod.mk                        |  10 +
 sys/dev/acpica/Makefile                 |   5 +-
 sys/dev/acpica/acpi.c                   |   3 +-
 sys/dev/acpica/acpi_quirk.c             | 185 ++++++++++++
 sys/dev/acpica/acpi_quirks              | 497 ++++++++++++++++++++++++++++++++
 sys/dev/acpica/acpi_timer.c             |   3 +-
 sys/platform/pc32/acpica/acpi_machdep.c |  21 ++
 sys/platform/pc32/acpica/acpi_madt.c    |   9 +
 sys/platform/pc64/acpica/acpi_machdep.c |   7 +
 sys/platform/pc64/acpica/acpi_madt.c    |   9 +
 sys/tools/acpi_quirks2h.awk             | 187 ++++++++++++
 12 files changed, 937 insertions(+), 5 deletions(-)
 create mode 100644 sys/dev/acpica/acpi_quirk.c
 create mode 100644 sys/dev/acpica/acpi_quirks
 create mode 100644 sys/tools/acpi_quirks2h.awk

diff --git a/sys/conf/files b/sys/conf/files
index 2f4d630..d316f81 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4,6 +4,11 @@
 # limitations in config: backslash-newline doesn't work in strings, and
 # dependency lines other than the first are silently ignored.
 #
+acpi_quirks.h			optional acpi				   \
+	dependency	"$S/tools/acpi_quirks2h.awk $S/dev/acpica/acpi_quirks" \
+	compile-with	"${AWK} -f $S/tools/acpi_quirks2h.awk $S/dev/acpica/acpi_quirks" \
+	no-obj no-implicit-rule before-depend				   \
+	clean		"acpi_quirks.h"
 aicasm.nx			optional ahc				   \
 	dependency 	"$S/dev/disk/aic7xxx/aicasm/*.[chyl]"		   \
 	compile-with	"${MAKE} -f $S/dev/disk/aic7xxx/aicasm/Makefile MAKESRCPATH=$S/dev/disk/aic7xxx/aicasm" \
@@ -2053,6 +2058,7 @@ ${OSACPI_MI_DIR}/acpi_pcib.c		optional acpi pci
 ${OSACPI_MI_DIR}/acpi_pcib_acpi.c	optional acpi pci
 ${OSACPI_MI_DIR}/acpi_pcib_pci.c	optional acpi pci
 ${OSACPI_MI_DIR}/acpi_powerres.c	optional acpi
+${OSACPI_MI_DIR}/acpi_quirk.c		optional acpi
 ${OSACPI_MI_DIR}/acpi_resource.c	optional acpi
 ${OSACPI_MI_DIR}/acpi_smbat.c		optional acpi
 ${OSACPI_MI_DIR}/acpi_thermal.c		optional acpi
diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk
index 2e605c7..d9b1bf4 100644
--- a/sys/conf/kmod.mk
+++ b/sys/conf/kmod.mk
@@ -399,6 +399,16 @@ usbdevs_data.h: @/tools/usbdevs2h.awk @/bus/u4b/usbdevs
 	${AWK} -f @/tools/usbdevs2h.awk @/bus/u4b/usbdevs -d
 .endif
 
+.if !empty(SRCS:Macpi_quirks.h)
+CLEANFILES+=	acpi_quirks.h
+.if !exists(@)
+acpi_quirks.h: @
+.else
+acpi_quirks.h: @/tools/acpi_quirks2h.awk @/dev/acpica/acpi_quirks
+.endif
+	${AWK} -f @/tools/acpi_quirks2h.awk @/dev/acpica/acpi_quirks
+.endif
+
 .if !empty(SRCS:Massym.s)
 CLEANFILES+=	assym.s genassym.o
 assym.s: genassym.o
diff --git a/sys/dev/acpica/Makefile b/sys/dev/acpica/Makefile
index bb4308d..ac8a311 100644
--- a/sys/dev/acpica/Makefile
+++ b/sys/dev/acpica/Makefile
@@ -74,13 +74,14 @@ SRCS+=  acpi_package.c
 # The PCI part of ACPI5 doesn't work with the current infrastructure
 SRCS+=	acpi_pci.c acpi_pcib.c acpi_pcib_acpi.c acpi_pcib_pci.c
 SRCS+=	acpi_pci_link.c
-SRCS+=  acpi_powerres.c acpi_resource.c acpi_thermal.c
+SRCS+=  acpi_powerres.c acpi_quirk.c acpi_resource.c acpi_thermal.c
 SRCS+=  acpi_timer.c acpi_hpet.c acpi_if.c acpi_wmi_if.c
 SRCS+=  OsdDebug.c
 SRCS+=  OsdHardware.c OsdInterrupt.c OsdMemory.c OsdSchedule.c
 SRCS+=  OsdStream.c OsdSynch.c OsdTable.c OsdEnvironment.c
 SRCS+=  opt_acpi.h opt_ddb.h
-SRCS+=  device_if.h bus_if.h pci_if.h pcib_if.h isa_if.h acpi_if.h acpi_wmi_if.h
+SRCS+=  device_if.h bus_if.h pci_if.h pcib_if.h isa_if.h acpi_if.h
+SRCS+=  acpi_quirks.h acpi_wmi_if.h
 
 .if ACPI_NO_SEMAPHORES
 CFLAGS+=-DACPI_NO_SEMAPHORES
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 4d15fd0..ca9fdc8 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -88,6 +88,7 @@ static struct dev_ops acpi_ops = {
 
 /* Global mutex for locking access to the ACPI subsystem. */
 struct lock acpi_lock;
+
 /* Bitmap of device quirks. */
 int		acpi_quirks;
 
@@ -302,10 +303,8 @@ acpi_Startup(void)
     }
 
     /* Set up any quirks we have for this system. */
-#ifdef notyet
     if (acpi_quirks == ACPI_Q_OK)
 	acpi_table_quirks(&acpi_quirks);
-#endif
 
     /* If the user manually set the disabled hint to 0, force-enable ACPI. */
     if (resource_int_value("acpi", 0, "disabled", &val) == 0 && val == 0)
diff --git a/sys/dev/acpica/acpi_quirk.c b/sys/dev/acpica/acpi_quirk.c
new file mode 100644
index 0000000..c0e113e
--- /dev/null
+++ b/sys/dev/acpica/acpi_quirk.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2004 Nate Lawson (SDG)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_quirk.c 193530 2009-06-05 18:44:36Z jkim $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <contrib/dev/acpica/source/include/acpi.h>
+
+#include <dev/acpica/acpivar.h>
+
+enum ops_t {
+	OP_NONE,
+	OP_LEQ,
+	OP_GEQ,
+	OP_EQL,
+};
+
+enum val_t {
+	OEM,
+	OEM_REV,
+	CREATOR,
+	CREATOR_REV,
+};
+
+struct acpi_q_rule {
+    char	sig[ACPI_NAME_SIZE];	/* Table signature to match */
+    enum val_t	val;
+    union {
+	char	*id;
+	enum ops_t op;
+    } x;
+    union {
+	char	*tid;
+	int	rev;
+    } y;
+};
+
+struct acpi_q_entry {
+    const struct acpi_q_rule *match;
+    int		quirks;
+};
+
+#include "acpi_quirks.h"
+
+static int	aq_revcmp(int revision, enum ops_t op, int value);
+static int	aq_strcmp(char *actual, char *possible);
+static int	aq_match_header(ACPI_TABLE_HEADER *hdr,
+		    const struct acpi_q_rule *match);
+
+static int
+aq_revcmp(int revision, enum ops_t op, int value)
+{
+    switch (op) {
+    case OP_LEQ:
+	if (revision <= value)
+	    return (TRUE);
+	break;
+    case OP_GEQ:
+	if (revision >= value)
+	    return (TRUE);
+	break;
+    case OP_EQL:
+	if (revision == value)
+	    return (TRUE);
+	break;
+    case OP_NONE:
+	return (TRUE);
+    default:
+	panic("aq_revcmp: invalid op %d", op);
+    }
+
+    return (FALSE);
+}
+
+static int
+aq_strcmp(char *actual, char *possible)
+{
+    if (actual == NULL || possible == NULL)
+	return (TRUE);
+    return (strncmp(actual, possible, strlen(possible)) == 0);
+}
+
+static int
+aq_match_header(ACPI_TABLE_HEADER *hdr, const struct acpi_q_rule *match)
+{
+    int result;
+
+    result = FALSE;
+    switch (match->val) {
+    case OEM:
+	if (aq_strcmp(hdr->OemId, match->x.id) &&
+	    aq_strcmp(hdr->OemTableId, match->y.tid))
+	    result = TRUE;
+	break;
+    case CREATOR:
+	if (aq_strcmp(hdr->AslCompilerId, match->x.id))
+	    result = TRUE;
+	break;
+    case OEM_REV:
+	if (aq_revcmp(hdr->OemRevision, match->x.op, match->y.rev))
+	    result = TRUE;
+	break;
+    case CREATOR_REV:
+	if (aq_revcmp(hdr->AslCompilerRevision, match->x.op, match->y.rev))
+	    result = TRUE;
+	break;
+    }
+
+    return (result);
+}
+
+int
+acpi_table_quirks(int *quirks)
+{
+    const struct acpi_q_entry *entry;
+    const struct acpi_q_rule *match;
+    ACPI_TABLE_HEADER fadt, dsdt, xsdt, *hdr;
+    int done;
+
+    /* First, allow the machdep system to set its idea of quirks. */
+    KASSERT(quirks != NULL, ("acpi quirks ptr is NULL"));
+    acpi_machdep_quirks(quirks);
+
+    if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_FADT, 0, &fadt)))
+	bzero(&fadt, sizeof(fadt));
+    if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &dsdt)))
+	bzero(&dsdt, sizeof(dsdt));
+    if (ACPI_FAILURE(AcpiGetTableHeader(ACPI_SIG_XSDT, 0, &xsdt)))
+	bzero(&xsdt, sizeof(xsdt));
+
+    /* Then, override the quirks with any matched from table signatures. */
+    for (entry = acpi_quirks_table; entry->match; entry++) {
+	done = TRUE;
+	for (match = entry->match; match->sig[0] != '\0'; match++) {
+	    if (!strncmp(match->sig, "FADT", ACPI_NAME_SIZE))
+		hdr = &fadt;
+	    else if (!strncmp(match->sig, ACPI_SIG_DSDT, ACPI_NAME_SIZE))
+		hdr = &dsdt;
+	    else if (!strncmp(match->sig, ACPI_SIG_XSDT, ACPI_NAME_SIZE))
+		hdr = &xsdt;
+	    else
+		panic("invalid quirk header\n");
+
+	    /* If we don't match any, skip to the next entry. */
+	    if (aq_match_header(hdr, match) == FALSE) {
+		done = FALSE;
+		break;
+	    }
+	}
+
+	/* If all entries matched, update the quirks and return. */
+	if (done) {
+	    *quirks = entry->quirks;
+	    break;
+	}
+    }
+
+    return (0);
+}
diff --git a/sys/dev/acpica/acpi_quirks b/sys/dev/acpica/acpi_quirks
new file mode 100644
index 0000000..33e854e
--- /dev/null
+++ b/sys/dev/acpica/acpi_quirks
@@ -0,0 +1,497 @@
+# $FreeBSD: head/sys/dev/acpica/acpi_quirks 147612 2005-06-26 18:19:14Z dwmalone $
+#
+# Quirks for ACPI tables can be added here.
+#
+# Comments start with '#'. Any number of spaces/tabs are ok within a line.
+# Be sure to include a reference to a PR when adding new quirks.  Quirks
+# that do not contain a PR were discovered by reliable sources with no
+# supporting info (i.e., other OS's).
+#
+
+# ABit BP6
+name:		ABit_BP6
+oem:		FADT "AWARD " "AWRDACPI"
+oem_rev:	FADT <= 0x30302e31
+quirks:		ACPI_Q_BROKEN
+
+# AMI INT 01/18/00
+name:		AMI_INT
+oem:		FADT "AMIINT" ""
+oem_rev:	FADT <= 10
+quirks:		ACPI_Q_BROKEN
+
+# ASUS P2B-D
+name:		ASUS_P2B_D
+oem:		FADT "ASUS  " "P2B-D   "
+oem_rev:	FADT <= 0x58582e32
+quirks:		ACPI_Q_BROKEN
+
+# ASUS P2B-F
+name:		ASUS_P2B_F
+oem:		FADT "ASUS  " "P2B-F   "
+oem_rev:	FADT <= 0x58582e31
+quirks:		ACPI_Q_BROKEN
+
+# ASUS P2B-DS 02/03/99
+name:		ASUS_P2B_DS
+oem:		FADT "ASUS  " "P2B-DS  "
+oem_rev:	FADT <= 0x58582e31
+creator_rev:	FADT <= 0x31303030
+quirks:		ACPI_Q_BROKEN
+
+# ASUS P2B-DS 10/21/99
+name:		ASUS_P2B_2
+oem:		FADT "ASUS  " "P2B-DS  "
+oem_rev:	FADT <= 0x58582e32
+creator_rev:	FADT <= 0x31303030
+quirks:		ACPI_Q_BROKEN
+
+# ASUS P2L97-DS 02/02/99
+name:		ASUS_P2L97_DS
+oem:		FADT "ASUS  " "P2L97-DS"
+oem_rev:	FADT <= 0x58582e31
+creator_rev:	FADT <= 0x31303030
+quirks:		ACPI_Q_BROKEN
+
+# ASUS P5A and P5A-B 03/12/99
+# PR:	i386/72450
+# Testing indicates that the ACPI timer runs twice as fast but otherwise
+# this system works normally.
+name:		ASUS_P5A
+oem:		FADT "ASUS  " "P5A     "
+oem_rev:	FADT <= 0x58582e31
+quirks:		ACPI_Q_TIMER
+
+# Compaq Armada 3500
+name:		Compaq_Armada_3500
+oem:		FADT "COMPAQ" "CPQB05E "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Compaq Armada 6500
+name:		Compaq_Armada_6500
+oem:		FADT "PTLTD "  "  FACP  "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Compaq M500
+name:		Compaq_M500
+oem:		FADT "COMPAQ" "CPQB151 "
+oem_rev:	FADT <= 0x19990722
+quirks:		ACPI_Q_BROKEN
+
+# Compaq Panther
+name:		Compaq_Panther
+oem:		FADT "COMPAQ" "PANTHER "
+oem_rev:	FADT <= 1
+creator_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Compaq Presario 1692
+name:		Compaq_Presario_1692
+oem:		FADT "COMPAQ" "VIPER II"
+oem_rev:	FADT <= 0x06040000
+creator:	FADT "PTL "
+creator_rev:	FADT <= 0xF4240
+quirks:		ACPI_Q_BROKEN
+
+# Compaq Presario 1925
+name:		Compaq_Presario_1925
+oem:		FADT "PTLTD " "  FACP  "
+oem_rev:	FADT <= 0x06040000
+quirks:		ACPI_Q_BROKEN
+
+# Compaq R3000Z
+name:		Compaq_R3000Z
+oem:		FADT "NVIDIA" "CK8     "
+oem_rev:	FADT = 0x6040000
+creator:	FADT "PTL_"
+quirks:		ACPI_Q_MADT_IRQ0
+
+# Compaq Thunder 05/18/99
+# XXX Note creator rev should be "=", I think
+name:		Compaq_Thunder
+oem:		FADT "COMPAQ" "THUNDER "
+oem_rev:	FADT <= 1
+creator_rev:	FADT <= 0
+quirks:		ACPI_Q_BROKEN
+
+# Compaq RaceBait 12/06/99
+name:		Compaq_RaceBait
+oem:		FADT "COMPAQ" "RACEBAIT"
+oem_rev:	FADT <= 2
+quirks:		ACPI_Q_BROKEN
+
+# Dell CP??? 01/27/99
+name:		Dell_CPxxx
+oem:		FADT "Dell  " "CP???  "
+oem_rev:	FADT <= 0x27cf011b
+quirks:		ACPI_Q_BROKEN
+
+# Dell CPt
+# XXX Is ">=" correct?
+name:		Dell_CPt
+oem:		FADT "DELL  " "CPt C  "
+oem_rev:	FADT >= 0x27cf090e
+quirks:		ACPI_Q_BROKEN
+
+# Dell CPt A02
+# XXX Is ">=" correct?
+name:		Dell_CPt_A02
+oem:		FADT "DELL  " "CPt C  "
+oem_rev:	FADT >= 0x27cf090f
+quirks:		ACPI_Q_BROKEN
+
+# Dell Latitude LT
+name:		Dell_Latitude_LT
+oem:		FADT "SHARP " "        "
+quirks:		ACPI_Q_BROKEN
+
+# Dell Inspiron 3500
+name:		Dell_Inspiron_3500
+oem:		FADT "Dell  " "I 3500 "
+quirks:		ACPI_Q_BROKEN
+
+# Dell PE1300
+name:		Dell_PE1300
+oem:		FADT "Dell  " "PE1300  "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Dell Personal Workstation 1300
+name:		Dell_PE1300_2
+oem:		FADT "DELL  " "PE1300  "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# FIC PA2013
+name:		FIC_PA2013
+oem:		FADT "FIC   " "PA2013  "
+oem_rev:	FADT <= 0x30302e31
+quirks:		ACPI_Q_BROKEN
+
+# FIC VB601
+name:		FIC_VB601
+oem:		FADT "FIC   " "VB601   "
+oem_rev:	FADT <= 0x30302e31
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu Capricorn
+name:		Fujitsu_Capricorn
+oem:		FADT "FUJ   " "CAPRICOR"
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu M63E
+name:		Fujitsu_M63E
+oem:		FADT "FUJ000" "M63E    "
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu M65
+name:		Fujitsu_M65
+oem:		FADT "FUJ   " "M65     "
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu Sprint
+name:		Fujitsu_Sprint
+oem:		XSDT "FUJ   " "SPRINT  "
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu Tandem
+name:		Fujitsu_Tandem
+oem:		FADT "FUJ   " "TANDEM  "
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu Elm
+name:		Fujitsu_Elm
+oem:		FADT "FUJ   " "M19A/XA "
+oem_rev:	FADT = 1
+creator:	FADT "ACER"
+creator_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu Maple
+name:		Fujitsu_Maple
+oem:		FADT "FUJ   " "M9D     "
+oem_rev:	FADT = 1
+creator:	FADT "ACER"
+creator_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu Sycamore
+name:		Fujitsu_Sycamore
+oem:		FADT "Fuj   " "M11EJ   "
+oem_rev:	FADT = 1
+creator:	FADT "ACER"
+creator_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Fujitsu V66NAS
+name:		Fujitsu_V66NAS
+oem:		FADT "FUJ   " "V66NAS  "
+quirks:		ACPI_Q_BROKEN
+
+# Gateway E1200
+name:		Gateway_E1200
+oem:		FADT "INTEL " "MAUI    "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Gateway E1400
+name:		Gateway_E1400
+oem:		FADT "SUMATR" "SU81010A"
+oem_rev:	FADT <= 0x1999072
+quirks:		ACPI_Q_BROKEN
+
+# Gateway Profile
+name:		Gateway_Profile
+oem:		FADT "GATEWA" "PROFILE "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Gateway Solo
+name:		Gateway_Solo
+oem:		FADT "GATEWA" "SOLO9300"
+oem_rev:	FADT <= 0x06040000
+quirks:		ACPI_Q_BROKEN
+
+# Gigabyte
+name:		Gigabyte_Award
+oem:		FADT "GBT" "AWRDACPI"
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# GA-5AX (Rev 4)
+# Testing indicates that the ACPI timer runs twice as fast but otherwise
+# this system works normally.
+name:		GBT_AWRDACPI
+oem:		FADT "GBT   " "AWRDACPI"
+oem_rev:	FADT <= 0x42302e31
+quirks:		ACPI_Q_TIMER
+
+# Hitachi Flora 220CX
+name:		Hitachi_Flora_220CX
+oem:		FADT "HTCLTD" "HTC2041 "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Hitachi Flora 220MP
+name:		Hitachi_Flora_220MP
+oem:		FADT "HTCLTD" "        "
+quirks:		ACPI_Q_BROKEN
+
+# Hitachi Flora 270EX
+name:		Hitachi_Flora_270EX
+oem:		FADT "HTCLTD" "270-EX  "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Hitachi Flora 270VX-NH7
+name:		Hitachi_Flora_270VX_NH7
+oem:		FADT "HTCLTD" "HTC2051 "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# HP Ashaki 02/24/99
+name:		HP_Ashaki
+oem:		FADT "HP    " "ASHAKI  "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# HP HPBDD
+name:		HP_HPBDD
+oem:		FADT "HP    " "HPBDD_IO"
+oem_rev:	FADT <= 0x1006
+quirks:		ACPI_Q_BROKEN
+
+# HP HPCCD HX
+name:		HP_HPCCD_HX
+oem:		FADT "HP    " "HPCCD HX"
+oem_rev:	FADT <= 0x10000
+quirks:		ACPI_Q_BROKEN
+
+# HP Kayak XUMP
+name:		HP_Kayak_XUMP
+oem:		FADT "HP    " "COGNAC  "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# HP LH 4
+name:		HP_LH_4
+oem:		FADT "HP    " "LH 4    "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# HP Puma 02/12/99
+name:		HP_Puma
+oem:		FADT "HP    " "Puma    "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# HP Scimitar
+name:		HP_Scimitar
+oem:		FADT "HP    " "HWPC203 "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# IBM Aptiva 145
+name:		IBM_Aptiva_145
+oem:		FADT "XXXXXX" "AWRDACPI"
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# IBM TP240 SandShark
+name:		IBM_TP240_SandShark
+oem:		FADT "IBM   " "SShark-1"
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Intel Kauai
+name:		Intel_Kauai
+oem:		FADT "INTEL " "KAUAI   "
+quirks:		ACPI_Q_BROKEN
+
+# Intel L440GX
+name:		Intel_L440GX
+oem:		FADT "Intel " "L440GX  "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Intel OR840 09/14/99
+name:		Intel_OR840
+oem:		FADT "Intel " "OR840   "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Intel Seattle2
+name:		Intel_Seattle2
+oem:		FADT "INTEL " "SEATTLE2"
+oem_rev:	FADT <= 0x19990216
+quirks:		ACPI_Q_BROKEN
+
+# Iwill DBS100
+name:		Iwill_DBS100
+oem:		FADT "AWARD " "AWRDACPI"
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Micron Atlanta
+name:		Micron_Atlanta
+oem:		FADT "MICRON" "ATLANTA "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Micron Trek 2U375
+name:		Micron_Trek_2U375
+oem:		FADT "MICRON" "Trek2AGP"
+oem_rev:	FADT = 1
+quirks:		ACPI_Q_BROKEN
+
+# NCR S20GX
+name:		NCR_S20GX
+oem:		FADT "Intel " "L440GX  "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# NEC PowerMate 8100
+name:		NEC_PowerMate_8100
+oem:		FADT "INTEL " "JN440BX1"
+oem_rev:	FADT >= 0x19990203
+oem_rev:	FADT <= 0x19990810
+creator_rev:	FADT = 0xf4240
+quirks:		ACPI_Q_BROKEN
+
+# NEC VersaNote
+name:		NEC_VersaNote
+oem:		FADT "INTEL " "440BX   "
+oem_rev:	FADT = 0
+creator:	FADT "PTL "
+creator_rev:	FADT = 0xf4240
+quirks:		ACPI_Q_BROKEN
+
+# NEC VersaNote C2
+name:		NEC_VersaNote_C2
+oem:		FADT "NEC   " "ND000011"
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# NEC Versa LXAGP
+name:		NEC_VersaNote_LXAGP
+oem:		FADT "NEC   " "ND000010"
+oem_rev:	FADT <= 0x97
+quirks:		ACPI_Q_BROKEN
+
+# NEC Z1
+name:		NEC_Z1
+oem:		FADT "AMIINT" ""
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# QDIGRP 01/05/99
+name:		QDIGRP_Award
+oem:		FADT "QDIGRP" "AWRDACPI"
+oem_rev:	FADT <= 0
+quirks:		ACPI_Q_BROKEN
+
+# Siemens Mobile 750
+name:		Siemens_Mobile_750
+oem:		FADT "TSANYO" "        "
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
+
+# Sony F290
+name:		Sony_F290
+oem:		FADT "SONY  " "K0      "
+oem_rev:	FADT <= 0x13108b4
+quirks:		ACPI_Q_BROKEN
+
+# Sony N505
+name:		Sony_N505
+oem:		FADT "SONY " "H0       "
+oem_rev:	FADT <= 0x06040000
+quirks:		ACPI_Q_BROKEN
+
+# Sony PCG-777
+# Sony PCG-888
+# Sony PCG-F16
+# Sony Z505DX
+name:		Sony_PCG_xxx
+oem:		FADT "SONY  " "        "
+quirks:		ACPI_Q_BROKEN
+
+# Sony PCV-L300
+name:		Sony_PCV_L300
+oem:		FADT "ASUS  " "SHACHI  "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Sony PCV-S520
+# Sony PCV-S720
+name:		Sony_PCV_Sx20
+oem:		FADT "SONY  " "440BX CR"
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# SuperMicro
+name:		SuperMicro_MTB
+oem:		FADT "SUPERM" "SUPERMTB"
+oem_rev:	FADT <= 2
+quirks:		ACPI_Q_BROKEN
+
+# Toshiba Portege 3300
+# Toshiba Satellite 4030XCDT
+name:		Toshiba_750
+oem:		FADT "TOSHIB" "750     "
+oem_rev:	FADT <= 1
+quirks:		ACPI_Q_BROKEN
+
+# Tyan
+name:		Tyan_TBLE
+oem:		FADT "TYANCP" "TYANTBLE"
+oem_rev:	FADT <= 9
+quirks:		ACPI_Q_BROKEN
+
+# VIA VP3A
+name:		VIA_VP3A
+oem:		FADT "VIAVP3" "AWRDACPI"
+oem_rev:	FADT = 0
+quirks:		ACPI_Q_BROKEN
diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c
index 37ba2c2..628a9ff 100644
--- a/sys/dev/acpica/acpi_timer.c
+++ b/sys/dev/acpica/acpi_timer.c
@@ -130,7 +130,8 @@ acpi_timer_identify(driver_t *driver, device_t parent)
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
-    if (acpi_disabled("timer") || acpi_timer_dev)
+    if (acpi_disabled("timer") || (acpi_quirks & ACPI_Q_TIMER) ||
+	acpi_timer_dev)
 	return (ENXIO);
 
     if ((dev = BUS_ADD_CHILD(parent, parent, 0, "acpi_timer", 0)) == NULL) {
diff --git a/sys/platform/pc32/acpica/acpi_machdep.c b/sys/platform/pc32/acpica/acpi_machdep.c
index fa8a21e..4914614 100644
--- a/sys/platform/pc32/acpica/acpi_machdep.c
+++ b/sys/platform/pc32/acpica/acpi_machdep.c
@@ -356,3 +356,24 @@ acpi_machdep_init(device_t dev)
 
 	return (0);
 }
+
+/* Check BIOS date.  If 1998 or older, disable ACPI. */
+int
+acpi_machdep_quirks(int *quirks)
+{
+	char *va;
+	int year;
+
+	/* BIOS address 0xffff5 contains the date in the format mm/dd/yy. */
+	va = pmap_mapbios(0xffff0, 16);
+	ksscanf(va + 11, "%2d", &year);
+	pmap_unmapbios((vm_offset_t)va, 16);
+
+	/* 
+	 * Date must be >= 1/1/1999 or we don't trust ACPI.
+	 */
+	if (year > 90 && year < 99)
+		*quirks = ACPI_Q_BROKEN;
+
+	return (0);
+}
diff --git a/sys/platform/pc32/acpica/acpi_madt.c b/sys/platform/pc32/acpica/acpi_madt.c
index 0f1e4d2..f7e5995 100644
--- a/sys/platform/pc32/acpica/acpi_madt.c
+++ b/sys/platform/pc32/acpica/acpi_madt.c
@@ -42,6 +42,9 @@
 #include <machine_base/apic/ioapic.h>
 #include <machine_base/apic/apicvar.h>
 
+#include <contrib/dev/acpica/source/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+
 #include "acpi_sdt.h"
 #include "acpi_sdt_var.h"
 #include "acpi_sci_var.h"
@@ -615,6 +618,12 @@ madt_ioapic_enum_callback(void *xarg, const struct acpi_madt_ent *ent)
 		if (intsrc_ent->mint_bus != MADT_INT_BUS_ISA)
 			return 0;
 
+		if (acpi_quirks & ACPI_Q_MADT_IRQ0 &&
+		    intsrc_ent->mint_src == 0 && intsrc_ent->mint_gsi == 2) {
+			MADT_VPRINTF("MADT: Skipping timer override\n");
+			return 0;
+		}
+
 		ent_trig = (intsrc_ent->mint_flags & MADT_INT_TRIG_MASK) >>
 		    MADT_INT_TRIG_SHIFT;
 		if (ent_trig == MADT_INT_TRIG_RSVD)
diff --git a/sys/platform/pc64/acpica/acpi_machdep.c b/sys/platform/pc64/acpica/acpi_machdep.c
index 32266e0..8067ef8 100644
--- a/sys/platform/pc64/acpica/acpi_machdep.c
+++ b/sys/platform/pc64/acpica/acpi_machdep.c
@@ -358,3 +358,10 @@ acpi_machdep_init(device_t dev)
 
 	return (0);
 }
+
+int
+acpi_machdep_quirks(int *quirks)
+{
+	return (0);
+}
+
diff --git a/sys/platform/pc64/acpica/acpi_madt.c b/sys/platform/pc64/acpica/acpi_madt.c
index d8f7249..a741a8a 100644
--- a/sys/platform/pc64/acpica/acpi_madt.c
+++ b/sys/platform/pc64/acpica/acpi_madt.c
@@ -42,6 +42,9 @@
 #include <machine_base/apic/ioapic.h>
 #include <machine_base/apic/apicvar.h>
 
+#include <contrib/dev/acpica/source/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+
 #include "acpi_sdt.h"
 #include "acpi_sdt_var.h"
 #include "acpi_sci_var.h"
@@ -615,6 +618,12 @@ madt_ioapic_enum_callback(void *xarg, const struct acpi_madt_ent *ent)
 		if (intsrc_ent->mint_bus != MADT_INT_BUS_ISA)
 			return 0;
 
+		if (acpi_quirks & ACPI_Q_MADT_IRQ0 &&
+		    intsrc_ent->mint_src == 0 && intsrc_ent->mint_gsi == 2) {
+			MADT_VPRINTF("MADT: Skipping timer override\n");
+			return 0;
+		}
+
 		ent_trig = (intsrc_ent->mint_flags & MADT_INT_TRIG_MASK) >>
 		    MADT_INT_TRIG_SHIFT;
 		if (ent_trig == MADT_INT_TRIG_RSVD)
diff --git a/sys/tools/acpi_quirks2h.awk b/sys/tools/acpi_quirks2h.awk
new file mode 100644
index 0000000..096c8ee
--- /dev/null
+++ b/sys/tools/acpi_quirks2h.awk
@@ -0,0 +1,187 @@
+#!/usr/bin/awk -f
+#
+# $FreeBSD: head/sys/tools/acpi_quirks2h.awk 167814 2007-03-22 18:16:43Z jkim $
+
+#-
+# Copyright (c) 2004 Mark Santcroos <marks@ripe.net>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+BEGIN {
+	OUTPUT="acpi_quirks.h"
+}
+
+# Print header and id
+NR == 1 {
+	VERSION = $0;
+	gsub("\^# ", "", VERSION)
+	gsub("\\$", "", VERSION)
+
+	printf("/*\n") > OUTPUT;
+	printf(" * THIS FILE IS AUTOMAGICALLY GENERATED.  DO NOT EDIT.\n") \
+	    > OUTPUT;
+	printf(" *\n") > OUTPUT;
+	printf(" * Generated from:\n") > OUTPUT;
+	printf(" * %s\n", VERSION) > OUTPUT;
+	printf(" */\n\n") > OUTPUT;
+}
+
+# Ignore comments and empty lines
+/^#/, NF == 0 {
+}
+
+#
+# NAME field: this is the first line of every entry
+#
+$1 == "name:" {
+	ENTRY_NAME = $2;
+	printf("const struct acpi_q_rule %s[] = {\n", ENTRY_NAME) > OUTPUT;
+}
+
+#
+# OEM field
+#
+$1 == "oem:" {
+	LENGTH = length();
+
+	# Parse table type to match
+	TABLE = $2;
+
+	# Parse OEM ID
+	M = match ($0, /\"[^\"]*\"/);
+	OEM_ID = substr($0, M, RLENGTH);
+
+	# Parse OEM Table ID
+	ANCHOR = LENGTH - (M + RLENGTH - 1);
+	REMAINDER = substr($0, M + RLENGTH, ANCHOR);
+	M = match (REMAINDER, /\"[^\"]*\"/);
+	OEM_TABLE_ID = substr(REMAINDER, M, RLENGTH);
+
+	printf("\t{ \"%s\", OEM, {%s}, {%s} },\n",
+	    TABLE, OEM_ID, OEM_TABLE_ID) > OUTPUT;
+}
+
+#
+# CREATOR field
+#
+$1 == "creator:" {
+	# Parse table type to match
+	TABLE = $2;
+
+	M = match ($0, /\"[^\"]*\"/);
+	CREATOR = substr($0, M, RLENGTH);
+
+	printf("\t{ \"%s\", CREATOR, {%s} },\n",
+	    TABLE, CREATOR) > OUTPUT;
+}
+
+#
+# OEM REVISION field
+#
+$1 == "oem_rev:" {
+	TABLE = $2;
+	SIGN = $3;
+	VALUE = $4;
+
+	# Parse operand
+	OPERAND = trans_sign(SIGN);
+
+	printf("\t{ \"%s\", OEM_REV, {.op = %s}, {.rev = %s} },\n",
+	    TABLE, OPERAND, VALUE) > OUTPUT;
+}
+
+#
+# CREATOR REVISION field
+#
+$1 == "creator_rev:" {
+	TABLE = $2;
+	SIGN = $3;
+	VALUE = $4;
+
+	# Parse operand
+	OPERAND = trans_sign(SIGN);
+
+	printf("\t{ \"%s\", CREATOR_REV, {.op = %s}, {.rev = %s} },\n",
+	    TABLE, OPERAND, VALUE) > OUTPUT;
+}
+
+#
+# QUIRKS field: This is the last line of every entry
+#
+$1 == "quirks:" {
+	printf("\t{ \"\" }\n};\n\n") > OUTPUT;
+
+	QUIRKS = $0;
+	sub(/^quirks:[ ]*/ , "", QUIRKS);
+
+	QUIRK_COUNT++;
+	QUIRK_LIST[QUIRK_COUNT] = QUIRKS;
+	QUIRK_NAME[QUIRK_COUNT] = ENTRY_NAME;
+}
+
+#
+# All information is gathered, now create acpi_quirks_table
+#
+END {
+	# Header
+	printf("const struct acpi_q_entry acpi_quirks_table[] = {\n") \
+	    > OUTPUT;
+
+	# Array of all quirks
+	for (i = 1; i <= QUIRK_COUNT; i++) {
+		printf("\t{ %s, %s },\n", QUIRK_NAME[i], QUIRK_LIST[i]) \
+		    > OUTPUT;
+	}
+
+	# Footer
+	printf("\t{ NULL, 0 }\n") > OUTPUT;
+	printf("};\n") > OUTPUT;
+
+	exit(0);
+}
+
+#
+# Translate math SIGN into verbal OPERAND
+#
+function trans_sign(TMP_SIGN)
+{
+	if (TMP_SIGN == "=")
+		TMP_OPERAND = "OP_EQL";
+	else if (TMP_SIGN == "!=")
+		TMP_OPERAND = "OP_NEQ";
+	else if (TMP_SIGN == "<=")
+		TMP_OPERAND = "OP_LEQ";
+	else if (TMP_SIGN == ">=")
+		TMP_OPERAND = "OP_GEQ";
+	else if (TMP_SIGN == ">")
+		TMP_OPERAND = "OP_GTR";
+	else if (TMP_SIGN == "<")
+		TMP_OPERAND = "OP_LES";
+	else {
+		printf("error: unknown sign: " TMP_SIGN "\n");
+		exit(1);
+	}
+
+	return (TMP_OPERAND);
+}
-- 
1.8.2.2

