Bring in the FreeBSD-5 ACPICA code as a module. Note: not hooked up yet,
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 21 Feb 2004 06:48:09 +0000 (06:48 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 21 Feb 2004 06:48:09 +0000 (06:48 +0000)
still under development.  Also note that the original ACPICA code is being
left intact.

50 files changed:
sys/dev/acpica5/Makefile [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdDebug.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdHardware.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdInterrupt.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdMemory.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdSchedule.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdStream.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdSynch.c [new file with mode: 0644]
sys/dev/acpica5/Osd/OsdTable.c [new file with mode: 0644]
sys/dev/acpica5/acdragonfly.h [new file with mode: 0644]
sys/dev/acpica5/acpi.c [new file with mode: 0644]
sys/dev/acpica5/acpi_acad.c [new file with mode: 0644]
sys/dev/acpica5/acpi_battery.c [new file with mode: 0644]
sys/dev/acpica5/acpi_button.c [new file with mode: 0644]
sys/dev/acpica5/acpi_cmbat.c [new file with mode: 0644]
sys/dev/acpica5/acpi_cpu.c [new file with mode: 0644]
sys/dev/acpica5/acpi_ec.c [new file with mode: 0644]
sys/dev/acpica5/acpi_isab.c [new file with mode: 0644]
sys/dev/acpica5/acpi_lid.c [new file with mode: 0644]
sys/dev/acpica5/acpi_package.c [new file with mode: 0644]
sys/dev/acpica5/acpi_pci.c [new file with mode: 0644]
sys/dev/acpica5/acpi_pci_link.c [new file with mode: 0644]
sys/dev/acpica5/acpi_pcib.c [new file with mode: 0644]
sys/dev/acpica5/acpi_pcib_acpi.c [new file with mode: 0644]
sys/dev/acpica5/acpi_pcib_pci.c [new file with mode: 0644]
sys/dev/acpica5/acpi_pcibvar.h [new file with mode: 0644]
sys/dev/acpica5/acpi_powerres.c [new file with mode: 0644]
sys/dev/acpica5/acpi_resource.c [new file with mode: 0644]
sys/dev/acpica5/acpi_thermal.c [new file with mode: 0644]
sys/dev/acpica5/acpi_timer.c [new file with mode: 0644]
sys/dev/acpica5/acpica_support.c [new file with mode: 0644]
sys/dev/acpica5/acpica_support.h [new file with mode: 0644]
sys/dev/acpica5/acpiio.h [new file with mode: 0644]
sys/dev/acpica5/acpivar.h [new file with mode: 0644]
sys/i386/acpica5/Makefile [new file with mode: 0644]
sys/i386/acpica5/OsdEnvironment.c [new file with mode: 0644]
sys/i386/acpica5/acpi_machdep.c [new file with mode: 0644]
sys/i386/acpica5/acpi_toshiba.c [new file with mode: 0644]
sys/i386/acpica5/acpi_wakecode.S [new file with mode: 0644]
sys/i386/acpica5/acpi_wakeup.c [new file with mode: 0644]
sys/i386/acpica5/genwakecode.sh [new file with mode: 0644]
sys/i386/acpica5/madt.c [new file with mode: 0644]
sys/platform/pc32/acpica5/Makefile [new file with mode: 0644]
sys/platform/pc32/acpica5/OsdEnvironment.c [new file with mode: 0644]
sys/platform/pc32/acpica5/acpi_machdep.c [new file with mode: 0644]
sys/platform/pc32/acpica5/acpi_toshiba.c [new file with mode: 0644]
sys/platform/pc32/acpica5/acpi_wakecode.S [new file with mode: 0644]
sys/platform/pc32/acpica5/acpi_wakeup.c [new file with mode: 0644]
sys/platform/pc32/acpica5/genwakecode.sh [new file with mode: 0644]
sys/platform/pc32/acpica5/madt.c [new file with mode: 0644]

diff --git a/sys/dev/acpica5/Makefile b/sys/dev/acpica5/Makefile
new file mode 100644 (file)
index 0000000..08f8cc9
--- /dev/null
@@ -0,0 +1,110 @@
+# $FreeBSD: src/sys/modules/acpi/acpi/Makefile,v 1.3 2004/01/08 16:38:32 njl Exp $
+# $DragonFly: src/sys/dev/acpica5/Makefile,v 1.1 2004/02/21 06:48:08 dillon Exp $
+
+SYSACPICA?= contrib/dev/acpica-unix-20031203
+
+.PATH: ${.CURDIR}/../../${MACHINE_ARCH}/acpica5        \
+       ${.CURDIR}/../../bus/pci                        \
+       ${.CURDIR}/Osd                                  \
+       ${.CURDIR}                                      \
+       ${.CURDIR}/../../${SYSACPICA}/interpreter/dispatcher    \
+       ${.CURDIR}/../../${SYSACPICA}/interpreter/executer      \
+       ${.CURDIR}/../../${SYSACPICA}/interpreter/parser        \
+       ${.CURDIR}/../../${SYSACPICA}/events                    \
+       ${.CURDIR}/../../${SYSACPICA}/hardware                  \
+       ${.CURDIR}/../../${SYSACPICA}/namespace                 \
+       ${.CURDIR}/../../${SYSACPICA}/resources                 \
+       ${.CURDIR}/../../${SYSACPICA}/tables                    \
+       ${.CURDIR}/../../${SYSACPICA}/utilities                 \
+
+KMOD   = acpi
+
+# ACPI CA sources
+CFLAGS+=   -I${.OBJDIR} -I${.CURDIR} -I${.CURDIR}/../../${SYSACPICA}/include
+SRCS+= dsfield.c dsinit.c dsmethod.c dsmthdat.c
+SRCS+= dsobject.c dsopcode.c dsutils.c dswexec.c dswload.c
+SRCS+= dswscope.c dswstate.c evevent.c evgpe.c evgpeblk.c
+SRCS+= evmisc.c evregion.c evrgnini.c evsci.c evxface.c
+SRCS+= evxfevnt.c evxfregn.c exconfig.c exconvrt.c excreate.c
+SRCS+= exdump.c exfield.c exfldio.c exmisc.c exmutex.c
+SRCS+= exnames.c exoparg1.c exoparg2.c exoparg3.c exoparg6.c
+SRCS+= exprep.c exregion.c exresnte.c exresolv.c exresop.c
+SRCS+= exstore.c exstoren.c exstorob.c exsystem.c exutils.c
+SRCS+= hwacpi.c hwgpe.c hwregs.c hwsleep.c hwtimer.c
+SRCS+= nsaccess.c nsalloc.c nsdump.c nseval.c nsinit.c
+SRCS+= nsload.c nsnames.c nsobject.c nsparse.c nssearch.c
+SRCS+= nsutils.c nswalk.c nsxfeval.c nsxfname.c nsxfobj.c
+SRCS+= psargs.c psopcode.c psparse.c psscope.c
+SRCS+= pstree.c psutils.c pswalk.c psxface.c
+SRCS+= rsaddr.c rscalc.c rscreate.c rsdump.c rsio.c
+SRCS+= rsirq.c rslist.c rsmemory.c rsmisc.c rsutils.c
+SRCS+= rsxface.c tbconvrt.c tbget.c tbgetall.c tbinstal.c
+SRCS+= tbrsdt.c tbutils.c tbxface.c tbxfroot.c utalloc.c
+SRCS+= utclib.c utcopy.c utdebug.c utdelete.c uteval.c
+SRCS+= utglobal.c utinit.c utmath.c utmisc.c utobject.c
+SRCS+= utxface.c
+
+# OSD layer
+#
+SRCS+=  acpi.c acpi_acad.c acpi_battery.c acpi_button.c acpi_cmbat.c acpi_cpu.c
+SRCS+=  acpi_ec.c acpi_isab.c acpi_lid.c
+SRCS+=  acpi_package.c acpi_pci.c acpi_pcib.c acpi_pcib_acpi.c
+SRCS+=  acpi_pcib_pci.c acpi_powerres.c acpi_resource.c acpi_thermal.c
+SRCS+=  acpi_timer.c acpi_pci_link.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_bus.h opt_ddb.h
+SRCS+=  device_if.h bus_if.h pci_if.h pcib_if.h isa_if.h
+
+# Debugging support
+DBSRC= dbcmds.c dbdisply.c dbexec.c dbfileio.c dbhistry.c
+DBSRC+=        dbinput.c dbstats.c dbutils.c dbxface.c
+DBSRC+=        dmbuffer.c dmnames.c dmopcode.c dmobject.c dmresrc.c dmresrcl.c
+DBSRC+=        dmresrcs.c dmutils.c dmwalk.c
+
+.if ACPI_MAX_THREADS
+CFLAGS+=-DACPI_MAX_THREADS=${ACPI_MAX_THREADS}
+.endif
+.if ACPI_NO_SEMAPHORES
+CFLAGS+=-DACPI_NO_SEMAPHORES
+.endif
+.if ACPI_DEBUG
+CFLAGS+=-DACPI_DEBUG
+SRCS+= ${DBSRC}
+opt_ddb.h: Makefile
+       echo "#define DDB 1" > ${.TARGET}
+.else
+opt_ddb.h: Makefile
+       echo -n > ${.TARGET}
+.endif
+
+# Machine-specific code such as sleep/wakeup
+SRCS+= acpi_machdep.c acpi_wakecode.h acpi_wakeup.c
+.if ${MACHINE} == "i386"
+SRCS+= madt.c
+.endif
+CLEANFILES+=   acpi_wakecode.h acpi_wakecode.o acpi_wakecode.bin ${DBSRC}
+CLEANFILES+=   platform/acenv.h
+
+acpi_wakecode.h: acpi_wakecode.S
+       ${MAKE} -f ${.CURDIR}/../../${MACHINE_ARCH}/acpica5/Makefile \
+               MAKESRCPATH=${.CURDIR}/../../${MACHINE_ARCH}/acpica5
+
+# acpi.h includes "platform/acenv.h".  This is the easiest way to create
+# a modified acenv.h
+#
+${.OBJDIR}/acpi.h: ${.CURDIR}/../../${SYSACPICA}/include/acpi.h
+       cp ${.ALLSRC} ${.TARGET}
+
+${.OBJDIR}/platform/acenv.h: ${.CURDIR}/../../${SYSACPICA}/include/platform/acenv.h
+       if [ ! -d ${.OBJDIR}/platform ]; then mkdir ${.OBJDIR}/platform; fi
+       cat ${.ALLSRC} | \
+       sed -e 's/__FreeBSD__/__DragonFly__/' | \
+       sed -e 's/acfreebsd.h/acdragonfly.h/' > ${.TARGET}.new
+       mv -f ${.TARGET}.new ${.TARGET}
+
+SRCS+= ${.OBJDIR}/acpi.h ${.OBJDIR}/platform/acenv.h
+
+.include <bsd.kmod.mk>
+
diff --git a/sys/dev/acpica5/Osd/OsdDebug.c b/sys/dev/acpica5/Osd/OsdDebug.c
new file mode 100644 (file)
index 0000000..dee8cc9
--- /dev/null
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdDebug.c,v 1.5 2003/04/29 18:50:34 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdDebug.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.8 : Debugging support
+ */
+
+#include "opt_ddb.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/cons.h>
+#include <sys/kernel.h>
+
+#include <sys/bus.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_output.h>
+
+#include "acpi.h"
+#include "acdebug.h"
+#include <dev/acpica5/acpivar.h>
+
+UINT32
+AcpiOsGetLine(char *Buffer)
+{
+#ifdef DDB
+    char       *cp;
+
+    db_readline(Buffer, 80);
+    for (cp = Buffer; *cp != 0; cp++)
+       if (*cp == '\n')
+           *cp = 0;
+    return(AE_OK);
+#else
+    printf("AcpiOsGetLine called but no input support");
+    return(AE_NOT_EXIST);
+#endif
+}
+
+void
+AcpiOsDbgAssert(void *FailedAssertion, void *FileName, UINT32 LineNumber, char *Message)
+{
+    printf("ACPI: %s:%d - %s\n", (char *)FileName, LineNumber, Message);
+    printf("ACPI: assertion  %s\n", (char *)FailedAssertion);
+}
+
+ACPI_STATUS
+AcpiOsSignal (
+    UINT32                  Function,
+    void                    *Info)
+{
+    ACPI_SIGNAL_FATAL_INFO     *fatal;
+    char                       *message;
+    
+    switch(Function) {
+    case ACPI_SIGNAL_FATAL:
+       fatal = (ACPI_SIGNAL_FATAL_INFO *)Info;
+       printf("ACPI fatal signal, type 0x%x  code 0x%x  argument 0x%x",
+             fatal->Type, fatal->Code, fatal->Argument);
+       Debugger("AcpiOsSignal");
+       break;
+       
+    case ACPI_SIGNAL_BREAKPOINT:
+       message = (char *)Info;
+       Debugger(message);
+       break;
+
+    default:
+       return(AE_BAD_PARAMETER);
+    }
+    return(AE_OK);
+}
+
+#ifdef ACPI_DEBUGGER
+void
+acpi_EnterDebugger(void)
+{
+    ACPI_PARSE_OBJECT  obj;
+    static int         initted = 0;
+
+    if (!initted) {
+       printf("Initialising ACPICA debugger...\n");
+       AcpiDbInitialize();
+       initted = 1;
+    }
+
+    printf("Entering ACPICA debugger...\n");
+    AcpiDbUserCommands('A', &obj);
+}
+#endif
diff --git a/sys/dev/acpica5/Osd/OsdHardware.c b/sys/dev/acpica5/Osd/OsdHardware.c
new file mode 100644 (file)
index 0000000..c7e1971
--- /dev/null
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (c) 2000, 2001 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdHardware.c,v 1.11 2003/08/28 21:22:25 jhb Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdHardware.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.7 : Hardware Abstraction
+ */
+
+#include "acpi.h"
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/pci_cfgreg.h>
+#include <bus/pci/pcireg.h>
+
+/*
+ * ACPICA's rather gung-ho approach to hardware resource ownership is a little
+ * troublesome insofar as there is no easy way for us to know in advance 
+ * exactly which I/O resources it's going to want to use.
+ * 
+ * In order to deal with this, we ignore resource ownership entirely, and simply
+ * use the native I/O space accessor functionality.  This is Evil, but it works.
+ *
+ * XXX use an intermediate #define for the tag/handle
+ */
+
+#ifdef __i386__
+#define ACPI_BUS_SPACE_IO      I386_BUS_SPACE_IO
+#define ACPI_BUS_HANDLE                0
+#endif
+#ifdef __ia64__
+#define ACPI_BUS_SPACE_IO      IA64_BUS_SPACE_IO
+#define ACPI_BUS_HANDLE                0
+#endif
+#ifdef __amd64__
+#define ACPI_BUS_SPACE_IO      AMD64_BUS_SPACE_IO
+#define ACPI_BUS_HANDLE                0
+#endif
+
+ACPI_STATUS
+AcpiOsReadPort (
+    ACPI_IO_ADDRESS    InPort,
+    UINT32             *Value,
+    UINT32             Width)
+{
+    switch (Width) {
+    case 8:
+        *(u_int8_t *)Value = bus_space_read_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
+        break;
+    case 16:
+        *(u_int16_t *)Value = bus_space_read_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
+        break;
+    case 32:
+        *(u_int32_t *)Value = bus_space_read_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, InPort);
+        break;
+    default:
+        /* debug trap goes here */
+       break;
+    }
+
+    return(AE_OK);
+}
+
+ACPI_STATUS
+AcpiOsWritePort (
+    ACPI_IO_ADDRESS    OutPort,
+    UINT32             Value,
+    UINT32             Width)
+{
+    switch (Width) {
+    case 8:
+        bus_space_write_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
+        break;
+    case 16:
+        bus_space_write_2(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
+        break;
+    case 32:
+        bus_space_write_4(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value);
+        break;
+    default:
+        /* debug trap goes here */
+       break;
+    }
+
+    return(AE_OK);
+}
+
+ACPI_STATUS
+AcpiOsReadPciConfiguration (
+    ACPI_PCI_ID                *PciId,
+    UINT32             Register,
+    void               *Value,
+    UINT32             Width)
+{
+    u_int32_t  byte_width = Width / 8;
+    u_int32_t  val;
+
+    if (!pci_cfgregopen())
+        return(AE_NOT_EXIST);
+
+    val = pci_cfgregread(PciId->Bus, PciId->Device, PciId->Function, Register, byte_width);
+    switch (Width) {
+    case 8:
+       *(u_int8_t *)Value = val & 0xff;
+       break;
+    case 16:
+       *(u_int16_t *)Value = val & 0xffff;
+       break;
+    case 32:
+       *(u_int32_t *)Value = val;
+       break;
+    default:
+       /* debug trap goes here */
+       break;
+    }
+    
+
+    return(AE_OK);
+}
+
+
+ACPI_STATUS
+AcpiOsWritePciConfiguration (
+    ACPI_PCI_ID                *PciId,
+    UINT32             Register,
+    ACPI_INTEGER       Value,
+    UINT32             Width)
+{
+    u_int32_t  byte_width = Width / 8;
+
+    if (!pci_cfgregopen())
+       return(AE_NOT_EXIST);
+
+    pci_cfgregwrite(PciId->Bus, PciId->Device, PciId->Function, Register, Value, byte_width);
+
+    return(AE_OK);
+}
+
+/* XXX should use acpivar.h but too many include dependencies */
+extern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int
+    *number);
+
+/*
+ * Depth-first recursive case for finding the bus, given the slot/function.
+ */
+static int
+acpi_bus_number(ACPI_HANDLE root, ACPI_HANDLE curr, ACPI_PCI_ID *PciId)
+{
+    ACPI_HANDLE parent;
+    ACPI_OBJECT_TYPE type;
+    UINT32 adr;
+    int bus, slot, func, class, subclass, header;
+
+    /* Try to get the _BBN object of the root, otherwise assume it is 0 */
+    bus = 0;
+    if (root == curr) {
+        if (ACPI_FAILURE(acpi_EvaluateInteger(root, "_BBN", &bus)) &&
+          bootverbose)
+            printf("acpi_bus_number: root bus has no _BBN, assuming 0\n");
+       return (bus);
+    }
+    if (ACPI_FAILURE(AcpiGetParent(curr, &parent)))
+        return (bus);
+    
+    /* First, recurse up the tree until we find the host bus */
+    bus = acpi_bus_number(root, parent, PciId);
+
+    /* Validate parent bus device type */
+    if (ACPI_FAILURE(AcpiGetType(parent, &type)) || type != ACPI_TYPE_DEVICE) {
+        printf("acpi_bus_number: not a device, type %d\n", type);
+        return (bus);
+    }
+    /* Get the parent's slot and function */
+    if (ACPI_FAILURE(acpi_EvaluateInteger(parent, "_ADR", &adr))) {
+        printf("acpi_bus_number: can't get _ADR\n");
+        return (bus);
+    }
+    slot = ACPI_HIWORD(adr);
+    func = ACPI_LOWORD(adr);
+
+    /* Is this a PCI-PCI or Cardbus-PCI bridge? */
+    class = pci_cfgregread(bus, slot, func, PCIR_CLASS, 1);
+    if (class != PCIC_BRIDGE)
+        return (bus);
+    subclass = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 1);
+    /* Find the header type, masking off the multifunction bit */
+    header = pci_cfgregread(bus, slot, func, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE;
+    if (header == PCIM_HDRTYPE_BRIDGE && subclass == PCIS_BRIDGE_PCI)
+        bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_1, 1);
+    if (header == PCIM_HDRTYPE_CARDBUS && subclass == PCIS_BRIDGE_CARDBUS)
+        bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_2, 1);
+    return (bus);
+}
+
+/*
+ * Find the bus number for a device
+ *
+ * rhandle: handle for the root bus
+ * chandle: handle for the device
+ * PciId: pointer to device slot and function, we fill out bus
+ */
+void
+AcpiOsDerivePciId (
+    ACPI_HANDLE                rhandle,
+    ACPI_HANDLE                chandle,
+    ACPI_PCI_ID                **PciId)
+{
+    ACPI_HANDLE parent;
+    int bus;
+
+    if (pci_cfgregopen() == 0)
+        panic("AcpiOsDerivePciId unable to initialize pci bus");
+
+    /* Try to read _BBN for bus number if we're at the root */
+    bus = 0;
+    if (rhandle == chandle) {
+        if (ACPI_FAILURE(acpi_EvaluateInteger(rhandle, "_BBN", &bus)) &&
+          bootverbose)
+            printf("AcpiOsDerivePciId: root bus has no _BBN, assuming 0\n");
+    }
+    /*
+     * Get the parent handle and call the recursive case.  It is not
+     * clear why we seem to be getting a chandle that points to a child
+     * of the desired slot/function but passing in the parent handle
+     * here works.
+     */
+    if (ACPI_SUCCESS(AcpiGetParent(chandle, &parent)))
+        bus = acpi_bus_number(rhandle, parent, *PciId);
+    (*PciId)->Bus = bus;
+    if (bootverbose) {
+        printf("AcpiOsDerivePciId: bus %d dev %d func %d\n",
+            (*PciId)->Bus, (*PciId)->Device, (*PciId)->Function);
+    }
+}
diff --git a/sys/dev/acpica5/Osd/OsdInterrupt.c b/sys/dev/acpica5/Osd/OsdInterrupt.c
new file mode 100644 (file)
index 0000000..0a44013
--- /dev/null
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdInterrupt.c,v 1.15 2003/11/12 16:24:16 jhb Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdInterrupt.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.5 : Interrupt handling
+ */
+
+#include "acpi.h"
+
+#include <sys/bus.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/acpica5/acpivar.h>
+
+#define _COMPONENT     ACPI_OS_SERVICES
+ACPI_MODULE_NAME("INTERRUPT")
+
+static void            InterruptWrapper(void *arg);
+static OSD_HANDLER     InterruptHandler;
+
+static UINT32 InterruptOverride = 0;
+
+/*
+ * XXX this does not correctly free resources in the case of partically successful
+ * attachment.
+ */
+ACPI_STATUS
+AcpiOsInstallInterruptHandler(UINT32 InterruptNumber, OSD_HANDLER ServiceRoutine, void *Context)
+{
+    struct acpi_softc  *sc;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if ((sc = devclass_get_softc(devclass_find("acpi"), 0)) == NULL)
+       panic("can't find ACPI device to register interrupt");
+    if (sc->acpi_dev == NULL)
+       panic("acpi softc has invalid device");
+
+    if ((InterruptNumber < 0) || (InterruptNumber > 255))
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+    if (ServiceRoutine == NULL)
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+    if (InterruptHandler != NULL && InterruptHandler != ServiceRoutine) {
+       device_printf(sc->acpi_dev, "can't register more than one ACPI interrupt\n");
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+    }
+    InterruptHandler = ServiceRoutine;
+
+    /*
+     * This isn't strictly true, as we ought to be able to handle > 1 interrupt.  The ACPI
+     * spec doesn't call for this though.
+     */
+    if (sc->acpi_irq != NULL) {
+       device_printf(sc->acpi_dev, "attempt to register more than one interrupt handler\n");
+       return_ACPI_STATUS(AE_ALREADY_EXISTS);
+    }
+    sc->acpi_irq_rid = 0;
+    if (InterruptOverride != 0) {
+           device_printf(sc->acpi_dev,
+               "Overriding SCI Interrupt from IRQ %u to IRQ %u\n",
+               InterruptNumber, InterruptOverride);
+           InterruptNumber = InterruptOverride;
+    }
+    bus_set_resource(sc->acpi_dev, SYS_RES_IRQ, 0, InterruptNumber, 1);
+    if ((sc->acpi_irq = bus_alloc_resource(sc->acpi_dev, SYS_RES_IRQ, &sc->acpi_irq_rid, 0, ~0, 1, 
+                                          RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+       device_printf(sc->acpi_dev, "could not allocate SCI interrupt\n");
+       return_ACPI_STATUS(AE_ALREADY_EXISTS);
+    }
+    if (bus_setup_intr(sc->acpi_dev, sc->acpi_irq, INTR_TYPE_MISC, (driver_intr_t *)InterruptWrapper,
+                      Context, &sc->acpi_irq_handle)) {
+       device_printf(sc->acpi_dev, "could not set up SCI interrupt\n");
+       return_ACPI_STATUS(AE_ALREADY_EXISTS);
+    }
+       
+    return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_STATUS
+AcpiOsRemoveInterruptHandler (UINT32 InterruptNumber, OSD_HANDLER ServiceRoutine)
+{
+    struct acpi_softc  *sc;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if ((InterruptNumber < 0) || (InterruptNumber > 255))
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+    if (ServiceRoutine == NULL)
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+    if ((sc = devclass_get_softc(devclass_find("acpi"), 0)) == NULL)
+       panic("can't find ACPI device to deregister interrupt");
+
+    if (sc->acpi_irq == NULL)
+       return_ACPI_STATUS(AE_NOT_EXIST);
+
+    bus_teardown_intr(sc->acpi_dev, sc->acpi_irq, sc->acpi_irq_handle);
+    bus_release_resource(sc->acpi_dev, SYS_RES_IRQ, 0, sc->acpi_irq);
+    bus_delete_resource(sc->acpi_dev, SYS_RES_IRQ, 0);
+
+    sc->acpi_irq = NULL;
+
+    return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_STATUS
+acpi_OverrideInterruptLevel(UINT32 InterruptNumber)
+{
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (InterruptOverride != 0)
+       return_ACPI_STATUS(AE_ALREADY_EXISTS);
+    InterruptOverride = InterruptNumber;
+    return_ACPI_STATUS(AE_OK);
+}
+
+/*
+ * Interrupt handler wrapper.
+ */
+static void
+InterruptWrapper(void *arg)
+{
+    ACPI_LOCK_DECL;
+
+    ACPI_LOCK;
+    InterruptHandler(arg);
+    ACPI_UNLOCK;
+}
diff --git a/sys/dev/acpica5/Osd/OsdMemory.c b/sys/dev/acpica5/Osd/OsdMemory.c
new file mode 100644 (file)
index 0000000..683d165
--- /dev/null
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 2000 Mitsaru Iwasaki
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdMemory.c,v 1.10 2003/07/14 02:42:15 marcel Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdMemory.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.2 : Memory Management
+ */
+
+#include "acpi.h"
+
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+static MALLOC_DEFINE(M_ACPICA, "acpica", "ACPI CA memory pool");
+
+void *
+AcpiOsAllocate(ACPI_SIZE Size)
+{
+    return(malloc(Size, M_ACPICA, M_NOWAIT));
+}
+
+void
+AcpiOsFree (void *Memory)
+{
+    free(Memory, M_ACPICA);
+}
+
+ACPI_STATUS
+AcpiOsMapMemory (ACPI_PHYSICAL_ADDRESS PhysicalAddress, ACPI_SIZE Length, void **LogicalAddress)
+{
+    *LogicalAddress = pmap_mapdev((vm_offset_t)PhysicalAddress, Length);
+    if (*LogicalAddress == NULL)
+       return(AE_BAD_ADDRESS);
+    return(AE_OK);
+}
+
+void
+AcpiOsUnmapMemory (void *LogicalAddress, ACPI_SIZE Length)
+{
+    pmap_unmapdev((vm_offset_t)LogicalAddress, Length);
+}
+
+ACPI_STATUS
+AcpiOsGetPhysicalAddress(void *LogicalAddress, ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
+{
+    /* we can't necessarily do this, so cop out */
+    return(AE_BAD_ADDRESS);
+}
+
+/*
+ * There is no clean way to do this.  We make the charitable assumption
+ * that callers will not pass garbage to us.
+ */
+BOOLEAN
+AcpiOsReadable (void *Pointer, ACPI_SIZE Length)
+{
+    return(TRUE);
+}
+
+BOOLEAN
+AcpiOsWritable (void *Pointer, ACPI_SIZE Length)
+{
+    return(TRUE);
+}
+
+ACPI_STATUS
+AcpiOsReadMemory (
+    ACPI_PHYSICAL_ADDRESS      Address,
+    UINT32                     *Value,
+    UINT32                     Width)
+{
+    void       *LogicalAddress;
+
+    if (AcpiOsMapMemory(Address, Width / 8, &LogicalAddress) != AE_OK) {
+       return(AE_NOT_EXIST);
+    }
+
+    switch (Width) {
+    case 8:
+       *(u_int8_t *)Value = (*(volatile u_int8_t *)LogicalAddress);
+       break;
+    case 16:
+       *(u_int16_t *)Value = (*(volatile u_int16_t *)LogicalAddress);
+       break;
+    case 32:
+       *(u_int32_t *)Value = (*(volatile u_int32_t *)LogicalAddress);
+       break;
+    case 64:
+       *(u_int64_t *)Value = (*(volatile u_int64_t *)LogicalAddress);
+       break;
+    default:
+       /* debug trap goes here */
+       break;
+    }
+
+    AcpiOsUnmapMemory(LogicalAddress, Width / 8);
+
+    return(AE_OK);
+}
+
+ACPI_STATUS
+AcpiOsWriteMemory (
+    ACPI_PHYSICAL_ADDRESS      Address,
+    UINT32                     Value,
+    UINT32                     Width)
+{
+    void       *LogicalAddress;
+
+    if (AcpiOsMapMemory(Address, Width / 8, &LogicalAddress) != AE_OK) {
+       return(AE_NOT_EXIST);
+    }
+
+    switch (Width) {
+    case 8:
+       (*(volatile u_int8_t *)LogicalAddress) = Value & 0xff;
+       break;
+    case 16:
+       (*(volatile u_int16_t *)LogicalAddress) = Value & 0xffff;
+       break;
+    case 32:
+       (*(volatile u_int32_t *)LogicalAddress) = Value & 0xffffffff;
+       break;
+    case 64:
+       (*(volatile u_int64_t *)LogicalAddress) = Value;
+       break;
+    default:
+       /* debug trap goes here */
+       break;
+    }
+
+    AcpiOsUnmapMemory(LogicalAddress, Width / 8);
+
+    return(AE_OK);
+}
diff --git a/sys/dev/acpica5/Osd/OsdSchedule.c b/sys/dev/acpica5/Osd/OsdSchedule.c
new file mode 100644 (file)
index 0000000..36dd084
--- /dev/null
@@ -0,0 +1,290 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdSchedule.c,v 1.26 2003/10/02 05:09:37 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdSchedule.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.3 : Scheduling services
+ */
+
+#include "acpi.h"
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/taskqueue.h>
+#include <machine/clock.h>
+
+#include <sys/bus.h>
+
+#include <dev/acpica5/acpivar.h>
+
+#define _COMPONENT     ACPI_OS_SERVICES
+ACPI_MODULE_NAME("SCHEDULE")
+
+/*
+ * This is a little complicated due to the fact that we need to build and then
+ * free a 'struct task' for each task we enqueue.
+ */
+
+MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task");
+
+static void    AcpiOsExecuteQueue(void *arg, int pending);
+
+struct acpi_task {
+    struct task                        at_task;
+    OSD_EXECUTION_CALLBACK     at_function;
+    void                       *at_context;
+};
+
+struct acpi_task_queue {
+    STAILQ_ENTRY(acpi_task_queue) at_q;
+    struct acpi_task           *at;
+};
+
+#if __FreeBSD_version >= 500000
+/*
+ * Private task queue definition for ACPI
+ */
+TASKQUEUE_DECLARE(acpi);
+static void    *taskqueue_acpi_ih;
+
+static void
+taskqueue_acpi_enqueue(void *context)
+{  
+    swi_sched(taskqueue_acpi_ih, 0);
+}
+
+static void
+taskqueue_acpi_run(void *dummy)
+{
+    taskqueue_run(taskqueue_acpi);
+}
+
+TASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0,
+                swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL,
+                    SWI_TQ, 0, &taskqueue_acpi_ih));
+
+#ifdef ACPI_USE_THREADS
+STAILQ_HEAD(, acpi_task_queue) acpi_task_queue;
+static struct mtx      acpi_task_mtx;
+
+static void
+acpi_task_thread(void *arg)
+{
+    struct acpi_task_queue     *atq;
+    OSD_EXECUTION_CALLBACK     Function;
+    void                       *Context;
+
+    for (;;) {
+       mtx_lock(&acpi_task_mtx);
+       if ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) {
+           msleep(&acpi_task_queue, &acpi_task_mtx, PCATCH, "actask", 0);
+           mtx_unlock(&acpi_task_mtx);
+           continue;
+       }
+
+       STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q);
+       mtx_unlock(&acpi_task_mtx);
+
+       Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function;
+       Context = atq->at->at_context;
+
+       mtx_lock(&Giant);
+       Function(Context);
+
+       free(atq->at, M_ACPITASK);
+       free(atq, M_ACPITASK);
+       mtx_unlock(&Giant);
+    }
+
+    kthread_exit(0);
+}
+
+int
+acpi_task_thread_init(void)
+{
+    int                i, err;
+    struct proc        *acpi_kthread_proc;
+
+    err = 0;
+    STAILQ_INIT(&acpi_task_queue);
+    mtx_init(&acpi_task_mtx, "ACPI task", NULL, MTX_DEF);
+
+    for (i = 0; i < ACPI_MAX_THREADS; i++) {
+       err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc,
+                            0, 0, "acpi_task%d", i);
+       if (err != 0) {
+           printf("%s: kthread_create failed(%d)\n", __func__, err);
+           break;
+       }
+    }
+    return (err);
+}
+#endif
+#endif
+
+ACPI_STATUS
+AcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, void *Context)
+{
+    struct acpi_task   *at;
+    int pri;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (Function == NULL)
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+    at = malloc(sizeof(*at), M_ACPITASK, M_NOWAIT);    /* Interrupt Context */
+    if (at == NULL)
+       return_ACPI_STATUS(AE_NO_MEMORY);
+    bzero(at, sizeof(*at));
+
+    at->at_function = Function;
+    at->at_context = Context;
+    switch (Priority) {
+    case OSD_PRIORITY_GPE:
+       pri = 4;
+       break;
+    case OSD_PRIORITY_HIGH:
+       pri = 3;
+       break;
+    case OSD_PRIORITY_MED:
+       pri = 2;
+       break;
+    case OSD_PRIORITY_LO:
+       pri = 1;
+       break;
+    default:
+       free(at, M_ACPITASK);
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+    }
+    TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at);
+
+#if __FreeBSD_version < 500000
+    taskqueue_enqueue(taskqueue_swi, (struct task *)at);
+#else
+    taskqueue_enqueue(taskqueue_acpi, (struct task *)at);
+#endif
+    return_ACPI_STATUS(AE_OK);
+}
+
+static void
+AcpiOsExecuteQueue(void *arg, int pending)
+{
+    struct acpi_task           *at;
+    struct acpi_task_queue     *atq;
+    OSD_EXECUTION_CALLBACK     Function;
+    void                       *Context;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    at = (struct acpi_task *)arg;
+    atq = NULL;
+    Function = NULL;
+    Context = NULL;
+
+#ifdef ACPI_USE_THREADS
+    atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT);
+    if (atq == NULL) {
+       printf("%s: no memory\n", __func__);
+       return;
+    }
+
+    atq->at = at;
+
+    mtx_lock(&acpi_task_mtx);
+    STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q);
+    mtx_unlock(&acpi_task_mtx);
+    wakeup_one(&acpi_task_queue);
+#else
+    Function = (OSD_EXECUTION_CALLBACK)at->at_function;
+    Context = at->at_context;
+
+    Function(Context);
+    free(at, M_ACPITASK);
+#endif
+
+    return_VOID;
+}
+
+/*
+ * We don't have any sleep granularity better than hz, so
+ * make do with that.
+ */
+void
+AcpiOsSleep(UINT32 Seconds, UINT32 Milliseconds)
+{
+    int                timo;
+    static int dummy;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    timo = (Seconds * hz) + Milliseconds * hz / 1000;
+
+    /* 
+     * If requested sleep time is less than our hz resolution, use
+     * DELAY instead for better granularity.
+     */
+    if (timo > 0)
+       tsleep(&dummy, 0, "acpislp", timo);
+    else
+       DELAY(Milliseconds * 1000);
+
+    return_VOID;
+}
+
+void
+AcpiOsStall(UINT32 Microseconds)
+{
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    DELAY(Microseconds);
+    return_VOID;
+}
+
+UINT32
+AcpiOsGetThreadId(void)
+{
+    struct proc *p;
+    /* XXX do not add FUNCTION_TRACE here, results in recursive call */
+
+    p = curproc;
+#if __FreeBSD_version < 500000
+    if (p == NULL)
+       p = &proc0;
+#endif
+    KASSERT(p != NULL, ("%s: curproc is NULL!", __func__));
+    return(p->p_pid + 1);      /* can't return 0 */
+}
diff --git a/sys/dev/acpica5/Osd/OsdStream.c b/sys/dev/acpica5/Osd/OsdStream.c
new file mode 100644 (file)
index 0000000..3da30fd
--- /dev/null
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdStream.c,v 1.3 2003/04/29 18:50:34 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdStream.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.6 : Stream I/O
+ */
+
+#include "acpi.h"
+
+void
+AcpiOsPrintf (const char *Format, ...)
+{
+    va_list    ap;
+
+    va_start(ap, Format);
+    vprintf(Format, ap);
+    va_end(ap);
+}
+
+void
+AcpiOsVprintf (const char *Format, va_list Args)
+{
+    vprintf(Format, Args);
+}
+
diff --git a/sys/dev/acpica5/Osd/OsdSynch.c b/sys/dev/acpica5/Osd/OsdSynch.c
new file mode 100644 (file)
index 0000000..9682647
--- /dev/null
@@ -0,0 +1,400 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdSynch.c,v 1.18 2003/09/26 21:22:10 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdSynch.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * 6.1 : Mutual Exclusion and Synchronisation
+ */
+
+#include "acpi.h"
+
+#include "opt_acpi.h"
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/thread.h>
+#include <sys/thread2.h>
+
+#define _COMPONENT     ACPI_OS_SERVICES
+ACPI_MODULE_NAME("SYNCH")
+
+static MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
+
+#if defined(__DragonFly__)
+# define AS_LOCK(as)           s = splhigh()
+# define AS_UNLOCK(as)         splx(s)
+# define AS_LOCK_DECL          int s
+# define msleep(a, b, c, d, e) tsleep(a, c, d, e)
+#elif __FreeBSD_version < 500000
+# define AS_LOCK(as)           s = splhigh()
+# define AS_UNLOCK(as)         splx(s)
+# define AS_LOCK_DECL          int s
+# define msleep(a, b, c, d, e) tsleep(a, c, d, e)
+#else
+# define AS_LOCK(as)           mtx_lock(&(as)->as_mtx)
+# define AS_UNLOCK(as)         mtx_unlock(&(as)->as_mtx)
+# define AS_LOCK_DECL
+#endif
+
+/*
+ * Simple counting semaphore implemented using a mutex. (Subsequently used
+ * in the OSI code to implement a mutex.  Go figure.)
+ */
+struct acpi_semaphore {
+#if __FreeBSD_version >= 500000
+    struct mtx as_mtx;
+#endif
+    UINT32     as_units;
+    UINT32     as_maxunits;
+    UINT32     as_pendings;
+    UINT32     as_resetting;
+    UINT32     as_timeouts;
+};
+
+#ifndef ACPI_NO_SEMAPHORES
+#ifndef ACPI_SEMAPHORES_MAX_PENDING
+#define ACPI_SEMAPHORES_MAX_PENDING    4
+#endif
+static int     acpi_semaphore_debug = 0;
+TUNABLE_INT("debug.acpi_semaphore_debug", &acpi_semaphore_debug);
+SYSCTL_DECL(_debug_acpi);
+SYSCTL_INT(_debug_acpi, OID_AUTO, semaphore_debug, CTLFLAG_RW,
+          &acpi_semaphore_debug, 0, "Enable ACPI semaphore debug messages");
+#endif
+
+ACPI_STATUS
+AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, ACPI_HANDLE *OutHandle)
+{
+#ifndef ACPI_NO_SEMAPHORES
+    struct acpi_semaphore      *as;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (OutHandle == NULL)
+       return(AE_BAD_PARAMETER);
+    if (InitialUnits > MaxUnits)
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+    if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT)) == NULL)
+       return_ACPI_STATUS(AE_NO_MEMORY);
+
+    bzero(as, sizeof(*as));
+#if __FreeBSD_version >= 500000
+    mtx_init(&as->as_mtx, "ACPI semaphore", NULL, MTX_DEF);
+#endif
+    as->as_units = InitialUnits;
+    as->as_maxunits = MaxUnits;
+    as->as_pendings = as->as_resetting = as->as_timeouts = 0;
+
+    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
+       "created semaphore %p max %d, initial %d\n", 
+       as, InitialUnits, MaxUnits));
+
+    *OutHandle = (ACPI_HANDLE)as;
+    return_ACPI_STATUS(AE_OK);
+#else
+    *OutHandle = (ACPI_HANDLE)OutHandle;
+    return(AE_OK);
+#endif
+}
+
+ACPI_STATUS
+AcpiOsDeleteSemaphore (ACPI_HANDLE Handle)
+{
+#ifndef ACPI_NO_SEMAPHORES
+#if __FreeBSD_version >= 500000
+    struct acpi_semaphore *as = (struct acpi_semaphore *)Handle;
+#endif
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed semaphore %p\n", as));
+#if __FreeBSD_version >= 500000
+    mtx_destroy(&as->as_mtx);
+#endif
+    free(Handle, M_ACPISEM);
+    return_ACPI_STATUS(AE_OK);
+#else
+    return(AE_OK);
+#endif
+}
+
+/*
+ * This implementation has a bug, in that it has to stall for the entire
+ * timeout before it will return AE_TIME.  A better implementation would
+ * use getmicrotime() to correctly adjust the timeout after being woken up.
+ */
+ACPI_STATUS
+AcpiOsWaitSemaphore(ACPI_HANDLE Handle, UINT32 Units, UINT16 Timeout)
+{
+#ifndef ACPI_NO_SEMAPHORES
+    struct acpi_semaphore      *as = (struct acpi_semaphore *)Handle;
+    ACPI_STATUS                        result;
+    int                                rv, tmo;
+    struct timeval             timeouttv, currenttv, timelefttv;
+    AS_LOCK_DECL;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (as == NULL)
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+    if (cold)
+       return_ACPI_STATUS(AE_OK);
+
+#if 0
+    if (as->as_units < Units && as->as_timeouts > 10) {
+       printf("%s: semaphore %p too many timeouts, resetting\n", __func__, as);
+       AS_LOCK(as);
+       as->as_units = as->as_maxunits;
+       if (as->as_pendings)
+           as->as_resetting = 1;
+       as->as_timeouts = 0;
+       wakeup(as);
+       AS_UNLOCK(as);
+       return_ACPI_STATUS(AE_TIME);
+    }
+
+    if (as->as_resetting) {
+       return_ACPI_STATUS(AE_TIME);
+    }
+#endif
+
+    /* a timeout of ACPI_WAIT_FOREVER means "forever" */
+    if (Timeout == ACPI_WAIT_FOREVER) {
+       tmo = 0;
+       timeouttv.tv_sec = ((0xffff/1000) + 1); /* cf. ACPI spec */
+       timeouttv.tv_usec = 0;
+    } else {
+       /* compute timeout using microseconds per tick */
+       tmo = (Timeout * 1000) / (1000000 / hz);
+       if (tmo <= 0)
+           tmo = 1;
+       timeouttv.tv_sec  = Timeout / 1000;
+       timeouttv.tv_usec = (Timeout % 1000) * 1000;
+    }
+
+    /* calculate timeout value in timeval */
+    getmicrotime(&currenttv);
+    timevaladd(&timeouttv, &currenttv);
+
+    AS_LOCK(as);
+    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
+       "get %d units from semaphore %p (has %d), timeout %d\n",
+       Units, as, as->as_units, Timeout));
+    for (;;) {
+       if (as->as_maxunits == ACPI_NO_UNIT_LIMIT) {
+           result = AE_OK;
+           break;
+       }
+       if (as->as_units >= Units) {
+           as->as_units -= Units;
+           result = AE_OK;
+           break;
+       }
+
+       /* limit number of pending treads */
+       if (as->as_pendings >= ACPI_SEMAPHORES_MAX_PENDING) {
+           result = AE_TIME;
+           break;
+       }
+
+       /* if timeout values of zero is specified, return immediately */
+       if (Timeout == 0) {
+           result = AE_TIME;
+           break;
+       }
+
+#if __FreeBSD_version >= 500000
+       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
+           "semaphore blocked, calling msleep(%p, %p, %d, \"acsem\", %d)\n",
+           as, &as->as_mtx, PCATCH, tmo));
+#endif
+
+       as->as_pendings++;
+
+       if (acpi_semaphore_debug) {
+           printf("%s: Sleep %d, pending %d, semaphore %p, thread %d\n",
+               __func__, Timeout, as->as_pendings, as, AcpiOsGetThreadId());
+       }
+
+       rv = msleep(as, &as->as_mtx, PCATCH, "acsem", tmo);
+
+       as->as_pendings--;
+
+#if 0
+       if (as->as_resetting) {
+           /* semaphore reset, return immediately */
+           if (as->as_pendings == 0) {
+               as->as_resetting = 0;
+           }
+           result = AE_TIME;
+           break;
+       }
+#endif
+
+       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "msleep(%d) returned %d\n", tmo, rv));
+       if (rv == EWOULDBLOCK) {
+           result = AE_TIME;
+           break;
+       }
+
+       /* check if we already awaited enough */
+       timelefttv = timeouttv;
+       getmicrotime(&currenttv);
+       timevalsub(&timelefttv, &currenttv);
+       if (timelefttv.tv_sec < 0) {
+           ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "await semaphore %p timeout\n", as));
+           result = AE_TIME;
+           break;
+       }
+
+       /* adjust timeout for the next sleep */
+       tmo = (timelefttv.tv_sec * 1000000 + timelefttv.tv_usec) / (1000000 / hz);
+       if (tmo <= 0)
+           tmo = 1;
+
+       if (acpi_semaphore_debug) {
+           printf("%s: Wakeup timeleft(%lu, %lu), tmo %u, semaphore %p, thread %d\n",
+               __func__, timelefttv.tv_sec, timelefttv.tv_usec, tmo, as, AcpiOsGetThreadId());
+       }
+    }
+
+    if (acpi_semaphore_debug) {
+       if (result == AE_TIME && Timeout > 0) {
+           printf("%s: Timeout %d, pending %d, semaphore %p\n",
+               __func__, Timeout, as->as_pendings, as);
+       }
+       if (result == AE_OK && (as->as_timeouts > 0 || as->as_pendings > 0)) {
+           printf("%s: Acquire %d, units %d, pending %d, semaphore %p, thread %d\n",
+               __func__, Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId());
+       }
+    }
+
+    if (result == AE_TIME) {
+       as->as_timeouts++;
+    } else {
+       as->as_timeouts = 0;
+    }
+
+    AS_UNLOCK(as);
+
+    return_ACPI_STATUS(result);
+#else
+    return(AE_OK);
+#endif
+}
+
+ACPI_STATUS
+AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units)
+{
+#ifndef ACPI_NO_SEMAPHORES
+    struct acpi_semaphore      *as = (struct acpi_semaphore *)Handle;
+    AS_LOCK_DECL;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (as == NULL)
+       return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+    AS_LOCK(as);
+    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
+       "return %d units to semaphore %p (has %d)\n",
+       Units, as, as->as_units));
+    if (as->as_maxunits != ACPI_NO_UNIT_LIMIT) {
+       as->as_units += Units;
+       if (as->as_units > as->as_maxunits)
+           as->as_units = as->as_maxunits;
+    }
+
+    if (acpi_semaphore_debug && (as->as_timeouts > 0 || as->as_pendings > 0)) {
+       printf("%s: Release %d, units %d, pending %d, semaphore %p, thread %d\n",
+           __func__, Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId());
+    }
+
+    wakeup(as);
+    AS_UNLOCK(as);
+    return_ACPI_STATUS(AE_OK);
+#else
+    return(AE_OK);
+#endif
+}
+
+ACPI_STATUS
+AcpiOsCreateLock (ACPI_HANDLE *OutHandle)
+{
+    lwkt_token_t tok;
+
+    if (OutHandle == NULL)
+       return (AE_BAD_PARAMETER);
+    MALLOC(tok, lwkt_token_t, sizeof(*tok), M_ACPISEM, M_WAITOK | M_ZERO);
+    if (tok == NULL)
+       return (AE_NO_MEMORY);
+
+    lwkt_inittoken(tok);
+    *OutHandle = (ACPI_HANDLE)tok;
+    return (AE_OK);
+}
+
+void
+AcpiOsDeleteLock (ACPI_HANDLE Handle)
+{
+#if 0
+    lwkt_token_t tok = (lwkt_token_t)Handle;
+
+    if (Handle == NULL)
+        return;
+    /*mtx_destroy(m);*/
+#endif
+}
+
+/*
+ * The Flags parameter seems to state whether or not caller is an ISR
+ * (and thus can't block) but since we have ithreads, we don't worry
+ * about potentially blocking.
+ */
+void
+AcpiOsAcquireLock (ACPI_HANDLE Handle, UINT32 Flags)
+{
+    lwkt_token_t tok = (lwkt_token_t)Handle;
+
+    if (Handle == NULL)
+        return;
+    lwkt_gettoken(tok);
+}
+
+void
+AcpiOsReleaseLock (ACPI_HANDLE Handle, UINT32 Flags)
+{
+    lwkt_token_t tok = (lwkt_token_t)Handle;
+
+    if (Handle == NULL)
+        return;
+    lwkt_reltoken(tok);
+}
diff --git a/sys/dev/acpica5/Osd/OsdTable.c b/sys/dev/acpica5/Osd/OsdTable.c
new file mode 100644 (file)
index 0000000..ffee06b
--- /dev/null
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2002 Mitsaru Iwasaki
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/Osd/OsdTable.c,v 1.6 2004/02/14 03:17:30 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/Osd/OsdTable.c,v 1.1 2004/02/21 06:48:09 dillon Exp $
+ */
+
+/*
+ * ACPI Table interfaces
+ */
+
+#include "acpi.h"
+
+#include <sys/kernel.h>
+#include <sys/linker.h>
+
+#undef _COMPONENT
+#define _COMPONENT      ACPI_TABLES
+
+static char acpi_osname[128];
+TUNABLE_STR("hw.acpi.osname", acpi_osname, sizeof(acpi_osname));
+
+ACPI_STATUS
+AcpiOsPredefinedOverride (
+    const ACPI_PREDEFINED_NAMES *InitVal,
+    ACPI_STRING                 *NewVal)
+{
+    if (InitVal == NULL || NewVal == NULL)
+       return (AE_BAD_PARAMETER);
+
+    *NewVal = NULL;
+    if (strncmp(InitVal->Name, "_OS_", 4) == 0 && strlen(acpi_osname) > 0) {
+       printf("ACPI: Overriding _OS definition with \"%s\"\n", acpi_osname);
+       *NewVal = acpi_osname;
+    }
+
+    return (AE_OK);
+}
+
+ACPI_STATUS
+AcpiOsTableOverride (
+    ACPI_TABLE_HEADER       *ExistingTable,
+    ACPI_TABLE_HEADER       **NewTable)
+{
+    caddr_t                 acpi_dsdt, p;
+
+    if (ExistingTable == NULL || NewTable == NULL)
+    {
+        return(AE_BAD_PARAMETER);
+    }
+
+    (*NewTable) = NULL;
+
+    if (strncmp(ExistingTable->Signature, "DSDT", 4) != 0)
+    {
+        return(AE_OK);
+    }
+
+    if ((acpi_dsdt = preload_search_by_type("acpi_dsdt")) == NULL)
+    {
+        return(AE_OK);
+    }
+        
+    if ((p = preload_search_info(acpi_dsdt, MODINFO_ADDR)) == NULL)
+    {
+        return(AE_OK);
+    }
+
+    (*NewTable) = *(void **)p;
+
+    printf("ACPI: DSDT was overridden.\n");
+
+    return(AE_OK);
+}
diff --git a/sys/dev/acpica5/acdragonfly.h b/sys/dev/acpica5/acdragonfly.h
new file mode 100644 (file)
index 0000000..b5d9c73
--- /dev/null
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * Name: acfreebsd.h - OS specific defines, etc.
+ *       $Revision: 11 $
+ *      $DragonFly: src/sys/dev/acpica5/acdragonfly.h,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ *
+ * 1. Copyright Notice
+ *
+ * Some or all of this work - Copyright (c) 1999 - 2003, Intel Corp.
+ * All rights reserved.
+ *
+ * 2. License
+ *
+ * 2.1. This is your license from Intel Corp. under its intellectual property
+ * rights.  You may have additional license terms from the party that provided
+ * you this software, covering your right to use that party's intellectual
+ * property rights.
+ *
+ * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
+ * copy of the source code appearing in this file ("Covered Code") an
+ * irrevocable, perpetual, worldwide license under Intel's copyrights in the
+ * base code distributed originally by Intel ("Original Intel Code") to copy,
+ * make derivatives, distribute, use and display any portion of the Covered
+ * Code in any form, with the right to sublicense such rights; and
+ *
+ * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
+ * license (with the right to sublicense), under only those claims of Intel
+ * patents that are infringed by the Original Intel Code, to make, use, sell,
+ * offer to sell, and import the Covered Code and derivative works thereof
+ * solely to the minimum extent necessary to exercise the above copyright
+ * license, and in no event shall the patent license extend to any additions
+ * to or modifications of the Original Intel Code.  No other license or right
+ * is granted directly or by implication, estoppel or otherwise;
+ *
+ * The above copyright and patent license is granted only if the following
+ * conditions are met:
+ *
+ * 3. Conditions
+ *
+ * 3.1. Redistribution of Source with Rights to Further Distribute Source.
+ * Redistribution of source code of any substantial portion of the Covered
+ * Code or modification with rights to further distribute source must include
+ * the above Copyright Notice, the above License, this list of Conditions,
+ * and the following Disclaimer and Export Compliance provision.  In addition,
+ * Licensee must cause all Covered Code to which Licensee contributes to
+ * contain a file documenting the changes Licensee made to create that Covered
+ * Code and the date of any change.  Licensee must include in that file the
+ * documentation of any changes made by any predecessor Licensee.  Licensee
+ * must include a prominent statement that the modification is derived,
+ * directly or indirectly, from Original Intel Code.
+ *
+ * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
+ * Redistribution of source code of any substantial portion of the Covered
+ * Code or modification without rights to further distribute source must
+ * include the following Disclaimer and Export Compliance provision in the
+ * documentation and/or other materials provided with distribution.  In
+ * addition, Licensee may not authorize further sublicense of source of any
+ * portion of the Covered Code, and must include terms to the effect that the
+ * license from Licensee to its licensee is limited to the intellectual
+ * property embodied in the software Licensee provides to its licensee, and
+ * not to intellectual property embodied in modifications its licensee may
+ * make.
+ *
+ * 3.3. Redistribution of Executable. Redistribution in executable form of any
+ * substantial portion of the Covered Code or modification must reproduce the
+ * above Copyright Notice, and the following Disclaimer and Export Compliance
+ * provision in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3.4. Intel retains all right, title, and interest in and to the Original
+ * Intel Code.
+ *
+ * 3.5. Neither the name Intel nor any other trademark owned or controlled by
+ * Intel shall be used in advertising or otherwise to promote the sale, use or
+ * other dealings in products derived from or relating to the Covered Code
+ * without prior written authorization from Intel.
+ *
+ * 4. Disclaimer and Export Compliance
+ *
+ * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
+ * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
+ * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
+ * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
+ * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ *
+ * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
+ * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
+ * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
+ * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
+ * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
+ * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
+ * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
+ * LIMITED REMEDY.
+ *
+ * 4.3. Licensee shall not export, either directly or indirectly, any of this
+ * software or system incorporating such software without first obtaining any
+ * required license or other approval from the U. S. Department of Commerce or
+ * any other agency or department of the United States Government.  In the
+ * event Licensee exports any such software from the United States or
+ * re-exports any such software from a foreign destination, Licensee shall
+ * ensure that the distribution and export/re-export of the software is in
+ * compliance with all laws, regulations, orders, or other restrictions of the
+ * U.S. Export Administration Regulations. Licensee agrees that neither it nor
+ * any of its subsidiaries will export/re-export any technical data, process,
+ * software, or service, directly or indirectly, to any country for which the
+ * United States government or any agency thereof requires an export license,
+ * other governmental approval, or letter of assurance, without first obtaining
+ * such license, approval or letter.
+ *
+ *****************************************************************************/
+
+#ifndef __ACDRAGONFLY_H_
+#define __ACDRAGONFLY_H_
+
+/*
+ * Some systems' ASL may have problems because they look for names 
+ * of Microsoft operating systems.  To override this, set hw.acpi.os_name
+ * to the appropriate string.
+ */
+#define ACPI_OS_NAME                "DragonFly"
+
+/* DragonFly uses GCC */
+
+#include <platform/acgcc.h>
+#include <machine/acpica_machdep.h>
+
+#ifdef _KERNEL
+#include "opt_acpi.h"
+#endif
+
+#ifdef ACPI_DEBUG
+#define ACPI_DEBUG_OUTPUT      /* for backward compatibility */
+#define ACPI_DISASSEMBLER
+#endif
+
+#ifdef _KERNEL
+#include <sys/ctype.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+#include <stdarg.h>
+
+#ifdef DEBUGGER_THREADING
+#undef DEBUGGER_THREADING
+#endif /* DEBUGGER_THREADING */
+#define DEBUGGER_THREADING 0    /* integrated with DDB */
+#ifdef ACPI_DEBUG_OUTPUT
+#include "opt_ddb.h"
+#ifdef DDB
+#define ACPI_DEBUGGER
+#endif /* DDB */
+#endif /* ACPI_DEBUG_OUTPUT */
+
+#else /* _KERNEL */
+
+/* Not building kernel code, so use libc */
+#define ACPI_USE_STANDARD_HEADERS
+#define ACPI_FLUSH_CPU_CACHE()
+#include <sys/types.h>
+
+#define __cli()
+#define __sti()
+
+#endif /* _KERNEL */
+
+/* Always use DragonFly code over our local versions */
+#define ACPI_USE_SYSTEM_CLIBRARY
+
+/* DragonFly doesn't have strupr, should be fixed. (move to libkern) */
+static __inline char *
+strupr(char *str)
+{
+    char *c = str;
+    while(*c) {
+    *c = toupper(*c);
+    c++;
+    }
+    return(str);
+}
+
+#ifdef _KERNEL
+/* Or strstr (used in debugging mode, also move to libkern) */
+static __inline char *
+strstr(char *s, char *find)
+{
+    char c, sc;
+    size_t len;
+
+    if ((c = *find++) != 0) {
+    len = strlen(find);
+    do {
+        do {
+        if ((sc = *s++) == 0)
+            return (NULL);
+        } while (sc != c);
+    } while (strncmp(s, find, len) != 0);
+    s--;
+    }
+    return ((char *)s);
+}
+#endif /* _KERNEL */
+
+#endif /* __ACDRAGONFLY_H_ */
diff --git a/sys/dev/acpica5/acpi.c b/sys/dev/acpica5/acpi.c
new file mode 100644 (file)
index 0000000..6595134
--- /dev/null
@@ -0,0 +1,2449 @@
+/*-
+ * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000, 2001 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ *     $FreeBSD: src/sys/dev/acpica/acpi.c,v 1.118 2004/02/19 18:20:03 njl Exp $
+ *     $DragonFly: src/sys/dev/acpica5/acpi.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/ioccom.h>
+#include <sys/reboot.h>
+#include <sys/sysctl.h>
+#include <sys/ctype.h>
+#include <sys/linker.h>
+#include <sys/power.h>
+#include <sys/sbuf.h>
+
+#include <machine/clock.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <bus/isa/isavar.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+#include <dev/acpica5/acpiio.h>
+#include <acnamesp.h>
+
+MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT     ACPI_BUS
+ACPI_MODULE_NAME("ACPI")
+
+static d_open_t                acpiopen;
+static d_close_t       acpiclose;
+static d_ioctl_t       acpiioctl;
+
+#define CDEV_MAJOR 152
+static struct cdevsw acpi_cdevsw = {
+       .d_name = "acpi",
+       .d_maj  = CDEV_MAJOR,
+       .d_flags = 0,
+       .d_port = NULL,
+       .d_autoq = 0,
+       .old_open = acpiopen,
+       .old_close = acpiclose,
+       .old_ioctl = acpiioctl
+};
+
+static const char* sleep_state_names[] = {
+    "S0", "S1", "S2", "S3", "S4", "S5", "NONE"};
+
+/* this has to be static, as the softc is gone when we need it */
+static int acpi_off_state = ACPI_STATE_S5;
+
+#if __FreeBSD_version >= 500000
+struct mtx     acpi_mutex;
+#endif
+
+static int     acpi_modevent(struct module *mod, int event, void *junk);
+static void    acpi_identify(driver_t *driver, device_t parent);
+static int     acpi_probe(device_t dev);
+static int     acpi_attach(device_t dev);
+static device_t        acpi_add_child(device_t bus, int order, const char *name,
+                       int unit);
+static int     acpi_print_child(device_t bus, device_t child);
+static int     acpi_read_ivar(device_t dev, device_t child, int index,
+                       uintptr_t *result);
+static int     acpi_write_ivar(device_t dev, device_t child, int index,
+                       uintptr_t value);
+static int     acpi_set_resource(device_t dev, device_t child, int type,
+                       int rid, u_long start, u_long count);
+static int     acpi_get_resource(device_t dev, device_t child, int type,
+                       int rid, u_long *startp, u_long *countp);
+static struct resource *acpi_alloc_resource(device_t bus, device_t child,
+                       int type, int *rid, u_long start, u_long end,
+                       u_long count, u_int flags);
+static int     acpi_release_resource(device_t bus, device_t child, int type,
+                       int rid, struct resource *r);
+static uint32_t        acpi_isa_get_logicalid(device_t dev);
+static int     acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count);
+static int     acpi_isa_pnp_probe(device_t bus, device_t child,
+                       struct isa_pnp_id *ids);
+static void    acpi_probe_children(device_t bus);
+static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level,
+                       void *context, void **status);
+static void    acpi_shutdown_pre_sync(void *arg, int howto);
+static void    acpi_shutdown_final(void *arg, int howto);
+static void    acpi_enable_fixed_events(struct acpi_softc *sc);
+static void    acpi_system_eventhandler_sleep(void *arg, int state);
+static void    acpi_system_eventhandler_wakeup(void *arg, int state);
+static int     acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
+static int     acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
+static int     acpi_pm_func(u_long cmd, void *arg, ...);
+
+static device_method_t acpi_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_identify,         acpi_identify),
+    DEVMETHOD(device_probe,            acpi_probe),
+    DEVMETHOD(device_attach,           acpi_attach),
+    DEVMETHOD(device_detach,           bus_generic_detach),
+    DEVMETHOD(device_shutdown,         bus_generic_shutdown),
+    DEVMETHOD(device_suspend,          bus_generic_suspend),
+    DEVMETHOD(device_resume,           bus_generic_resume),
+
+    /* Bus interface */
+    DEVMETHOD(bus_add_child,           acpi_add_child),
+    DEVMETHOD(bus_print_child,         acpi_print_child),
+    DEVMETHOD(bus_read_ivar,           acpi_read_ivar),
+    DEVMETHOD(bus_write_ivar,          acpi_write_ivar),
+    DEVMETHOD(bus_set_resource,                acpi_set_resource),
+    DEVMETHOD(bus_get_resource,                acpi_get_resource),
+    DEVMETHOD(bus_alloc_resource,      acpi_alloc_resource),
+    DEVMETHOD(bus_release_resource,    acpi_release_resource),
+    DEVMETHOD(bus_driver_added,                bus_generic_driver_added),
+    DEVMETHOD(bus_activate_resource,   bus_generic_activate_resource),
+    DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+    DEVMETHOD(bus_setup_intr,          bus_generic_setup_intr),
+    DEVMETHOD(bus_teardown_intr,       bus_generic_teardown_intr),
+
+    /* ISA emulation */
+    DEVMETHOD(isa_pnp_probe,           acpi_isa_pnp_probe),
+
+    {0, 0}
+};
+
+static driver_t acpi_driver = {
+    "acpi",
+    acpi_methods,
+    sizeof(struct acpi_softc),
+};
+
+static devclass_t acpi_devclass;
+DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, 0);
+MODULE_VERSION(acpi, 100);
+
+SYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RW, NULL, "ACPI debugging");
+static char acpi_ca_version[12];
+SYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD,
+             acpi_ca_version, 0, "Version of Intel ACPI-CA");
+
+/*
+ * ACPI can only be loaded as a module by the loader; activating it after
+ * system bootstrap time is not useful, and can be fatal to the system.
+ * It also cannot be unloaded, since the entire system bus heirarchy hangs
+ * off it.
+ */
+static int
+acpi_modevent(struct module *mod, int event, void *junk)
+{
+    switch(event) {
+    case MOD_LOAD:
+       if (!cold) {
+           printf("The ACPI driver cannot be loaded after boot.\n");
+           return (EPERM);
+       }
+       break;
+    case MOD_UNLOAD:
+       if (!cold && power_pm_get_type() == POWER_PM_TYPE_ACPI)
+           return (EBUSY);
+       break;
+    default:
+       break;
+    }
+    return (0);
+}
+
+/*
+ * Perform early initialization.
+ */
+ACPI_STATUS
+acpi_Startup(void)
+{
+#ifdef ACPI_DEBUGGER
+    char *debugpoint;
+#endif
+    static int error, started = 0;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (started)
+       return_VALUE(error);
+    started = 1;
+
+#if __FreeBSD_version >= 500000
+    /* Initialise the ACPI mutex */
+    mtx_init(&acpi_mutex, "ACPI global lock", NULL, MTX_DEF);
+#endif
+
+    /* Start up the ACPI CA subsystem. */
+#ifdef ACPI_DEBUGGER
+    debugpoint = getenv("debug.acpi.debugger");
+    if (debugpoint) {
+       if (!strcmp(debugpoint, "init"))
+           acpi_EnterDebugger();
+       freeenv(debugpoint);
+    }
+#endif
+    if (ACPI_FAILURE(error = AcpiInitializeSubsystem())) {
+       printf("ACPI: initialisation failed: %s\n", AcpiFormatException(error));
+       return_VALUE(error);
+    }
+#ifdef ACPI_DEBUGGER
+    debugpoint = getenv("debug.acpi.debugger");
+    if (debugpoint) {
+       if (!strcmp(debugpoint, "tables"))
+           acpi_EnterDebugger();
+       freeenv(debugpoint);
+    }
+#endif
+
+    if (ACPI_FAILURE(error = AcpiLoadTables())) {
+       printf("ACPI: table load failed: %s\n", AcpiFormatException(error));
+       return_VALUE(error);
+    }
+    return_VALUE(AE_OK);
+}
+
+/*
+ * Detect ACPI, perform early initialisation
+ */
+static void
+acpi_identify(driver_t *driver, device_t parent)
+{
+    device_t   child;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (!cold)
+       return_VOID;
+
+    /* Check that we haven't been disabled with a hint. */
+    if (resource_disabled("acpi", 0))
+       return_VOID;
+
+    snprintf(acpi_ca_version, sizeof(acpi_ca_version), "0x%x",
+            ACPI_CA_VERSION);
+
+    /* Make sure we're not being doubly invoked. */
+    if (device_find_child(parent, "acpi", 0) != NULL)
+       return_VOID;
+
+    /* Initialize ACPI-CA. */
+    if (ACPI_FAILURE(acpi_Startup()))
+       return_VOID;
+
+    /* Attach the actual ACPI device. */
+    if ((child = BUS_ADD_CHILD(parent, 0, "acpi", 0)) == NULL) {
+       device_printf(parent, "ACPI: could not attach\n");
+       return_VOID;
+    }
+}
+
+/*
+ * Fetch some descriptive data from ACPI to put in our attach message
+ */
+static int
+acpi_probe(device_t dev)
+{
+    ACPI_TABLE_HEADER  th;
+    char               buf[20];
+    int                        error;
+    struct sbuf                sb;
+    ACPI_STATUS                status;
+    ACPI_LOCK_DECL;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    if (power_pm_get_type() != POWER_PM_TYPE_NONE &&
+       power_pm_get_type() != POWER_PM_TYPE_ACPI) {
+
+       device_printf(dev, "Other PM system enabled.\n");
+       return_VALUE(ENXIO);
+    }
+
+    ACPI_LOCK;
+
+    if (ACPI_FAILURE(status = AcpiGetTableHeader(ACPI_TABLE_XSDT, 1, &th))) {
+       device_printf(dev, "couldn't get XSDT header: %s\n",
+                     AcpiFormatException(status));
+       error = ENXIO;
+    } else {
+       sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
+       sbuf_bcat(&sb, th.OemId, 6);
+       sbuf_trim(&sb);
+       sbuf_putc(&sb, ' ');
+       sbuf_bcat(&sb, th.OemTableId, 8);
+       sbuf_trim(&sb);
+       sbuf_finish(&sb);
+       device_set_desc_copy(dev, sbuf_data(&sb));
+       sbuf_delete(&sb);
+       error = 0;
+    }
+    ACPI_UNLOCK;
+    return_VALUE(error);
+}
+
+static int
+acpi_attach(device_t dev)
+{
+    struct acpi_softc  *sc;
+    ACPI_STATUS                status;
+    int                        error;
+    UINT32             flags;
+    char               *env;
+#ifdef ACPI_DEBUGGER
+    char               *debugpoint;
+#endif
+    ACPI_LOCK_DECL;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+    ACPI_LOCK;
+    sc = device_get_softc(dev);
+    bzero(sc, sizeof(*sc));
+    sc->acpi_dev = dev;
+
+#ifdef ACPI_DEBUGGER
+    debugpoint = getenv("debug.acpi.debugger");
+    if (debugpoint) {
+       if (!strcmp(debugpoint, "spaces"))
+           acpi_EnterDebugger();
+       freeenv(debugpoint);
+    }
+#endif
+
+    /* Install the default address space handlers. */
+    error = ENXIO;
+    status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+               ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL);
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "Could not initialise SystemMemory handler: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+    status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+               ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL);
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "Could not initialise SystemIO handler: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+    status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+               ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "could not initialise PciConfig handler: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+
+    /*
+     * Bring ACPI fully online.
+     *
+     * Note that some systems (specifically, those with namespace evaluation
+     * issues that require the avoidance of parts of the namespace) must
+     * avoid running _INI and _STA on everything, as well as dodging the final
+     * object init pass.
+     *
+     * For these devices, we set ACPI_NO_DEVICE_INIT and ACPI_NO_OBJECT_INIT).
+     *
+     * XXX We should arrange for the object init pass after we have attached
+     *     all our child devices, but on many systems it works here.
+     */
+#ifdef ACPI_DEBUGGER
+    debugpoint = getenv("debug.acpi.debugger");
+    if (debugpoint) {
+       if (!strcmp(debugpoint, "enable"))
+           acpi_EnterDebugger();
+       freeenv(debugpoint);
+    }
+#endif
+    flags = 0;
+    if (testenv("debug.acpi.avoid"))
+       flags = ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
+    if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) {
+       device_printf(dev, "Could not enable ACPI: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+
+    /*
+     * Call the ECDT probe function to provide EC functionality before
+     * the namespace has been evaluated.
+     */
+    acpi_ec_ecdt_probe(dev);
+
+    if (ACPI_FAILURE(status = AcpiInitializeObjects(flags))) {
+       device_printf(dev, "Could not initialize ACPI objects: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+
+    /*
+     * Setup our sysctl tree.
+     *
+     * XXX: This doesn't check to make sure that none of these fail.
+     */
+    sysctl_ctx_init(&sc->acpi_sysctl_ctx);
+    sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx,
+                              SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
+                              device_get_name(dev), CTLFLAG_RD, 0, "");
+    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "supported_sleep_state", CTLTYPE_STRING | CTLFLAG_RD,
+       0, 0, acpi_supported_sleep_state_sysctl, "A", "");
+    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW,
+       &sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
+    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW,
+       &sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
+    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW,
+       &sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", "");
+    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW,
+       &sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", "");
+    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW,
+       &sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", "");
+    SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "sleep_delay", CTLFLAG_RD | CTLFLAG_RW,
+       &sc->acpi_sleep_delay, 0, "sleep delay");
+    SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "s4bios", CTLFLAG_RD | CTLFLAG_RW,
+       &sc->acpi_s4bios, 0, "S4BIOS mode");
+    SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "verbose", CTLFLAG_RD | CTLFLAG_RW,
+       &sc->acpi_verbose, 0, "verbose mode");
+    SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "disable_on_poweroff", CTLFLAG_RD | CTLFLAG_RW,
+       &sc->acpi_disable_on_poweroff, 0, "ACPI subsystem disable on poweroff");
+
+    /*
+     * Default to 5 seconds before sleeping to give some machines time to
+     * stabilize.
+     */
+    sc->acpi_sleep_delay = 5;
+    sc->acpi_disable_on_poweroff = 1;
+    if (bootverbose)
+       sc->acpi_verbose = 1;
+    if ((env = getenv("hw.acpi.verbose")) && strcmp(env, "0")) {
+       sc->acpi_verbose = 1;
+       freeenv(env);
+    }
+
+    /* Only enable S4BIOS by default if the FACS says it is available. */
+    if (AcpiGbl_FACS->S4Bios_f != 0)
+           sc->acpi_s4bios = 1;
+
+    /*
+     * Dispatch the default sleep state to devices.
+     * TBD: should be configured from userland policy manager.
+     */
+    sc->acpi_power_button_sx = ACPI_POWER_BUTTON_DEFAULT_SX;
+    sc->acpi_sleep_button_sx = ACPI_SLEEP_BUTTON_DEFAULT_SX;
+    sc->acpi_lid_switch_sx = ACPI_LID_SWITCH_DEFAULT_SX;
+    sc->acpi_standby_sx = ACPI_STATE_S1;
+    sc->acpi_suspend_sx = ACPI_STATE_S3;
+
+    acpi_enable_fixed_events(sc);
+
+    /*
+     * Scan the namespace and attach/initialise children.
+     */
+#ifdef ACPI_DEBUGGER
+    debugpoint = getenv("debug.acpi.debugger");
+    if (debugpoint) {
+       if (!strcmp(debugpoint, "probe"))
+           acpi_EnterDebugger();
+       freeenv(debugpoint);
+    }
+#endif
+
+    /* Register our shutdown handlers */
+    EVENTHANDLER_REGISTER(shutdown_pre_sync, acpi_shutdown_pre_sync, sc,
+       SHUTDOWN_PRI_LAST);
+    EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc,
+       SHUTDOWN_PRI_LAST);
+
+    /*
+     * Register our acpi event handlers.
+     * XXX should be configurable eg. via userland policy manager.
+     */
+    EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep,
+       sc, ACPI_EVENT_PRI_LAST);
+    EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup,
+       sc, ACPI_EVENT_PRI_LAST);
+
+    /* Flag our initial states. */
+    sc->acpi_enabled = 1;
+    sc->acpi_sstate = ACPI_STATE_S0;
+    sc->acpi_sleep_disabled = 0;
+
+    /* Create the control device */
+    sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644,
+                             "acpi");
+    sc->acpi_dev_t->si_drv1 = sc;
+
+#ifdef ACPI_DEBUGGER
+    debugpoint = getenv("debug.acpi.debugger");
+    if (debugpoint) {
+       if (strcmp(debugpoint, "running") == 0)
+           acpi_EnterDebugger();
+       freeenv(debugpoint);
+    }
+#endif
+
+#ifdef ACPI_USE_THREADS
+    if ((error = acpi_task_thread_init()))
+       goto out;
+#endif
+
+    if ((error = acpi_machdep_init(dev)))
+       goto out;
+
+    /* Register ACPI again to pass the correct argument of pm_func. */
+    power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc);
+
+    if (!acpi_disabled("bus"))
+       acpi_probe_children(dev);
+
+    error = 0;
+
+ out:
+    ACPI_UNLOCK;
+    return_VALUE (error);
+}
+
+/*
+ * Handle a new device being added
+ */
+static device_t
+acpi_add_child(device_t bus, int order, const char *name, int unit)
+{
+    struct acpi_device *ad;
+    device_t           child;
+
+    if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL)
+       return (NULL);
+
+    resource_list_init(&ad->ad_rl);
+    
+    child = device_add_child_ordered(bus, order, name, unit);
+    if (child != NULL)
+       device_set_ivars(child, ad);
+    return (child);
+}
+
+static int
+acpi_print_child(device_t bus, device_t child)
+{
+    struct acpi_device  *adev = device_get_ivars(child);
+    struct resource_list *rl = &adev->ad_rl;
+    int retval = 0;
+
+    retval += bus_print_child_header(bus, child);
+    retval += resource_list_print_type(rl, "port",  SYS_RES_IOPORT, "%#lx");
+    retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
+    retval += resource_list_print_type(rl, "irq",   SYS_RES_IRQ,    "%ld");
+    retval += resource_list_print_type(rl, "drq",   SYS_RES_DRQ,    "%ld");
+    retval += bus_print_child_footer(bus, child);
+
+    return (retval);
+}
+
+
+/*
+ * Handle per-device ivars
+ */
+static int
+acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+{
+    struct acpi_device *ad;
+
+    if ((ad = device_get_ivars(child)) == NULL) {
+       printf("device has no ivars\n");
+       return (ENOENT);
+    }
+
+    /* ACPI and ISA compatibility ivars */
+    switch(index) {
+    case ACPI_IVAR_HANDLE:
+       *(ACPI_HANDLE *)result = ad->ad_handle;
+       break;
+    case ACPI_IVAR_MAGIC:
+       *(int *)result = ad->ad_magic;
+       break;
+    case ACPI_IVAR_PRIVATE:
+       *(void **)result = ad->ad_private;
+       break;
+    case ISA_IVAR_VENDORID:
+    case ISA_IVAR_SERIAL:
+    case ISA_IVAR_COMPATID:
+       *(int *)result = -1;
+       break;
+    case ISA_IVAR_LOGICALID:
+       *(int *)result = acpi_isa_get_logicalid(child);
+       break;
+    default:
+       return (ENOENT);
+    }
+
+    return (0);
+}
+
+static int
+acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
+{
+    struct acpi_device *ad;
+
+    if ((ad = device_get_ivars(child)) == NULL) {
+       printf("device has no ivars\n");
+       return (ENOENT);
+    }
+
+    switch(index) {
+    case ACPI_IVAR_HANDLE:
+       ad->ad_handle = (ACPI_HANDLE)value;
+       break;
+    case ACPI_IVAR_MAGIC:
+       ad->ad_magic = (int)value;
+       break;
+    case ACPI_IVAR_PRIVATE:
+       ad->ad_private = (void *)value;
+       break;
+    default:
+       panic("bad ivar write request (%d)", index);
+       return (ENOENT);
+    }
+
+    return (0);
+}
+
+ACPI_HANDLE
+acpi_get_handle(device_t dev)
+{
+    uintptr_t up;
+    ACPI_HANDLE        h;
+
+    if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, &up))
+       return(NULL);
+    h = (ACPI_HANDLE)up;
+    return (h);
+}
+           
+int
+acpi_set_handle(device_t dev, ACPI_HANDLE h)
+{
+    uintptr_t up;
+
+    up = (uintptr_t)h;
+    return (BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, up));
+}
+           
+int
+acpi_get_magic(device_t dev)
+{
+    uintptr_t up;
+    int        m;
+
+    if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, &up))
+       return(0);
+    m = (int)up;
+    return (m);
+}
+
+int
+acpi_set_magic(device_t dev, int m)
+{
+    uintptr_t up;
+
+    up = (uintptr_t)m;
+    return (BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, up));
+}
+
+void *
+acpi_get_private(device_t dev)
+{
+    uintptr_t up;
+    void *p;
+
+    if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, &up))
+       return (NULL);
+    p = (void *)up;
+    return (p);
+}
+
+int
+acpi_set_private(device_t dev, void *p)
+{
+    uintptr_t up;
+
+    up = (uintptr_t)p;
+    return (BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, up));
+}
+
+ACPI_OBJECT_TYPE
+acpi_get_type(device_t dev)
+{
+    ACPI_HANDLE                h;
+    ACPI_OBJECT_TYPE   t;
+
+    if ((h = acpi_get_handle(dev)) == NULL)
+       return (ACPI_TYPE_NOT_FOUND);
+    if (AcpiGetType(h, &t) != AE_OK)
+       return (ACPI_TYPE_NOT_FOUND);
+    return (t);
+}
+
+/*
+ * Handle child resource allocation/removal
+ */
+static int
+acpi_set_resource(device_t dev, device_t child, int type, int rid,
+                 u_long start, u_long count)
+{
+    struct acpi_device         *ad = device_get_ivars(child);
+    struct resource_list       *rl = &ad->ad_rl;
+
+    resource_list_add(rl, type, rid, start, start + count -1, count);
+
+    return(0);
+}
+
+static int
+acpi_get_resource(device_t dev, device_t child, int type, int rid,
+                 u_long *startp, u_long *countp)
+{
+    struct acpi_device         *ad = device_get_ivars(child);
+    struct resource_list       *rl = &ad->ad_rl;
+    struct resource_list_entry *rle;
+
+    rle = resource_list_find(rl, type, rid);
+    if (!rle)
+       return(ENOENT);
+       
+    if (startp)
+       *startp = rle->start;
+    if (countp)
+       *countp = rle->count;
+
+    return (0);
+}
+
+static struct resource *
+acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
+                   u_long start, u_long end, u_long count, u_int flags)
+{
+    struct acpi_device *ad = device_get_ivars(child);
+    struct resource_list *rl = &ad->ad_rl;
+
+    return (resource_list_alloc(rl, bus, child, type, rid, start, end, count,
+           flags));
+}
+
+static int
+acpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r)
+{
+    struct acpi_device *ad = device_get_ivars(child);
+    struct resource_list *rl = &ad->ad_rl;
+
+    return (resource_list_release(rl, bus, child, type, rid, r));
+}
+
+/* Allocate an IO port or memory resource, given its GAS. */
+struct resource *
+acpi_bus_alloc_gas(device_t dev, int *rid, ACPI_GENERIC_ADDRESS *gas)
+{
+    int type;
+
+    if (gas == NULL || !ACPI_VALID_ADDRESS(gas->Address) ||
+       gas->RegisterBitWidth < 8)
+       return (NULL);
+
+    switch (gas->AddressSpaceId) {
+    case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+       type = SYS_RES_MEMORY;
+       break;
+    case ACPI_ADR_SPACE_SYSTEM_IO:
+       type = SYS_RES_IOPORT;
+       break;
+    default:
+       return (NULL);
+    }
+
+    bus_set_resource(dev, type, *rid, gas->Address, gas->RegisterBitWidth / 8);
+    return (bus_alloc_resource(dev, type, rid, 0, ~0, 1, RF_ACTIVE));
+}
+
+/*
+ * Handle ISA-like devices probing for a PnP ID to match.
+ */
+#define PNP_EISAID(s)                          \
+       ((((s[0] - '@') & 0x1f) << 2)           \
+        | (((s[1] - '@') & 0x18) >> 3)         \
+        | (((s[1] - '@') & 0x07) << 13)        \
+        | (((s[2] - '@') & 0x1f) << 8)         \
+        | (PNP_HEXTONUM(s[4]) << 16)           \
+        | (PNP_HEXTONUM(s[3]) << 20)           \
+        | (PNP_HEXTONUM(s[6]) << 24)           \
+        | (PNP_HEXTONUM(s[5]) << 28))
+
+static uint32_t
+acpi_isa_get_logicalid(device_t dev)
+{
+    ACPI_DEVICE_INFO   *devinfo;
+    ACPI_BUFFER                buf;
+    ACPI_HANDLE                h;
+    ACPI_STATUS                error;
+    u_int32_t          pnpid;
+    ACPI_LOCK_DECL;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    pnpid = 0;
+    buf.Pointer = NULL;
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+
+    ACPI_LOCK;
+    
+    /* Fetch and validate the HID. */
+    if ((h = acpi_get_handle(dev)) == NULL)
+       goto out;
+    error = AcpiGetObjectInfo(h, &buf);
+    if (ACPI_FAILURE(error))
+       goto out;
+    devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+
+    if ((devinfo->Valid & ACPI_VALID_HID) != 0)
+       pnpid = PNP_EISAID(devinfo->HardwareId.Value);
+
+out:
+    if (buf.Pointer != NULL)
+       AcpiOsFree(buf.Pointer);
+    ACPI_UNLOCK;
+    return_VALUE (pnpid);
+}
+
+static int
+acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
+{
+    ACPI_DEVICE_INFO   *devinfo;
+    ACPI_BUFFER                buf;
+    ACPI_HANDLE                h;
+    ACPI_STATUS                error;
+    uint32_t           *pnpid;
+    int                        valid, i;
+    ACPI_LOCK_DECL;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    pnpid = cids;
+    valid = 0;
+    buf.Pointer = NULL;
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+
+    ACPI_LOCK;
+    
+    /* Fetch and validate the CID */
+    if ((h = acpi_get_handle(dev)) == NULL)
+       goto out;
+    error = AcpiGetObjectInfo(h, &buf);
+    if (ACPI_FAILURE(error))
+       goto out;
+    devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+    if ((devinfo->Valid & ACPI_VALID_CID) == 0)
+       goto out;
+
+    if (devinfo->CompatibilityId.Count < count)
+       count = devinfo->CompatibilityId.Count;
+    for (i = 0; i < count; i++) {
+       if (strncmp(devinfo->CompatibilityId.Id[i].Value, "PNP", 3) != 0)
+           continue;
+       *pnpid++ = PNP_EISAID(devinfo->CompatibilityId.Id[i].Value);
+       valid++;
+    }
+
+out:
+    if (buf.Pointer != NULL)
+       AcpiOsFree(buf.Pointer);
+    ACPI_UNLOCK;
+    return_VALUE (valid);
+}
+
+static int
+acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids)
+{
+    int                        result, cid_count, i;
+    uint32_t           lid, cids[8];
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /*
+     * ISA-style drivers attached to ACPI may persist and
+     * probe manually if we return ENOENT.  We never want
+     * that to happen, so don't ever return it.
+     */
+    result = ENXIO;
+
+    /* Scan the supplied IDs for a match */
+    lid = acpi_isa_get_logicalid(child);
+    cid_count = acpi_isa_get_compatid(child, cids, 8);
+    while (ids && ids->ip_id) {
+       if (lid == ids->ip_id) {
+           result = 0;
+           goto out;
+       }
+       for (i = 0; i < cid_count; i++) {
+           if (cids[i] == ids->ip_id) {
+               result = 0;
+               goto out;
+           }
+       }
+       ids++;
+    }
+
+ out:
+    return_VALUE (result);
+}
+
+/*
+ * Scan relevant portions of the ACPI namespace and attach child devices.
+ *
+ * Note that we only expect to find devices in the \_PR_, \_TZ_, \_SI_ and
+ * \_SB_ scopes, and \_PR_ and \_TZ_ become obsolete in the ACPI 2.0 spec.
+ */
+static void
+acpi_probe_children(device_t bus)
+{
+    ACPI_HANDLE        parent;
+    ACPI_STATUS        status;
+    static char        *scopes[] = {"\\_PR_", "\\_TZ_", "\\_SI", "\\_SB_", NULL};
+    int                i;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+    ACPI_ASSERTLOCK;
+
+    /* Create any static children by calling device identify methods. */
+    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
+    bus_generic_probe(bus);
+
+    /*
+     * Scan the namespace and insert placeholders for all the devices that
+     * we find.
+     *
+     * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because
+     * we want to create nodes for all devices, not just those that are
+     * currently present. (This assumes that we don't want to create/remove
+     * devices as they appear, which might be smarter.)
+     */
+    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "namespace scan\n"));
+    for (i = 0; scopes[i] != NULL; i++) {
+       status = AcpiGetHandle(ACPI_ROOT_OBJECT, scopes[i], &parent);
+       if (ACPI_SUCCESS(status)) {
+           AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, acpi_probe_child,
+                             bus, NULL);
+       }
+    }
+
+    /*
+     * Scan all of the child devices we have created and let them probe/attach.
+     */
+    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "first bus_generic_attach\n"));
+    bus_generic_attach(bus);
+
+    /*
+     * Some of these children may have attached others as part of their attach
+     * process (eg. the root PCI bus driver), so rescan.
+     */
+    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "second bus_generic_attach\n"));
+    bus_generic_attach(bus);
+
+    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "done attaching children\n"));
+    return_VOID;
+}
+
+/*
+ * Evaluate a child device and determine whether we might attach a device to
+ * it.
+ */
+static ACPI_STATUS
+acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+    ACPI_OBJECT_TYPE   type;
+    device_t           child, bus = (device_t)context;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /* Skip this device if we think we'll have trouble with it. */
+    if (acpi_avoid(handle))
+       return_ACPI_STATUS (AE_OK);
+
+    if (ACPI_SUCCESS(AcpiGetType(handle, &type))) {
+       switch(type) {
+       case ACPI_TYPE_DEVICE:
+       case ACPI_TYPE_PROCESSOR:
+       case ACPI_TYPE_THERMAL:
+       case ACPI_TYPE_POWER:
+           if (acpi_disabled("children"))
+               break;
+
+           /* 
+            * Create a placeholder device for this node.  Sort the placeholder
+            * so that the probe/attach passes will run breadth-first.
+            */
+           ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n",
+                            acpi_name(handle)));
+           child = BUS_ADD_CHILD(bus, level * 10, NULL, -1);
+           if (child == NULL)
+               break;
+           acpi_set_handle(child, handle);
+
+           /*
+            * Check that the device is present.  If it's not present,
+            * leave it disabled (so that we have a device_t attached to
+            * the handle, but we don't probe it).
+            */
+           if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) {
+               device_disable(child);
+               break;
+           }
+
+           /*
+            * Get the device's resource settings and attach them.
+            * Note that if the device has _PRS but no _CRS, we need
+            * to decide when it's appropriate to try to configure the
+            * device.  Ignore the return value here; it's OK for the
+            * device not to have any resources.
+            */
+           acpi_parse_resources(child, handle, &acpi_res_parse_set);
+
+           /* If we're debugging, probe/attach now rather than later */
+           ACPI_DEBUG_EXEC(device_probe_and_attach(child));
+           break;
+       }
+    }
+
+    return_ACPI_STATUS (AE_OK);
+}
+
+static void
+acpi_shutdown_pre_sync(void *arg, int howto)
+{
+    struct acpi_softc *sc = arg;
+
+    ACPI_ASSERTLOCK;
+
+    /*
+     * Disable all ACPI events before soft off, otherwise the system
+     * will be turned on again on some laptops.
+     *
+     * XXX this should probably be restricted to masking some events just
+     *     before powering down, since we may still need ACPI during the
+     *     shutdown process.
+     */
+    if (sc->acpi_disable_on_poweroff)
+       acpi_Disable(sc);
+}
+
+static void
+acpi_shutdown_final(void *arg, int howto)
+{
+    ACPI_STATUS        status;
+
+    ACPI_ASSERTLOCK;
+
+    if ((howto & RB_POWEROFF) != 0) {
+       printf("Powering system off using ACPI\n");
+       status = AcpiEnterSleepStatePrep(acpi_off_state);
+       if (ACPI_FAILURE(status)) {
+           printf("AcpiEnterSleepStatePrep failed - %s\n",
+                  AcpiFormatException(status));
+           return;
+       }
+       ACPI_DISABLE_IRQS();
+       status = AcpiEnterSleepState(acpi_off_state);
+       if (ACPI_FAILURE(status)) {
+           printf("ACPI power-off failed - %s\n", AcpiFormatException(status));
+       } else {
+           DELAY(1000000);
+           printf("ACPI power-off failed - timeout\n");
+       }
+    } else {
+       printf("Shutting down ACPI\n");
+       AcpiTerminate();
+    }
+}
+
+static void
+acpi_enable_fixed_events(struct acpi_softc *sc)
+{
+    static int first_time = 1;
+
+    ACPI_ASSERTLOCK;
+
+    /* Enable and clear fixed events and install handlers. */
+    if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
+       AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
+       AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
+                                    acpi_event_power_button_sleep, sc);
+       if (first_time)
+           device_printf(sc->acpi_dev, "Power Button (fixed)\n");
+    }
+    if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
+       AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON);
+       AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
+                                    acpi_event_sleep_button_sleep, sc);
+       if (first_time)
+           device_printf(sc->acpi_dev, "Sleep Button (fixed)\n");
+    }
+
+    first_time = 0;
+}
+
+/*
+ * Returns true if the device is actually present and should
+ * be attached to.  This requires the present, enabled, UI-visible 
+ * and diagnostics-passed bits to be set.
+ */
+BOOLEAN
+acpi_DeviceIsPresent(device_t dev)
+{
+    ACPI_DEVICE_INFO   *devinfo;
+    ACPI_HANDLE                h;
+    ACPI_BUFFER                buf;
+    ACPI_STATUS                error;
+    int                        ret;
+
+    ACPI_ASSERTLOCK;
+    
+    ret = FALSE;
+    if ((h = acpi_get_handle(dev)) == NULL)
+       return (FALSE);
+    buf.Pointer = NULL;
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+    error = AcpiGetObjectInfo(h, &buf);
+    if (ACPI_FAILURE(error))
+       return (FALSE);
+    devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+
+    /* If no _STA method, must be present */
+    if ((devinfo->Valid & ACPI_VALID_STA) == 0)
+       ret = TRUE;
+
+    /* Return true for 'present' and 'functioning' */
+    if ((devinfo->CurrentStatus & 0x9) == 0x9)
+       ret = TRUE;
+
+    AcpiOsFree(buf.Pointer);
+    return (ret);
+}
+
+/*
+ * Returns true if the battery is actually present and inserted.
+ */
+BOOLEAN
+acpi_BatteryIsPresent(device_t dev)
+{
+    ACPI_DEVICE_INFO   *devinfo;
+    ACPI_HANDLE                h;
+    ACPI_BUFFER                buf;
+    ACPI_STATUS                error;
+    int                        ret;
+
+    ACPI_ASSERTLOCK;
+    
+    ret = FALSE;
+    if ((h = acpi_get_handle(dev)) == NULL)
+       return (FALSE);
+    buf.Pointer = NULL;
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+    error = AcpiGetObjectInfo(h, &buf);
+    if (ACPI_FAILURE(error))
+       return (FALSE);
+    devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+
+    /* If no _STA method, must be present */
+    if ((devinfo->Valid & ACPI_VALID_STA) == 0)
+       ret = TRUE;
+
+    /* Return true for 'present' and 'functioning' */
+    if ((devinfo->CurrentStatus & 0x19) == 0x19)
+       ret = TRUE;
+
+    AcpiOsFree(buf.Pointer);
+    return (ret);
+}
+
+/*
+ * Match a HID string against a device
+ */
+BOOLEAN
+acpi_MatchHid(device_t dev, char *hid) 
+{
+    ACPI_DEVICE_INFO   *devinfo;
+    ACPI_HANDLE                h;
+    ACPI_BUFFER                buf;
+    ACPI_STATUS                error;
+    int                        ret, i;
+
+    ACPI_ASSERTLOCK;
+
+    ret = FALSE;
+    if (hid == NULL)
+       return (FALSE);
+    if ((h = acpi_get_handle(dev)) == NULL)
+       return (FALSE);
+    buf.Pointer = NULL;
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+    error = AcpiGetObjectInfo(h, &buf);
+    if (ACPI_FAILURE(error))
+       return (FALSE);
+    devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+
+    if ((devinfo->Valid & ACPI_VALID_HID) != 0 &&
+       strcmp(hid, devinfo->HardwareId.Value) == 0)
+           ret = TRUE;
+    else if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
+       for (i = 0; i < devinfo->CompatibilityId.Count; i++) {
+           if (strcmp(hid, devinfo->CompatibilityId.Id[i].Value) == 0) {
+               ret = TRUE;
+               break;
+           }
+       }
+    }
+
+    AcpiOsFree(buf.Pointer);
+    return (ret);
+}
+
+/*
+ * Return the handle of a named object within our scope, ie. that of (parent)
+ * or one if its parents.
+ */
+ACPI_STATUS
+acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
+{
+    ACPI_HANDLE                r;
+    ACPI_STATUS                status;
+
+    ACPI_ASSERTLOCK;
+
+    /* Walk back up the tree to the root */
+    for (;;) {
+       status = AcpiGetHandle(parent, path, &r);
+       if (ACPI_SUCCESS(status)) {
+           *result = r;
+           return (AE_OK);
+       }
+       if (status != AE_NOT_FOUND)
+           return (AE_OK);
+       if (ACPI_FAILURE(AcpiGetParent(parent, &r)))
+           return (AE_NOT_FOUND);
+       parent = r;
+    }
+}
+
+/*
+ * Allocate a buffer with a preset data size.
+ */
+ACPI_BUFFER *
+acpi_AllocBuffer(int size)
+{
+    ACPI_BUFFER        *buf;
+
+    if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
+       return (NULL);
+    buf->Length = size;
+    buf->Pointer = (void *)(buf + 1);
+    return (buf);
+}
+
+/*
+ * Evaluate a path that should return an integer.
+ */
+ACPI_STATUS
+acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number)
+{
+    ACPI_STATUS        status;
+    ACPI_BUFFER        buf;
+    ACPI_OBJECT        param;
+
+    ACPI_ASSERTLOCK;
+
+    if (handle == NULL)
+       handle = ACPI_ROOT_OBJECT;
+
+    /*
+     * Assume that what we've been pointed at is an Integer object, or
+     * a method that will return an Integer.
+     */
+    buf.Pointer = &param;
+    buf.Length = sizeof(param);
+    status = AcpiEvaluateObject(handle, path, NULL, &buf);
+    if (ACPI_SUCCESS(status)) {
+       if (param.Type == ACPI_TYPE_INTEGER)
+           *number = param.Integer.Value;
+       else
+           status = AE_TYPE;
+    }
+
+    /* 
+     * In some applications, a method that's expected to return an Integer
+     * may instead return a Buffer (probably to simplify some internal
+     * arithmetic).  We'll try to fetch whatever it is, and if it's a Buffer,
+     * convert it into an Integer as best we can.
+     *
+     * This is a hack.
+     */
+    if (status == AE_BUFFER_OVERFLOW) {
+       if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL) {
+           status = AE_NO_MEMORY;
+       } else {
+           status = AcpiEvaluateObject(handle, path, NULL, &buf);
+           if (ACPI_SUCCESS(status))
+               status = acpi_ConvertBufferToInteger(&buf, number);
+           AcpiOsFree(buf.Pointer);
+       }
+    }
+    return (status);
+}
+
+ACPI_STATUS
+acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, int *number)
+{
+    ACPI_OBJECT        *p;
+    int                i;
+
+    p = (ACPI_OBJECT *)bufp->Pointer;
+    if (p->Type == ACPI_TYPE_INTEGER) {
+       *number = p->Integer.Value;
+       return (AE_OK);
+    }
+    if (p->Type != ACPI_TYPE_BUFFER)
+       return (AE_TYPE);
+    if (p->Buffer.Length > sizeof(int))
+       return (AE_BAD_DATA);
+
+    *number = 0;
+    for (i = 0; i < p->Buffer.Length; i++)
+       *number += (*(p->Buffer.Pointer + i) << (i * 8));
+    return (AE_OK);
+}
+
+/*
+ * Iterate over the elements of an a package object, calling the supplied
+ * function for each element.
+ *
+ * XXX possible enhancement might be to abort traversal on error.
+ */
+ACPI_STATUS
+acpi_ForeachPackageObject(ACPI_OBJECT *pkg,
+       void (*func)(ACPI_OBJECT *comp, void *arg), void *arg)
+{
+    ACPI_OBJECT        *comp;
+    int                i;
+    
+    if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE)
+       return (AE_BAD_PARAMETER);
+
+    /* Iterate over components */
+    i = 0;
+    comp = pkg->Package.Elements;
+    for (; i < pkg->Package.Count; i++, comp++)
+       func(comp, arg);
+
+    return (AE_OK);
+}
+
+/*
+ * Find the (index)th resource object in a set.
+ */
+ACPI_STATUS
+acpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp)
+{
+    ACPI_RESOURCE      *rp;
+    int                        i;
+
+    rp = (ACPI_RESOURCE *)buf->Pointer;
+    i = index;
+    while (i-- > 0) {
+       /* Range check */       
+       if (rp > (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
+           return (AE_BAD_PARAMETER);
+
+       /* Check for terminator */
+       if (rp->Id == ACPI_RSTYPE_END_TAG || rp->Length == 0)
+           return (AE_NOT_FOUND);
+       rp = ACPI_NEXT_RESOURCE(rp);
+    }
+    if (resp != NULL)
+       *resp = rp;
+
+    return (AE_OK);
+}
+
+/*
+ * Append an ACPI_RESOURCE to an ACPI_BUFFER.
+ *
+ * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER
+ * provided to contain it.  If the ACPI_BUFFER is empty, allocate a sensible
+ * backing block.  If the ACPI_RESOURCE is NULL, return an empty set of
+ * resources.
+ */
+#define ACPI_INITIAL_RESOURCE_BUFFER_SIZE      512
+
+ACPI_STATUS
+acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
+{
+    ACPI_RESOURCE      *rp;
+    void               *newp;
+    
+    /* Initialise the buffer if necessary. */
+    if (buf->Pointer == NULL) {
+       buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE;
+       if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL)
+           return (AE_NO_MEMORY);
+       rp = (ACPI_RESOURCE *)buf->Pointer;
+       rp->Id = ACPI_RSTYPE_END_TAG;
+       rp->Length = 0;
+    }
+    if (res == NULL)
+       return (AE_OK);
+    
+    /*
+     * Scan the current buffer looking for the terminator.
+     * This will either find the terminator or hit the end
+     * of the buffer and return an error.
+     */
+    rp = (ACPI_RESOURCE *)buf->Pointer;
+    for (;;) {
+       /* Range check, don't go outside the buffer */
+       if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
+           return (AE_BAD_PARAMETER);
+       if (rp->Id == ACPI_RSTYPE_END_TAG || rp->Length == 0)
+           break;
+       rp = ACPI_NEXT_RESOURCE(rp);
+    }
+
+    /*
+     * Check the size of the buffer and expand if required.
+     *
+     * Required size is:
+     * size of existing resources before terminator + 
+     * size of new resource and header +
+     *         size of terminator.
+     *
+     * Note that this loop should really only run once, unless
+     * for some reason we are stuffing a *really* huge resource.
+     */
+    while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) + 
+           res->Length + ACPI_RESOURCE_LENGTH_NO_DATA +
+           ACPI_RESOURCE_LENGTH) >= buf->Length) {
+       if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL)
+           return (AE_NO_MEMORY);
+       bcopy(buf->Pointer, newp, buf->Length);
+       rp = (ACPI_RESOURCE *)((u_int8_t *)newp +
+                              ((u_int8_t *)rp - (u_int8_t *)buf->Pointer));
+       AcpiOsFree(buf->Pointer);
+       buf->Pointer = newp;
+       buf->Length += buf->Length;
+    }
+    
+    /* Insert the new resource. */
+    bcopy(res, rp, res->Length + ACPI_RESOURCE_LENGTH_NO_DATA);
+    
+    /* And add the terminator. */
+    rp = ACPI_NEXT_RESOURCE(rp);
+    rp->Id = ACPI_RSTYPE_END_TAG;
+    rp->Length = 0;
+
+    return (AE_OK);
+}
+
+/*
+ * Set interrupt model.
+ */
+ACPI_STATUS
+acpi_SetIntrModel(int model)
+{
+    ACPI_OBJECT_LIST ArgList;
+    ACPI_OBJECT Arg;
+
+    Arg.Type = ACPI_TYPE_INTEGER;
+    Arg.Integer.Value = model;
+    ArgList.Count = 1;
+    ArgList.Pointer = &Arg;
+    return (AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &ArgList, NULL));
+}
+
+#define ACPI_MINIMUM_AWAKETIME 5
+
+static void
+acpi_sleep_enable(void *arg)
+{
+    ((struct acpi_softc *)arg)->acpi_sleep_disabled = 0;
+}
+
+/*
+ * Set the system sleep state
+ *
+ * Currently we support S1-S5 but S4 is only S4BIOS
+ */
+ACPI_STATUS
+acpi_SetSleepState(struct acpi_softc *sc, int state)
+{
+    ACPI_STATUS        status = AE_OK;
+    UINT8      TypeA;
+    UINT8      TypeB;
+
+    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
+    ACPI_ASSERTLOCK;
+
+    /* Avoid reentry if already attempting to suspend. */
+    if (sc->acpi_sstate != ACPI_STATE_S0)
+       return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+    /* We recently woke up so don't suspend again for a while. */
+    if (sc->acpi_sleep_disabled)
+       return_ACPI_STATUS (AE_OK);
+
+    switch (state) {
+    case ACPI_STATE_S1:
+    case ACPI_STATE_S2:
+    case ACPI_STATE_S3:
+    case ACPI_STATE_S4:
+       status = AcpiGetSleepTypeData((UINT8)state, &TypeA, &TypeB);
+       if (status == AE_NOT_FOUND) {
+           device_printf(sc->acpi_dev,
+                         "Sleep state S%d not supported by BIOS\n", state);
+           break;
+       } else if (ACPI_FAILURE(status)) {
+           device_printf(sc->acpi_dev, "AcpiGetSleepTypeData failed - %s\n",
+                         AcpiFormatException(status));
+           break;
+       }
+
+       sc->acpi_sstate = state;
+       sc->acpi_sleep_disabled = 1;
+
+       /* Inform all devices that we are going to sleep. */
+       if (DEVICE_SUSPEND(root_bus) != 0) {
+           /*
+            * Re-wake the system.
+            *
+            * XXX note that a better two-pass approach with a 'veto' pass
+            *     followed by a "real thing" pass would be better, but the
+            *     current bus interface does not provide for this.
+            */
+           DEVICE_RESUME(root_bus);
+           return_ACPI_STATUS (AE_ERROR);
+       }
+
+       status = AcpiEnterSleepStatePrep(state);
+       if (ACPI_FAILURE(status)) {
+           device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
+                         AcpiFormatException(status));
+           break;
+       }
+
+       if (sc->acpi_sleep_delay > 0)
+           DELAY(sc->acpi_sleep_delay * 1000000);
+
+       if (state != ACPI_STATE_S1) {
+           acpi_sleep_machdep(sc, state);
+
+           /* AcpiEnterSleepState() may be incomplete, unlock if locked. */
+           if (AcpiGbl_MutexInfo[ACPI_MTX_HARDWARE].OwnerId !=
+               ACPI_MUTEX_NOT_ACQUIRED) {
+
+               AcpiUtReleaseMutex(ACPI_MTX_HARDWARE);
+           }
+
+           /* Re-enable ACPI hardware on wakeup from sleep state 4. */
+           if (state == ACPI_STATE_S4)
+               AcpiEnable();
+       } else {
+           status = AcpiEnterSleepState((UINT8)state);
+           if (ACPI_FAILURE(status)) {
+               device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n",
+                             AcpiFormatException(status));
+               break;
+           }
+       }
+       AcpiLeaveSleepState((UINT8)state);
+       DEVICE_RESUME(root_bus);
+       sc->acpi_sstate = ACPI_STATE_S0;
+       acpi_enable_fixed_events(sc);
+       break;
+    case ACPI_STATE_S5:
+       /*
+        * Shut down cleanly and power off.  This will call us back through the
+        * shutdown handlers.
+        */
+       shutdown_nice(RB_POWEROFF);
+       break;
+    case ACPI_STATE_S0:
+    default:
+       status = AE_BAD_PARAMETER;
+       break;
+    }
+
+    /* Disable a second sleep request for a short period */
+    if (sc->acpi_sleep_disabled)
+       timeout(acpi_sleep_enable, (caddr_t)sc, hz * ACPI_MINIMUM_AWAKETIME);
+
+    return_ACPI_STATUS (status);
+}
+
+/*
+ * Enable/Disable ACPI
+ */
+ACPI_STATUS
+acpi_Enable(struct acpi_softc *sc)
+{
+    ACPI_STATUS        status;
+    u_int32_t  flags;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+    ACPI_ASSERTLOCK;
+
+    flags = ACPI_NO_ADDRESS_SPACE_INIT | ACPI_NO_HARDWARE_INIT |
+           ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
+    if (!sc->acpi_enabled)
+       status = AcpiEnableSubsystem(flags);
+    else
+       status = AE_OK;
+
+    if (status == AE_OK)
+       sc->acpi_enabled = 1;
+
+    return_ACPI_STATUS (status);
+}
+
+ACPI_STATUS
+acpi_Disable(struct acpi_softc *sc)
+{
+    ACPI_STATUS        status;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+    ACPI_ASSERTLOCK;
+
+    if (sc->acpi_enabled)
+       status = AcpiDisable();
+    else
+       status = AE_OK;
+
+    if (status == AE_OK)
+       sc->acpi_enabled = 0;
+
+    return_ACPI_STATUS (status);
+}
+
+/*
+ * ACPI Event Handlers
+ */
+
+/* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
+
+static void
+acpi_system_eventhandler_sleep(void *arg, int state)
+{
+    ACPI_LOCK_DECL;
+    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
+
+    ACPI_LOCK;
+    if (state >= ACPI_STATE_S0 && state <= ACPI_S_STATES_MAX)
+       acpi_SetSleepState((struct acpi_softc *)arg, state);
+    ACPI_UNLOCK;
+    return_VOID;
+}
+
+static void
+acpi_system_eventhandler_wakeup(void *arg, int state)
+{
+    ACPI_LOCK_DECL;
+    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
+
+    /* Well, what to do? :-) */
+
+    ACPI_LOCK;
+    ACPI_UNLOCK;
+
+    return_VOID;
+}
+
+/* 
+ * ACPICA Event Handlers (FixedEvent, also called from button notify handler)
+ */
+UINT32
+acpi_event_power_button_sleep(void *context)
+{
+    struct acpi_softc  *sc = (struct acpi_softc *)context;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_power_button_sx);
+
+    return_VALUE (ACPI_INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_event_power_button_wake(void *context)
+{
+    struct acpi_softc  *sc = (struct acpi_softc *)context;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_power_button_sx);
+
+    return_VALUE (ACPI_INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_event_sleep_button_sleep(void *context)
+{
+    struct acpi_softc  *sc = (struct acpi_softc *)context;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_sleep_button_sx);
+
+    return_VALUE (ACPI_INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_event_sleep_button_wake(void *context)
+{
+    struct acpi_softc  *sc = (struct acpi_softc *)context;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_sleep_button_sx);
+
+    return_VALUE (ACPI_INTERRUPT_HANDLED);
+}
+
+/*
+ * XXX This is kinda ugly, and should not be here.
+ */
+struct acpi_staticbuf {
+    ACPI_BUFFER        buffer;
+    char       data[512];
+};
+
+char *
+acpi_name(ACPI_HANDLE handle)
+{
+    static struct acpi_staticbuf       buf;
+
+    ACPI_ASSERTLOCK;
+
+    buf.buffer.Length = 512;
+    buf.buffer.Pointer = &buf.data[0];
+
+    if (ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf.buffer)))
+       return (buf.buffer.Pointer);
+
+    return ("(unknown path)");
+}
+
+/*
+ * Debugging/bug-avoidance.  Avoid trying to fetch info on various
+ * parts of the namespace.
+ */
+int
+acpi_avoid(ACPI_HANDLE handle)
+{
+    char       *cp, *env, *np;
+    int                len;
+
+    np = acpi_name(handle);
+    if (*np == '\\')
+       np++;
+    if ((env = getenv("debug.acpi.avoid")) == NULL)
+       return (0);
+
+    /* Scan the avoid list checking for a match */
+    cp = env;
+    for (;;) {
+       while ((*cp != 0) && isspace(*cp))
+           cp++;
+       if (*cp == 0)
+           break;
+       len = 0;
+       while ((cp[len] != 0) && !isspace(cp[len]))
+           len++;
+       if (!strncmp(cp, np, len)) {
+           freeenv(env);
+           return(1);
+       }
+       cp += len;
+    }
+    freeenv(env);
+
+    return (0);
+}
+
+/*
+ * Debugging/bug-avoidance.  Disable ACPI subsystem components.
+ */
+int
+acpi_disabled(char *subsys)
+{
+    char       *cp, *env;
+    int                len;
+
+    if ((env = getenv("debug.acpi.disable")) == NULL)
+       return (0);
+    if (!strcmp(env, "all")) {
+       freeenv(env);
+       return (1);
+    }
+
+    /* scan the disable list checking for a match */
+    cp = env;
+    for (;;) {
+       while ((*cp != 0) && isspace(*cp))
+           cp++;
+       if (*cp == 0)
+           break;
+       len = 0;
+       while ((cp[len] != 0) && !isspace(cp[len]))
+           len++;
+       if (!strncmp(cp, subsys, len)) {
+           freeenv(env);
+           return (1);
+       }
+       cp += len;
+    }
+    freeenv(env);
+
+    return (0);
+}
+
+/*
+ * Device wake capability enable/disable.
+ */
+void
+acpi_device_enable_wake_capability(ACPI_HANDLE h, int enable)
+{
+    ACPI_OBJECT_LIST           ArgList;
+    ACPI_OBJECT                        Arg;
+
+    /*
+     * TBD: All Power Resources referenced by elements 2 through N
+     *      of the _PRW object are put into the ON state.
+     */
+
+    ArgList.Count = 1;
+    ArgList.Pointer = &Arg;
+
+    Arg.Type = ACPI_TYPE_INTEGER;
+    Arg.Integer.Value = enable;
+
+    (void)AcpiEvaluateObject(h, "_PSW", &ArgList, NULL);
+}
+
+void
+acpi_device_enable_wake_event(ACPI_HANDLE h)
+{
+    struct acpi_softc          *sc;
+    ACPI_STATUS                        status;
+    ACPI_BUFFER                        prw_buffer;
+    ACPI_OBJECT                        *res;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    sc = devclass_get_softc(acpi_devclass, 0);
+    if (sc == NULL)
+       return;
+
+    /*
+     * _PRW object is only required for devices that have the ability
+     * to wake the system from a system sleeping state.
+     */
+    prw_buffer.Length = ACPI_ALLOCATE_BUFFER;
+    status = AcpiEvaluateObject(h, "_PRW", NULL, &prw_buffer);
+    if (ACPI_FAILURE(status))
+       return;
+
+    res = (ACPI_OBJECT *)prw_buffer.Pointer;
+    if (res == NULL)
+       return;
+
+    if ((res->Type != ACPI_TYPE_PACKAGE) || (res->Package.Count < 2)) {
+       goto out;
+    }
+
+    /*
+     * The element 1 of the _PRW object:
+     * The lowest power system sleeping state that can be entered
+     * while still providing wake functionality.
+     * The sleeping state being entered must be greater or equal to
+     * the power state declared in element 1 of the _PRW object.
+     */
+    if (res->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
+       goto out;
+
+    if (sc->acpi_sstate > res->Package.Elements[1].Integer.Value)
+       goto out;
+
+    /*
+     * The element 0 of the _PRW object:
+     */
+    switch(res->Package.Elements[0].Type) {
+    case ACPI_TYPE_INTEGER:
+       /* 
+        * If the data type of this package element is numeric, then this
+        * _PRW package element is the bit index in the GPEx_EN, in the
+        * GPE blocks described in the FADT, of the enable bit that is
+        * enabled for the wake event.
+        */
+
+       status = AcpiEnableGpe(NULL, res->Package.Elements[0].Integer.Value,
+                              ACPI_EVENT_WAKE_ENABLE);
+       if (ACPI_FAILURE(status))
+           printf("%s: EnableEvent Failed\n", __func__);
+       break;
+    case ACPI_TYPE_PACKAGE:
+       /*
+        * XXX TBD
+        *
+        * If the data type of this package element is a package, then this
+        * _PRW package element is itself a package containing two
+        * elements. The first is an object reference to the GPE Block
+        * device that contains the GPE that will be triggered by the wake
+        * event. The second element is numeric and it contains the bit
+        * index in the GPEx_EN, in the GPE Block referenced by the
+        * first element in the package, of the enable bit that is enabled for
+        * the wake event.
+        * For example, if this field is a package then it is of the form:
+        * Package() {\_SB.PCI0.ISA.GPE, 2}
+        */
+       break;
+    default:
+       break;
+    }
+
+out:
+    if (prw_buffer.Pointer != NULL)
+       AcpiOsFree(prw_buffer.Pointer);
+}
+
+/*
+ * Control interface.
+ *
+ * We multiplex ioctls for all participating ACPI devices here.  Individual 
+ * drivers wanting to be accessible via /dev/acpi should use the
+ * register/deregister interface to make their handlers visible.
+ */
+struct acpi_ioctl_hook
+{
+    TAILQ_ENTRY(acpi_ioctl_hook) link;
+    u_long                      cmd;
+    acpi_ioctl_fn               fn;
+    void                        *arg;
+};
+
+static TAILQ_HEAD(,acpi_ioctl_hook)    acpi_ioctl_hooks;
+static int                             acpi_ioctl_hooks_initted;
+
+/*
+ * Register an ioctl handler.
+ */
+int
+acpi_register_ioctl(u_long cmd, acpi_ioctl_fn fn, void *arg)
+{
+    struct acpi_ioctl_hook     *hp;
+
+    if ((hp = malloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL)
+       return (ENOMEM);
+    hp->cmd = cmd;
+    hp->fn = fn;
+    hp->arg = arg;
+    if (acpi_ioctl_hooks_initted == 0) {
+       TAILQ_INIT(&acpi_ioctl_hooks);
+       acpi_ioctl_hooks_initted = 1;
+    }
+    TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
+    return (0);
+}
+
+/*
+ * Deregister an ioctl handler.
+ */
+void   
+acpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn)
+{
+    struct acpi_ioctl_hook     *hp;
+
+    TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
+       if ((hp->cmd == cmd) && (hp->fn == fn))
+           break;
+
+    if (hp != NULL) {
+       TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
+       free(hp, M_ACPIDEV);
+    }
+}
+
+static int
+acpiopen(dev_t dev, int flag, int fmt, d_thread_t *td)
+{
+    return (0);
+}
+
+static int
+acpiclose(dev_t dev, int flag, int fmt, d_thread_t *td)
+{
+    return (0);
+}
+
+static int
+acpiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
+{
+    struct acpi_softc          *sc;
+    struct acpi_ioctl_hook     *hp;
+    int                                error, xerror, state;
+    ACPI_LOCK_DECL;
+
+    ACPI_LOCK;
+
+    error = state = 0;
+    sc = dev->si_drv1;
+
+    /*
+     * Scan the list of registered ioctls, looking for handlers.
+     */
+    if (acpi_ioctl_hooks_initted) {
+       TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
+           if (hp->cmd == cmd) {
+               xerror = hp->fn(cmd, addr, hp->arg);
+               if (xerror != 0)
+                   error = xerror;
+               goto out;
+           }
+       }
+    }
+
+    /*
+     * Core ioctls are not permitted for non-writable user.
+     * Currently, other ioctls just fetch information.
+     * Not changing system behavior.
+     */
+    if((flag & FWRITE) == 0)
+       return (EPERM);
+
+    /* Core system ioctls. */
+    switch (cmd) {
+    case ACPIIO_ENABLE:
+       if (ACPI_FAILURE(acpi_Enable(sc)))
+           error = ENXIO;
+       break;
+    case ACPIIO_DISABLE:
+       if (ACPI_FAILURE(acpi_Disable(sc)))
+           error = ENXIO;
+       break;
+    case ACPIIO_SETSLPSTATE:
+       if (!sc->acpi_enabled) {
+           error = ENXIO;
+           break;
+       }
+       state = *(int *)addr;
+       if (state >= ACPI_STATE_S0  && state <= ACPI_S_STATES_MAX) {
+           if (ACPI_FAILURE(acpi_SetSleepState(sc, state)))
+               error = EINVAL;
+       } else {
+           error = EINVAL;
+       }
+       break;
+    default:
+       if (error == 0)
+           error = EINVAL;
+       break;
+    }
+
+out:
+    ACPI_UNLOCK;
+    return (error);
+}
+
+static int
+acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    char sleep_state[4];
+    char buf[16];
+    int error;
+    UINT8 state, TypeA, TypeB;
+
+    buf[0] = '\0';
+    for (state = ACPI_STATE_S1; state < ACPI_S_STATES_MAX+1; state++) {
+       if (ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) {
+           sprintf(sleep_state, "S%d ", state);
+           strcat(buf, sleep_state);
+       }
+    }
+    error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+    return (error);
+}
+
+static int
+acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    char sleep_state[10];
+    int error;
+    u_int new_state, old_state;
+
+    old_state = *(u_int *)oidp->oid_arg1;
+    if (old_state > ACPI_S_STATES_MAX+1) {
+       strcpy(sleep_state, "unknown");
+    } else {
+       bzero(sleep_state, sizeof(sleep_state));
+       strncpy(sleep_state, sleep_state_names[old_state],
+               sizeof(sleep_state_names[old_state]));
+    }
+    error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req);
+    if (error == 0 && req->newptr != NULL) {
+       new_state = ACPI_STATE_S0;
+       for (; new_state <= ACPI_S_STATES_MAX + 1; new_state++) {
+           if (strncmp(sleep_state, sleep_state_names[new_state],
+                       sizeof(sleep_state)) == 0)
+               break;
+       }
+       if (new_state <= ACPI_S_STATES_MAX + 1) {
+           if (new_state != old_state)
+               *(u_int *)oidp->oid_arg1 = new_state;
+       } else {
+           error = EINVAL;
+       }
+    }
+
+    return (error);
+}
+
+/* Inform devctl(4) when we receive a Notify. */
+void
+acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify)
+{
+    char               notify_buf[16];
+    ACPI_BUFFER                handle_buf;
+    ACPI_STATUS                status;
+
+    if (subsystem == NULL)
+       return;
+
+    handle_buf.Pointer = NULL;
+    handle_buf.Length = ACPI_ALLOCATE_BUFFER;
+    status = AcpiNsHandleToPathname(h, &handle_buf);
+    if (ACPI_FAILURE(status))
+       return;
+    snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x", notify);
+#if 0
+    devctl_notify("ACPI", subsystem, handle_buf.Pointer, notify_buf);
+#endif
+    AcpiOsFree(handle_buf.Pointer);
+}
+
+#ifdef ACPI_DEBUG
+/*
+ * Support for parsing debug options from the kernel environment.
+ *
+ * Bits may be set in the AcpiDbgLayer and AcpiDbgLevel debug registers
+ * by specifying the names of the bits in the debug.acpi.layer and
+ * debug.acpi.level environment variables.  Bits may be unset by 
+ * prefixing the bit name with !.
+ */
+struct debugtag
+{
+    char       *name;
+    UINT32     value;
+};
+
+static struct debugtag dbg_layer[] = {
+    {"ACPI_UTILITIES",         ACPI_UTILITIES},
+    {"ACPI_HARDWARE",          ACPI_HARDWARE},
+    {"ACPI_EVENTS",            ACPI_EVENTS},
+    {"ACPI_TABLES",            ACPI_TABLES},
+    {"ACPI_NAMESPACE",         ACPI_NAMESPACE},
+    {"ACPI_PARSER",            ACPI_PARSER},
+    {"ACPI_DISPATCHER",                ACPI_DISPATCHER},
+    {"ACPI_EXECUTER",          ACPI_EXECUTER},
+    {"ACPI_RESOURCES",         ACPI_RESOURCES},
+    {"ACPI_CA_DEBUGGER",       ACPI_CA_DEBUGGER},
+    {"ACPI_OS_SERVICES",       ACPI_OS_SERVICES},
+    {"ACPI_CA_DISASSEMBLER",   ACPI_CA_DISASSEMBLER},
+    {"ACPI_ALL_COMPONENTS",    ACPI_ALL_COMPONENTS},
+
+    {"ACPI_BUS",               ACPI_BUS},
+    {"ACPI_SYSTEM",            ACPI_SYSTEM},
+    {"ACPI_POWER",             ACPI_POWER},
+    {"ACPI_EC",                ACPI_EC},
+    {"ACPI_AC_ADAPTER",                ACPI_AC_ADAPTER},
+    {"ACPI_BATTERY",           ACPI_BATTERY},
+    {"ACPI_BUTTON",            ACPI_BUTTON},
+    {"ACPI_PROCESSOR",         ACPI_PROCESSOR},
+    {"ACPI_THERMAL",           ACPI_THERMAL},
+    {"ACPI_FAN",               ACPI_FAN},
+    {"ACPI_ALL_DRIVERS",       ACPI_ALL_DRIVERS},
+    {NULL, 0}
+};
+
+static struct debugtag dbg_level[] = {
+    {"ACPI_LV_ERROR",          ACPI_LV_ERROR},
+    {"ACPI_LV_WARN",           ACPI_LV_WARN},
+    {"ACPI_LV_INIT",           ACPI_LV_INIT},
+    {"ACPI_LV_DEBUG_OBJECT",   ACPI_LV_DEBUG_OBJECT},
+    {"ACPI_LV_INFO",           ACPI_LV_INFO},
+    {"ACPI_LV_ALL_EXCEPTIONS", ACPI_LV_ALL_EXCEPTIONS},
+
+    /* Trace verbosity level 1 [Standard Trace Level] */
+    {"ACPI_LV_INIT_NAMES",     ACPI_LV_INIT_NAMES},
+    {"ACPI_LV_PARSE",          ACPI_LV_PARSE},
+    {"ACPI_LV_LOAD",           ACPI_LV_LOAD},
+    {"ACPI_LV_DISPATCH",       ACPI_LV_DISPATCH},
+    {"ACPI_LV_EXEC",           ACPI_LV_EXEC},
+    {"ACPI_LV_NAMES",          ACPI_LV_NAMES},
+    {"ACPI_LV_OPREGION",       ACPI_LV_OPREGION},
+    {"ACPI_LV_BFIELD",         ACPI_LV_BFIELD},
+    {"ACPI_LV_TABLES",         ACPI_LV_TABLES},
+    {"ACPI_LV_VALUES",         ACPI_LV_VALUES},
+    {"ACPI_LV_OBJECTS",                ACPI_LV_OBJECTS},
+    {"ACPI_LV_RESOURCES",      ACPI_LV_RESOURCES},
+    {"ACPI_LV_USER_REQUESTS",  ACPI_LV_USER_REQUESTS},
+    {"ACPI_LV_PACKAGE",                ACPI_LV_PACKAGE},
+    {"ACPI_LV_VERBOSITY1",     ACPI_LV_VERBOSITY1},
+
+    /* Trace verbosity level 2 [Function tracing and memory allocation] */
+    {"ACPI_LV_ALLOCATIONS",    ACPI_LV_ALLOCATIONS},
+    {"ACPI_LV_FUNCTIONS",      ACPI_LV_FUNCTIONS},
+    {"ACPI_LV_OPTIMIZATIONS",  ACPI_LV_OPTIMIZATIONS},
+    {"ACPI_LV_VERBOSITY2",     ACPI_LV_VERBOSITY2},
+    {"ACPI_LV_ALL",            ACPI_LV_ALL},
+
+    /* Trace verbosity level 3 [Threading, I/O, and Interrupts] */
+    {"ACPI_LV_MUTEX",          ACPI_LV_MUTEX},
+    {"ACPI_LV_THREADS",                ACPI_LV_THREADS},
+    {"ACPI_LV_IO",             ACPI_LV_IO},
+    {"ACPI_LV_INTERRUPTS",     ACPI_LV_INTERRUPTS},
+    {"ACPI_LV_VERBOSITY3",     ACPI_LV_VERBOSITY3},
+
+    /* Exceptionally verbose output -- also used in the global "DebugLevel"  */
+    {"ACPI_LV_AML_DISASSEMBLE",        ACPI_LV_AML_DISASSEMBLE},
+    {"ACPI_LV_VERBOSE_INFO",   ACPI_LV_VERBOSE_INFO},
+    {"ACPI_LV_FULL_TABLES",    ACPI_LV_FULL_TABLES},
+    {"ACPI_LV_EVENTS",         ACPI_LV_EVENTS},
+    {"ACPI_LV_VERBOSE",                ACPI_LV_VERBOSE},
+    {NULL, 0}
+};    
+
+static void
+acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
+{
+    char       *ep;
+    int                i, l;
+    int                set;
+
+    while (*cp) {
+       if (isspace(*cp)) {
+           cp++;
+           continue;
+       }
+       ep = cp;
+       while (*ep && !isspace(*ep))
+           ep++;
+       if (*cp == '!') {
+           set = 0;
+           cp++;
+           if (cp == ep)
+               continue;
+       } else {
+           set = 1;
+       }
+       l = ep - cp;
+       for (i = 0; tag[i].name != NULL; i++) {
+           if (!strncmp(cp, tag[i].name, l)) {
+               if (set)
+                   *flag |= tag[i].value;
+               else
+                   *flag &= ~tag[i].value;
+               printf("ACPI_DEBUG: set '%s'\n", tag[i].name);
+           }
+       }
+       cp = ep;
+    }
+}
+
+static void
+acpi_set_debugging(void *junk)
+{
+    char       *cp;
+
+    if (cold) {
+       AcpiDbgLayer = 0;
+       AcpiDbgLevel = 0;
+    }
+
+    if ((cp = getenv("debug.acpi.layer")) != NULL) {
+       acpi_parse_debug(cp, &dbg_layer[0], &AcpiDbgLayer);
+       freeenv(cp);
+    }
+    if ((cp = getenv("debug.acpi.level")) != NULL) {
+       acpi_parse_debug(cp, &dbg_level[0], &AcpiDbgLevel);
+       freeenv(cp);
+    }
+
+    if (cold) {
+       printf("ACPI debug layer 0x%x debug level 0x%x\n",
+              AcpiDbgLayer, AcpiDbgLevel);
+    }
+}
+SYSINIT(acpi_debugging, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_set_debugging,
+       NULL);
+
+static int
+acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    int                 error, *dbg;
+    struct      debugtag *tag;
+    struct      sbuf sb;
+
+    if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL)
+       return (ENOMEM);
+    if (strcmp(oidp->oid_arg1, "debug.acpi.layer") == 0) {
+       tag = &dbg_layer[0];
+       dbg = &AcpiDbgLayer;
+    } else {
+       tag = &dbg_level[0];
+       dbg = &AcpiDbgLevel;
+    }
+
+    /* Get old values if this is a get request. */
+    if (*dbg == 0) {
+       sbuf_cpy(&sb, "NONE");
+    } else if (req->newptr == NULL) {
+       for (; tag->name != NULL; tag++) {
+           if ((*dbg & tag->value) == tag->value)
+               sbuf_printf(&sb, "%s ", tag->name);
+       }
+    }
+    sbuf_trim(&sb);
+    sbuf_finish(&sb);
+
+    error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
+    sbuf_delete(&sb);
+
+    /* If the user is setting a string, parse it. */
+    if (error == 0 && req->newptr != NULL) {
+       *dbg = 0;
+       setenv((char *)oidp->oid_arg1, (char *)req->newptr);
+       acpi_set_debugging(NULL);
+    }
+
+    return (error);
+}
+SYSCTL_PROC(_debug_acpi, OID_AUTO, layer, CTLFLAG_RW | CTLTYPE_STRING,
+           "debug.acpi.layer", 0, acpi_debug_sysctl, "A", "");
+SYSCTL_PROC(_debug_acpi, OID_AUTO, level, CTLFLAG_RW | CTLTYPE_STRING,
+           "debug.acpi.level", 0, acpi_debug_sysctl, "A", "");
+#endif
+
+static int
+acpi_pm_func(u_long cmd, void *arg, ...)
+{
+       int     state, acpi_state;
+       int     error;
+       struct  acpi_softc *sc;
+       va_list ap;
+
+       error = 0;
+       switch (cmd) {
+       case POWER_CMD_SUSPEND:
+               sc = (struct acpi_softc *)arg;
+               if (sc == NULL) {
+                       error = EINVAL;
+                       goto out;
+               }
+
+               va_start(ap, arg);
+               state = va_arg(ap, int);
+               va_end(ap);     
+
+               switch (state) {
+               case POWER_SLEEP_STATE_STANDBY:
+                       acpi_state = sc->acpi_standby_sx;
+                       break;
+               case POWER_SLEEP_STATE_SUSPEND:
+                       acpi_state = sc->acpi_suspend_sx;
+                       break;
+               case POWER_SLEEP_STATE_HIBERNATE:
+                       acpi_state = ACPI_STATE_S4;
+                       break;
+               default:
+                       error = EINVAL;
+                       goto out;
+               }
+
+               acpi_SetSleepState(sc, acpi_state);
+               break;
+       default:
+               error = EINVAL;
+               goto out;
+       }
+
+out:
+       return (error);
+}
+
+static void
+acpi_pm_register(void *arg)
+{
+    if (!cold || resource_disabled("acpi", 0))
+       return;
+
+    power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, NULL);
+}
+
+SYSINIT(power, SI_SUB_KLD, SI_ORDER_ANY, acpi_pm_register, 0);
diff --git a/sys/dev/acpica5/acpi_acad.c b/sys/dev/acpica5/acpi_acad.c
new file mode 100644 (file)
index 0000000..3dc493b
--- /dev/null
@@ -0,0 +1,280 @@
+/*-
+ * Copyright (c) 2000 Takanori Watanabe
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_acad.c,v 1.20 2003/10/25 05:03:24 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_acad.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/power.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+#include <dev/acpica5/acpiio.h>
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT     ACPI_AC_ADAPTER
+ACPI_MODULE_NAME("AC_ADAPTER")
+
+/* Number of times to retry initialization before giving up. */
+#define ACPI_ACAD_RETRY_MAX            6
+
+#define ACPI_DEVICE_CHECK_PNP          0x00
+#define ACPI_DEVICE_CHECK_EXISTENCE    0x01
+#define ACPI_POWERSOURCE_STAT_CHANGE   0x80
+
+struct acpi_acad_softc {
+    int status;
+    int initializing;
+};
+
+static void    acpi_acad_get_status(void *);
+static void    acpi_acad_notify_handler(ACPI_HANDLE, UINT32, void *);
+static int     acpi_acad_probe(device_t);
+static int     acpi_acad_attach(device_t);
+static int     acpi_acad_ioctl(u_long, caddr_t, void *);
+static int     acpi_acad_sysctl(SYSCTL_HANDLER_ARGS);
+static void    acpi_acad_init_acline(void *arg);
+
+static device_method_t acpi_acad_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,    acpi_acad_probe),
+    DEVMETHOD(device_attach,   acpi_acad_attach),
+
+    {0, 0}
+};
+
+static driver_t acpi_acad_driver = {
+    "acpi_acad",
+    acpi_acad_methods,
+    sizeof(struct acpi_acad_softc),
+};
+
+static devclass_t acpi_acad_devclass;
+DRIVER_MODULE(acpi_acad, acpi, acpi_acad_driver, acpi_acad_devclass, 0, 0);
+
+static void
+acpi_acad_get_status(void *context)
+{
+    struct acpi_acad_softc *sc;
+    device_t   dev;
+    ACPI_HANDLE        h;
+    int                newstatus;
+
+    dev = context;
+    sc = device_get_softc(dev);
+    h = acpi_get_handle(dev);
+    if (ACPI_FAILURE(acpi_EvaluateInteger(h, "_PSR", &newstatus))) {
+       sc->status = -1;
+       return;
+    }
+
+    if (sc->status != newstatus) {
+       sc->status = newstatus;
+
+       /* Set system power profile based on AC adapter status */
+       power_profile_set_state(sc->status ? POWER_PROFILE_PERFORMANCE :
+                               POWER_PROFILE_ECONOMY);
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "%s Line\n", sc->status ? "On" : "Off");
+
+       acpi_UserNotify("ACAD", h, sc->status);
+    }
+}
+
+static void
+acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+    device_t dev = context;
+
+    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+               "Notify 0x%x\n", notify);
+
+    switch (notify) {
+    case ACPI_DEVICE_CHECK_PNP:
+    case ACPI_DEVICE_CHECK_EXISTENCE:
+    case ACPI_POWERSOURCE_STAT_CHANGE:
+       /* Temporarily.  It is better to notify policy manager */
+       AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_get_status, context);
+       break;
+    default:
+       break;
+    }
+}
+
+static int
+acpi_acad_probe(device_t dev)
+{
+    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE &&
+       acpi_MatchHid(dev, "ACPI0003")) {
+
+       device_set_desc(dev, "AC Adapter");
+       return (0);
+    }
+    return (ENXIO);
+}
+
+static int
+acpi_acad_attach(device_t dev)
+{
+    struct acpi_acad_softc *sc;
+    struct acpi_softc     *acpi_sc;
+    ACPI_HANDLE        handle;
+    int                error;
+
+    sc = device_get_softc(dev);
+    if (sc == NULL)
+       return (ENXIO);
+    handle = acpi_get_handle(dev);
+
+    error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS, acpi_acad_ioctl, dev);
+    if (error != 0)
+       return (error);
+
+    if (device_get_unit(dev) == 0) {
+       acpi_sc = acpi_device_get_parent_softc(dev);
+       SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
+                       SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
+                       OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD,
+                       &sc->status, 0, acpi_acad_sysctl, "I", "");
+    }
+
+    /* Get initial status after whole system is up. */
+    sc->status = -1;
+    sc->initializing = 0;
+
+    /*
+     * Also install a system notify handler even though this is not
+     * required by the specification.  The Casio FIVA needs this.
+     */
+    AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
+                            acpi_acad_notify_handler, dev);
+    AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY,
+                            acpi_acad_notify_handler, dev);
+    AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_init_acline, dev);
+
+    return (0);
+}
+
+static int
+acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
+{
+    struct acpi_acad_softc *sc;
+    device_t dev;
+
+    dev = (device_t)arg;
+    sc = device_get_softc(dev);
+    if (sc == NULL)
+       return (ENXIO);
+
+    /*
+     * No security check required: information retrieval only.  If
+     * new functions are added here, a check might be required.
+     */
+    switch (cmd) {
+    case ACPIIO_ACAD_GET_STATUS:
+       acpi_acad_get_status(dev);
+       *(int *)addr = sc->status;
+       break;
+    default:
+       break;
+    }
+
+    return (0);
+}
+
+static int
+acpi_acad_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    int val, error;
+
+    if (acpi_acad_get_acline(&val) != 0)
+       return (ENXIO);
+
+    val = *(u_int *)oidp->oid_arg1;
+    error = sysctl_handle_int(oidp, &val, 0, req);
+    return (error);
+}
+
+static void
+acpi_acad_init_acline(void *arg)
+{
+    struct acpi_acad_softc *sc;
+    device_t   dev;
+    int                retry, status;
+
+    dev = (device_t)arg;
+    sc = device_get_softc(dev);
+    if (sc->initializing)
+       return;
+
+    sc->initializing = 1;
+    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+               "acline initialization start\n");
+
+    status = 0;
+    for (retry = 0; retry < ACPI_ACAD_RETRY_MAX; retry++) {
+       acpi_acad_get_status(dev);
+       if (status != sc->status)
+           break;
+       AcpiOsSleep(10, 0);
+    }
+
+    sc->initializing = 0;
+    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+               "acline initialization done, tried %d times\n", retry + 1);
+}
+
+/*
+ * Public interfaces.
+ */
+int
+acpi_acad_get_acline(int *status)
+{
+    struct acpi_acad_softc *sc;
+    device_t dev;
+
+    dev = devclass_get_device(acpi_acad_devclass, 0);
+    if (dev == NULL)
+       return (ENXIO);
+    sc = device_get_softc(dev);
+    if (sc == NULL)
+       return (ENXIO);
+
+    acpi_acad_get_status(dev);
+    *status = sc->status;
+
+    return (0);
+}
diff --git a/sys/dev/acpica5/acpi_battery.c b/sys/dev/acpica5/acpi_battery.c
new file mode 100644 (file)
index 0000000..1f33171
--- /dev/null
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_battery.c,v 1.8 2003/08/11 15:34:43 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_battery.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/ioccom.h>
+#include <sys/sysctl.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+#include <dev/acpica5/acpiio.h>
+
+MALLOC_DEFINE(M_ACPIBATT, "acpibatt", "ACPI generic battery data");
+
+struct acpi_batteries {
+    TAILQ_ENTRY(acpi_batteries)        link;
+    struct acpi_battdesc       battdesc;
+};
+
+static TAILQ_HEAD(,acpi_batteries) acpi_batteries;
+static int                     acpi_batteries_initted = 0;
+static int                     acpi_batteries_units = 0;
+static int                     acpi_battery_info_expire = 5;
+static struct acpi_battinfo    acpi_battery_battinfo;
+
+int
+acpi_battery_get_units(void)
+{
+    return (acpi_batteries_units);
+}
+
+int
+acpi_battery_get_battdesc(int logical_unit, struct acpi_battdesc *battdesc)
+{
+    struct acpi_batteries *bp;
+    int i;
+
+    if (logical_unit < 0 || logical_unit >= acpi_batteries_units)
+       return (ENXIO);
+
+    i = 0;
+    TAILQ_FOREACH(bp, &acpi_batteries, link) {
+       if (logical_unit == i) {
+           battdesc->type = bp->battdesc.type;
+           battdesc->phys_unit = bp->battdesc.phys_unit;
+           return (0);
+       }
+       i++;
+    }
+
+    return (ENXIO);
+}
+
+int
+acpi_battery_get_battinfo(int unit, struct acpi_battinfo *battinfo)
+{
+    struct acpi_battdesc battdesc;
+    int error;
+
+    error = 0;
+    if (unit == -1) {
+       error = acpi_cmbat_get_battinfo(-1, battinfo);
+       goto out;
+    } else {
+       error = acpi_battery_get_battdesc(unit, &battdesc);
+       if (error != 0)
+           goto out;
+
+       switch (battdesc.type) {
+       case ACPI_BATT_TYPE_CMBAT:
+           error = acpi_cmbat_get_battinfo(battdesc.phys_unit, battinfo);
+           break;
+       default:
+           error = ENXIO;
+           break;
+       }
+    }
+
+out:
+    return (error);
+}
+
+int
+acpi_battery_get_info_expire(void)
+{
+    return (acpi_battery_info_expire);
+}
+
+static int
+acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg)
+{
+    union acpi_battery_ioctl_arg *ioctl_arg;
+    int        error, logical_unit;
+
+    ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
+    error = 0;
+
+    /*
+     * No security check required: information retrieval only.  If
+     * new functions are added here, a check might be required.
+     */
+    switch (cmd) {
+    case ACPIIO_BATT_GET_UNITS:
+       *(int *)addr = acpi_battery_get_units();
+       break;
+    case ACPIIO_BATT_GET_BATTDESC:
+       logical_unit = ioctl_arg->unit;
+       error = acpi_battery_get_battdesc(logical_unit, &ioctl_arg->battdesc);
+       break;
+    case ACPIIO_BATT_GET_BATTINFO:
+       logical_unit = ioctl_arg->unit;
+       error = acpi_battery_get_battinfo(logical_unit, &ioctl_arg->battinfo);
+       break;
+    default:
+       error = EINVAL;
+       break;
+    }
+
+    return (error);
+}
+
+static int
+acpi_battery_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    int        val, error;
+
+    acpi_battery_get_battinfo(-1, &acpi_battery_battinfo);
+    val = *(u_int *)oidp->oid_arg1;
+    error = sysctl_handle_int(oidp, &val, 0, req);
+    return (error);
+}
+
+static int
+acpi_battery_init(void)
+{
+    struct acpi_softc  *sc;
+    device_t            dev;
+    int                         error;
+
+    dev = devclass_get_device(devclass_find("acpi"), 0);
+    if (dev == NULL)
+       return (ENXIO);
+    sc = device_get_softc(dev);
+    if (sc == NULL)
+       return (ENXIO);
+
+    error = 0;
+    TAILQ_INIT(&acpi_batteries);
+    acpi_batteries_initted = 1;
+
+    error = acpi_register_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl,
+                               NULL);
+    if (error != 0)
+       return (error);
+    error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTDESC, acpi_battery_ioctl,
+                               NULL);
+    if (error != 0)
+       return (error);
+    error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl,
+                               NULL);
+    if (error != 0)
+       return (error);
+
+    sysctl_ctx_init(&sc->acpi_battery_sysctl_ctx);
+    sc->acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_battery_sysctl_ctx,
+                                  SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+                                  OID_AUTO, "battery", CTLFLAG_RD, 0, "");
+    SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx,
+       SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+       OID_AUTO, "life", CTLTYPE_INT | CTLFLAG_RD,
+       &acpi_battery_battinfo.cap, 0, acpi_battery_sysctl, "I", "");
+    SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx,
+       SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+       OID_AUTO, "time", CTLTYPE_INT | CTLFLAG_RD,
+       &acpi_battery_battinfo.min, 0, acpi_battery_sysctl, "I", "");
+    SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx,
+       SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+       OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RD,
+       &acpi_battery_battinfo.state, 0, acpi_battery_sysctl, "I", "");
+    SYSCTL_ADD_INT(&sc->acpi_battery_sysctl_ctx,
+       SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+       OID_AUTO, "units", CTLFLAG_RD, &acpi_batteries_units, 0, "");
+    SYSCTL_ADD_INT(&sc->acpi_battery_sysctl_ctx,
+       SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree),
+       OID_AUTO, "info_expire", CTLFLAG_RD | CTLFLAG_RW,
+       &acpi_battery_info_expire, 0, "");
+
+    return (error);
+}
+
+int
+acpi_battery_register(int type, int phys_unit)
+{
+    struct acpi_batteries *bp;
+    int error;
+
+    error = 0;
+    bp = malloc(sizeof(*bp), M_ACPIBATT, M_NOWAIT);
+    if (bp == NULL)
+       return (ENOMEM);
+
+    bp->battdesc.type = type;
+    bp->battdesc.phys_unit = phys_unit;
+    if (acpi_batteries_initted == 0) {
+       if ((error = acpi_battery_init()) != 0) {
+           free(bp, M_ACPIBATT);
+           return (error);
+       }
+    }
+               
+    TAILQ_INSERT_TAIL(&acpi_batteries, bp, link);
+    acpi_batteries_units++;
+
+    return (0);
+}
diff --git a/sys/dev/acpica5/acpi_button.c b/sys/dev/acpica5/acpi_button.c
new file mode 100644 (file)
index 0000000..13e843b
--- /dev/null
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_button.c,v 1.20 2004/02/19 18:16:34 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_button.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT     ACPI_BUTTON
+ACPI_MODULE_NAME("BUTTON")
+
+struct acpi_button_softc {
+    device_t   button_dev;
+    ACPI_HANDLE        button_handle;
+    boolean_t  button_type;
+#define                ACPI_POWER_BUTTON       0
+#define                ACPI_SLEEP_BUTTON       1
+    boolean_t  fixed;
+};
+
+#define                ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP    0x80
+#define                ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP   0x02
+
+static int     acpi_button_probe(device_t dev);
+static int     acpi_button_attach(device_t dev);
+static int     acpi_button_suspend(device_t dev);
+static int     acpi_button_resume(device_t dev);
+static void    acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify,
+                                          void *context);
+static ACPI_STATUS
+               acpi_button_fixed_handler(void *context);
+static void    acpi_button_notify_sleep(void *arg);
+static void    acpi_button_notify_wakeup(void *arg);
+
+static device_method_t acpi_button_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,    acpi_button_probe),
+    DEVMETHOD(device_attach,   acpi_button_attach),
+    DEVMETHOD(device_suspend,  acpi_button_suspend),
+    DEVMETHOD(device_shutdown, acpi_button_suspend),
+    DEVMETHOD(device_resume,   acpi_button_resume),
+
+    {0, 0}
+};
+
+static driver_t acpi_button_driver = {
+    "acpi_button",
+    acpi_button_methods,
+    sizeof(struct acpi_button_softc),
+};
+
+static devclass_t acpi_button_devclass;
+DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass,
+             0, 0);
+
+static int
+acpi_button_probe(device_t dev)
+{
+    struct acpi_button_softc   *sc;
+    int ret = ENXIO;
+
+    sc = device_get_softc(dev);
+    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) {
+       if (acpi_MatchHid(dev, "PNP0C0C")) {
+           device_set_desc(dev, "Power Button");
+           sc->button_type = ACPI_POWER_BUTTON;
+           ret = 0;
+       } else if (acpi_MatchHid(dev, "ACPI_FPB")) {
+           device_set_desc(dev, "Power Button (fixed)");
+           sc->button_type = ACPI_POWER_BUTTON;
+           sc->fixed = 1;
+           ret = 0;
+       } else if (acpi_MatchHid(dev, "PNP0C0E")) {
+           device_set_desc(dev, "Sleep Button");
+           sc->button_type = ACPI_SLEEP_BUTTON;
+           ret = 0;
+       } else if (acpi_MatchHid(dev, "ACPI_FSB")) {
+           device_set_desc(dev, "Sleep Button (fixed)");
+           sc->button_type = ACPI_SLEEP_BUTTON;
+           sc->fixed = 1;
+           ret = 0;
+       }
+    }
+    return (ret);
+}
+
+static int
+acpi_button_attach(device_t dev)
+{
+    struct acpi_button_softc   *sc;
+    ACPI_STATUS                        status;
+    int event;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    sc = device_get_softc(dev);
+    sc->button_dev = dev;
+    sc->button_handle = acpi_get_handle(dev);
+    event = (sc->button_type == ACPI_SLEEP_BUTTON) ?
+           ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON;
+
+    /* 
+     * Install the new handler.  We could remove any fixed handlers added
+     * from the FADT once we have a duplicate from the AML but some systems
+     * only return events on one or the other so we have to keep both.
+     */
+    if (sc->fixed) {
+       AcpiClearEvent(event);
+       status = AcpiInstallFixedEventHandler(event,
+                       acpi_button_fixed_handler, sc);
+    } else {
+       status = AcpiInstallNotifyHandler(sc->button_handle,
+                       ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc);
+    }
+    if (ACPI_FAILURE(status)) {
+       device_printf(sc->button_dev, "couldn't install notify handler - %s\n",
+                     AcpiFormatException(status));
+       return_VALUE (ENXIO);
+    }
+    acpi_device_enable_wake_capability(sc->button_handle, 1);
+
+    return_VALUE (0);
+}
+
+static int
+acpi_button_suspend(device_t dev)
+{
+    struct acpi_button_softc   *sc;
+
+    sc = device_get_softc(dev);
+    acpi_device_enable_wake_event(sc->button_handle);
+    return (0);
+}
+
+static int
+acpi_button_resume(device_t dev)
+{
+    return (0);
+}
+
+static void
+acpi_button_notify_sleep(void *arg)
+{
+    struct acpi_button_softc   *sc;
+    struct acpi_softc          *acpi_sc;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    sc = (struct acpi_button_softc *)arg;
+    acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
+    if (acpi_sc == NULL)
+       return_VOID;
+
+    acpi_UserNotify("Button", sc->button_handle, sc->button_type);
+
+    switch (sc->button_type) {
+    case ACPI_POWER_BUTTON:
+       ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n");
+       acpi_event_power_button_sleep(acpi_sc);
+       break;
+    case ACPI_SLEEP_BUTTON:
+       ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n");
+       acpi_event_sleep_button_sleep(acpi_sc);
+       break;
+    default:
+       break;          /* unknown button type */
+    }
+}
+
+static void
+acpi_button_notify_wakeup(void *arg)
+{
+    struct acpi_button_softc   *sc;
+    struct acpi_softc          *acpi_sc;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    sc = (struct acpi_button_softc *)arg;
+    acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
+    if (acpi_sc == NULL)
+       return_VOID;
+
+    acpi_UserNotify("Button", sc->button_handle, sc->button_type);
+
+    switch (sc->button_type) {
+    case ACPI_POWER_BUTTON:
+       ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n");
+       acpi_event_power_button_wake(acpi_sc);
+       break;
+    case ACPI_SLEEP_BUTTON:
+       ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n");
+       acpi_event_sleep_button_wake(acpi_sc);
+       break;
+    default:
+       break;          /* unknown button type */
+    }
+}
+
+static void 
+acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+    struct acpi_button_softc   *sc = (struct acpi_button_softc *)context;
+
+    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
+
+    switch (notify) {
+    case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
+       AcpiOsQueueForExecution(OSD_PRIORITY_LO,
+                               acpi_button_notify_sleep, sc);
+       break;   
+    case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
+       AcpiOsQueueForExecution(OSD_PRIORITY_LO,
+                               acpi_button_notify_wakeup, sc);
+       break;   
+    default:
+       break;          /* unknown notification value */
+    }
+}
+
+static ACPI_STATUS 
+acpi_button_fixed_handler(void *context)
+{
+    struct acpi_button_softc   *sc = (struct acpi_button_softc *)context;
+
+    ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context);
+
+    if (context == NULL)
+       return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+    acpi_button_notify_handler(sc->button_handle,
+                              ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc);
+    return_ACPI_STATUS (AE_OK);
+}
diff --git a/sys/dev/acpica5/acpi_cmbat.c b/sys/dev/acpica5/acpi_cmbat.c
new file mode 100644 (file)
index 0000000..5296a6e
--- /dev/null
@@ -0,0 +1,662 @@
+/*-
+ * Copyright (c) 2000 Munehiro Matsuda
+ * Copyright (c) 2000 Takanori Watanabe
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_cmbat.c,v 1.27 2003/12/23 18:27:35 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_cmbat.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/ioccom.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+#include <dev/acpica5/acpiio.h>
+
+MALLOC_DEFINE(M_ACPICMBAT, "acpicmbat", "ACPI control method battery data");
+
+/* Number of times to retry initialization before giving up. */
+#define ACPI_CMBAT_RETRY_MAX   6
+
+/* Check the battery once a minute. */
+#define        CMBAT_POLLRATE  (60 * hz)
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define        _COMPONENT      ACPI_BATTERY
+ACPI_MODULE_NAME("BATTERY")
+
+#define        ACPI_BATTERY_BST_CHANGE 0x80
+#define        ACPI_BATTERY_BIF_CHANGE 0x81
+
+struct acpi_cmbat_softc {
+    device_t       dev;
+
+    struct acpi_bif bif;
+    struct acpi_bst bst;
+    struct timespec bif_lastupdated;
+    struct timespec bst_lastupdated;
+    int                    bif_updating;
+    int                    bst_updating;
+
+    int                    present;
+    int                    cap;
+    int                    min;
+    int                    full_charge_time;
+    int                    initializing;
+};
+
+static struct timespec acpi_cmbat_info_lastupdated;
+
+/* XXX: devclass_get_maxunit() don't give us the current allocated units. */
+static int             acpi_cmbat_units = 0;
+
+static int             acpi_cmbat_info_expired(struct timespec *);
+static void            acpi_cmbat_info_updated(struct timespec *);
+static void            acpi_cmbat_get_bst(void *);
+static void            acpi_cmbat_get_bif(void *);
+static void            acpi_cmbat_notify_handler(ACPI_HANDLE, UINT32, void *);
+static int             acpi_cmbat_probe(device_t);
+static int             acpi_cmbat_attach(device_t);
+static int             acpi_cmbat_resume(device_t);
+static int             acpi_cmbat_ioctl(u_long, caddr_t, void *);
+static int             acpi_cmbat_is_bst_valid(struct acpi_bst*);
+static int             acpi_cmbat_is_bif_valid(struct acpi_bif*);
+static int             acpi_cmbat_get_total_battinfo(struct acpi_battinfo *);
+static void            acpi_cmbat_init_battery(void *);
+
+static device_method_t acpi_cmbat_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,    acpi_cmbat_probe),
+    DEVMETHOD(device_attach,   acpi_cmbat_attach),
+    DEVMETHOD(device_resume,   acpi_cmbat_resume),
+
+    {0, 0}
+};
+
+static driver_t acpi_cmbat_driver = {
+    "acpi_cmbat",
+    acpi_cmbat_methods,
+    sizeof(struct acpi_cmbat_softc),
+};
+
+static devclass_t acpi_cmbat_devclass;
+DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0);
+
+static int
+acpi_cmbat_info_expired(struct timespec *lastupdated)
+{
+    struct timespec    curtime;
+
+    if (lastupdated == NULL)
+       return (1);
+    if (!timespecisset(lastupdated))
+       return (1);
+
+    getnanotime(&curtime);
+    timespecsub(&curtime, lastupdated);
+    return (curtime.tv_sec < 0 ||
+           curtime.tv_sec > acpi_battery_get_info_expire());
+}
+
+
+static void
+acpi_cmbat_info_updated(struct timespec *lastupdated)
+{
+    if (lastupdated != NULL)
+       getnanotime(lastupdated);
+}
+
+static void
+acpi_cmbat_get_bst(void *context)
+{
+    device_t   dev;
+    struct acpi_cmbat_softc *sc;
+    ACPI_STATUS        as;
+    ACPI_OBJECT        *res;
+    ACPI_HANDLE        h;
+    ACPI_BUFFER        bst_buffer;
+
+    dev = context;
+    sc = device_get_softc(dev);
+    h = acpi_get_handle(dev);
+
+    if (!acpi_cmbat_info_expired(&sc->bst_lastupdated))
+       return;
+    if (sc->bst_updating)
+       return;
+    sc->bst_updating = 1;
+
+    bst_buffer.Pointer = NULL;
+    bst_buffer.Length = ACPI_ALLOCATE_BUFFER;
+    as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
+    if (ACPI_FAILURE(as)) {
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "error fetching current battery status -- %s\n",
+                   AcpiFormatException(as));
+       goto end;
+    }
+
+    res = (ACPI_OBJECT *)bst_buffer.Pointer;
+    if (!ACPI_PKG_VALID(res, 4)) {
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "battery status corrupted\n");
+       goto end;
+    }
+
+    if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0)
+       goto end;
+    if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0)
+       goto end;
+    if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0)
+       goto end;
+    if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0)
+       goto end;
+    acpi_cmbat_info_updated(&sc->bst_lastupdated);
+
+end:
+    if (bst_buffer.Pointer != NULL)
+       AcpiOsFree(bst_buffer.Pointer);
+    sc->bst_updating = 0;
+}
+
+static void
+acpi_cmbat_get_bif(void *context)
+{
+    device_t   dev;
+    struct acpi_cmbat_softc *sc;
+    ACPI_STATUS        as;
+    ACPI_OBJECT        *res;
+    ACPI_HANDLE        h;
+    ACPI_BUFFER        bif_buffer;
+
+    dev = context;
+    sc = device_get_softc(dev);
+    h = acpi_get_handle(dev);
+
+    if (!acpi_cmbat_info_expired(&sc->bif_lastupdated))
+       return;
+    if (sc->bif_updating)
+       return;
+    sc->bif_updating = 1;
+
+    bif_buffer.Pointer = NULL;
+    bif_buffer.Length = ACPI_ALLOCATE_BUFFER;
+    as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer);
+    if (ACPI_FAILURE(as)) {
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "error fetching current battery info -- %s\n",
+                   AcpiFormatException(as));
+       goto end;
+    }
+
+    res = (ACPI_OBJECT *)bif_buffer.Pointer;
+    if (!ACPI_PKG_VALID(res, 13)) {
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "battery info corrupted\n");
+       goto end;
+    }
+
+    if (acpi_PkgInt32(res,  0, &sc->bif.units) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  1, &sc->bif.dcap) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  2, &sc->bif.lfcap) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  3, &sc->bif.btech) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  4, &sc->bif.dvol) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  5, &sc->bif.wcap) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  6, &sc->bif.lcap) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  7, &sc->bif.gra1) != 0)
+       goto end;
+    if (acpi_PkgInt32(res,  8, &sc->bif.gra2) != 0)
+       goto end;
+    if (acpi_PkgStr(res,  9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0)
+       goto end;
+    if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
+       goto end;
+    if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0)
+       goto end;
+    if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
+       goto end;
+    acpi_cmbat_info_updated(&sc->bif_lastupdated);
+
+end:
+    if (bif_buffer.Pointer != NULL)
+       AcpiOsFree(bif_buffer.Pointer);
+    sc->bif_updating = 0;
+}
+
+static void
+acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+    device_t dev;
+    struct acpi_cmbat_softc    *sc;
+
+    dev = (device_t)context;
+    if ((sc = device_get_softc(dev)) == NULL)
+       return;
+
+    acpi_UserNotify("CMBAT", h, notify);
+
+    switch (notify) {
+    case ACPI_NOTIFY_DEVICE_CHECK:
+    case ACPI_BATTERY_BST_CHANGE:
+       timespecclear(&sc->bst_lastupdated);
+       break;
+    case ACPI_NOTIFY_BUS_CHECK:
+    case ACPI_BATTERY_BIF_CHANGE:
+       timespecclear(&sc->bif_lastupdated);
+       AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_get_bif, dev);
+       break;
+    default:
+       break;
+    }
+}
+
+static int
+acpi_cmbat_probe(device_t dev)
+{
+    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE &&
+       !acpi_disabled("cmbat") && acpi_MatchHid(dev, "PNP0C0A")) {
+
+       device_set_desc(dev, "Control Method Battery");
+       return (0);
+    }
+    return (ENXIO);
+}
+
+static int
+acpi_cmbat_attach(device_t dev)
+{
+    int                error;
+    ACPI_HANDLE        handle;
+    struct acpi_cmbat_softc *sc;
+
+    if ((sc = device_get_softc(dev)) == NULL)
+       return (ENXIO);
+
+    handle = acpi_get_handle(dev);
+
+    /*
+     * Install a system notify handler in addition to the device notify.
+     * Toshiba notebook uses this alternate notify for its battery.
+     */
+    AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
+                            acpi_cmbat_notify_handler, dev);
+    AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY,
+                            acpi_cmbat_notify_handler, dev);
+
+    sc->bif_updating = sc->bst_updating = 0;
+    sc->dev = dev;
+
+    timespecclear(&sc->bif_lastupdated);
+    timespecclear(&sc->bst_lastupdated);
+
+    if (acpi_cmbat_units == 0) {
+       error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF,
+                                   acpi_cmbat_ioctl, NULL);
+       if (error != 0)
+           return (error);
+       error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST,
+                                   acpi_cmbat_ioctl, NULL);
+       if (error != 0)
+               return (error);
+    }
+
+    error = acpi_battery_register(ACPI_BATT_TYPE_CMBAT, acpi_cmbat_units);
+    if (error != 0)
+       return (error);
+
+    acpi_cmbat_units++;
+    timespecclear(&acpi_cmbat_info_lastupdated);
+    sc->initializing = 0;
+    AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
+
+    return (0);
+}
+
+static int
+acpi_cmbat_resume(device_t dev)
+{
+    AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
+    return (0);
+}
+
+static int
+acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg)
+{
+    device_t   dev;
+    union acpi_battery_ioctl_arg *ioctl_arg;
+    struct acpi_cmbat_softc *sc;
+    struct acpi_bif    *bifp;
+    struct acpi_bst    *bstp;
+
+    ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
+    dev = devclass_get_device(acpi_cmbat_devclass, ioctl_arg->unit);
+    if (dev == NULL)
+       return (ENXIO);
+    sc = device_get_softc(dev);
+    if (sc == NULL)
+       return (ENXIO);
+
+    /*
+     * No security check required: information retrieval only.  If
+     * new functions are added here, a check might be required.
+     */
+    switch (cmd) {
+    case ACPIIO_CMBAT_GET_BIF:
+       acpi_cmbat_get_bif(dev);
+       bifp = &ioctl_arg->bif;
+       bifp->units = sc->bif.units;
+       bifp->dcap = sc->bif.dcap;
+       bifp->lfcap = sc->bif.lfcap;
+       bifp->btech = sc->bif.btech;
+       bifp->dvol = sc->bif.dvol;
+       bifp->wcap = sc->bif.wcap;
+       bifp->lcap = sc->bif.lcap;
+       bifp->gra1 = sc->bif.gra1;
+       bifp->gra2 = sc->bif.gra2;
+       strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
+       strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
+       strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
+       strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
+       break;
+    case ACPIIO_CMBAT_GET_BST:
+       bstp = &ioctl_arg->bst;
+       if (acpi_BatteryIsPresent(dev)) {
+           acpi_cmbat_get_bst(dev);
+           bstp->state = sc->bst.state;
+           bstp->rate = sc->bst.rate;
+           bstp->cap = sc->bst.cap;
+           bstp->volt = sc->bst.volt;
+       } else {
+           bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
+       }
+       break;
+    default:
+       break;
+    }
+
+    return (0);
+}
+
+static int
+acpi_cmbat_is_bst_valid(struct acpi_bst *bst)
+{
+    if (bst->state >= ACPI_BATT_STAT_MAX || bst->cap == 0xffffffff ||
+       bst->volt == 0xffffffff)
+
+       return (0);
+    else
+       return (1);
+}
+
+static int
+acpi_cmbat_is_bif_valid(struct acpi_bif *bif)
+{
+    if (bif->lfcap == 0)
+       return (0);
+    else
+       return (1);
+}
+
+static int
+acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo)
+{
+    int                i;
+    int                error;
+    int                batt_stat;
+    int                valid_rate, valid_units;
+    int                cap, min;
+    int                total_cap, total_min, total_full;
+    device_t   dev;
+    struct acpi_cmbat_softc *sc;
+    static int bat_units = 0;
+    static struct acpi_cmbat_softc **bat = NULL;
+
+    cap = min = -1;
+    batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
+    error = 0;
+
+    /* Allocate array of softc pointers */
+    if (bat_units != acpi_cmbat_units) {
+       if (bat != NULL) {
+           free(bat, M_ACPICMBAT);
+           bat = NULL;
+       }
+       bat_units = 0;
+    }
+    if (bat == NULL) {
+       bat_units = acpi_cmbat_units;
+       bat = malloc(sizeof(struct acpi_cmbat_softc *) * bat_units,
+                    M_ACPICMBAT, M_NOWAIT);
+       if (bat == NULL) {
+           error = ENOMEM;
+           goto out;
+       }
+
+       /* Collect softc pointers */
+       for (i = 0; i < acpi_cmbat_units; i++) {
+           if ((dev = devclass_get_device(acpi_cmbat_devclass, i)) == NULL) {
+               error = ENXIO;
+               goto out;
+           }
+           if ((sc = device_get_softc(dev)) == NULL) {
+               error = ENXIO;
+               goto out;
+           }
+           bat[i] = sc;
+       }
+    }
+
+    /* Get battery status, valid rate and valid units */
+    batt_stat = valid_rate = valid_units = 0;
+    for (i = 0; i < acpi_cmbat_units; i++) {
+       bat[i]->present = acpi_BatteryIsPresent(bat[i]->dev);
+       if (!bat[i]->present)
+           continue;
+
+       acpi_cmbat_get_bst(bat[i]->dev);
+
+       /* If battery not installed, we get strange values */
+       if (!acpi_cmbat_is_bst_valid(&(bat[i]->bst)) ||
+           !acpi_cmbat_is_bif_valid(&(bat[i]->bif))) {
+
+           bat[i]->present = 0;
+           continue;
+       }
+
+       valid_units++;
+       bat[i]->cap = 100 * bat[i]->bst.cap / bat[i]->bif.lfcap;
+       batt_stat |= bat[i]->bst.state;
+
+       if (bat[i]->bst.rate > 0) {
+           /*
+            * XXX Hack to calculate total battery time.
+            * Systems with 2 or more battries, they may get used
+            * one by one, thus bst.rate is set only to the one
+            * in use. For remaining batteries bst.rate = 0, which
+            * makes it impossible to calculate remaining time.
+            * Some other systems may need sum of bst.rate in
+            * dis-charging state.
+            * There for we sum up the bst.rate that is valid
+            * (in dis-charging state), and use the sum to
+            * calcutate remaining batteries' time.
+            */
+           if (bat[i]->bst.state & ACPI_BATT_STAT_DISCHARG)
+               valid_rate += bat[i]->bst.rate;
+       }
+    }
+
+    /* Calculate total battery capacity and time */
+    total_cap = total_min = total_full = 0;
+    for (i = 0; i < acpi_cmbat_units; i++) {
+       if (!bat[i]->present)
+           continue;
+
+       if (valid_rate > 0) {
+           /* Use the sum of bst.rate */
+           bat[i]->min = 60 * bat[i]->bst.cap / valid_rate;
+       } else if (bat[i]->full_charge_time > 0) {
+           bat[i]->min = (bat[i]->full_charge_time * bat[i]->cap) / 100;
+       } else {
+           /* Couldn't find valid rate and full battery time */
+           bat[i]->min = 0;
+       }
+       total_min += bat[i]->min;
+       total_cap += bat[i]->cap;
+       total_full += bat[i]->full_charge_time;
+    }
+
+    /* Battery life */
+    if (valid_units == 0) {
+       cap = -1;
+       batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
+    } else {
+       cap = total_cap / valid_units;
+    }
+
+    /* Battery time */
+    if (valid_units == 0) {
+       min = -1;
+    } else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) {
+       if (total_full == 0)
+           min = -1;
+       else
+           min = (total_full * cap) / 100;
+    } else {
+       min = total_min;
+    }
+    acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated);
+
+out:
+    battinfo->cap = cap;
+    battinfo->min = min;
+    battinfo->state = batt_stat;
+
+    return (error);
+}
+
+static void
+acpi_cmbat_init_battery(void *arg)
+{
+    int                retry;
+    device_t   dev = (device_t)arg;
+    struct acpi_cmbat_softc *sc = device_get_softc(dev);
+
+    if (sc->initializing)
+       return;
+
+    sc->initializing = 1;
+    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+               "battery initialization start\n");
+
+    for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10, 0)) {
+       sc->present = acpi_BatteryIsPresent(dev);
+       if (!sc->present)
+           continue;
+
+       timespecclear(&sc->bst_lastupdated);
+       timespecclear(&sc->bif_lastupdated);
+
+       acpi_cmbat_get_bst(dev);
+       if (!acpi_cmbat_is_bst_valid(&sc->bst))
+           continue;
+
+       acpi_cmbat_get_bif(dev);
+       if (!acpi_cmbat_is_bif_valid(&sc->bif))
+           continue;
+       break;
+    }
+
+    sc->initializing = 0;
+    if (retry == ACPI_CMBAT_RETRY_MAX) {
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "battery initialization failed, giving up\n");
+    } else {
+       ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
+                   "battery initialization done, tried %d times\n", retry + 1);
+    }
+}
+
+/*
+ * Public interfaces.
+ */
+int
+acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo)
+{
+    int                error;
+    device_t   dev;
+    struct acpi_cmbat_softc *sc;
+
+    if (unit == -1)
+       return (acpi_cmbat_get_total_battinfo(battinfo));
+
+    if (acpi_cmbat_info_expired(&acpi_cmbat_info_lastupdated)) {
+       error = acpi_cmbat_get_total_battinfo(battinfo);
+       if (error)
+           goto out;
+    }
+
+    error = 0;
+    if (unit >= acpi_cmbat_units) {
+       error = ENXIO;
+       goto out;
+    }
+
+    if ((dev = devclass_get_device(acpi_cmbat_devclass, unit)) == NULL) {
+       error = ENXIO;
+       goto out;
+    }
+    if ((sc = device_get_softc(dev)) == NULL) {
+       error = ENXIO;
+       goto out;
+    }
+
+    if (!sc->present) {
+       battinfo->cap = -1;
+       battinfo->min = -1;
+       battinfo->state = ACPI_BATT_STAT_NOT_PRESENT;
+    } else {
+       battinfo->cap = sc->cap;
+       battinfo->min = sc->min;
+       battinfo->state = sc->bst.state;
+    }
+
+out:
+    return (error);
+}
diff --git a/sys/dev/acpica5/acpi_cpu.c b/sys/dev/acpica5/acpi_cpu.c
new file mode 100644 (file)
index 0000000..0319682
--- /dev/null
@@ -0,0 +1,1076 @@
+/*-
+ * Copyright (c) 2003 Nate Lawson (SDG)
+ * Copyright (c) 2001 Michael Smith
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.29 2003/12/28 22:15:24 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_cpu.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/globaldata.h>
+#include <sys/power.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+
+#include <bus/pci/pcivar.h>
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/globaldata.h>
+#include <machine/smp.h>
+#include <sys/rman.h>
+
+#include "acpi.h"
+#include "acpivar.h"
+
+/*
+ * Support for ACPI Processor devices, including ACPI 2.0 throttling
+ * and C[1-3] sleep states.
+ *
+ * TODO: implement scans of all CPUs to be sure all Cx states are
+ * equivalent.
+ */
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT     ACPI_PROCESSOR
+ACPI_MODULE_NAME("PROCESSOR")
+
+struct acpi_cx {
+    struct resource    *p_lvlx;        /* Register to read to enter state. */
+    uint32_t            type;          /* C1-3 (C4 and up treated as C3). */
+    uint32_t            trans_lat;     /* Transition latency (usec). */
+    uint32_t            power;         /* Power consumed (mW). */
+};
+#define MAX_CX_STATES   8
+
+struct acpi_cx_stats {
+    int                         long_slp;      /* Count of sleeps >= trans_lat. */
+    int                         short_slp;     /* Count of sleeps < trans_lat. */
+};
+
+struct acpi_cpu_softc {
+    device_t            cpu_dev;
+    ACPI_HANDLE                 cpu_handle;
+    uint32_t            acpi_id;       /* ACPI processor id */
+    uint32_t            cpu_p_blk;     /* ACPI P_BLK location */
+    uint32_t            cpu_p_blk_len; /* P_BLK length (must be 6). */
+    struct resource    *cpu_p_cnt;     /* Throttling control register */
+    struct acpi_cx      cpu_cx_states[MAX_CX_STATES];
+    int                         cpu_cx_count;  /* Number of valid Cx states. */
+};
+
+#define CPU_GET_REG(reg, width)                                        \
+    (bus_space_read_ ## width(rman_get_bustag((reg)),                  \
+                     rman_get_bushandle((reg)), 0))
+#define CPU_SET_REG(reg, width, val)                                   \
+    (bus_space_write_ ## width(rman_get_bustag((reg)),                         \
+                      rman_get_bushandle((reg)), 0, (val)))
+
+/*
+ * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and
+ * reported to the user in tenths of a percent.
+ */
+static uint32_t                 cpu_duty_offset;
+static uint32_t                 cpu_duty_width;
+#define CPU_MAX_SPEED          (1 << cpu_duty_width)
+#define CPU_SPEED_PERCENT(x)   ((1000 * (x)) / CPU_MAX_SPEED)
+#define CPU_SPEED_PRINTABLE(x) (CPU_SPEED_PERCENT(x) / 10),    \
+                               (CPU_SPEED_PERCENT(x) % 10)
+#define CPU_P_CNT_THT_EN (1<<4)
+#define PM_USEC(x)      ((x) >> 2)     /* ~4 clocks per usec (3.57955 Mhz) */
+
+#define ACPI_CPU_NOTIFY_PERF_STATES    0x80    /* _PSS changed. */
+#define ACPI_CPU_NOTIFY_CX_STATES      0x81    /* _CST changed. */
+
+#define CPU_QUIRK_NO_C3                0x0001  /* C3-type states are not usable. */
+#define CPU_QUIRK_NO_THROTTLE  0x0002  /* Throttling is not usable. */
+
+#define PCI_VENDOR_INTEL       0x8086
+#define PCI_DEVICE_82371AB_3   0x7113  /* PIIX4 chipset for quirks. */
+#define PCI_REVISION_A_STEP    0
+#define PCI_REVISION_B_STEP    1
+#define PCI_REVISION_4E                2
+#define PCI_REVISION_4M                3
+
+/* Platform hardware resource information. */
+static uint32_t                 cpu_smi_cmd;   /* Value to write to SMI_CMD. */
+static uint8_t          cpu_pstate_cnt;/* Register to take over throttling. */
+static uint8_t          cpu_cst_cnt;   /* Indicate we are _CST aware. */
+static uint32_t                 cpu_rid;       /* Driver-wide resource id. */
+static uint32_t                 cpu_quirks;    /* Indicate any hardware bugs. */
+
+/* Runtime state. */
+static int              cpu_cx_count;  /* Number of valid states */
+static uint32_t                 cpu_cx_next;   /* State to use for next sleep. */
+static uint32_t                 cpu_non_c3;    /* Index of lowest non-C3 state. */
+static struct acpi_cx_stats cpu_cx_stats[MAX_CX_STATES];
+static int              cpu_idle_busy; /* Count of CPUs in acpi_cpu_idle. */
+
+/* Values for sysctl. */
+static uint32_t                 cpu_throttle_state;
+static uint32_t                 cpu_throttle_max;
+static int              cpu_cx_lowest;
+static char             cpu_cx_supported[64];
+
+static device_t                *cpu_devices;
+static int              cpu_ndevices;
+static struct acpi_cpu_softc **cpu_softc;
+
+static struct sysctl_ctx_list  acpi_cpu_sysctl_ctx;
+static struct sysctl_oid       *acpi_cpu_sysctl_tree;
+
+static int     acpi_cpu_probe(device_t dev);
+static int     acpi_cpu_attach(device_t dev);
+static int     acpi_pcpu_get_id(uint32_t idx, uint32_t *acpi_id,
+                                uint32_t *cpu_id);
+static int     acpi_cpu_shutdown(device_t dev);
+static int     acpi_cpu_throttle_probe(struct acpi_cpu_softc *sc);
+static int     acpi_cpu_cx_probe(struct acpi_cpu_softc *sc);
+static int     acpi_cpu_cx_cst(struct acpi_cpu_softc *sc);
+static void    acpi_cpu_startup(void *arg);
+static void    acpi_cpu_startup_throttling(void);
+static void    acpi_cpu_startup_cx(void);
+static void    acpi_cpu_throttle_set(uint32_t speed);
+static void    acpi_cpu_idle(void);
+static void    acpi_cpu_c1(void);
+static void    acpi_pm_ticksub(uint32_t *end, const uint32_t *start);
+static void    acpi_cpu_notify(ACPI_HANDLE h, UINT32 notify, void *context);
+static int     acpi_cpu_quirks(struct acpi_cpu_softc *sc);
+static int     acpi_cpu_throttle_sysctl(SYSCTL_HANDLER_ARGS);
+static int     acpi_cpu_history_sysctl(SYSCTL_HANDLER_ARGS);
+static int     acpi_cpu_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS);
+
+static device_method_t acpi_cpu_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,    acpi_cpu_probe),
+    DEVMETHOD(device_attach,   acpi_cpu_attach),
+    DEVMETHOD(device_shutdown, acpi_cpu_shutdown),
+
+    {0, 0}
+};
+
+static driver_t acpi_cpu_driver = {
+    "acpi_cpu",
+    acpi_cpu_methods,
+    sizeof(struct acpi_cpu_softc),
+};
+
+static devclass_t acpi_cpu_devclass;
+DRIVER_MODULE(acpi_cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, 0, 0);
+
+static int
+acpi_cpu_probe(device_t dev)
+{
+    if (!acpi_disabled("cpu") && acpi_get_type(dev) == ACPI_TYPE_PROCESSOR) {
+       device_set_desc(dev, "CPU");
+       if (cpu_softc == NULL)
+               cpu_softc = malloc(sizeof(struct acpi_cpu_softc *) *
+                   SMP_MAXCPU, M_TEMP /* XXX */, M_WAITOK | M_ZERO);
+       return (0);
+    }
+
+    return (ENXIO);
+}
+
+static int
+acpi_cpu_attach(device_t dev)
+{
+    struct acpi_cpu_softc *sc;
+    struct acpi_softc    *acpi_sc;
+    ACPI_OBJECT                   pobj;
+    ACPI_BUFFER                   buf;
+    ACPI_STATUS                   status;
+    int                           thr_ret, cx_ret, cpu_id;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    ACPI_ASSERTLOCK;
+
+    sc = device_get_softc(dev);
+    sc->cpu_dev = dev;
+    sc->cpu_handle = acpi_get_handle(dev);
+
+    /* Get our Processor object. */
+    buf.Pointer = &pobj;
+    buf.Length = sizeof(pobj);
+    status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf);
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "Couldn't get Processor object - %s\n",
+                     AcpiFormatException(status));
+       return_VALUE (ENXIO);
+    }
+    if (pobj.Type != ACPI_TYPE_PROCESSOR) {
+       device_printf(dev, "Processor object has bad type %d\n", pobj.Type);
+       return_VALUE (ENXIO);
+    }
+
+    /*
+     * Find the processor associated with our unit.  We could use the
+     * ProcId as a key, however, some boxes do not have the same values
+     * in their Processor object as the ProcId values in the MADT.
+     */
+    sc->acpi_id = pobj.Processor.ProcId;
+    if (acpi_pcpu_get_id(device_get_unit(dev), &sc->acpi_id, &cpu_id) != 0)
+       return_VALUE (ENXIO);
+
+    /*
+     * Check if we already probed this processor.  We scan the bus twice
+     * so it's possible we've already seen this one.
+     */
+    if (cpu_softc[cpu_id] != NULL)
+       return (ENXIO);
+    cpu_softc[cpu_id] = sc;
+
+    /* Get various global values from the Processor object. */
+    sc->cpu_p_blk = pobj.Processor.PblkAddress;
+    sc->cpu_p_blk_len = pobj.Processor.PblkLength;
+    ACPI_DEBUG_PRINT((ACPI_DB_INFO, "acpi_cpu%d: P_BLK at %#x/%d\n",
+                    device_get_unit(dev), sc->cpu_p_blk, sc->cpu_p_blk_len));
+
+    acpi_sc = acpi_device_get_parent_softc(dev);
+    sysctl_ctx_init(&acpi_cpu_sysctl_ctx);
+    acpi_cpu_sysctl_tree = SYSCTL_ADD_NODE(&acpi_cpu_sysctl_ctx,
+                               SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
+                               OID_AUTO, "cpu", CTLFLAG_RD, 0, "");
+
+    /* If this is the first device probed, check for quirks. */
+    if (device_get_unit(dev) == 0)
+       acpi_cpu_quirks(sc);
+
+    /*
+     * Probe for throttling and Cx state support.
+     * If none of these is present, free up unused resources.
+     */
+    thr_ret = acpi_cpu_throttle_probe(sc);
+    cx_ret = acpi_cpu_cx_probe(sc);
+    if (thr_ret == 0 || cx_ret == 0) {
+       status = AcpiInstallNotifyHandler(sc->cpu_handle, ACPI_DEVICE_NOTIFY,
+                                         acpi_cpu_notify, sc);
+       if (device_get_unit(dev) == 0)
+           AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cpu_startup, NULL);
+    } else {
+       sysctl_ctx_free(&acpi_cpu_sysctl_ctx);
+    }
+
+    return_VALUE (0);
+}
+
+/*
+ * Find the nth present CPU and return its pc_cpuid as well as set the
+ * pc_acpi_id from the most reliable source.
+ */
+static int
+acpi_pcpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id)
+{
+    struct mdglobaldata *md;
+    uint32_t    i;
+
+    KASSERT(acpi_id != NULL, ("Null acpi_id"));
+    KASSERT(cpu_id != NULL, ("Null cpu_id"));
+    for (i = 0; i < ncpus; i++) {
+       if ((smp_active_mask & (1 << i)) == 0)
+           continue;
+       md = (struct mdglobaldata *)globaldata_find(i);
+       KASSERT(md != NULL, ("no pcpu data for %d", i));
+       if (idx-- == 0) {
+           /*
+            * If pc_acpi_id was not initialized (e.g., a non-APIC UP box)
+            * override it with the value from the ASL.  Otherwise, if the
+            * two don't match, prefer the MADT-derived value.  Finally,
+            * return the pc_cpuid to reference this processor.
+            */
+           if (md->gd_acpi_id == 0xffffffff)
+                md->gd_acpi_id = *acpi_id;
+           else if (md->gd_acpi_id != *acpi_id)
+               *acpi_id = md->gd_acpi_id;
+           *cpu_id = md->mi.gd_cpuid;
+           return (0);
+       }
+    }
+
+    return (ESRCH);
+}
+
+static int
+acpi_cpu_shutdown(device_t dev)
+{
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /* Disable any entry to the idle function. */
+    cpu_cx_count = 0;
+
+    /* Wait for all processors to exit acpi_cpu_idle(). */
+#ifdef SMP
+    /*smp_rendezvous(NULL, NULL, NULL, NULL);*/
+    KKASSERT(0);       /* XXX use rendezvous */
+#endif
+    while (cpu_idle_busy > 0)
+       DELAY(1);
+
+    return_VALUE (0);
+}
+
+static int
+acpi_cpu_throttle_probe(struct acpi_cpu_softc *sc)
+{
+    uint32_t            duty_end;
+    ACPI_BUFFER                 buf;
+    ACPI_OBJECT                 obj;
+    ACPI_GENERIC_ADDRESS gas;
+    ACPI_STATUS                 status;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    ACPI_ASSERTLOCK;
+
+    /* Get throttling parameters from the FADT.  0 means not supported. */
+    if (device_get_unit(sc->cpu_dev) == 0) {
+       cpu_smi_cmd = AcpiGbl_FADT->SmiCmd;
+       cpu_pstate_cnt = AcpiGbl_FADT->PstateCnt;
+       cpu_cst_cnt = AcpiGbl_FADT->CstCnt;
+       cpu_duty_offset = AcpiGbl_FADT->DutyOffset;
+       cpu_duty_width = AcpiGbl_FADT->DutyWidth;
+    }
+    if (cpu_duty_width == 0 || (cpu_quirks & CPU_QUIRK_NO_THROTTLE) != 0)
+       return (ENXIO);
+
+    /* Validate the duty offset/width. */
+    duty_end = cpu_duty_offset + cpu_duty_width - 1;
+    if (duty_end > 31) {
+       device_printf(sc->cpu_dev, "CLK_VAL field overflows P_CNT register\n");
+       return (ENXIO);
+    }
+    if (cpu_duty_offset <= 4 && duty_end >= 4) {
+       device_printf(sc->cpu_dev, "CLK_VAL field overlaps THT_EN bit\n");
+       return (ENXIO);
+    }
+
+    /*
+     * If not present, fall back to using the processor's P_BLK to find
+     * the P_CNT register.
+     *
+     * Note that some systems seem to duplicate the P_BLK pointer
+     * across multiple CPUs, so not getting the resource is not fatal.
+     */
+    buf.Pointer = &obj;
+    buf.Length = sizeof(obj);
+    status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf);
+    if (ACPI_SUCCESS(status)) {
+       if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) {
+           device_printf(sc->cpu_dev, "_PTC buffer too small\n");
+           return (ENXIO);
+       }
+       memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas));
+       sc->cpu_p_cnt = acpi_bus_alloc_gas(sc->cpu_dev, &cpu_rid, &gas);
+       if (sc->cpu_p_cnt != NULL) {
+           ACPI_DEBUG_PRINT((ACPI_DB_INFO, "acpi_cpu%d: P_CNT from _PTC\n",
+                            device_get_unit(sc->cpu_dev)));
+       }
+    }
+
+    /* If _PTC not present or other failure, try the P_BLK. */
+    if (sc->cpu_p_cnt == NULL) {
+       /* The spec says P_BLK must be at least 6 bytes long. */
+       if (sc->cpu_p_blk == 0 || sc->cpu_p_blk_len != 6)
+           return (ENXIO);
+       gas.Address = sc->cpu_p_blk;
+       gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
+       gas.RegisterBitWidth = 32;
+       sc->cpu_p_cnt = acpi_bus_alloc_gas(sc->cpu_dev, &cpu_rid, &gas);
+       if (sc->cpu_p_cnt != NULL) {
+           ACPI_DEBUG_PRINT((ACPI_DB_INFO, "acpi_cpu%d: P_CNT from P_BLK\n",
+                            device_get_unit(sc->cpu_dev)));
+       } else {
+           device_printf(sc->cpu_dev, "Failed to attach throttling P_CNT\n");
+           return (ENXIO);
+       }
+    }
+    cpu_rid++;
+
+    return (0);
+}
+
+static int
+acpi_cpu_cx_probe(struct acpi_cpu_softc *sc)
+{
+    ACPI_GENERIC_ADDRESS gas;
+    struct acpi_cx     *cx_ptr;
+    int                         error;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /* Bus mastering arbitration control is needed for C3. */
+    if (AcpiGbl_FADT->V1_Pm2CntBlk == 0 || AcpiGbl_FADT->Pm2CntLen == 0) {
+       cpu_quirks |= CPU_QUIRK_NO_C3;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                        "acpi_cpu%d: No BM control, C3 disabled\n",
+                        device_get_unit(sc->cpu_dev)));
+    }
+
+    /*
+     * First, check for the ACPI 2.0 _CST sleep states object.
+     * If not usable, fall back to the P_BLK's P_LVL2 and P_LVL3.
+     */
+    sc->cpu_cx_count = 0;
+    error = acpi_cpu_cx_cst(sc);
+    if (error != 0) {
+       cx_ptr = sc->cpu_cx_states;
+
+       /* C1 has been required since just after ACPI 1.0 */
+       cx_ptr->type = ACPI_STATE_C1;
+       cx_ptr->trans_lat = 0;
+       cpu_non_c3 = 0;
+       cx_ptr++;
+       sc->cpu_cx_count++;
+
+       if (sc->cpu_p_blk_len != 6)
+           goto done;
+
+       /* Validate and allocate resources for C2 (P_LVL2). */
+       gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
+       gas.RegisterBitWidth = 8;
+       if (AcpiGbl_FADT->Plvl2Lat < 100) {
+           gas.Address = sc->cpu_p_blk + 4;
+           cx_ptr->p_lvlx = acpi_bus_alloc_gas(sc->cpu_dev, &cpu_rid, &gas);
+           if (cx_ptr->p_lvlx != NULL) {
+               cpu_rid++;
+               cx_ptr->type = ACPI_STATE_C2;
+               cx_ptr->trans_lat = AcpiGbl_FADT->Plvl2Lat;
+               cpu_non_c3 = 1;
+               cx_ptr++;
+               sc->cpu_cx_count++;
+           }
+       }
+
+       /* Validate and allocate resources for C3 (P_LVL3). */
+       if (AcpiGbl_FADT->Plvl3Lat < 1000 &&
+           (cpu_quirks & CPU_QUIRK_NO_C3) == 0) {
+
+           gas.Address = sc->cpu_p_blk + 5;
+           cx_ptr->p_lvlx = acpi_bus_alloc_gas(sc->cpu_dev, &cpu_rid, &gas);
+           if (cx_ptr->p_lvlx != NULL) {
+               cpu_rid++;
+               cx_ptr->type = ACPI_STATE_C3;
+               cx_ptr->trans_lat = AcpiGbl_FADT->Plvl3Lat;
+               cx_ptr++;
+               sc->cpu_cx_count++;
+           }
+       }
+    }
+
+done:
+    /* If no valid registers were found, don't attach. */
+    if (sc->cpu_cx_count == 0)
+       return (ENXIO);
+
+    return (0);
+}
+
+/*
+ * Parse a _CST package and set up its Cx states.  Since the _CST object
+ * can change dynamically, our notify handler may call this function
+ * to clean up and probe the new _CST package.
+ */
+static int
+acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
+{
+    struct      acpi_cx *cx_ptr;
+    ACPI_STATUS         status;
+    ACPI_BUFFER         buf;
+    ACPI_OBJECT        *top;
+    ACPI_OBJECT        *pkg;
+    uint32_t    count;
+    int                 i;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    buf.Pointer = NULL;
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+    status = AcpiEvaluateObject(sc->cpu_handle, "_CST", NULL, &buf);
+    if (ACPI_FAILURE(status))
+       return (ENXIO);
+
+    /* _CST is a package with a count and at least one Cx package. */
+    top = (ACPI_OBJECT *)buf.Pointer;
+    if (!ACPI_PKG_VALID(top, 2) || acpi_PkgInt32(top, 0, &count) != 0) {
+       device_printf(sc->cpu_dev, "Invalid _CST package\n");
+       AcpiOsFree(buf.Pointer);
+       return (ENXIO);
+    }
+    if (count != top->Package.Count - 1) {
+       device_printf(sc->cpu_dev, "Invalid _CST state count (%d != %d)\n",
+              count, top->Package.Count - 1);
+       count = top->Package.Count - 1;
+    }
+    if (count > MAX_CX_STATES) {
+       device_printf(sc->cpu_dev, "_CST has too many states (%d)\n", count);
+       count = MAX_CX_STATES;
+    }
+
+    /* Set up all valid states. */
+    sc->cpu_cx_count = 0;
+    cx_ptr = sc->cpu_cx_states;
+    for (i = 0; i < count; i++) {
+       pkg = &top->Package.Elements[i + 1];
+       if (!ACPI_PKG_VALID(pkg, 4) ||
+           acpi_PkgInt32(pkg, 1, &cx_ptr->type) != 0 ||
+           acpi_PkgInt32(pkg, 2, &cx_ptr->trans_lat) != 0 ||
+           acpi_PkgInt32(pkg, 3, &cx_ptr->power) != 0) {
+
+           device_printf(sc->cpu_dev, "Skipping invalid Cx state package\n");
+           continue;
+       }
+
+       /* Validate the state to see if we should use it. */
+       switch (cx_ptr->type) {
+       case ACPI_STATE_C1:
+           cpu_non_c3 = i;
+           cx_ptr++;
+           sc->cpu_cx_count++;
+           continue;
+       case ACPI_STATE_C2:
+           if (cx_ptr->trans_lat > 100) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                "acpi_cpu%d: C2[%d] not available.\n",
+                                device_get_unit(sc->cpu_dev), i));
+               continue;
+           }
+           cpu_non_c3 = i;
+           break;
+       case ACPI_STATE_C3:
+       default:
+           if (cx_ptr->trans_lat > 1000 ||
+               (cpu_quirks & CPU_QUIRK_NO_C3) != 0) {
+
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                "acpi_cpu%d: C3[%d] not available.\n",
+                                device_get_unit(sc->cpu_dev), i));
+               continue;
+           }
+           break;
+       }
+
+#ifdef notyet
+       /* Free up any previous register. */
+       if (cx_ptr->p_lvlx != NULL) {
+           bus_release_resource(sc->cpu_dev, 0, 0, cx_ptr->p_lvlx);
+           cx_ptr->p_lvlx = NULL;
+       }
+#endif
+
+       /* Allocate the control register for C2 or C3. */
+       acpi_PkgGas(sc->cpu_dev, pkg, 0, &cpu_rid, &cx_ptr->p_lvlx);
+       if (cx_ptr->p_lvlx != NULL) {
+           cpu_rid++;
+           ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                            "acpi_cpu%d: Got C%d - %d latency\n",
+                            device_get_unit(sc->cpu_dev), cx_ptr->type,
+                            cx_ptr->trans_lat));
+           cx_ptr++;
+           sc->cpu_cx_count++;
+       }
+    }
+    AcpiOsFree(buf.Pointer);
+
+    return (0);
+}
+
+/*
+ * Call this *after* all CPUs have been attached.
+ */
+static void
+acpi_cpu_startup(void *arg)
+{
+    struct acpi_cpu_softc *sc;
+    int count, i;
+
+    /* Get set of CPU devices */
+    devclass_get_devices(acpi_cpu_devclass, &cpu_devices, &cpu_ndevices);
+
+    /*
+     * Make sure all the processors' Cx counts match.  We should probably
+     * also check the contents of each.  However, no known systems have
+     * non-matching Cx counts so we'll deal with this later.
+     */
+    count = MAX_CX_STATES;
+    for (i = 0; i < cpu_ndevices; i++) {
+       sc = device_get_softc(cpu_devices[i]);
+       count = min(sc->cpu_cx_count, count);
+    }
+    cpu_cx_count = count;
+
+    /* Perform throttling and Cx final initialization. */
+    sc = device_get_softc(cpu_devices[0]);
+    if (sc->cpu_p_cnt != NULL)
+       acpi_cpu_startup_throttling();
+    if (cpu_cx_count > 0)
+       acpi_cpu_startup_cx();
+}
+
+/*
+ * Takes the ACPI lock to avoid fighting anyone over the SMI command
+ * port.
+ */
+static void
+acpi_cpu_startup_throttling()
+{
+    ACPI_LOCK_DECL;
+
+    /* Initialise throttling states */
+    cpu_throttle_max = CPU_MAX_SPEED;
+    cpu_throttle_state = CPU_MAX_SPEED;
+
+    SYSCTL_ADD_INT(&acpi_cpu_sysctl_ctx,
+                  SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+                  OID_AUTO, "throttle_max", CTLFLAG_RD,
+                  &cpu_throttle_max, 0, "maximum CPU speed");
+    SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx,
+                   SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+                   OID_AUTO, "throttle_state",
+                   CTLTYPE_INT | CTLFLAG_RW, &cpu_throttle_state,
+                   0, acpi_cpu_throttle_sysctl, "I", "current CPU speed");
+
+    /* If ACPI 2.0+, signal platform that we are taking over throttling. */
+    ACPI_LOCK;
+    if (cpu_pstate_cnt != 0)
+       AcpiOsWritePort(cpu_smi_cmd, cpu_pstate_cnt, 8);
+
+    /* Set initial speed to maximum. */
+    acpi_cpu_throttle_set(cpu_throttle_max);
+    ACPI_UNLOCK;
+
+    printf("acpi_cpu: throttling enabled, %d steps (100%% to %d.%d%%), "
+          "currently %d.%d%%\n", CPU_MAX_SPEED, CPU_SPEED_PRINTABLE(1),
+          CPU_SPEED_PRINTABLE(cpu_throttle_state));
+}
+
+static void
+acpi_cpu_startup_cx()
+{
+    struct acpi_cpu_softc *sc;
+    struct sbuf                 sb;
+    int i;
+    ACPI_LOCK_DECL;
+
+    sc = device_get_softc(cpu_devices[0]);
+    sbuf_new(&sb, cpu_cx_supported, sizeof(cpu_cx_supported), SBUF_FIXEDLEN);
+    for (i = 0; i < cpu_cx_count; i++) {
+       sbuf_printf(&sb, "C%d/%d ", sc->cpu_cx_states[i].type,
+                   sc->cpu_cx_states[i].trans_lat);
+    }
+    sbuf_trim(&sb);
+    sbuf_finish(&sb);
+    SYSCTL_ADD_STRING(&acpi_cpu_sysctl_ctx,
+                     SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+                     OID_AUTO, "cx_supported", CTLFLAG_RD, cpu_cx_supported,
+                     0, "Cx/microsecond values for supported Cx states");
+    SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx,
+                   SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+                   OID_AUTO, "cx_lowest", CTLTYPE_INT | CTLFLAG_RW,
+                   NULL, 0, acpi_cpu_cx_lowest_sysctl, "I",
+                   "lowest Cx sleep state to use");
+    SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx,
+                   SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
+                   OID_AUTO, "cx_history", CTLTYPE_STRING | CTLFLAG_RD,
+                   NULL, 0, acpi_cpu_history_sysctl, "A", "");
+
+#ifdef notyet
+    /* Signal platform that we can handle _CST notification. */
+    if (cpu_cst_cnt != 0) {
+       ACPI_LOCK;
+       AcpiOsWritePort(cpu_smi_cmd, cpu_cst_cnt, 8);
+       ACPI_UNLOCK;
+    }
+#endif
+
+    /* Take over idling from cpu_idle_default(). */
+    cpu_cx_next = cpu_cx_lowest;
+    KKASSERT(0);
+    /* cpu_idle_hook = acpi_cpu_idle; */
+}
+
+/*
+ * Set CPUs to the new state.
+ *
+ * Must be called with the ACPI lock held.
+ */
+static void
+acpi_cpu_throttle_set(uint32_t speed)
+{
+    struct acpi_cpu_softc      *sc;
+    int                                i;
+    uint32_t                   p_cnt, clk_val;
+
+    ACPI_ASSERTLOCK;
+
+    /* Iterate over processors */
+    for (i = 0; i < cpu_ndevices; i++) {
+       sc = device_get_softc(cpu_devices[i]);
+       if (sc->cpu_p_cnt == NULL)
+           continue;
+
+       /* Get the current P_CNT value and disable throttling */
+       p_cnt = CPU_GET_REG(sc->cpu_p_cnt, 4);
+       p_cnt &= ~CPU_P_CNT_THT_EN;
+       CPU_SET_REG(sc->cpu_p_cnt, 4, p_cnt);
+
+       /* If we're at maximum speed, that's all */
+       if (speed < CPU_MAX_SPEED) {
+           /* Mask the old CLK_VAL off and or-in the new value */
+           clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset;
+           p_cnt &= ~clk_val;
+           p_cnt |= (speed << cpu_duty_offset);
+
+           /* Write the new P_CNT value and then enable throttling */
+           CPU_SET_REG(sc->cpu_p_cnt, 4, p_cnt);
+           p_cnt |= CPU_P_CNT_THT_EN;
+           CPU_SET_REG(sc->cpu_p_cnt, 4, p_cnt);
+       }
+       ACPI_VPRINT(sc->cpu_dev, acpi_device_get_parent_softc(sc->cpu_dev),
+                   "set speed to %d.%d%%\n", CPU_SPEED_PRINTABLE(speed));
+    }
+    cpu_throttle_state = speed;
+}
+
+/*
+ * Idle the CPU in the lowest state possible.
+ * This function is called with interrupts disabled.
+ */
+static void
+acpi_cpu_idle()
+{
+    struct     acpi_cpu_softc *sc;
+    struct     acpi_cx *cx_next;
+    uint32_t   start_time, end_time;
+    int                bm_active, i, asleep;
+
+    /* If disabled, return immediately. */
+    if (cpu_cx_count == 0) {
+       ACPI_ENABLE_IRQS();
+       return;
+    }
+
+    /*
+     * Look up our CPU id to get our softc.  If it's NULL, we'll use C1
+     * since there is no ACPI processor object for this CPU.  This occurs
+     * for logical CPUs in the HTT case.
+     */
+    sc = cpu_softc[mdcpu->mi.gd_cpuid];
+    if (sc == NULL) {
+       acpi_cpu_c1();
+       return;
+    }
+
+    /* Record that a CPU is in the idle function. */
+    atomic_add_int(&cpu_idle_busy, 1);
+
+    /*
+     * Check for bus master activity.  If there was activity, clear
+     * the bit and use the lowest non-C3 state.  Note that the USB
+     * driver polling for new devices keeps this bit set all the
+     * time if USB is enabled.
+     */
+    AcpiGetRegister(ACPI_BITREG_BUS_MASTER_STATUS, &bm_active,
+                   ACPI_MTX_DO_NOT_LOCK);
+    if (bm_active != 0) {
+       AcpiSetRegister(ACPI_BITREG_BUS_MASTER_STATUS, 1,
+                       ACPI_MTX_DO_NOT_LOCK);
+       cpu_cx_next = min(cpu_cx_next, cpu_non_c3);
+    }
+
+    /* Perform the actual sleep based on the Cx-specific semantics. */
+    cx_next = &sc->cpu_cx_states[cpu_cx_next];
+    switch (cx_next->type) {
+    case ACPI_STATE_C0:
+       panic("acpi_cpu_idle: attempting to sleep in C0");
+       /* NOTREACHED */
+    case ACPI_STATE_C1:
+       /* Execute HLT (or equivalent) and wait for an interrupt. */
+       acpi_cpu_c1();
+
+       /*
+        * We can't calculate the time spent in C1 since the place we
+        * wake up is an ISR.  Use a constant time of 1 ms.
+        */
+       start_time = 0;
+       end_time = 1000;
+       break;
+    case ACPI_STATE_C2:
+       /*
+        * Read from P_LVLx to enter C2, checking time spent asleep.
+        * Use the ACPI timer for measuring sleep time.  Since we need to
+        * get the time very close to the CPU start/stop clock logic, this
+        * is the only reliable time source.
+        */
+       AcpiHwLowLevelRead(32, &start_time, &AcpiGbl_FADT->XPmTmrBlk);
+       CPU_GET_REG(cx_next->p_lvlx, 1);
+
+       /*
+        * Read the end time twice.  Since it may take an arbitrary time
+        * to enter the idle state, the first read may be executed before
+        * the processor has stopped.  Doing it again provides enough
+        * margin that we are certain to have a correct value.
+        */
+       AcpiHwLowLevelRead(32, &end_time, &AcpiGbl_FADT->XPmTmrBlk);
+       AcpiHwLowLevelRead(32, &end_time, &AcpiGbl_FADT->XPmTmrBlk);
+       ACPI_ENABLE_IRQS();
+       break;
+    case ACPI_STATE_C3:
+    default:
+       /* Disable bus master arbitration and enable bus master wakeup. */
+       AcpiSetRegister(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+       AcpiSetRegister(ACPI_BITREG_BUS_MASTER_RLD, 1, ACPI_MTX_DO_NOT_LOCK);
+
+       /* Read from P_LVLx to enter C3, checking time spent asleep. */
+       AcpiHwLowLevelRead(32, &start_time, &AcpiGbl_FADT->XPmTmrBlk);
+       CPU_GET_REG(cx_next->p_lvlx, 1);
+
+       /* Read the end time twice.  See comment for C2 above. */
+       AcpiHwLowLevelRead(32, &end_time, &AcpiGbl_FADT->XPmTmrBlk);
+       AcpiHwLowLevelRead(32, &end_time, &AcpiGbl_FADT->XPmTmrBlk);
+
+       /* Enable bus master arbitration and disable bus master wakeup. */
+       AcpiSetRegister(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK);
+       AcpiSetRegister(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK);
+       ACPI_ENABLE_IRQS();
+       break;
+    }
+
+    /* Find the actual time asleep in microseconds, minus overhead. */
+    acpi_pm_ticksub(&end_time, &start_time);
+    asleep = PM_USEC(end_time) - cx_next->trans_lat;
+
+    /* Record statistics */
+    if (asleep < cx_next->trans_lat)
+       cpu_cx_stats[cpu_cx_next].short_slp++;
+    else
+       cpu_cx_stats[cpu_cx_next].long_slp++;
+
+    /*
+     * If we slept 100 us or more, use the lowest Cx state.
+     * Otherwise, find the lowest state that has a latency less than
+     * or equal to the length of our last sleep.
+     */
+    if (asleep >= 100)
+       cpu_cx_next = cpu_cx_lowest;
+    else {
+       for (i = cpu_cx_lowest; i >= 0; i--) {
+           if (sc->cpu_cx_states[i].trans_lat <= asleep) {
+               cpu_cx_next = i;
+               break;
+           }
+       }
+    }
+
+    /* Decrement reference count checked by acpi_cpu_shutdown(). */
+    atomic_subtract_int(&cpu_idle_busy, 1);
+}
+
+/* Put the CPU in C1 in a machine-dependant way. */
+static void
+acpi_cpu_c1()
+{
+#ifdef __ia64__
+    ia64_call_pal_static(PAL_HALT_LIGHT, 0, 0, 0);
+#else
+    __asm __volatile("sti; hlt");
+#endif
+}
+
+/* Find the difference between two PM tick counts. */
+static void
+acpi_pm_ticksub(uint32_t *end, const uint32_t *start)
+{
+    if (*end >= *start)
+       *end = *end - *start;
+    else if (AcpiGbl_FADT->TmrValExt == 0)
+       *end = (((0x00FFFFFF - *start) + *end + 1) & 0x00FFFFFF);
+    else
+       *end = ((0xFFFFFFFF - *start) + *end + 1);
+}
+
+/*
+ * Re-evaluate the _PSS and _CST objects when we are notified that they
+ * have changed.
+ *
+ * XXX Re-evaluation disabled until locking is done.
+ */
+static void
+acpi_cpu_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+    struct acpi_cpu_softc *sc = (struct acpi_cpu_softc *)context;
+
+    switch (notify) {
+    case ACPI_CPU_NOTIFY_PERF_STATES:
+       device_printf(sc->cpu_dev, "Performance states changed\n");
+       /* acpi_cpu_px_available(sc); */
+       break;
+    case ACPI_CPU_NOTIFY_CX_STATES:
+       device_printf(sc->cpu_dev, "Cx states changed\n");
+       /* acpi_cpu_cx_cst(sc); */
+       break;
+    default:
+       device_printf(sc->cpu_dev, "Unknown notify %#x\n", notify);
+       break;
+    }
+}
+
+static int
+acpi_cpu_quirks(struct acpi_cpu_softc *sc)
+{
+
+    /*
+     * C3 is not supported on multiple CPUs since this would require
+     * flushing all caches which is currently too expensive.
+     */
+    if (ncpus > 1)
+       cpu_quirks |= CPU_QUIRK_NO_C3;
+
+#ifdef notyet
+    /* Look for various quirks of the PIIX4 part. */
+    acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3);
+    if (acpi_dev != NULL) {
+       switch (pci_get_revid(acpi_dev)) {
+       /*
+        * Disable throttling control on PIIX4 A and B-step.
+        * See specification changes #13 ("Manual Throttle Duty Cycle")
+        * and #14 ("Enabling and Disabling Manual Throttle"), plus
+        * erratum #5 ("STPCLK# Deassertion Time") from the January
+        * 2002 PIIX4 specification update.  Note that few (if any)
+        * mobile systems ever used this part.
+        */
+       case PCI_REVISION_A_STEP:
+       case PCI_REVISION_B_STEP:
+           cpu_quirks |= CPU_QUIRK_NO_THROTTLE;
+           /* FALLTHROUGH */
+       /*
+        * Disable C3 support for all PIIX4 chipsets.  Some of these parts
+        * do not report the BMIDE status to the BM status register and
+        * others have a livelock bug if Type-F DMA is enabled.  Linux
+        * works around the BMIDE bug by reading the BM status directly
+        * but we take the simpler approach of disabling C3 for these
+        * parts.
+        *
+        * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
+        * Livelock") from the January 2002 PIIX4 specification update.
+        * Applies to all PIIX4 models.
+        */
+       case PCI_REVISION_4E:
+       case PCI_REVISION_4M:
+           cpu_quirks |= CPU_QUIRK_NO_C3;
+           break;
+       default:
+           break;
+       }
+    }
+#endif
+
+    return (0);
+}
+
+/* Handle changes in the CPU throttling setting. */
+static int
+acpi_cpu_throttle_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    uint32_t   *argp;
+    uint32_t    arg;
+    int                 error;
+    ACPI_LOCK_DECL;
+
+    argp = (uint32_t *)oidp->oid_arg1;
+    arg = *argp;
+    error = sysctl_handle_int(oidp, &arg, 0, req);
+
+    /* Error or no new value */
+    if (error != 0 || req->newptr == NULL)
+       return (error);
+    if (arg < 1 || arg > cpu_throttle_max)
+       return (EINVAL);
+
+    /* If throttling changed, notify the BIOS of the new rate. */
+    ACPI_LOCK;
+    if (*argp != arg) {
+       *argp = arg;
+       acpi_cpu_throttle_set(arg);
+    }
+    ACPI_UNLOCK;
+
+    return (0);
+}
+
+static int
+acpi_cpu_history_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    struct sbuf         sb;
+    char        buf[128];
+    int                 i;
+
+    sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
+    for (i = 0; i < cpu_cx_count; i++) {
+       sbuf_printf(&sb, "%u/%u ", cpu_cx_stats[i].long_slp,
+                   cpu_cx_stats[i].short_slp);
+    }
+    sbuf_trim(&sb);
+    sbuf_finish(&sb);
+    sysctl_handle_string(oidp, sbuf_data(&sb), 0, req);
+
+    return (0);
+}
+
+static int
+acpi_cpu_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS)
+{
+    struct      acpi_cpu_softc *sc;
+    int                 val, error, i;
+
+    sc = device_get_softc(cpu_devices[0]);
+    val = cpu_cx_lowest;
+    error = sysctl_handle_int(oidp, &val, 0, req);
+    if (error != 0 || req->newptr == NULL)
+       return (error);
+    if (val < 0 || val > cpu_cx_count - 1)
+       return (EINVAL);
+
+    /* Use the new value for the next idle slice. */
+    cpu_cx_lowest = val;
+    cpu_cx_next = val;
+
+    /* If not disabling, cache the new lowest non-C3 state. */
+    cpu_non_c3 = 0;
+    for (i = cpu_cx_lowest; i >= 0; i--) {
+       if (sc->cpu_cx_states[i].type < ACPI_STATE_C3) {
+           cpu_non_c3 = i;
+           break;
+       }
+    }
+
+    /* Reset the statistics counters. */
+    memset(cpu_cx_stats, 0, sizeof(cpu_cx_stats));
+
+    return (0);
+}
diff --git a/sys/dev/acpica5/acpi_ec.c b/sys/dev/acpica5/acpi_ec.c
new file mode 100644 (file)
index 0000000..f8e5edf
--- /dev/null
@@ -0,0 +1,953 @@
+/*-
+ * Copyright (c) 2003 Nate Lawson
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_ec.c,v 1.42 2004/01/03 02:01:39 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_ec.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+/******************************************************************************
+ *
+ * 1. Copyright Notice
+ *
+ * Some or all of this work - Copyright (c) 1999, Intel Corp.  All rights
+ * reserved.
+ *
+ * 2. License
+ *
+ * 2.1. This is your license from Intel Corp. under its intellectual property
+ * rights.  You may have additional license terms from the party that provided
+ * you this software, covering your right to use that party's intellectual
+ * property rights.
+ *
+ * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
+ * copy of the source code appearing in this file ("Covered Code") an
+ * irrevocable, perpetual, worldwide license under Intel's copyrights in the
+ * base code distributed originally by Intel ("Original Intel Code") to copy,
+ * make derivatives, distribute, use and display any portion of the Covered
+ * Code in any form, with the right to sublicense such rights; and
+ *
+ * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
+ * license (with the right to sublicense), under only those claims of Intel
+ * patents that are infringed by the Original Intel Code, to make, use, sell,
+ * offer to sell, and import the Covered Code and derivative works thereof
+ * solely to the minimum extent necessary to exercise the above copyright
+ * license, and in no event shall the patent license extend to any additions
+ * to or modifications of the Original Intel Code.  No other license or right
+ * is granted directly or by implication, estoppel or otherwise;
+ *
+ * The above copyright and patent license is granted only if the following
+ * conditions are met:
+ *
+ * 3. Conditions 
+ *
+ * 3.1. Redistribution of Source with Rights to Further Distribute Source.  
+ * Redistribution of source code of any substantial portion of the Covered
+ * Code or modification with rights to further distribute source must include
+ * the above Copyright Notice, the above License, this list of Conditions,
+ * and the following Disclaimer and Export Compliance provision.  In addition,
+ * Licensee must cause all Covered Code to which Licensee contributes to
+ * contain a file documenting the changes Licensee made to create that Covered
+ * Code and the date of any change.  Licensee must include in that file the
+ * documentation of any changes made by any predecessor Licensee.  Licensee 
+ * must include a prominent statement that the modification is derived,
+ * directly or indirectly, from Original Intel Code.
+ *
+ * 3.2. Redistribution of Source with no Rights to Further Distribute Source.  
+ * Redistribution of source code of any substantial portion of the Covered
+ * Code or modification without rights to further distribute source must
+ * include the following Disclaimer and Export Compliance provision in the
+ * documentation and/or other materials provided with distribution.  In
+ * addition, Licensee may not authorize further sublicense of source of any
+ * portion of the Covered Code, and must include terms to the effect that the
+ * license from Licensee to its licensee is limited to the intellectual
+ * property embodied in the software Licensee provides to its licensee, and
+ * not to intellectual property embodied in modifications its licensee may
+ * make.
+ *
+ * 3.3. Redistribution of Executable. Redistribution in executable form of any
+ * substantial portion of the Covered Code or modification must reproduce the
+ * above Copyright Notice, and the following Disclaimer and Export Compliance
+ * provision in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3.4. Intel retains all right, title, and interest in and to the Original
+ * Intel Code.
+ *
+ * 3.5. Neither the name Intel nor any other trademark owned or controlled by
+ * Intel shall be used in advertising or otherwise to promote the sale, use or
+ * other dealings in products derived from or relating to the Covered Code
+ * without prior written authorization from Intel.
+ *
+ * 4. Disclaimer and Export Compliance
+ *
+ * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
+ * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
+ * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
+ * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
+ * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
+ * PARTICULAR PURPOSE. 
+ *
+ * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
+ * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
+ * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
+ * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
+ * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
+ * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
+ * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
+ * LIMITED REMEDY.
+ *
+ * 4.3. Licensee shall not export, either directly or indirectly, any of this
+ * software or system incorporating such software without first obtaining any
+ * required license or other approval from the U. S. Department of Commerce or
+ * any other agency or department of the United States Government.  In the
+ * event Licensee exports any such software from the United States or
+ * re-exports any such software from a foreign destination, Licensee shall
+ * ensure that the distribution and export/re-export of the software is in
+ * compliance with all laws, regulations, orders, or other restrictions of the
+ * U.S. Export Administration Regulations. Licensee agrees that neither it nor
+ * any of its subsidiaries will export/re-export any technical data, process,
+ * software, or service, directly or indirectly, to any country for which the
+ * United States government or any agency thereof requires an export license,
+ * other governmental approval, or letter of assurance, without first obtaining
+ * such license, approval or letter.
+ *
+ *****************************************************************************/
+ /*
+  * $FreeBSD: src/sys/dev/acpica/acpi_ec.c,v 1.42 2004/01/03 02:01:39 njl Exp $
+  * $DragonFly: src/sys/dev/acpica5/acpi_ec.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+  *
+  */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/thread.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include "acpi.h"
+
+#include <dev/acpica5/acpivar.h>
+
+/*
+ * Hooks for the ACPI CA debugging infrastructure
+ */
+#define _COMPONENT     ACPI_EC
+ACPI_MODULE_NAME("EC")
+
+/*
+ * EC_COMMAND:
+ * -----------
+ */
+typedef UINT8                          EC_COMMAND;
+
+#define EC_COMMAND_UNKNOWN             ((EC_COMMAND) 0x00)
+#define EC_COMMAND_READ                        ((EC_COMMAND) 0x80)
+#define EC_COMMAND_WRITE               ((EC_COMMAND) 0x81)
+#define EC_COMMAND_BURST_ENABLE                ((EC_COMMAND) 0x82)
+#define EC_COMMAND_BURST_DISABLE       ((EC_COMMAND) 0x83)
+#define EC_COMMAND_QUERY               ((EC_COMMAND) 0x84)
+
+/* 
+ * EC_STATUS:
+ * ----------
+ * The encoding of the EC status register is illustrated below.
+ * Note that a set bit (1) indicates the property is TRUE
+ * (e.g. if bit 0 is set then the output buffer is full).
+ * +-+-+-+-+-+-+-+-+
+ * |7|6|5|4|3|2|1|0|   
+ * +-+-+-+-+-+-+-+-+
+ *  | | | | | | | |
+ *  | | | | | | | +- Output Buffer Full?
+ *  | | | | | | +--- Input Buffer Full?
+ *  | | | | | +----- <reserved>
+ *  | | | | +------- Data Register is Command Byte?
+ *  | | | +--------- Burst Mode Enabled?
+ *  | | +----------- SCI Event?
+ *  | +------------- SMI Event?
+ *  +--------------- <Reserved>
+ *
+ */
+typedef UINT8                          EC_STATUS;
+
+#define EC_FLAG_OUTPUT_BUFFER          ((EC_STATUS) 0x01)
+#define EC_FLAG_INPUT_BUFFER           ((EC_STATUS) 0x02)
+#define EC_FLAG_BURST_MODE             ((EC_STATUS) 0x10)
+#define EC_FLAG_SCI                    ((EC_STATUS) 0x20)
+
+/*
+ * EC_EVENT:
+ * ---------
+ */
+typedef UINT8                          EC_EVENT;
+
+#define EC_EVENT_UNKNOWN               ((EC_EVENT) 0x00)
+#define EC_EVENT_OUTPUT_BUFFER_FULL    ((EC_EVENT) 0x01)
+#define EC_EVENT_INPUT_BUFFER_EMPTY    ((EC_EVENT) 0x02)
+#define EC_EVENT_SCI                   ((EC_EVENT) 0x20)
+
+/*
+ * Register access primitives
+ */
+#define EC_GET_DATA(sc)                                                        \
+       bus_space_read_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0)
+
+#define EC_SET_DATA(sc, v)                                             \
+       bus_space_write_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0, (v))
+
+#define EC_GET_CSR(sc)                                                 \
+       bus_space_read_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0)
+
+#define EC_SET_CSR(sc, v)                                              \
+       bus_space_write_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0, (v))
+
+/* Embedded Controller Boot Resources Table (ECDT) */
+typedef struct {
+    ACPI_TABLE_HEADER          header;
+    ACPI_GENERIC_ADDRESS       control;
+    ACPI_GENERIC_ADDRESS       data;
+    UINT32                     uid;
+    UINT8                      gpe_bit;
+    char                       ec_id[0];
+} ACPI_TABLE_ECDT;
+
+/* Indicate that this device has already been probed via ECDT. */
+#define DEV_ECDT(x)            (acpi_get_private(x) == &acpi_ec_devclass)
+
+/* Indicate that this device should use the global lock. */
+#define DEV_GLK_FLAG           0x40000000
+
+/* Get/set GPE bit value in the magic ivar. */
+#define DEV_GET_GPEBIT(x)      ((x) & 0xff)
+#define DEV_SET_GPEBIT(x, y)   ((x) = ((x) & ~0xff) | ((y) & 0xff))
+
+/*
+ * Driver softc.
+ */
+struct acpi_ec_softc {
+    device_t           ec_dev;
+    ACPI_HANDLE                ec_handle;
+    UINT8              ec_gpebit;
+    UINT8              ec_csrvalue;
+    
+    int                        ec_data_rid;
+    struct resource    *ec_data_res;
+    bus_space_tag_t    ec_data_tag;
+    bus_space_handle_t ec_data_handle;
+
+    int                        ec_csr_rid;
+    struct resource    *ec_csr_res;
+    bus_space_tag_t    ec_csr_tag;
+    bus_space_handle_t ec_csr_handle;
+
+    int                        ec_glk;
+    int                        ec_glkhandle;
+    struct lwkt_token  ec_token;
+    int                        ec_polldelay;
+};
+
+/*
+ * XXX
+ * I couldn't find it in the spec but other implementations also use a
+ * value of 1 ms for the time to acquire global lock.
+ */
+#define EC_LOCK_TIMEOUT        1000
+
+/*
+ * Start with an interval of 1 us for status poll loop.  This delay
+ * will be dynamically adjusted based on the actual time waited.
+ */
+#define EC_POLL_DELAY  1
+
+/* Total time in ms spent in the poll loop waiting for a response. */
+#define EC_POLL_TIMEOUT        100
+
+#define EVENT_READY(event, status)                     \
+       (((event) == EC_EVENT_OUTPUT_BUFFER_FULL &&     \
+        ((status) & EC_FLAG_OUTPUT_BUFFER) != 0) ||    \
+        ((event) == EC_EVENT_INPUT_BUFFER_EMPTY &&     \
+        ((status) & EC_FLAG_INPUT_BUFFER) == 0))
+
+static int     ec_poll_timeout = EC_POLL_TIMEOUT;
+TUNABLE_INT("hw.acpi.ec.poll_timeout", &ec_poll_timeout);
+
+static __inline ACPI_STATUS
+EcLock(struct acpi_ec_softc *sc)
+{
+    ACPI_STATUS        status = AE_OK;
+
+    /* Always acquire this EC's mutex. */
+    lwkt_gettoken(&sc->ec_token);
+
+    /* If _GLK is non-zero, also acquire the global lock. */
+    if (sc->ec_glk) {
+       status = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->ec_glkhandle);
+       if (ACPI_FAILURE(status))
+           lwkt_reltoken(&sc->ec_token);
+    }
+
+    return (status);
+}
+
+static __inline void
+EcUnlock(struct acpi_ec_softc *sc)
+{
+    if (sc->ec_glk)
+       AcpiReleaseGlobalLock(sc->ec_glkhandle);
+    lwkt_reltoken(&sc->ec_token);
+}
+
+static void            EcGpeHandler(void *Context);
+static ACPI_STATUS     EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, 
+                               void *Context, void **return_Context);
+static ACPI_STATUS     EcSpaceHandler(UINT32 Function,
+                               ACPI_PHYSICAL_ADDRESS Address,
+                               UINT32 width, ACPI_INTEGER *Value,
+                               void *Context, void *RegionContext);
+static ACPI_STATUS     EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
+static ACPI_STATUS     EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd);
+static ACPI_STATUS     EcRead(struct acpi_ec_softc *sc, UINT8 Address,
+                               UINT8 *Data);
+static ACPI_STATUS     EcWrite(struct acpi_ec_softc *sc, UINT8 Address,
+                               UINT8 *Data);
+static int             acpi_ec_probe(device_t dev);
+static int             acpi_ec_attach(device_t dev);
+
+static device_method_t acpi_ec_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,    acpi_ec_probe),
+    DEVMETHOD(device_attach,   acpi_ec_attach),
+
+    {0, 0}
+};
+
+static driver_t acpi_ec_driver = {
+    "acpi_ec",
+    acpi_ec_methods,
+    sizeof(struct acpi_ec_softc),
+};
+
+static devclass_t acpi_ec_devclass;
+DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
+
+/*
+ * Look for an ECDT and if we find one, set up default GPE and 
+ * space handlers to catch attempts to access EC space before
+ * we have a real driver instance in place.
+ * TODO: if people report invalid ECDTs, add a tunable to disable them.
+ */
+void
+acpi_ec_ecdt_probe(device_t parent)
+{
+    ACPI_TABLE_ECDT *ecdt;
+    ACPI_STATUS             status;
+    device_t        child;
+    ACPI_HANDLE             h;
+    int                     magic;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /* Find and validate the ECDT. */
+    status = AcpiGetFirmwareTable("ECDT", 1, ACPI_LOGICAL_ADDRESSING, 
+               (ACPI_TABLE_HEADER **)&ecdt);
+    if (ACPI_FAILURE(status) ||
+       ecdt->control.RegisterBitWidth != 8 ||
+       ecdt->data.RegisterBitWidth != 8) {
+       return;
+    }
+
+    /* Create the child device with the given unit number. */
+    child = BUS_ADD_CHILD(parent, 0, "acpi_ec", ecdt->uid);
+    if (child == NULL) {
+       printf("acpi_ec_ecdt_probe: can't add child\n");
+       return;
+    }
+
+    /* Find and save the ACPI handle for this device. */
+    status = AcpiGetHandle(NULL, ecdt->ec_id, &h);
+    if (ACPI_FAILURE(status)) {
+       device_delete_child(parent, child);
+       printf("acpi_ec_ecdt_probe: can't get handle\n");
+       return;
+    }
+    acpi_set_handle(child, h);
+
+    /* Set the data and CSR register addresses. */
+    bus_set_resource(child, SYS_RES_IOPORT, 0, ecdt->data.Address,
+       /*count*/1);
+    bus_set_resource(child, SYS_RES_IOPORT, 1, ecdt->control.Address,
+       /*count*/1);
+
+    /*
+     * Store values for the probe/attach routines to use.  Store the
+     * ECDT GPE bit and set the global lock flag (just to be safe).
+     * We'll determine whether we really want to use the global lock
+     * in a later call to attach.
+     */
+    acpi_set_private(child, &acpi_ec_devclass);
+    magic = DEV_GLK_FLAG;
+    DEV_SET_GPEBIT(magic, ecdt->gpe_bit);
+    acpi_set_magic(child, magic);
+
+    /* Finish the attach process. */
+    if (device_probe_and_attach(child) != 0)
+       device_delete_child(parent, child);
+}
+
+static int
+acpi_ec_probe(device_t dev)
+{
+    ACPI_HANDLE h;
+    ACPI_STATUS status;
+    device_t   peer;
+    char       desc[64];
+    int                magic, uid, glk, gpebit, ret = ENXIO;
+
+    /* Check that this is a device and that EC is not disabled. */
+    if (acpi_get_type(dev) != ACPI_TYPE_DEVICE || acpi_disabled("ec"))
+       return (ENXIO);
+
+    /*
+     * If probed via ECDT, set description and continue.  Otherwise,
+     * we can access the namespace and make sure this is not a
+     * duplicate probe.
+     */
+    magic = acpi_get_magic(dev);
+    if (DEV_ECDT(dev)) {
+       snprintf(desc, sizeof(desc), "Embedded Controller: ECDT, GPE %#x, GLK",
+                DEV_GET_GPEBIT(magic));
+       device_set_desc_copy(dev, desc);
+       ret = 0;
+    } else if (acpi_MatchHid(dev, "PNP0C09")) {
+       h = acpi_get_handle(dev);
+
+       /*
+        * Read the unit ID to check for duplicate attach and the
+        * global lock value to see if we should acquire it when
+        * accessing the EC.
+        */
+       status = acpi_EvaluateInteger(h, "_UID", &uid);
+       if (ACPI_FAILURE(status))
+           uid = 0;
+       status = acpi_EvaluateInteger(h, "_GLK", &glk);
+       if (ACPI_FAILURE(status))
+           glk = 0;
+
+       /*
+        * Evaluate the _GPE method to find the GPE bit used by the EC to
+        * signal status (SCI).  Note that we don't handle the case where
+        * it can return a package instead of an int.
+        */
+       status = acpi_EvaluateInteger(h, "_GPE", &gpebit);
+       if (ACPI_FAILURE(status)) {
+           device_printf(dev, "can't evaluate _GPE - %s\n",
+                         AcpiFormatException(status));
+           return (ENXIO);
+       }
+
+       /* Store the values we got from the namespace for attach. */
+       magic = glk != 0 ? DEV_GLK_FLAG : 0;
+       DEV_SET_GPEBIT(magic, gpebit);
+       acpi_set_magic(dev, magic);
+
+       /*
+        * Check for a duplicate probe.  This can happen when a probe
+        * via ECDT succeeded already.  If there is a duplicate, override
+        * its value for GLK in the peer's softc since the ECDT case
+        * always enables the global lock to be safe.  Otherwise, just
+        * continue on to attach.
+        */
+       peer = devclass_get_device(acpi_ec_devclass, uid);
+       if (peer == NULL || !device_is_alive(peer)) {
+           snprintf(desc, sizeof(desc), "Embedded Controller: GPE %#x%s",
+                    gpebit, glk != 0 ? ", GLK" : "");
+           device_set_desc_copy(dev, desc);
+           ret = 0;
+       } else {
+           struct acpi_ec_softc *sc;
+
+           /*
+            * Set the peer's sc->ec_glk with locks held so we won't
+            * override it between another thread's lock/unlock calls.
+            */
+           sc = device_get_softc(peer);
+           if (sc->ec_glk != glk) {
+               ACPI_VPRINT(peer, acpi_device_get_parent_softc(peer),
+                   "Changing GLK from %d to %d\n", sc->ec_glk, glk);
+               lwkt_gettoken(&sc->ec_token);
+               sc->ec_glk = glk != 0 ? 1 : 0;
+               lwkt_reltoken(&sc->ec_token);
+           }
+       }
+    }
+
+    return (ret);
+}
+
+static int
+acpi_ec_attach(device_t dev)
+{
+    struct acpi_ec_softc       *sc;
+    ACPI_STATUS                        Status;
+    int                                magic, errval = 0;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /* Fetch/initialize softc (assumes softc is pre-zeroed). */
+    sc = device_get_softc(dev);
+    sc->ec_dev = dev;
+    sc->ec_handle = acpi_get_handle(dev);
+    sc->ec_polldelay = EC_POLL_DELAY;
+    lwkt_inittoken(&sc->ec_token);
+
+    /* Retrieve previously probed values via device ivars. */
+    magic = acpi_get_magic(dev);
+    sc->ec_glk = (magic & DEV_GLK_FLAG) != 0 ? 1 : 0;
+    sc->ec_gpebit = DEV_GET_GPEBIT(magic);
+
+    /* Attach bus resources for data and command/status ports. */
+    sc->ec_data_rid = 0;
+    sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT,
+                       &sc->ec_data_rid, 0, ~0, 1, RF_ACTIVE);
+    if (sc->ec_data_res == NULL) {
+       device_printf(dev, "can't allocate data port\n");
+       errval = ENXIO;
+       goto out;
+    }
+    sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
+    sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
+
+    sc->ec_csr_rid = 1;
+    sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT,
+                       &sc->ec_csr_rid, 0, ~0, 1, RF_ACTIVE);
+    if (sc->ec_csr_res == NULL) {
+       device_printf(dev, "can't allocate command/status port\n");
+       errval = ENXIO;
+       goto out;
+    }
+    sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
+    sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
+
+    /*
+     * Install a handler for this EC's GPE bit.  We want edge-triggered
+     * behavior.
+     */
+    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching GPE handler\n"));
+    Status = AcpiInstallGpeHandler(NULL, sc->ec_gpebit,
+               ACPI_EVENT_EDGE_TRIGGERED, &EcGpeHandler, sc);
+    if (ACPI_FAILURE(Status)) {
+       device_printf(dev, "can't install GPE handler for %s - %s\n",
+                     acpi_name(sc->ec_handle), AcpiFormatException(Status));
+       errval = ENXIO;
+       goto out;
+    }
+
+    /* 
+     * Install address space handler
+     */
+    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching address space handler\n"));
+    Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
+               &EcSpaceHandler, &EcSpaceSetup, sc);
+    if (ACPI_FAILURE(Status)) {
+       device_printf(dev, "can't install address space handler for %s - %s\n",
+                     acpi_name(sc->ec_handle), AcpiFormatException(Status));
+       Status = AcpiRemoveGpeHandler(NULL, sc->ec_gpebit, &EcGpeHandler);
+       if (ACPI_FAILURE(Status))
+           panic("Added GPE handler but can't remove it");
+       errval = ENXIO;
+       goto out;
+    }
+
+    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "acpi_ec_attach complete\n"));
+    return (0);
+
+ out:
+    if (sc->ec_csr_res)
+       bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_csr_rid, 
+                            sc->ec_csr_res);
+    if (sc->ec_data_res)
+       bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_data_rid,
+                            sc->ec_data_res);
+    /* mtx_destroy(&sc->ec_mtx); */
+    return (errval);
+}
+
+static void
+EcGpeQueryHandler(void *Context)
+{
+    struct acpi_ec_softc       *sc = (struct acpi_ec_softc *)Context;
+    UINT8                      Data;
+    ACPI_STATUS                        Status;
+    EC_STATUS                  EcStatus;
+    char                       qxx[5];
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+    KASSERT(Context != NULL, ("EcGpeQueryHandler called with NULL"));
+
+    Status = EcLock(sc);
+    if (ACPI_FAILURE(Status)) {
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "GpeQuery lock error: %s\n", AcpiFormatException(Status));
+       return;
+    }
+
+    /*
+     * If the EC_SCI bit of the status register is not set, then pass
+     * it along to any potential waiters as it may be an IBE/OBF event.
+     */
+    EcStatus = EC_GET_CSR(sc);
+    if ((EcStatus & EC_EVENT_SCI) == 0) {
+       sc->ec_csrvalue = EcStatus;
+       wakeup(&sc->ec_csrvalue);
+       EcUnlock(sc);
+       goto re_enable;
+    }
+
+    /*
+     * Send a query command to the EC to find out which _Qxx call it
+     * wants to make.  This command clears the SCI bit and also the
+     * interrupt source since we are edge-triggered.
+     */
+    Status = EcCommand(sc, EC_COMMAND_QUERY);
+    if (ACPI_FAILURE(Status)) {
+       EcUnlock(sc);
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "GPE query failed - %s\n", AcpiFormatException(Status));
+       goto re_enable;
+    }
+    Data = EC_GET_DATA(sc);
+    EcUnlock(sc);
+
+    /* Ignore the value for "no outstanding event". (13.3.5) */
+    if (Data == 0)
+       goto re_enable;
+
+    /* Evaluate _Qxx to respond to the controller. */
+    sprintf(qxx, "_Q%02x", Data);
+    strupr(qxx);
+    Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
+    if (ACPI_FAILURE(Status) && Status != AE_NOT_FOUND) {
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "evaluation of GPE query method %s failed - %s\n", 
+                   qxx, AcpiFormatException(Status));
+    }
+
+re_enable:
+    /* Re-enable the GPE event so we'll get future requests. */
+    Status = AcpiEnableGpe(NULL, sc->ec_gpebit, ACPI_NOT_ISR);
+    if (ACPI_FAILURE(Status))
+       printf("EcGpeQueryHandler: AcpiEnableEvent failed\n");
+}
+
+/*
+ * Handle a GPE.  Currently we only handle SCI events as others must
+ * be handled by polling in EcWaitEvent().  This is because some ECs
+ * treat events as level when they should be edge-triggered.
+ */
+static void
+EcGpeHandler(void *Context)
+{
+    struct acpi_ec_softc *sc = Context;
+    ACPI_STATUS                       Status;
+
+    KASSERT(Context != NULL, ("EcGpeHandler called with NULL"));
+
+    /* Disable further GPEs while we handle this one. */
+    AcpiDisableGpe(NULL, sc->ec_gpebit, ACPI_ISR);
+
+    /* Schedule the GPE query handler. */
+    Status = AcpiOsQueueForExecution(OSD_PRIORITY_GPE, EcGpeQueryHandler,
+               Context);
+    if (ACPI_FAILURE(Status)) {
+       printf("Queuing GPE query handler failed.\n");
+       Status = AcpiEnableGpe(NULL, sc->ec_gpebit, ACPI_ISR);
+       if (ACPI_FAILURE(Status))
+           printf("EcGpeHandler: AcpiEnableEvent failed\n");
+    }
+}
+
+static ACPI_STATUS
+EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context,
+            void **RegionContext)
+{
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /*
+     * If deactivating a region, always set the output to NULL.  Otherwise,
+     * just pass the context through.
+     */
+    if (Function == ACPI_REGION_DEACTIVATE)
+       *RegionContext = NULL;
+    else
+       *RegionContext = Context;
+
+    return_ACPI_STATUS (AE_OK);
+}
+
+static ACPI_STATUS
+EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width,
+              ACPI_INTEGER *Value, void *Context, void *RegionContext)
+{
+    struct acpi_ec_softc       *sc = (struct acpi_ec_softc *)Context;
+    ACPI_STATUS                        Status = AE_OK;
+    UINT8                      EcAddr, EcData;
+    int                                i;
+
+    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address);
+
+    if (Address > 0xFF || width % 8 != 0 || Value == NULL || Context == NULL)
+       return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+    /*
+     * Perform the transaction.
+     */
+    EcAddr = Address;
+    for (i = 0; i < width; i += 8) {
+       Status = EcLock(sc);
+       if (ACPI_FAILURE(Status))
+           return (Status);
+
+       switch (Function) {
+       case ACPI_READ:
+           EcData = 0;
+           Status = EcRead(sc, EcAddr, &EcData);
+           break;
+       case ACPI_WRITE:
+           EcData = (UINT8)((*Value) >> i);
+           Status = EcWrite(sc, EcAddr, &EcData);
+           break;
+       default:
+           device_printf(sc->ec_dev, "invalid EcSpaceHandler function %d\n",
+                         Function);
+           Status = AE_BAD_PARAMETER;
+           break;
+       }
+
+       EcUnlock(sc);
+       if (ACPI_FAILURE(Status))
+           return (Status);
+
+       *Value |= (ACPI_INTEGER)EcData << i;
+       if (++EcAddr == 0)
+           return_ACPI_STATUS (AE_BAD_PARAMETER);
+    }
+    return_ACPI_STATUS (Status);
+}
+
+static ACPI_STATUS
+EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
+{
+    EC_STATUS  EcStatus;
+    ACPI_STATUS        Status;
+    int                i, period, retval;
+    static int EcDbgMaxDelay;
+
+    /* mtx_assert(&sc->ec_mtx, MA_OWNED); */
+    Status = AE_NO_HARDWARE_RESPONSE;
+
+    /* 
+     * Wait for 1 us before checking the CSR.  Testing shows about
+     * 50% of requests complete in 1 us and 90% of them complete
+     * in 5 us or less.
+     */
+    AcpiOsStall(1);
+
+    /*
+     * Poll the EC status register to detect completion of the last
+     * command.  First, wait up to 1 ms in chunks of sc->ec_polldelay
+     * microseconds.
+     */
+    for (i = 0; i < 1000 / sc->ec_polldelay; i++) {
+       EcStatus = EC_GET_CSR(sc);
+       if (EVENT_READY(Event, EcStatus)) {
+           Status = AE_OK;
+           break;
+       }
+       AcpiOsStall(sc->ec_polldelay);
+    }
+
+    /* Scale poll delay by the amount of time actually waited. */
+    period = i * sc->ec_polldelay;
+    if (period <= 5)
+       sc->ec_polldelay = 1;
+    else if (period <= 20)
+       sc->ec_polldelay = 5;
+    else if (period <= 100)
+       sc->ec_polldelay = 10;
+    else
+       sc->ec_polldelay = 100;
+
+    /*
+     * If we still don't have a response, wait up to ec_poll_timeout ms
+     * for completion, sleeping for chunks of ~10 ms.
+     */
+    if (Status != AE_OK) {
+       retval = -1;
+       for (i = 0; i < ec_poll_timeout / 10; i++) {
+           if (retval != 0)
+               EcStatus = EC_GET_CSR(sc);
+           else
+               EcStatus = sc->ec_csrvalue;
+           if (EVENT_READY(Event, EcStatus)) {
+               Status = AE_OK;
+               break;
+           }
+           retval = tsleep(&sc->ec_csrvalue, 0, "ecpoll", 1 + hz / 100);
+       }
+    }
+
+    /* Calculate new delay and print it if it exceeds the max. */
+    if (period == 1000)
+       period += i * 10000;
+    if (period > EcDbgMaxDelay) {
+       EcDbgMaxDelay = period;
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "info: new max delay is %d us\n", period);
+    }
+
+    return (Status);
+}    
+
+static ACPI_STATUS
+EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd)
+{
+    ACPI_STATUS        Status;
+    EC_EVENT   Event;
+
+    /*mtx_assert(&sc->ec_mtx, MA_OWNED);*/
+
+    /* Decide what to wait for based on command type. */
+    switch (cmd) {
+    case EC_COMMAND_READ:
+    case EC_COMMAND_WRITE:
+    case EC_COMMAND_BURST_DISABLE:
+       Event = EC_EVENT_INPUT_BUFFER_EMPTY;
+       break;
+    case EC_COMMAND_QUERY:
+    case EC_COMMAND_BURST_ENABLE:
+       Event = EC_EVENT_OUTPUT_BUFFER_FULL;
+       break;
+    default:
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "EcCommand: Invalid command %#x\n", cmd);
+       return (AE_BAD_PARAMETER);
+    }
+
+    /* Run the command and wait for the chosen event. */
+    EC_SET_CSR(sc, cmd);
+    Status = EcWaitEvent(sc, Event);
+    if (ACPI_FAILURE(Status)) {
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "EcCommand: no response to %#x\n", cmd);
+    }
+
+    return (Status);
+}
+
+static ACPI_STATUS
+EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
+{
+    ACPI_STATUS        Status;
+
+    /*mtx_assert(&sc->ec_mtx, MA_OWNED);*/
+
+#ifdef notyet
+    /* If we can't start burst mode, continue anyway. */
+    EcCommand(sc, EC_COMMAND_BURST_ENABLE);
+#endif
+
+    Status = EcCommand(sc, EC_COMMAND_READ);
+    if (ACPI_FAILURE(Status))
+       return (Status);
+
+    EC_SET_DATA(sc, Address);
+    Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
+    if (ACPI_FAILURE(Status)) {
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "EcRead: Failed waiting for EC to send data.\n");
+       return (Status);
+    }
+
+    *Data = EC_GET_DATA(sc);
+
+#ifdef notyet
+    if (sc->ec_burstactive) {
+       Status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
+       if (ACPI_FAILURE(Status))
+           return (Status);
+    }
+#endif
+
+    return (AE_OK);
+}    
+
+static ACPI_STATUS
+EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
+{
+    ACPI_STATUS        Status;
+
+    /*mtx_assert(&sc->ec_mtx, MA_OWNED);*/
+
+#ifdef notyet
+    /* If we can't start burst mode, continue anyway. */
+    EcCommand(sc, EC_COMMAND_BURST_ENABLE);
+#endif
+
+    Status = EcCommand(sc, EC_COMMAND_WRITE);
+    if (ACPI_FAILURE(Status))
+       return (Status);
+
+    EC_SET_DATA(sc, Address);
+    Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY);
+    if (ACPI_FAILURE(Status)) {
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "EcRead: Failed waiting for EC to process address\n");
+       return (Status);
+    }
+
+    EC_SET_DATA(sc, *Data);
+    Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY);
+    if (ACPI_FAILURE(Status)) {
+       ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
+                   "EcWrite: Failed waiting for EC to process data\n");
+       return (Status);
+    }
+
+#ifdef notyet
+    if (sc->ec_burstactive) {
+       Status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
+       if (ACPI_FAILURE(Status))
+           return (Status);
+    }
+#endif
+
+    return (AE_OK);
+}
diff --git a/sys/dev/acpica5/acpi_isab.c b/sys/dev/acpica5/acpi_isab.c
new file mode 100644 (file)
index 0000000..255c9ef
--- /dev/null
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_isab.c,v 1.4 2003/08/24 17:48:01 obrien Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_isab.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+/*
+ * ISA Bridge driver for Generic ISA Bus Devices.  See section 10.7 of the
+ * ACPI 2.0a specification for details on this device.
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+
+#include "acpi.h"
+
+#include "acpivar.h"
+#include <bus/isa/isavar.h>
+
+/*
+ * Hooks for the ACPI CA debugging infrastructure
+ */
+#define _COMPONENT     ACPI_BUS
+ACPI_MODULE_NAME("ISA_ACPI")
+
+struct acpi_isab_softc {
+       device_t        ap_dev;
+       ACPI_HANDLE     ap_handle;
+};
+
+
+static int     acpi_isab_probe(device_t bus);
+static int     acpi_isab_attach(device_t bus);
+static int     acpi_isab_read_ivar(device_t dev, device_t child, int which,
+                   uintptr_t *result);
+
+static device_method_t acpi_isab_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         acpi_isab_probe),
+       DEVMETHOD(device_attach,        acpi_isab_attach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_print_child,      bus_generic_print_child),
+       DEVMETHOD(bus_read_ivar,        acpi_isab_read_ivar),
+       DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
+       DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+       DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
+       DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
+
+       {0, 0}
+};
+
+static driver_t acpi_isab_driver = {
+       "isab",
+       acpi_isab_methods,
+       sizeof(struct acpi_isab_softc),
+};
+
+DRIVER_MODULE(acpi_isab, acpi, acpi_isab_driver, isab_devclass, 0, 0);
+
+static int
+acpi_isab_probe(device_t dev)
+{
+
+       if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
+           !acpi_disabled("isa") &&
+           devclass_get_device(isab_devclass, 0) == dev &&
+           (acpi_MatchHid(dev, "PNP0A05") || acpi_MatchHid(dev, "PNP0A06"))) {
+               device_set_desc(dev, "ACPI Generic ISA bridge");
+               return(0);
+       }
+       return(ENXIO);
+}
+
+static int
+acpi_isab_attach(device_t dev)
+{
+       struct acpi_isab_softc *sc;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = device_get_softc(dev);
+       sc->ap_dev = dev;
+       sc->ap_handle = acpi_get_handle(dev);
+
+       return (isab_attach(dev));
+}
+
+static int
+acpi_isab_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+       struct acpi_isab_softc *sc = device_get_softc(dev);
+
+       switch (which) {
+       case  ACPI_IVAR_HANDLE:
+               *result = (uintptr_t)sc->ap_handle;
+               return(0);
+       }
+       return(ENOENT);
+}
diff --git a/sys/dev/acpica5/acpi_lid.c b/sys/dev/acpica5/acpi_lid.c
new file mode 100644 (file)
index 0000000..ee62981
--- /dev/null
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Michael Smith <msmith@freebd.org>
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_lid.c,v 1.15 2003/10/25 05:03:24 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_lid.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/proc.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT     ACPI_BUTTON
+ACPI_MODULE_NAME("LID")
+
+struct acpi_lid_softc {
+    device_t   lid_dev;
+    ACPI_HANDLE        lid_handle;
+    int                lid_status;     /* open or closed */
+};
+
+static int     acpi_lid_probe(device_t dev);
+static int     acpi_lid_attach(device_t dev);
+static int     acpi_lid_suspend(device_t dev);
+static int     acpi_lid_resume(device_t dev);
+static void    acpi_lid_notify_status_changed(void *arg);
+static void    acpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify,
+                                       void *context);
+
+static device_method_t acpi_lid_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,    acpi_lid_probe),
+    DEVMETHOD(device_attach,   acpi_lid_attach),
+    DEVMETHOD(device_suspend,  acpi_lid_suspend),
+    DEVMETHOD(device_resume,   acpi_lid_resume),
+
+    {0, 0}
+};
+
+static driver_t acpi_lid_driver = {
+    "acpi_lid",
+    acpi_lid_methods,
+    sizeof(struct acpi_lid_softc),
+};
+
+static devclass_t acpi_lid_devclass;
+DRIVER_MODULE(acpi_lid, acpi, acpi_lid_driver, acpi_lid_devclass, 0, 0);
+
+static int
+acpi_lid_probe(device_t dev)
+{
+    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("lid") &&
+       acpi_MatchHid(dev, "PNP0C0D")) {
+
+       device_set_desc(dev, "Control Method Lid Switch");
+       return (0);
+    }
+    return (ENXIO);
+}
+
+static int
+acpi_lid_attach(device_t dev)
+{
+    struct acpi_lid_softc      *sc;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    sc = device_get_softc(dev);
+    sc->lid_dev = dev;
+    sc->lid_handle = acpi_get_handle(dev);
+
+    /* Install notification handler */
+    AcpiInstallNotifyHandler(sc->lid_handle, ACPI_DEVICE_NOTIFY,
+                            acpi_lid_notify_handler, sc);
+    acpi_device_enable_wake_capability(sc->lid_handle, 1);
+
+    return_VALUE (0);
+}
+
+static int
+acpi_lid_suspend(device_t dev)
+{
+    struct acpi_lid_softc      *sc;
+
+    sc = device_get_softc(dev);
+    acpi_device_enable_wake_event(sc->lid_handle);
+    return (0);
+}
+
+static int
+acpi_lid_resume(device_t dev)
+{
+    return (0);
+}
+
+static void
+acpi_lid_notify_status_changed(void *arg)
+{
+    struct acpi_lid_softc      *sc;
+    struct acpi_softc          *acpi_sc;
+    ACPI_STATUS                        status;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    sc = (struct acpi_lid_softc *)arg;
+
+    /*
+     * Evaluate _LID and check the return value, update lid status.
+     * Zero:           The lid is closed
+     * Non-zero:       The lid is open
+     */
+    status = acpi_EvaluateInteger(sc->lid_handle, "_LID", &sc->lid_status);
+    if (ACPI_FAILURE(status))
+       return_VOID;
+
+    acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
+    if (acpi_sc == NULL)
+        return_VOID;
+
+    ACPI_VPRINT(sc->lid_dev, acpi_sc, "Lid %s\n",
+               sc->lid_status ? "opened" : "closed");
+
+    acpi_UserNotify("Lid", sc->lid_handle, sc->lid_status);
+
+    if (sc->lid_status == 0)
+       EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx);
+    else
+       EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);
+
+    return_VOID;
+}
+
+/* XXX maybe not here */
+#define        ACPI_NOTIFY_STATUS_CHANGED      0x80
+
+static void 
+acpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+    struct acpi_lid_softc      *sc = (struct acpi_lid_softc *)context;
+
+    ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
+
+    switch (notify) {
+    case ACPI_NOTIFY_STATUS_CHANGED:
+       AcpiOsQueueForExecution(OSD_PRIORITY_LO,
+                               acpi_lid_notify_status_changed, sc);
+       break;
+    default:
+       break;
+    }
+
+    return_VOID;
+}
diff --git a/sys/dev/acpica5/acpi_package.c b/sys/dev/acpica5/acpi_package.c
new file mode 100644 (file)
index 0000000..4767d7e
--- /dev/null
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2003 Nate Lawson
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_package.c,v 1.2 2003/12/23 18:26:53 njl Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_package.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/sbuf.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include "acpi.h"
+#include <dev/acpica5/acpivar.h>
+
+/*
+ * Package manipulation convenience functions
+ */
+
+int
+acpi_PkgInt(ACPI_OBJECT *res, int idx, ACPI_INTEGER *dst)
+{
+    ACPI_OBJECT                *obj;
+
+    obj = &res->Package.Elements[idx];
+    if (obj == NULL || obj->Type != ACPI_TYPE_INTEGER)
+       return (EINVAL);
+    *dst = obj->Integer.Value;
+
+    return (0);
+}
+
+int
+acpi_PkgInt32(ACPI_OBJECT *res, int idx, uint32_t *dst)
+{
+    ACPI_INTEGER       tmp;
+    int                        error;
+
+    error = acpi_PkgInt(res, idx, &tmp);
+    if (error == 0)
+       *dst = (uint32_t)tmp;
+
+    return (error);
+}
+
+int
+acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size)
+{
+    ACPI_OBJECT                *obj;
+    void               *ptr;
+    size_t              length;
+
+    obj = &res->Package.Elements[idx];
+    if (obj == NULL)
+       return (EINVAL);
+    bzero(dst, sizeof(dst));
+
+    switch (obj->Type) {
+    case ACPI_TYPE_STRING:
+       ptr = obj->String.Pointer;
+       length = obj->String.Length;
+       break;
+    case ACPI_TYPE_BUFFER:
+       ptr = obj->Buffer.Pointer;
+       length = obj->Buffer.Length;
+       break;
+    default:
+       return (EINVAL);
+    }
+
+    /* Make sure string will fit, including terminating NUL */
+    if (++length > size)
+       return (E2BIG);
+
+    strlcpy(dst, ptr, length);
+    return (0);
+}
+
+int
+acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *rid,
+       struct resource **dst)
+{
+    ACPI_GENERIC_ADDRESS gas;
+    ACPI_OBJECT                *obj;
+
+    obj = &res->Package.Elements[idx];
+    if (obj == NULL || obj->Type != ACPI_TYPE_BUFFER ||
+       obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) {
+
+       return (EINVAL);
+    }
+
+    memcpy(&gas, obj->Buffer.Pointer + 3, sizeof(gas));
+    *dst = acpi_bus_alloc_gas(dev, rid, &gas);
+    if (*dst == NULL)
+       return (ENXIO);
+
+    return (0);
+}
diff --git a/sys/dev/acpica5/acpi_pci.c b/sys/dev/acpica5/acpi_pci.c
new file mode 100644 (file)
index 0000000..d84485d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000, BSDi
+ * 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 unmodified, 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 ``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 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_pci.c,v 1.6 2003/09/17 08:32:44 iwasaki Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_pci.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+
+#include "acpi.h"
+
+#include "acpivar.h"
+
+#include <sys/pciio.h>
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pci_private.h>
+
+#include "pcib_if.h"
+#include "pci_if.h"
+
+/*
+ * Hooks for the ACPI CA debugging infrastructure
+ */
+#define _COMPONENT     ACPI_BUS
+ACPI_MODULE_NAME("PCI")
+
+struct acpi_pci_devinfo {
+       struct pci_devinfo ap_dinfo;
+       ACPI_HANDLE     ap_handle;
+};
+
+static int     acpi_pci_probe(device_t dev);
+static int     acpi_pci_attach(device_t dev);
+static int     acpi_pci_read_ivar(device_t dev, device_t child, int which,
+    uintptr_t *result);
+#if 0
+static int     acpi_pci_set_powerstate_method(device_t dev, device_t child,
+    int state);
+static int     acpi_pci_get_powerstate_method(device_t dev, device_t child);
+#endif
+static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level,
+    void *context, void **status);
+
+static device_method_t acpi_pci_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         acpi_pci_probe),
+       DEVMETHOD(device_attach,        acpi_pci_attach),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        pci_resume),
+
+       /* Bus interface */
+       DEVMETHOD(bus_print_child,      pci_print_child),
+       DEVMETHOD(bus_probe_nomatch,    pci_probe_nomatch),
+       DEVMETHOD(bus_read_ivar,        acpi_pci_read_ivar),
+       DEVMETHOD(bus_write_ivar,       pci_write_ivar),
+       DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
+       DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
+       DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
+
+       DEVMETHOD(bus_get_resource_list,pci_get_resource_list),
+       DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
+       DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
+       DEVMETHOD(bus_delete_resource,  pci_delete_resource),
+       DEVMETHOD(bus_alloc_resource,   pci_alloc_resource),
+       DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+       DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
+       DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
+
+       /* PCI interface */
+       DEVMETHOD(pci_read_config,      pci_read_config_method),
+       DEVMETHOD(pci_write_config,     pci_write_config_method),
+       DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method),
+       DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method),
+       DEVMETHOD(pci_enable_io,        pci_enable_io_method),
+       DEVMETHOD(pci_disable_io,       pci_disable_io_method),
+       /* XXX: We should override these two. */
+       DEVMETHOD(pci_get_powerstate,   pci_get_powerstate_method),
+       DEVMETHOD(pci_set_powerstate,   pci_set_powerstate_method),
+       DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
+
+       { 0, 0 }
+};
+
+static driver_t acpi_pci_driver = {
+       "pci",
+       acpi_pci_methods,
+       0,                      /* no softc */
+};
+
+DRIVER_MODULE(acpi_pci, pcib, acpi_pci_driver, pci_devclass, 0, 0);
+MODULE_VERSION(acpi_pci, 1);
+MODULE_DEPEND(acpi_pci, pci, 1, 1, 1);
+
+static int
+acpi_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+    struct acpi_pci_devinfo *dinfo;
+
+    switch (which) {
+    case  ACPI_IVAR_HANDLE:
+       dinfo = device_get_ivars(child);
+       *result = (uintptr_t)dinfo->ap_handle;
+       return(0);
+    }
+    return(pci_read_ivar(dev, child, which, result));
+}
+
+#if 0
+/*
+ * PCI power manangement
+ */
+static int
+acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
+{
+       /* XXX: TODO */
+       return (ENXIO);
+}
+
+static int
+acpi_pci_get_powerstate_method(device_t dev, device_t child)
+{
+       /* XXX: TODO */
+       return (ENXIO);
+}
+#endif
+
+static ACPI_STATUS
+acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,
+    void **status)
+{
+       struct acpi_pci_devinfo *dinfo;
+       device_t *devlist;
+       int devcount, i, func, slot;
+       UINT32 address;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (ACPI_FAILURE(acpi_EvaluateInteger(handle, "_ADR", &address)))
+               return_ACPI_STATUS(AE_OK);
+       slot = address >> 16;
+       func = address & 0xffff;
+       if (device_get_children((device_t)context, &devlist, &devcount) != 0)
+               return_ACPI_STATUS(AE_OK);
+       for (i = 0; i < devcount; i++) {
+               dinfo = device_get_ivars(devlist[i]);
+               if (dinfo->ap_dinfo.cfg.func == func &&
+                   dinfo->ap_dinfo.cfg.slot == slot) {
+                       dinfo->ap_handle = handle;
+                       free(devlist, M_TEMP);
+                       return_ACPI_STATUS(AE_OK);
+               }
+       }
+       free(devlist, M_TEMP);
+       return_ACPI_STATUS(AE_OK);
+}
+
+static int
+acpi_pci_probe(device_t dev)
+{
+
+       if (pcib_get_bus(dev) < 0)
+               return (ENXIO);
+       
+       device_set_desc(dev, "ACPI PCI bus");
+
+       if (acpi_get_handle(dev) == NULL)
+               return (ENXIO);
+       return (0);
+}
+
+static int
+acpi_pci_attach(device_t dev)
+{
+       int busno;
+
+       /*
+        * Since there can be multiple independantly numbered PCI
+        * busses on some large alpha systems, we can't use the unit
+        * number to decide what bus we are probing. We ask the parent 
+        * pcib what our bus number is.
+        */
+       busno = pcib_get_bus(dev);
+       if (bootverbose)
+               device_printf(dev, "physical bus=%d\n", busno);
+
+       /*
+        * First, PCI devices are added as in the normal PCI bus driver.
+        * Afterwards, the ACPI namespace under the bridge driver is
+        * walked to save ACPI handles to all the devices that appear in
+        * the ACPI namespace as immediate descendants of the bridge.
+        *
+        * XXX: Sometimes PCI devices show up in the ACPI namespace that
+        * pci_add_children() doesn't find.  We currently just ignore
+        * these devices.
+        */
+       pci_add_children(dev, busno, sizeof(struct acpi_pci_devinfo));
+       (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
+           acpi_pci_save_handle, dev, NULL);
+
+       return (bus_generic_attach(dev));
+}
diff --git a/sys/dev/acpica5/acpi_pci_link.c b/sys/dev/acpica5/acpi_pci_link.c
new file mode 100644 (file)
index 0000000..f727bc0
--- /dev/null
@@ -0,0 +1,1099 @@
+/*-
+ * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_pci_link.c,v 1.13 2004/01/20 21:38:48 jhb Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_pci_link.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica5/acpivar.h>
+#include <dev/acpica5/acpi_pcibvar.h>
+
+/*
+ * Hooks for the ACPI CA debugging infrastructure
+ */
+#define _COMPONENT     ACPI_BUS
+ACPI_MODULE_NAME("PCI_LINK")
+
+#define MAX_POSSIBLE_INTERRUPTS        16
+#define MAX_ISA_INTERRUPTS     16
+#define MAX_ACPI_INTERRUPTS    255
+
+struct acpi_pci_link_entry {
+       TAILQ_ENTRY(acpi_pci_link_entry) links;
+       ACPI_HANDLE     handle;
+       UINT8           current_irq;
+       UINT8           initial_irq;
+       ACPI_RESOURCE   possible_resources;
+       UINT8           number_of_interrupts;
+       UINT8           interrupts[MAX_POSSIBLE_INTERRUPTS];
+
+       UINT8           sorted_irq[MAX_POSSIBLE_INTERRUPTS];
+       int             references;
+       int             priority;
+};
+
+TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
+static struct acpi_pci_link_entries acpi_pci_link_entries;
+
+struct acpi_prt_entry {
+       TAILQ_ENTRY(acpi_prt_entry) links;
+       device_t        pcidev;
+       int             busno;
+       ACPI_PCI_ROUTING_TABLE prt;
+       struct acpi_pci_link_entry *pci_link;
+};
+
+TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
+static struct acpi_prt_entries acpi_prt_entries;
+
+static int     irq_penalty[MAX_ACPI_INTERRUPTS];
+
+#define ACPI_STA_PRESENT       0x00000001
+#define ACPI_STA_ENABLE                0x00000002
+#define ACPI_STA_SHOWINUI      0x00000004
+#define ACPI_STA_FUNCTIONAL    0x00000008
+
+/*
+ * PCI link object management
+ */
+
+static void
+acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
+{
+
+       switch (ActiveHighLow) {
+       case ACPI_ACTIVE_HIGH:
+               printf("high,");
+               break;
+
+       case ACPI_ACTIVE_LOW:
+               printf("low,");
+               break;
+
+       default:
+               printf("unknown,");
+               break;
+       }
+}
+
+static void
+acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
+{
+
+       switch (EdgeLevel) {
+       case ACPI_EDGE_SENSITIVE:
+               printf("edge,");
+               break;
+
+       case ACPI_LEVEL_SENSITIVE:
+               printf("level,");
+               break;
+
+       default:
+               printf("unknown,");
+               break;
+       }
+}
+
+static void
+acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
+{
+
+       switch (SharedExclusive) {
+       case ACPI_EXCLUSIVE:
+               printf("exclusive");
+               break;
+
+       case ACPI_SHARED:
+               printf("sharable");
+               break;
+
+       default:
+               printf("unknown");
+               break;
+       }
+}
+
+static void
+acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
+{
+       UINT8                   i;
+       ACPI_RESOURCE_IRQ       *Irq;
+       ACPI_RESOURCE_EXT_IRQ   *ExtIrq;
+
+       if (entry == NULL || entry->pci_link == NULL) {
+               return;
+       }
+
+       printf("%s irq %3d: ", acpi_name(entry->pci_link->handle),
+           entry->pci_link->current_irq);
+
+       printf("[");
+       for (i = 0; i < entry->pci_link->number_of_interrupts; i++) {
+               printf("%3d", entry->pci_link->interrupts[i]);
+       }
+       printf("] ");
+
+       switch (entry->pci_link->possible_resources.Id) {
+       case ACPI_RSTYPE_IRQ:
+               Irq = &entry->pci_link->possible_resources.Data.Irq;
+
+               acpi_pci_link_dump_polarity(Irq->ActiveHighLow);
+               acpi_pci_link_dump_trigger(Irq->EdgeLevel);
+               acpi_pci_link_dump_sharemode(Irq->SharedExclusive);
+               break;
+
+       case ACPI_RSTYPE_EXT_IRQ:
+               ExtIrq = &entry->pci_link->possible_resources.Data.ExtendedIrq;
+
+               acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow);
+               acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel);
+               acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive);
+               break;
+       }
+
+       printf(" %d.%d.%d", entry->busno,
+           (int)((entry->prt.Address & 0xffff0000) >> 16),
+           (int)entry->prt.Pin);
+
+       printf("\n");
+}
+
+static ACPI_STATUS
+acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
+{
+       ACPI_DEVICE_INFO        *devinfo;
+       ACPI_BUFFER             buf;
+       ACPI_STATUS             error;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (handle == NULL || sta == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "invalid argument\n"));
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
+       }
+
+       buf.Pointer = NULL;
+       buf.Length = ACPI_ALLOCATE_BUFFER;
+       error = AcpiGetObjectInfo(handle, &buf);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't get object info %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+       devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+
+       if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
+           strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n",
+                   acpi_name(handle)));
+               AcpiOsFree(buf.Pointer);
+               return_ACPI_STATUS (AE_TYPE);
+       }
+
+       if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
+               *sta = devinfo->CurrentStatus;
+       } else {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
+                   acpi_name(handle)));
+               *sta = 0;
+       }
+
+       AcpiOsFree(buf.Pointer);
+       return_ACPI_STATUS (AE_OK);
+}
+
+static ACPI_STATUS
+acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
+    UINT8 *number_of_interrupts, UINT8 interrupts[])
+{
+       UINT8                   count;
+       UINT8                   i;
+       UINT32                  NumberOfInterrupts;
+       UINT32                  *Interrupts;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (resources == NULL || number_of_interrupts == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
+       }
+
+       *number_of_interrupts = 0;
+       NumberOfInterrupts = 0;
+       Interrupts = NULL;
+
+       if (resources->Id == ACPI_RSTYPE_START_DPF)
+               resources = ACPI_NEXT_RESOURCE(resources);
+
+       if (resources->Id != ACPI_RSTYPE_IRQ &&
+           resources->Id != ACPI_RSTYPE_EXT_IRQ) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "Resource is not an IRQ entry - %d\n", resources->Id));
+               return_ACPI_STATUS (AE_TYPE);
+       }
+
+       switch (resources->Id) {
+       case ACPI_RSTYPE_IRQ:
+               NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts;
+               Interrupts = resources->Data.Irq.Interrupts;
+               break;
+
+       case ACPI_RSTYPE_EXT_IRQ:
+                NumberOfInterrupts = resources->Data.ExtendedIrq.NumberOfInterrupts;
+                Interrupts = resources->Data.ExtendedIrq.Interrupts;
+               break;
+       }
+       
+       if (NumberOfInterrupts == 0) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
+               return_ACPI_STATUS (AE_NULL_ENTRY);
+       }
+
+       count = 0;
+       for (i = 0; i < NumberOfInterrupts; i++) {
+               if (i >= MAX_POSSIBLE_INTERRUPTS) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs %d\n", i));
+                       break;
+               }
+
+               if (Interrupts[i] == 0) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n",
+                           Interrupts[i]));
+                       continue;
+               }
+               interrupts[count] = Interrupts[i];
+               count++;
+       }
+       *number_of_interrupts = count;
+
+       return_ACPI_STATUS (AE_OK);
+}
+
+static ACPI_STATUS
+acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
+{
+       ACPI_STATUS             error;
+       ACPI_BUFFER             buf;
+       ACPI_RESOURCE           *resources;
+       UINT8                   number_of_interrupts;
+       UINT8                   interrupts[MAX_POSSIBLE_INTERRUPTS];;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (link == NULL || irq == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
+       }
+
+       *irq = 0;
+       buf.Pointer = NULL;
+       buf.Length = ACPI_ALLOCATE_BUFFER;
+       error = AcpiGetCurrentResources(link->handle, &buf);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't get PCI interrupt link device _CRS %s - %s\n",
+                   acpi_name(link->handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+       if (buf.Pointer == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't allocate memory - %s\n",
+                   acpi_name(link->handle)));
+               return_ACPI_STATUS (AE_NO_MEMORY);
+       }
+
+       resources = (ACPI_RESOURCE *) buf.Pointer;
+
+       number_of_interrupts = 0;
+       bzero(interrupts, sizeof(interrupts));
+       error = acpi_pci_link_get_irq_resources(resources,
+                   &number_of_interrupts, interrupts);
+       AcpiOsFree(buf.Pointer);
+
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get current IRQ from PCI interrupt link %s - %s\n",
+                   acpi_name(link->handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+
+       if (number_of_interrupts == 0) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "PCI interrupt link device _CRS data is corrupted - %s\n",
+                   acpi_name(link->handle)));
+               return_ACPI_STATUS (AE_NULL_ENTRY);
+       }
+
+       *irq = interrupts[0];
+
+       return_ACPI_STATUS (AE_OK);
+}
+
+static ACPI_STATUS
+acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
+{
+       ACPI_STATUS             error;
+       ACPI_BUFFER             buf;
+       ACPI_RESOURCE           *resources;
+       struct acpi_pci_link_entry *link;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       entry->pci_link = NULL;
+       TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
+               if (link->handle == handle) {
+                       entry->pci_link = link;
+                       link->references++;
+                       return_ACPI_STATUS (AE_OK);
+               }
+       }
+
+       link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
+       if (link == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't allocate memory - %s\n", acpi_name(handle)));
+               return_ACPI_STATUS (AE_NO_MEMORY);
+       }
+
+       buf.Pointer = NULL;
+       buf.Length = ACPI_ALLOCATE_BUFFER;
+
+       bzero(link, sizeof(struct acpi_pci_link_entry));
+
+       link->handle = handle;
+
+       error = acpi_pci_link_get_current_irq(link, &link->current_irq);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get current IRQ from PCI interrupt link %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(error)));
+       }
+
+       link->initial_irq = link->current_irq;
+
+       error = AcpiGetPossibleResources(handle, &buf);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get PCI interrupt link device _PRS data %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(error)));
+               goto out;
+       }
+
+       if (buf.Pointer == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "_PRS nuffer is empty - %s\n", acpi_name(handle)));
+               error = AE_NO_MEMORY;
+               goto out;
+       }
+
+       resources = (ACPI_RESOURCE *) buf.Pointer;
+       bcopy(resources, &link->possible_resources,
+           sizeof(link->possible_resources));
+
+       error = acpi_pci_link_get_irq_resources(resources,
+           &link->number_of_interrupts, link->interrupts);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get possible IRQs from PCI interrupt link %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(error)));
+               goto out;
+       }
+
+       if (link->number_of_interrupts == 0) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "PCI interrupt link device _PRS data is corrupted - %s\n",
+                   acpi_name(handle)));
+               error = AE_NULL_ENTRY;
+               goto out;
+       }
+
+       link->references++;
+
+       TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
+       entry->pci_link = link;
+
+       error = AE_OK;
+out:
+       if (buf.Pointer != NULL) {
+               AcpiOsFree(buf.Pointer);
+       }
+
+       if (error != AE_OK && link != NULL) {
+               AcpiOsFree(link);
+       }
+
+       return_ACPI_STATUS (error);
+}
+
+static ACPI_STATUS
+acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
+{
+       ACPI_HANDLE             handle;
+       ACPI_STATUS             error;
+       UINT32                  sta;
+       struct acpi_prt_entry   *entry;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if ((prt == NULL) || (prt->Source == NULL) || (prt->Source[0] == '\0')) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't handle this routing table - hardwired\n"));
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
+       }
+
+       error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't get acpi handle - %s\n",
+                   AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+
+       error = acpi_pci_link_get_object_status(handle, &sta);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't get object status %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+
+       if (!(sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL))) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "PCI interrupt link is not functional - %s\n",
+                   acpi_name(handle)));
+               return_ACPI_STATUS (AE_ERROR);
+       }
+
+       TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
+               if (entry->busno == busno &&
+                   entry->prt.Address == prt->Address &&
+                   entry->prt.Pin == prt->Pin) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                           "PCI interrupt link entry already exists - %s\n",
+                           acpi_name(handle)));
+                       return_ACPI_STATUS (AE_ALREADY_EXISTS);
+               }
+       }
+
+       entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
+       if (entry == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't allocate memory - %s\n", acpi_name(handle)));
+               return_ACPI_STATUS (AE_NO_MEMORY);
+       }
+
+       bzero(entry, sizeof(struct acpi_prt_entry));
+
+       entry->pcidev = pcidev;
+       entry->busno = busno;
+       bcopy(prt, &entry->prt, sizeof(entry->prt));
+
+       error = acpi_pci_link_add_link(handle, entry);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't add prt entry to pci link %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(error)));
+               goto out;
+       }
+
+       TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
+       error = AE_OK;
+
+out:
+       if (error != AE_OK && entry != NULL) {
+               AcpiOsFree(entry);
+       }
+
+       return_ACPI_STATUS (error);
+}
+
+static int
+acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
+{
+       UINT8                   i;
+
+       if (irq == 0) {
+               return (0);
+       }
+
+       for (i = 0; i < link->number_of_interrupts; i++) {
+               if (link->interrupts[i] == irq) {
+                       return (1);
+               }
+       }
+
+       /* allow initial IRQ as valid one. */
+       if (link->initial_irq == irq) {
+               return (1);
+       }
+
+       return (0);
+}
+
+static ACPI_STATUS
+acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
+{
+       ACPI_STATUS             error;
+       ACPI_RESOURCE           resbuf;
+       ACPI_BUFFER             crsbuf;
+       UINT32                  sta;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (!acpi_pci_link_is_valid_irq(link, irq)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't set invalid IRQ %d - %s\n", irq,
+                   acpi_name(link->handle)));
+               return_ACPI_STATUS (AE_BAD_PARAMETER);
+       }
+
+       error = acpi_pci_link_get_current_irq(link, &link->current_irq);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get current IRQ from PCI interrupt link %s - %s\n",
+                   acpi_name(link->handle), AcpiFormatException(error)));
+       }
+
+       if (link->current_irq == irq) {
+               return_ACPI_STATUS (AE_OK);
+       }
+
+       bzero(&resbuf, sizeof(resbuf));
+       crsbuf.Pointer = NULL;
+
+       switch (link->possible_resources.Id) {
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "Resource is not an IRQ entry %s - %d\n",
+                   acpi_name(link->handle), link->possible_resources.Id));
+               return_ACPI_STATUS (AE_TYPE);
+
+       case ACPI_RSTYPE_IRQ:
+               resbuf.Id = ACPI_RSTYPE_IRQ;
+               resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
+
+               /* structure copy other fields */
+               resbuf.Data.Irq = link->possible_resources.Data.Irq;
+               resbuf.Data.Irq.NumberOfInterrupts = 1;
+               resbuf.Data.Irq.Interrupts[0] = irq;
+               break;
+
+       case ACPI_RSTYPE_EXT_IRQ:
+               resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
+               resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ);
+
+               /* structure copy other fields */
+               resbuf.Data.ExtendedIrq = link->possible_resources.Data.ExtendedIrq;
+               resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
+               resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
+               break;
+       }
+
+       error = acpi_AppendBufferResource(&crsbuf, &resbuf);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "couldn't setup buffer by acpi_AppendBufferResource - %s\n",
+                   acpi_name(link->handle)));
+               return_ACPI_STATUS (error);
+       }
+
+       if (crsbuf.Pointer == NULL) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                   "buffer setup by acpi_AppendBufferResource is corrupted - %s\n",
+                   acpi_name(link->handle)));
+               return_ACPI_STATUS (AE_NO_MEMORY);
+       }
+
+       error = AcpiSetCurrentResources(link->handle, &crsbuf);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't set PCI interrupt link device _SRS %s - %s\n",
+                   acpi_name(link->handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+
+       AcpiOsFree(crsbuf.Pointer);
+       link->current_irq = 0;
+
+       error = acpi_pci_link_get_object_status(link->handle, &sta);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get object status %s - %s\n",
+                   acpi_name(link->handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+
+       if (!(sta & ACPI_STA_ENABLE)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "PCI interrupt link is disabled - %s\n",
+                   acpi_name(link->handle)));
+               return_ACPI_STATUS (AE_ERROR);
+       }
+
+       error = acpi_pci_link_get_current_irq(link, &link->current_irq);
+       if (ACPI_FAILURE(error)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't get current IRQ from PCI interrupt link %s - %s\n",
+                   acpi_name(link->handle), AcpiFormatException(error)));
+               return_ACPI_STATUS (error);
+       }
+
+       if (link->current_irq == irq) {
+               error = AE_OK;
+       } else {
+               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                   "couldn't set IRQ %d to PCI interrupt link %d - %s\n",
+                   irq, link->current_irq, acpi_name(link->handle)));
+
+               link->current_irq = 0;
+               error = AE_ERROR;
+       }
+
+       return_ACPI_STATUS (error);
+}
+
+/*
+ * Auto arbitration for boot-disabled devices
+ */
+
+static void
+acpi_pci_link_bootdisabled_dump(void)
+
+{
+       int                     i;
+       int                     irq;
+       struct acpi_pci_link_entry *link;
+
+       TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
+               /* boot-disabled link only. */
+               if (link->current_irq != 0) {
+                       continue;
+               }
+
+               printf("%s:\n", acpi_name(link->handle));
+               printf("        interrupts:     ");
+               for (i = 0; i < link->number_of_interrupts; i++) {
+                       irq = link->sorted_irq[i];
+                       printf("%6d", irq);
+               }
+               printf("\n");
+               printf("        penalty:        ");
+               for (i = 0; i < link->number_of_interrupts; i++) {
+                       irq = link->sorted_irq[i];
+                       printf("%6d", irq_penalty[irq]);
+               }
+               printf("\n");
+               printf("        references:     %d\n", link->references);
+               printf("        priority:       %d\n", link->priority);
+       }
+}
+
+static void
+acpi_pci_link_init_irq_penalty(void)
+{
+       int                     irq;
+
+       bzero(irq_penalty, sizeof(irq_penalty));
+       for (irq = 0; irq < MAX_ISA_INTERRUPTS; irq++) {
+               /* 0, 1, 2, 8:  timer, keyboard, cascade */
+               if (irq == 0 || irq == 1 || irq == 2 || irq == 8) {
+                       irq_penalty[irq] = 100000;
+                       continue;
+               }
+
+               /* 13, 14, 15:  npx, ATA controllers */
+               if (irq == 13 || irq == 14 || irq == 15) {
+                       irq_penalty[irq] = 10000;
+                       continue;
+               }
+
+               /* 3,4,6,7,12:  typicially used by legacy hardware */
+               if (irq == 3 || irq == 4 || irq == 6 || irq == 7 || irq == 12) {
+                       irq_penalty[irq] = 1000;
+                       continue;
+               }
+       }
+}
+
+static int
+acpi_pci_link_is_irq_exclusive(ACPI_RESOURCE *res)
+{
+       if (res == NULL) {
+               return (0);
+       }
+
+       if (res->Id != ACPI_RSTYPE_IRQ &&
+           res->Id != ACPI_RSTYPE_EXT_IRQ) {
+               return (0);
+       }
+
+       if (res->Id == ACPI_RSTYPE_IRQ &&
+           res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) {
+               return (1);
+       }
+
+       if (res->Id == ACPI_RSTYPE_EXT_IRQ &&
+           res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE) {
+               return (1);
+       }
+
+       return (0);
+}
+
+static void
+acpi_pci_link_update_irq_penalty(device_t dev, int busno)
+{
+       int                     i;
+       int                     irq;
+       int                     rid;
+       struct resource         *res;
+       struct acpi_prt_entry   *entry;
+       struct acpi_pci_link_entry *link;
+
+       TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
+               if (entry->busno != busno) {
+                       continue;
+               }
+
+               link = entry->pci_link;
+               if (link == NULL) {
+                       continue;       /* impossible... */
+               }
+
+               if (link->current_irq != 0) {
+                       /* not boot-disabled link, we will use this IRQ. */
+                       irq_penalty[link->current_irq] += 100;
+                       continue;
+               }
+
+               /* boot-disabled link */
+               for (i = 0; i < link->number_of_interrupts; i++) {
+                       /* give 10 for each possible IRQs. */
+                       irq = link->interrupts[i];
+                       irq_penalty[irq] += 10;
+
+                       /* higher penalty if exclusive. */
+                       if (acpi_pci_link_is_irq_exclusive(&link->possible_resources)) {
+                               irq_penalty[irq] += 100;
+                       }
+
+                       /* XXX try to get this IRQ in non-sharable mode. */
+                       rid = 0;
+                       res = bus_alloc_resource(dev, SYS_RES_IRQ,
+                                                &rid, irq, irq, 1, 0);
+                       if (res != NULL) {
+                               bus_release_resource(dev, SYS_RES_IRQ,
+                                   rid, res);
+                       } else {
+                               /* this is in use, give 100. */
+                               irq_penalty[irq] += 100;
+                       }
+               }
+
+               /* initialize `sorted' possible IRQs. */
+               bcopy(link->interrupts, link->sorted_irq,
+                   sizeof(link->sorted_irq));
+       }
+}
+
+static void
+acpi_pci_link_set_bootdisabled_priority(void)
+{
+       int                     sum_penalty;
+       int                     i;
+       int                     irq;
+       struct acpi_pci_link_entry *link, *link_pri;
+       TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
+
+       if (bootverbose) {
+               printf("---- before setting priority for links ------------\n");
+               acpi_pci_link_bootdisabled_dump();
+       }
+
+       /* reset priority for all links. */
+       TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
+               link->priority = 0;
+       }
+
+       TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
+               /* not boot-disabled link, give no chance to be arbitrated. */
+               if (link->current_irq != 0) {
+                       link->priority = 0;
+                       continue;
+               }
+
+               /*
+                * Calculate the priority for each boot-disabled links.
+                * o IRQ penalty indicates difficulty to use. 
+                * o #references for devices indicates importance of the link.
+                * o #interrupts indicates flexibility of the link.
+                */
+               sum_penalty = 0;
+               for (i = 0; i < link->number_of_interrupts; i++) {
+                       irq = link->interrupts[i];
+                       sum_penalty += irq_penalty[irq];
+               }
+
+               link->priority = (sum_penalty * link->references) / link->number_of_interrupts;
+       }
+
+       /*
+        * Sort PCI links based on the priority.
+        * XXX Any other better ways rather than using work list?
+        */
+       TAILQ_INIT(&sorted_list);
+       while (!TAILQ_EMPTY(&acpi_pci_link_entries)) {
+               link = TAILQ_FIRST(&acpi_pci_link_entries);
+               /* find an entry which has the highest priority. */
+               TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links) {
+                       if (link->priority < link_pri->priority) {
+                               link = link_pri;
+                       }
+               }
+               /* move to work list. */
+               TAILQ_REMOVE(&acpi_pci_link_entries, link, links);
+               TAILQ_INSERT_TAIL(&sorted_list, link, links);
+       }
+
+       while (!TAILQ_EMPTY(&sorted_list)) {
+               /* move them back to the list, one by one... */
+               link = TAILQ_FIRST(&sorted_list);
+               TAILQ_REMOVE(&sorted_list, link, links);
+               TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
+       }
+}
+
+static void
+acpi_pci_link_fixup_bootdisabled_link(void)
+{
+       int                     i, j;
+       int                     irq1, irq2;
+       struct acpi_pci_link_entry *link;
+       ACPI_STATUS             error;
+
+       if (bootverbose) {
+               printf("---- before fixup boot-disabled links -------------\n");
+               acpi_pci_link_bootdisabled_dump();
+       }
+
+       TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
+               /* ignore non boot-disabled links. */
+               if (link->current_irq != 0) {
+                       continue;
+               }
+
+               /* sort IRQs based on their penalty descending. */
+               for (i = 0; i < link->number_of_interrupts; i++) {
+                       irq1 = link->sorted_irq[i];
+                       for (j = i + 1; j < link->number_of_interrupts; j++) {
+                               irq2 = link->sorted_irq[j];
+                               if (irq_penalty[irq1] < irq_penalty[irq2]) {
+                                       continue;
+                               }
+                               link->sorted_irq[i] = irq2;
+                               link->sorted_irq[j] = irq1;
+                               irq1 = irq2;
+                       }
+               }
+
+               /* try with lower penalty IRQ. */
+               for (i = 0; i < link->number_of_interrupts; i++) {
+                       irq1 = link->sorted_irq[i];
+                       error = acpi_pci_link_set_irq(link, irq1);
+                       if (error == AE_OK) {
+                               /* OK, we use this.  give another penalty. */
+                               irq_penalty[irq1] += 100 * link->references;
+                               break;
+                       }
+                       /* NG, try next IRQ... */
+               }
+       }
+
+       if (bootverbose) {
+               printf("---- after fixup boot-disabled links --------------\n");
+               acpi_pci_link_bootdisabled_dump();
+       }
+}
+
+/*
+ * Public interface
+ */
+
+int
+acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno)
+{
+       struct acpi_prt_entry   *entry;
+       ACPI_PCI_ROUTING_TABLE  *prt;
+       u_int8_t                *prtp;
+       ACPI_STATUS             error;
+       static int              first_time =1;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (acpi_disabled("pci_link")) {
+               return (0);
+       }
+
+       if (first_time) {
+               TAILQ_INIT(&acpi_prt_entries);
+               TAILQ_INIT(&acpi_pci_link_entries);
+               acpi_pci_link_init_irq_penalty();
+               first_time = 0;
+       }
+
+       if (prtbuf == NULL) {
+               return (-1);
+       }
+
+       prtp = prtbuf->Pointer;
+       if (prtp == NULL) {             /* didn't get routing table */
+               return (-1);
+       }
+
+       /* scan the PCI Routing Table */
+       for (;;) {
+               prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
+
+               if (prt->Length == 0)   /* end of table */
+                   break;
+
+               error = acpi_pci_link_add_prt(dev, prt, busno);
+               if (ACPI_FAILURE(error)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                           "couldn't add PCI interrupt link entry - %s\n",
+                           AcpiFormatException(error)));
+               }
+
+               /* skip to next entry */
+               prtp += prt->Length;
+       }
+
+       if (bootverbose) {
+               printf("---- initial configuration ------------------------\n");
+               TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
+                       if (entry->busno != busno) {
+                               continue;
+                       }
+
+                       acpi_pci_link_entry_dump(entry);
+               }
+       }
+
+       /* manual configuration. */
+       TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
+               int                     irq;
+               char                    prthint[32];
+
+               if (entry->busno != busno) {
+                       continue;
+               }
+
+               snprintf(prthint, sizeof(prthint),
+                   "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
+                   (int)((entry->prt.Address & 0xffff0000) >> 16),
+                   (int)entry->prt.Pin);
+
+               if (getenv_int(prthint, &irq) == 0)
+                       continue;
+
+               if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
+                       error = acpi_pci_link_set_irq(entry->pci_link, irq);
+                       if (ACPI_FAILURE(error)) {
+                               ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                                   "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
+                                   acpi_name(entry->pci_link->handle),
+                                   AcpiFormatException(error)));
+                       }
+                       continue;
+               }
+
+               /*
+                * Do auto arbitration for this device's PCI link
+                * if hint value 0 is specified.
+                */
+               if (irq == 0) {
+                       entry->pci_link->current_irq = 0;
+               }
+       }
+
+       /* auto arbitration */
+       acpi_pci_link_update_irq_penalty(dev, busno);
+       acpi_pci_link_set_bootdisabled_priority();
+       acpi_pci_link_fixup_bootdisabled_link();
+
+       if (bootverbose) {
+               printf("---- arbitrated configuration ---------------------\n");
+               TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
+                       if (entry->busno != busno) {
+                               continue;
+                       }
+
+                       acpi_pci_link_entry_dump(entry);
+               }
+       }
+
+       return (0);
+}
+
+int
+acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno)
+{
+       struct acpi_prt_entry   *entry;
+       ACPI_STATUS             error;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (acpi_disabled("pci_link")) {
+               return (0);
+       }
+
+       TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
+               if (entry->pcidev != dev) {
+                       continue;
+               }
+
+               error = acpi_pci_link_set_irq(entry->pci_link,
+                           entry->pci_link->current_irq);
+               if (ACPI_FAILURE(error)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+                           "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
+                           acpi_name(entry->pci_link->handle),
+                           AcpiFormatException(error)));
+               }
+       }
+
+       return (0);
+}
+
diff --git a/sys/dev/acpica5/acpi_pcib.c b/sys/dev/acpica5/acpi_pcib.c
new file mode 100644 (file)
index 0000000..586b052
--- /dev/null
@@ -0,0 +1,376 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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.
+ *
+ * $FreeBSD: src/sys/dev/acpica/acpi_pcib.c,v 1.36 2003/12/18 17:04:11 kan Exp $
+ * $DragonFly: src/sys/dev/acpica5/acpi_pcib.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+
+#include "acpi.h"
+
+#include "acpivar.h"
+#include "acpi_pcibvar.h"
+
+#include <machine/pci_cfgreg.h>
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pcib_private.h>
+#include "pcib_if.h"
+
+/*
+ * Hooks for the ACPI CA debugging infrastructure
+ */
+#define _COMPONENT     ACPI_BUS
+ACPI_MODULE_NAME("PCI")
+
+int
+acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno)
+{
+    device_t                   child;
+    ACPI_STATUS                        status;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+    /*
+     * Don't attach if we're not really there.
+     *
+     * XXX: This isn't entirely correct since we may be a PCI bus
+     * on a hot-plug docking station, etc.
+     */
+    if (!acpi_DeviceIsPresent(dev))
+       return_VALUE(ENXIO);
+
+    /*
+     * Get the PCI interrupt routing table for this bus.
+     */
+    prt->Length = ACPI_ALLOCATE_BUFFER;
+    status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt);
+    if (ACPI_FAILURE(status))
+       /* This is not an error, but it may reduce functionality. */
+       device_printf(dev,
+           "could not get PCI interrupt routing table for %s - %s\n",
+           acpi_name(acpi_get_handle(dev)), AcpiFormatException(status));
+
+    /*
+     * Attach the PCI bus proper.
+     */
+    if ((child = device_add_child(dev, "pci", busno)) == NULL) {
+       device_printf(device_get_parent(dev), "couldn't attach pci bus\n");
+       return_VALUE(ENXIO);
+    }
+
+    /*
+     * Now go scan the bus.
+     */
+    acpi_pci_link_config(dev, prt, busno);
+    return_VALUE(bus_generic_attach(dev));
+}
+
+int
+acpi_pcib_resume(device_t dev, ACPI_BUFFER *prt, int busno)
+{
+    acpi_pci_link_resume(dev, prt, busno);
+    return (bus_generic_resume(dev));
+}
+
+/*
+ * Route an interrupt for a child of the bridge.
+ *
+ * XXX clean up error messages
+ *
+ * XXX this function is somewhat bulky
+ */
+int
+acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
+    ACPI_BUFFER *prtbuf)
+{
+    ACPI_PCI_ROUTING_TABLE     *prt;
+    ACPI_HANDLE                        lnkdev;
+    ACPI_BUFFER                        crsbuf, prsbuf, buf;
+    ACPI_RESOURCE              *crsres, *prsres, resbuf;
+    ACPI_DEVICE_INFO           *devinfo;
+    ACPI_STATUS                        status;
+    UINT32                     NumberOfInterrupts;
+    UINT32                     *Interrupts;
+    u_int8_t                   *prtp;
+    int                                interrupt;
+    int                                i;
+
+    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+    
+    buf.Pointer = NULL;
+    crsbuf.Pointer = NULL;
+    prsbuf.Pointer = NULL;
+    interrupt = 255;
+
+    /* ACPI numbers pins 0-3, not 1-4 like the BIOS */
+    pin--;
+
+    prtp = prtbuf->Pointer;
+    if (prtp == NULL)                  /* didn't get routing table */
+       goto out;
+
+    /* scan the table looking for this device */
+    for (;;) {
+       prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
+
+       if (prt->Length == 0)           /* end of table */
+           goto out;
+
+       /*
+        * Compare the slot number (high word of Address) and pin number
+        * (note that ACPI uses 0 for INTA) to check for a match.
+        *
+        * Note that the low word of the Address field (function number)
+        * is required by the specification to be 0xffff.  We don't risk
+        * checking it here.
+        */
+       if ((((prt->Address & 0xffff0000) >> 16) == pci_get_slot(dev)) &&
+           (prt->Pin == pin)) {
+           if (bootverbose)
+               device_printf(pcib, "matched entry for %d.%d.INT%c (source %s)\n",
+                             pci_get_bus(dev), pci_get_slot(dev), 'A' + pin, prt->Source);
+           break;
+       }
+       
+       /* skip to next entry */
+       prtp += prt->Length;
+    }
+
+    /*
+     * If source is empty/NULL, the source index is the global IRQ number.
+     */
+    if ((prt->Source == NULL) || (prt->Source[0] == '\0')) {
+       if (bootverbose)
+           device_printf(pcib, "device is hardwired to IRQ %d\n",
+               prt->SourceIndex);
+       interrupt = prt->SourceIndex;
+       goto out;
+    }
+    
+    /*
+     * We have to find the source device (PCI interrupt link device)
+     */
+    if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) {
+       device_printf(pcib, "couldn't find PCI interrupt link device %s\n",
+           prt->Source);
+       goto out;
+    }
+
+    /*
+     * Verify that this is a PCI link device, and that it's present.
+     */
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+    if (ACPI_FAILURE(AcpiGetObjectInfo(lnkdev, &buf))) {
+       device_printf(pcib, "couldn't validate PCI interrupt link device %s\n",
+           prt->Source);
+       goto out;
+    }
+    devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
+    if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
+       strcmp("PNP0C0F", devinfo->HardwareId.Value) != 0) {
+
+       device_printf(pcib, "PCI interrupt link device %s has wrong _HID (%s)\n",
+                     prt->Source, devinfo->HardwareId.Value);
+       goto out;
+    }
+    if ((devinfo->Valid & ACPI_VALID_STA) != 0 &&
+       (devinfo->CurrentStatus & 0x9) != 0x9) {
+
+       device_printf(pcib, "PCI interrupt link device %s not present\n",
+                     prt->Source);
+       goto out;
+    }
+
+    /*
+     * Get the current and possible resources for the interrupt link device.
+     */
+    crsbuf.Length = ACPI_ALLOCATE_BUFFER;
+    if (ACPI_FAILURE(status = AcpiGetCurrentResources(lnkdev, &crsbuf))) {
+       device_printf(pcib, "couldn't get PCI interrupt link device _CRS data - %s\n",
+                     AcpiFormatException(status));
+       goto out;       /* this is fatal */
+    }
+    prsbuf.Length = ACPI_ALLOCATE_BUFFER;
+    if (ACPI_FAILURE(status = AcpiGetPossibleResources(lnkdev, &prsbuf))) {
+       device_printf(pcib, "couldn't get PCI interrupt link device _PRS data - %s\n",
+                     AcpiFormatException(status));
+       /* this is not fatal, since it may be hardwired */
+    }
+    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "got %ld bytes for %s._CRS\n",
+       (long)crsbuf.Length, acpi_name(lnkdev)));
+    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "got %ld bytes for %s._PRS\n",
+       (long)prsbuf.Length, acpi_name(lnkdev)));
+
+    /*
+     * The interrupt may already be routed, so check _CRS first.  We don't check the
+     * 'decoding' bit in the _STA result, since there's nothing in the spec that 
+     * mandates it be set, however some BIOS' will set it if the decode is active.
+     *
+     * The Source Index points to the particular resource entry we're interested in.
+     */
+    if (ACPI_FAILURE(acpi_FindIndexedResource(&crsbuf, prt->SourceIndex, &crsres))) {
+       device_printf(pcib, "_CRS buffer corrupt, cannot route interrupt\n");
+       goto out;
+    }
+
+    /* type-check the resource we've got */
+    if (crsres->Id != ACPI_RSTYPE_IRQ && crsres->Id != ACPI_RSTYPE_EXT_IRQ) {
+       device_printf(pcib, "_CRS resource entry has unsupported type %d\n",
+           crsres->Id);
+       goto out;
+    }
+
+    /* set variables based on resource type */
+    if (crsres->Id == ACPI_RSTYPE_IRQ) {
+       NumberOfInterrupts = crsres->Data.Irq.NumberOfInterrupts;
+       Interrupts = crsres->Data.Irq.Interrupts;
+    } else {
+       NumberOfInterrupts = crsres->Data.ExtendedIrq.NumberOfInterrupts;
+       Interrupts = crsres->Data.ExtendedIrq.Interrupts;
+    }
+
+    /* if there's more than one interrupt, we are confused */
+    if (NumberOfInterrupts > 1) {
+       device_printf(pcib, "device has too many interrupts (%d)\n",
+           NumberOfInterrupts);
+       goto out;
+    }
+
+    /* 
+     * If there's only one interrupt, and it's not zero, then we're already routed.
+     *
+     * Note that we could also check the 'decoding' bit in _STA, but can't depend on
+     * it since it's not part of the spec.
+     *
+     * XXX check ASL examples to see if this is an acceptable set of tests
+     */
+    if ((NumberOfInterrupts == 1) && (Interrupts[0] != 0)) {
+       device_printf(pcib, "slot %d INT%c is routed to irq %d\n",
+           pci_get_slot(dev), 'A' + pin, Interrupts[0]);
+       interrupt = Interrupts[0];
+       goto out;
+    }
+    
+    /* 
+     * There isn't an interrupt, so we have to look at _PRS to get one.
+     * Get the set of allowed interrupts from the _PRS resource indexed by SourceIndex.
+     */
+    if (prsbuf.Pointer == NULL) {
+       device_printf(pcib, "device has no routed interrupt and no _PRS on PCI interrupt link device\n");
+       goto out;
+    }
+    if (ACPI_FAILURE(acpi_FindIndexedResource(&prsbuf, prt->SourceIndex, &prsres))) {
+       device_printf(pcib, "_PRS buffer corrupt, cannot route interrupt\n");
+       goto out;
+    }
+
+    /* type-check the resource we've got */
+    if (prsres->Id != ACPI_RSTYPE_IRQ && prsres->Id != ACPI_RSTYPE_EXT_IRQ) {
+       device_printf(pcib, "_PRS resource entry has unsupported type %d\n",
+           prsres->Id);
+       goto out;
+    }
+
+    /* set variables based on resource type */
+    if (prsres->Id == ACPI_RSTYPE_IRQ) {
+       NumberOfInterrupts = prsres->Data.Irq.NumberOfInterrupts;
+       Interrupts = prsres->Data.Irq.Interrupts;
+    } else {
+       NumberOfInterrupts = prsres->Data.ExtendedIrq.NumberOfInterrupts;
+       Interrupts = prsres->Data.ExtendedIrq.Interrupts;
+    }
+
+    /* there has to be at least one interrupt available */
+    if (NumberOfInterrupts < 1) {
+       device_printf(pcib, "device has no interrupts\n");
+       goto out;
+    }
+
+    /*
+     * Pick an interrupt to use.  Note that a more scientific approach than just
+     * taking the first one available would be desirable.
+     *
+     * The PCI BIOS $PIR table offers "preferred PCI interrupts", but ACPI doesn't
+     * seem to offer a similar mechanism, so picking a "good" interrupt here is a
+     * difficult task.
+     *
+     * Build a resource buffer and pass it to AcpiSetCurrentResources to route the
+     * new interrupt.
+     */
+    device_printf(pcib, "possible interrupts:");
+    for (i = 0; i < NumberOfInterrupts; i++)
+       printf("  %d", Interrupts[i]);
+    printf("\n");
+
+    if (crsbuf.Pointer != NULL)                        /* should never happen */
+       AcpiOsFree(crsbuf.Pointer);
+    crsbuf.Pointer = NULL;
+    if (prsres->Id == ACPI_RSTYPE_IRQ) {
+       resbuf.Id = ACPI_RSTYPE_IRQ;
+       resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
+       resbuf.Data.Irq = prsres->Data.Irq;             /* structure copy other fields */
+       resbuf.Data.Irq.NumberOfInterrupts = 1;
+       resbuf.Data.Irq.Interrupts[0] = Interrupts[0];  /* just take first... */
+    } else {
+       resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
+       resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
+       resbuf.Data.ExtendedIrq = prsres->Data.ExtendedIrq;     /* structure copy other fields */
+       resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
+       resbuf.Data.ExtendedIrq.Interrupts[0] = Interrupts[0];  /* just take first... */
+    }
+    if (ACPI_FAILURE(status = acpi_AppendBufferResource(&crsbuf, &resbuf))) {
+       device_printf(pcib, "couldn't route interrupt %d via %s, interrupt resource build failed - %s\n",
+                     Interrupts[0], acpi_name(lnkdev), AcpiFormatException(status));
+       goto out;
+    }
+    if (ACPI_FAILURE(status = AcpiSetCurrentResources(lnkdev, &crsbuf))) {
+       device_printf(pcib, "couldn't route interrupt %d via %s - %s\n",
+                     Interrupts[0], acpi_name(lnkdev), AcpiFormatException(status));
+       goto out;
+    }
+    
+    /* successful, return the interrupt we just routed */
+    device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 
+       pci_get_slot(dev), 'A' + pin, Interrupts[0], acpi_name(lnkdev));
+    interrupt = Interrupts[0];
+
+ out:
+    if (crsbuf.Pointer != NULL)
+       AcpiOsFree(crsbuf.Pointer);
+    if (prsbuf.Pointer != NULL)
+       AcpiOsFree(prsbuf.Pointer);
+    if (buf.Pointer != NULL)
+       AcpiOsFree(buf.Pointer);
+
+    /* XXX APIC_IO interrupt mapping? */
+    return_VALUE(interrupt);
+}
+
diff --git a/sys/dev/acpica5/acpi_pcib_acpi.c b/sys/dev/acpica5/acpi_pcib_acpi.c
new file mode 100644 (file)
index 0000000..14afe3b
--- /dev/null
@@ -0,0 +1,292 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * 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 SOF