Sync ACPI with FreeBSD 7.2
authorAlexander Polakov <polachok@gmail.com>
Sun, 8 Nov 2009 20:26:01 +0000 (23:26 +0300)
committerAlexander Polakov <polachok@gmail.com>
Sun, 8 Nov 2009 20:26:02 +0000 (23:26 +0300)
28 files changed:
sys/dev/acpica5/Osd/OsdInterrupt.c
sys/dev/acpica5/acpi.c
sys/dev/acpica5/acpi_acad.c
sys/dev/acpica5/acpi_asus/acpi_asus.c
sys/dev/acpica5/acpi_battery.c
sys/dev/acpica5/acpi_button.c
sys/dev/acpica5/acpi_cmbat.c
sys/dev/acpica5/acpi_cpu_cstate.c
sys/dev/acpica5/acpi_cpu_pstate.c
sys/dev/acpica5/acpi_ec.c
sys/dev/acpica5/acpi_hpet.c
sys/dev/acpica5/acpi_if.m
sys/dev/acpica5/acpi_isab.c
sys/dev/acpica5/acpi_lid.c
sys/dev/acpica5/acpi_package.c
sys/dev/acpica5/acpi_pci.c
sys/dev/acpica5/acpi_pci_link.c
sys/dev/acpica5/acpi_pcib.c
sys/dev/acpica5/acpi_pcib_acpi.c
sys/dev/acpica5/acpi_pcib_pci.c
sys/dev/acpica5/acpi_pcibvar.h
sys/dev/acpica5/acpi_powerres.c
sys/dev/acpica5/acpi_resource.c
sys/dev/acpica5/acpi_thermal.c
sys/dev/acpica5/acpi_thinkpad/acpi_thinkpad.c
sys/dev/acpica5/acpi_toshiba/acpi_toshiba.c
sys/dev/acpica5/acpiio.h
sys/dev/acpica5/acpivar.h

index 06aa685..78a76fe 100644 (file)
@@ -157,9 +157,7 @@ acpi_OverrideInterruptLevel(UINT32 InterruptNumber)
 static void
 InterruptWrapper(void *arg)
 {
-    ACPI_LOCK_DECL;
-
-    ACPI_LOCK;
+    crit_enter();
     InterruptHandler(arg);
-    ACPI_UNLOCK;
+    crit_exit();
 }
index c5adcf2..fd22ed0 100644 (file)
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
- * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Takanori Watanabe <takawata@jp.kfreebsd.org>
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.kfreebsd.org>
  * Copyright (c) 2000, 2001 Michael Smith
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  * 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.160 2004/06/14 03:52:19 njl Exp $
- *     $DragonFly: src/sys/dev/acpica5/acpi.c,v 1.37 2008/10/03 00:26:21 hasso Exp $
+ * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi.c,v 1.243.2.4.4.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
+#include <sys/cdefs.h>
+
 #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/module.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
-#include <sys/device.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 <sys/rman.h>
-
-#include <sys/thread2.h>
-#include <sys/lock.h>
+#include <sys/device.h>
+#include <sys/spinlock.h>
+#include <sys/spinlock2.h>
 
-#include <machine/clock.h>
-#include <machine/globaldata.h>
+#include <sys/rman.h>
 #include <bus/isa/isavar.h>
+#include <bus/isa/pnpvar.h>
 
 #include "acpi.h"
-#include "accommon.h"
 #include <dev/acpica5/acpivar.h>
 #include <dev/acpica5/acpiio.h>
-#include <acnamesp.h>
+#include "achware.h"
+#include "acnamesp.h"
+#include "acglobal.h"
+
+#include "pci_if.h"
+#include <bus/pci/pcivar.h>
+#include <bus/pci/pci_private.h>
+
+#include <vm/vm_param.h>
 
 MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
 
+#define GIANT_REQUIRED
+#define mtx_lock(a)
+#define mtx_unlock(a)
 /* Hooks for the ACPI CA debugging infrastructure */
 #define _COMPONENT     ACPI_BUS
 ACPI_MODULE_NAME("ACPI")
@@ -72,87 +82,71 @@ static d_ioctl_t    acpiioctl;
 
 #define CDEV_MAJOR 152
 static struct dev_ops acpi_ops = {
-       { "acpi", CDEV_MAJOR, 0 },
-       .d_open = acpiopen,
-       .d_close = acpiclose,
-       .d_ioctl = acpiioctl
-};
-
-#if __FreeBSD_version >= 500000
-struct mtx     acpi_mutex;
-#endif
-
-/* Local pools for managing system resources for ACPI child devices. */
-struct rman acpi_rman_io, acpi_rman_mem;
-
-struct acpi_quirks {
-    char       *OemId;
-    uint32_t   OemRevision;
-    char       *value;
+        { "acpi", CDEV_MAJOR, 0 },
+        .d_open = acpiopen,
+        .d_close = acpiclose,
+        .d_ioctl = acpiioctl
 };
 
-#define ACPI_OEM_REV_ANY       0
-
-static struct acpi_quirks acpi_quirks_table[] = {
-#ifdef notyet
-    /* Bad PCI routing table.  Used on some SuperMicro boards. */
-    { "PTLTD ", 0x06040000, "pci_link" },
-#endif
-#ifdef ACPI_QUIRK_VMWARE
-    /*
-     * VMware's ACPI-fast24 timer runs roughly 65 times too fast, and not
-     * predictably/monotonic either. This is observed at least under SMP
-     * conditions.
-     *
-     * NOTE: this combination of OemId and OemRevision is NOT unique; it is
-     * known or suspected that at least some SuperMicro boards (see above) and
-     * the Compaq Presario 1952 use this combination. That's why this quirks
-     * entry is guarded by an #ifdef, and associated config option.
-     */
-    { "PTLTD ", 0x06040000, "timer" },
-#endif /* ACPI_QUIRK_VMWARE */
-    { NULL, 0, NULL }
-};
+/* Global mutex for locking access to the ACPI subsystem. */
+struct lock acpi_lock;
+/* Bitmap of device quirks. */
+int            acpi_quirks;
 
 static int     acpi_modevent(struct module *mod, int event, void *junk);
-static int     acpi_identify(driver_t *driver, device_t parent);
+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 int     acpi_suspend(device_t dev);
+static int     acpi_resume(device_t dev);
 static int     acpi_shutdown(device_t dev);
-static void    acpi_quirks_set(void);
-static device_t        acpi_add_child(device_t bus, device_t parent, int order,
-                       const char *name, int unit);
+static device_t        acpi_add_child(device_t bus, device_t parent, int order, const char *name,
+                       int unit);
 static int     acpi_print_child(device_t bus, device_t child);
+static void    acpi_probe_nomatch(device_t bus, device_t child);
+static void    acpi_driver_added(device_t dev, driver_t *driver);
 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 struct resource_list *acpi_get_rlist(device_t dev, device_t child);
+static int     acpi_sysres_alloc(device_t dev);
 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 void    acpi_delete_resource(device_t bus, device_t child, int type,
+                   int rid);
 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 char    *acpi_device_id_probe(device_t bus, device_t dev, char **ids);
+static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
+                   ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
+                   ACPI_BUFFER *ret);
+static int     acpi_device_pwr_for_sleep(device_t bus, device_t dev,
+                   int *dstate);
+static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
+                   void *context, void **retval);
+static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
+                   int max_depth, acpi_scan_cb_t user_fn, void *arg);
+static int     acpi_set_powerstate_method(device_t bus, device_t child,
+                   int state);
 static int     acpi_isa_pnp_probe(device_t bus, device_t child,
-                       struct isa_pnp_id *ids);
+                   struct isa_pnp_id *ids);
 static void    acpi_probe_children(device_t bus);
+static void    acpi_probe_order(ACPI_HANDLE handle, int *order);
 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);
+                   void *context, void **status);
+BOOLEAN        acpi_MatchHid(ACPI_HANDLE h, const char *hid);
+static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state);
 static void    acpi_shutdown_final(void *arg, int howto);
-static void    acpi_shutdown_poweroff(void *arg);
 static void    acpi_enable_fixed_events(struct acpi_softc *sc);
-static int     acpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw);
-static ACPI_STATUS acpi_wake_limit(ACPI_HANDLE h, UINT32 level, void *context,
-                   void **status);
-static int     acpi_wake_limit_walk(int sstate);
+static int     acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate);
+static int     acpi_wake_run_prep(ACPI_HANDLE handle, int sstate);
+static int     acpi_wake_prep_walk(int sstate);
 static int     acpi_wake_sysctl_walk(device_t dev);
-#ifdef dfly_notyet
 static int     acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS);
-#endif
 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);
@@ -170,12 +164,14 @@ static device_method_t acpi_methods[] = {
     DEVMETHOD(device_attach,           acpi_attach),
     DEVMETHOD(device_shutdown,         acpi_shutdown),
     DEVMETHOD(device_detach,           bus_generic_detach),
-    DEVMETHOD(device_suspend,          bus_generic_suspend),
-    DEVMETHOD(device_resume,           bus_generic_resume),
+    DEVMETHOD(device_suspend,          acpi_suspend),
+    DEVMETHOD(device_resume,           acpi_resume),
 
     /* Bus interface */
     DEVMETHOD(bus_add_child,           acpi_add_child),
     DEVMETHOD(bus_print_child,         acpi_print_child),
+    DEVMETHOD(bus_probe_nomatch,       acpi_probe_nomatch),
+    DEVMETHOD(bus_driver_added,                acpi_driver_added),
     DEVMETHOD(bus_read_ivar,           acpi_read_ivar),
     DEVMETHOD(bus_write_ivar,          acpi_write_ivar),
     DEVMETHOD(bus_get_resource_list,   acpi_get_rlist),
@@ -183,9 +179,9 @@ static device_method_t acpi_methods[] = {
     DEVMETHOD(bus_get_resource,                bus_generic_rl_get_resource),
     DEVMETHOD(bus_alloc_resource,      acpi_alloc_resource),
     DEVMETHOD(bus_release_resource,    acpi_release_resource),
+    DEVMETHOD(bus_delete_resource,     acpi_delete_resource),
     DEVMETHOD(bus_child_pnpinfo_str,   acpi_child_pnpinfo_str_method),
     DEVMETHOD(bus_child_location_str,  acpi_child_location_str_method),
-    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),
@@ -193,6 +189,12 @@ static device_method_t acpi_methods[] = {
 
     /* ACPI bus */
     DEVMETHOD(acpi_id_probe,           acpi_device_id_probe),
+    DEVMETHOD(acpi_evaluate_object,    acpi_device_eval_obj),
+    DEVMETHOD(acpi_pwr_for_sleep,      acpi_device_pwr_for_sleep),
+    DEVMETHOD(acpi_scan_children,      acpi_device_scan_children),
+
+    /* PCI emulation */
+    DEVMETHOD(pci_set_powerstate,      acpi_set_powerstate_method),
 
     /* ISA emulation */
     DEVMETHOD(isa_pnp_probe,           acpi_isa_pnp_probe),
@@ -210,10 +212,17 @@ static devclass_t acpi_devclass;
 DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, 0);
 MODULE_VERSION(acpi, 1);
 
+ACPI_SERIAL_DECL(acpi, "ACPI serializer")
+
+/* Local pools for managing system resources for ACPI child devices. */
+static struct rman acpi_rman_io, acpi_rman_mem;
+
+#define ACPI_MINIMUM_AWAKETIME 5
+
 static const char* sleep_state_names[] = {
     "S0", "S1", "S2", "S3", "S4", "S5", "NONE"};
 
-SYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RW, NULL, "ACPI debugging");
+SYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RD, 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");
@@ -228,6 +237,19 @@ SYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD,
 static int acpi_serialize_methods;
 TUNABLE_INT("hw.acpi.serialize_methods", &acpi_serialize_methods);
 
+/* Power devices off and on in suspend and resume.  XXX Remove once tested. */
+static int acpi_do_powerstate = 1;
+TUNABLE_INT("debug.acpi.do_powerstate", &acpi_do_powerstate);
+SYSCTL_INT(_debug_acpi, OID_AUTO, do_powerstate, CTLFLAG_RW,
+    &acpi_do_powerstate, 1, "Turn off devices when suspending.");
+
+/* Allow users to override quirks. */
+TUNABLE_INT("debug.acpi.quirks", &acpi_quirks);
+
+static int acpi_susp_bounce;
+SYSCTL_INT(_debug_acpi, OID_AUTO, suspend_bounce, CTLFLAG_RW,
+    &acpi_susp_bounce, 0, "Don't actually suspend, just test devices.");
+
 /*
  * 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.
@@ -237,7 +259,7 @@ TUNABLE_INT("hw.acpi.serialize_methods", &acpi_serialize_methods);
 static int
 acpi_modevent(struct module *mod, int event, void *junk)
 {
-    switch(event) {
+    switch (event) {
     case MOD_LOAD:
        if (!cold) {
            kprintf("The ACPI driver cannot be loaded after boot.\n");
@@ -260,234 +282,192 @@ acpi_modevent(struct module *mod, int event, void *junk)
 ACPI_STATUS
 acpi_Startup(void)
 {
-#ifdef ACPI_DEBUGGER
-    char *debugpoint;
-#endif
-    static int error, started = 0;
+    static int started = 0;
+    ACPI_STATUS status;
+    int val;
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
+    /* Only run the startup code once.  The MADT driver also calls this. */
     if (started)
-       return_VALUE (error);
+       return_VALUE (AE_OK);
     started = 1;
 
-    /* Start up the ACPI CA subsystem. */
-#ifdef ACPI_DEBUGGER
-    debugpoint = kgetenv("debug.acpi.debugger");
-    if (debugpoint) {
-       if (!strcmp(debugpoint, "init"))
-           acpi_EnterDebugger();
-       kfreeenv(debugpoint);
+    /*
+     * Pre-allocate space for RSDT/XSDT and DSDT tables and allow resizing
+     * if more tables exist.
+     */
+    if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 2, TRUE))) {
+       kprintf("ACPI: Table initialisation failed: %s\n",
+           AcpiFormatException(status));
+       return_VALUE (status);
     }
+
+    /* Set up any quirks we have for this system. */
+#ifdef notyet
+    if (acpi_quirks == ACPI_Q_OK)
+       acpi_table_quirks(&acpi_quirks);
 #endif
-    error = AcpiInitializeTables(NULL, 16, TRUE);
-    if (ACPI_FAILURE(error)) {
-       kprintf("ACPI: table initialization failed:\n");
-       return_VALUE (error);
-    }
 
-    /* Set up any quirks we have for this XSDT. */
-    acpi_quirks_set();
-    if (acpi_disabled("acpi"))
-       return_VALUE (AE_ERROR);
+    /* If the user manually set the disabled hint to 0, force-enable ACPI. */
+    if (resource_int_value("acpi", 0, "disabled", &val) == 0 && val == 0)
+       acpi_quirks &= ~ACPI_Q_BROKEN;
+    if (acpi_quirks & ACPI_Q_BROKEN) {
+       kprintf("ACPI disabled by blacklist.  Contact your BIOS vendor.\n");
+       status = AE_SUPPORT;
+    }
 
-    return_VALUE (AE_OK);
+    return_VALUE (status);
 }
 
 /*
  * Detect ACPI, perform early initialisation
  */
-static int
+static void
 acpi_identify(driver_t *driver, device_t parent)
 {
     device_t   child;
 
-    /*
-     * No sense rescanning an ACPI 'bus'.
-     */
-    if (device_get_state(parent) == DS_ATTACHED)
-       return(0);
-
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
     if (!cold)
-       return (ENXIO);
+       return_VOID;
 
     /* Check that we haven't been disabled with a hint. */
     if (resource_disabled("acpi", 0))
-       return (ENXIO);
+       return_VOID;
 
     /* Make sure we're not being doubly invoked. */
     if (device_find_child(parent, "acpi", 0) != NULL)
-       return (ENXIO);
+       return_VOID;
 
-    /* Initialize ACPI-CA. */
-    if (ACPI_FAILURE(acpi_Startup()))
-       return (ENXIO);
+    ksnprintf(acpi_ca_version, sizeof(acpi_ca_version), "%x", ACPI_CA_VERSION);
 
-    ksnprintf(acpi_ca_version, sizeof(acpi_ca_version), "%#x", ACPI_CA_VERSION);
+    /* Initialize root tables. */
+    if (ACPI_FAILURE(acpi_Startup())) {
+       kprintf("ACPI: Try disabling either ACPI or apic support.\n");
+       return_VOID;
+    }
 
     /* Attach the actual ACPI device. */
-    if ((child = BUS_ADD_CHILD(parent, parent, 0, "acpi", 0)) == NULL) {
-       device_printf(parent, "ACPI: could not attach\n");
-       return (ENXIO);
+    if ((child = BUS_ADD_CHILD(parent, parent, 10, "acpi", 0)) == NULL) {
+       device_printf(parent, "device_identify failed\n");
+       return_VOID;
     }
-    return (0);
-}
-
-/*
- * Get a mapping of the root table header, as ACPICA code no longer
- * keeps local copy of RSDT/XSDT
- *
- * return value: if non-NULL, mapped physical address of root table header.
- * caller is supposed to unmap the region by AcpiOsUnmapMemory()
- */
-static ACPI_TABLE_HEADER *
-acpi_map_rsdt_header(void)
-{
-    ACPI_PHYSICAL_ADDRESS rsdp_addr, addr;
-    ACPI_TABLE_RSDP *rsdp;
-
-    if ((rsdp_addr = AcpiOsGetRootPointer()) == 0)
-       return(NULL);
-    if ((rsdp = AcpiOsMapMemory(rsdp_addr, sizeof(*rsdp))) == NULL)
-       return(NULL);
-    if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress)
-       addr = (ACPI_PHYSICAL_ADDRESS)rsdp->XsdtPhysicalAddress;
-    else
-       addr = (ACPI_PHYSICAL_ADDRESS)rsdp->RsdtPhysicalAddress;
-    AcpiOsUnmapMemory(rsdp, sizeof(*rsdp));
-
-    return AcpiOsMapMemory(addr, sizeof(ACPI_TABLE_HEADER));
 }
 
 /*
- * Fetch some descriptive data from ACPI to put in our attach message
+ * 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;
+    ACPI_TABLE_RSDP    *rsdp;
+    ACPI_TABLE_HEADER  *rsdt;
+    ACPI_PHYSICAL_ADDRESS paddr;
+    char               buf[ACPI_OEM_ID_SIZE + ACPI_OEM_TABLE_ID_SIZE + 2];
     struct sbuf                sb;
-    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);
+       device_printf(dev, "probe failed, other PM system enabled.\n");
+       return_VALUE (ENXIO);
     }
 
-    ACPI_LOCK;
-
-    th = acpi_map_rsdt_header();
-    if (th == NULL) {
-       device_printf(dev, "couldn't get RSDT header\n");
-       error = ENXIO;
-       goto unlock;
-    }
+    if ((paddr = AcpiOsGetRootPointer()) == 0 ||
+       (rsdp = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_RSDP))) == NULL)
+       return_VALUE (ENXIO);
+    if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress != 0)
+       paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->XsdtPhysicalAddress;
+    else
+       paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->RsdtPhysicalAddress;
+    AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP));
 
+    if ((rsdt = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_HEADER))) == NULL)
+       return_VALUE (ENXIO);
     sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
-    sbuf_bcat(&sb, th->OemId, 6);
+    sbuf_bcat(&sb, rsdt->OemId, ACPI_OEM_ID_SIZE);
     sbuf_trim(&sb);
     sbuf_putc(&sb, ' ');
-    sbuf_bcat(&sb, th->OemTableId, 8);
+    sbuf_bcat(&sb, rsdt->OemTableId, ACPI_OEM_TABLE_ID_SIZE);
     sbuf_trim(&sb);
     sbuf_finish(&sb);
     device_set_desc_copy(dev, sbuf_data(&sb));
     sbuf_delete(&sb);
-    AcpiOsUnmapMemory(th, sizeof(*th));
-    error = 0;
-unlock:
-    ACPI_UNLOCK;
-    return_VALUE(error);
+    AcpiOsUnmapMemory(rsdt, sizeof(ACPI_TABLE_HEADER));
+
+    return_VALUE (0);
 }
 
 static int
 acpi_attach(device_t dev)
 {
     struct acpi_softc  *sc;
+    ACPI_TABLE_FACS    *facs;
     ACPI_STATUS                status;
     int                        error, state;
     UINT32             flags;
     UINT8              TypeA, TypeB;
     char               *env;
-    ACPI_TABLE_FACS    *facsp;
-#ifdef ACPI_DEBUGGER
-    char               *debugpoint;
-#endif
-    ACPI_LOCK_DECL;
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-#if __FreeBSD_version >= 500000
-    /* Initialise the ACPI mutex */
-    mtx_init(&acpi_mutex, "ACPI global lock", NULL, MTX_DEF);
-#endif
 
-    ACPI_LOCK;
+    //lwkt_serialize_init(&acpi_sxlock);
     sc = device_get_softc(dev);
-    bzero(sc, sizeof(*sc));
     sc->acpi_dev = dev;
-    callout_init(&sc->acpi_sleep_timer);
+    callout_init(&sc->susp_force_to);
 
     if ((error = acpi_task_thread_init())) {
-       device_printf(dev, "Could not start task thread.\n");
-       goto out;
+        device_printf(dev, "Could not start task thread.\n");
+        goto out;
     }
 
-    /*
-     * Set the globals from our tunables.  This is needed because ACPI-CA
-     * uses UINT8 for some values and we have no tunable_byte.
-     */
-    AcpiGbl_AllMethodsSerialized = (UINT8)acpi_serialize_methods;
-    AcpiGbl_EnableInterpreterSlack = TRUE;
-
     error = ENXIO;
-#ifdef ACPI_DEBUGGER
-    debugpoint = kgetenv("debug.acpi.debugger");
-    if (debugpoint) {
-       if (!strcmp(debugpoint, "tables"))
-           acpi_EnterDebugger();
-       kfreeenv(debugpoint);
-    }
-#endif
-
-    if (ACPI_FAILURE(status = AcpiInitializeSubsystem())) {
-       kprintf("ACPI: initialisation failed: %s\n",
-              AcpiFormatException(status));
-       goto out;
-    }
-    if (ACPI_FAILURE(status = AcpiLoadTables())) {
-       kprintf("ACPI: table load failed: %s\n", AcpiFormatException(status));
-       goto out;
-    }
 
     /* Initialize resource manager. */
     acpi_rman_io.rm_type = RMAN_ARRAY;
     acpi_rman_io.rm_start = 0;
     acpi_rman_io.rm_end = 0xffff;
-    acpi_rman_io.rm_descr = "I/O ports";
+    acpi_rman_io.rm_descr = "ACPI I/O ports";
     if (rman_init(&acpi_rman_io) != 0)
        panic("acpi rman_init IO ports failed");
     acpi_rman_mem.rm_type = RMAN_ARRAY;
     acpi_rman_mem.rm_start = 0;
     acpi_rman_mem.rm_end = ~0ul;
-    acpi_rman_mem.rm_descr = "I/O memory addresses";
+    acpi_rman_mem.rm_descr = "ACPI I/O memory addresses";
     if (rman_init(&acpi_rman_mem) != 0)
        panic("acpi rman_init memory failed");
 
-#ifdef ACPI_DEBUGGER
-    debugpoint = kgetenv("debug.acpi.debugger");
-    if (debugpoint) {
-       if (!strcmp(debugpoint, "spaces"))
-           acpi_EnterDebugger();
-       kfreeenv(debugpoint);
-    }
+    /* Initialise the ACPI mutex */
+#ifdef notyet
+    spin_init(&acpi_mutex);
 #endif
+
+    /*
+     * Set the globals from our tunables.  This is needed because ACPI-CA
+     * uses UINT8 for some values and we have no tunable_byte.
+     */
+    AcpiGbl_AllMethodsSerialized = acpi_serialize_methods;
+    AcpiGbl_EnableInterpreterSlack = TRUE;
+
+    /* Start up the ACPI CA subsystem. */
+    status = AcpiInitializeSubsystem();
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "Could not initialize Subsystem: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+
+    /* Load ACPI name space. */
+    status = AcpiLoadTables();
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "Could not load Namespace: %s\n",
+                     AcpiFormatException(status));
+       goto out;
+    }
+
     /* Install the default address space handlers. */
     status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
                ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL);
@@ -512,31 +492,21 @@ acpi_attach(device_t dev)
     }
 
     /*
-     * 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).
-     * For avoiding portions of the namespace without totally disabling _INI
-     * and _STA, use "debug.acpi.avoid.paths".
      *
      * 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 = kgetenv("debug.acpi.debugger");
-    if (debugpoint) {
-       if (!strcmp(debugpoint, "enable"))
-           acpi_EnterDebugger();
-       kfreeenv(debugpoint);
-    }
-#endif
     flags = 0;
     if (ktestenv("debug.acpi.avoid"))
        flags = ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
+
+    /* Bring the hardware and basic handlers online. */
     if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) {
        device_printf(dev, "Could not enable ACPI: %s\n",
                      AcpiFormatException(status));
@@ -546,9 +516,14 @@ acpi_attach(device_t dev)
     /*
      * Call the ECDT probe function to provide EC functionality before
      * the namespace has been evaluated.
+     *
+     * XXX This happens before the sysresource devices have been probed and
+     * attached so its resources come from nexus0.  In practice, this isn't
+     * a problem but should be addressed eventually.
      */
     acpi_ec_ecdt_probe(dev);
 
+    /* Bring device objects and regions online. */
     if (ACPI_FAILURE(status = AcpiInitializeObjects(flags))) {
        device_printf(dev, "Could not initialize ACPI objects: %s\n",
                      AcpiFormatException(status));
@@ -583,38 +558,42 @@ acpi_attach(device_t dev)
        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");
+       OID_AUTO, "sleep_delay", 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");
+       OID_AUTO, "s4bios", 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");
+       OID_AUTO, "verbose", 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");
+       OID_AUTO, "disable_on_reboot", CTLFLAG_RW,
+       &sc->acpi_do_disable, 0, "Disable ACPI when rebooting/halting system");
+    SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+       OID_AUTO, "handle_reboot", CTLFLAG_RW,
+       &sc->acpi_handle_reboot, 0, "Use ACPI Reset Register to reboot");
 
     /*
      * Default to 1 second before sleeping to give some machines time to
      * stabilize.
      */
     sc->acpi_sleep_delay = 1;
-    sc->acpi_disable_on_poweroff = 0;
     if (bootverbose)
        sc->acpi_verbose = 1;
-    if ((env = kgetenv("hw.acpi.verbose")) && strcmp(env, "0")) {
-       sc->acpi_verbose = 1;
+    if ((env = kgetenv("hw.acpi.verbose")) != NULL) {
+       if (strcmp(env, "0") != 0)
+           sc->acpi_verbose = 1;
        kfreeenv(env);
     }
 
     /* Only enable S4BIOS by default if the FACS says it is available. */
-    status = AcpiGetTableByIndex(ACPI_TABLE_INDEX_FACS,
-                               (ACPI_TABLE_HEADER **)&facsp);
-    if (ACPI_SUCCESS(status)) {
-       if ((facsp->Flags & ACPI_FACS_S4_BIOS_PRESENT) != 0)
-           sc->acpi_s4bios = 1;
+    status = AcpiGetTable(ACPI_SIG_FACS, 0, (ACPI_TABLE_HEADER **)&facs);
+    if (ACPI_FAILURE(status)) {
+       device_printf(dev, "couldn't get FACS: %s\n",
+                     AcpiFormatException(status));
+       error = ENXIO;
+       goto out;
     }
+    if (facs->Flags & ACPI_FACS_S4_BIOS_PRESENT)
+       sc->acpi_s4bios = 1;
 
     /*
      * Dispatch the default sleep state to devices.  The lid switch is set
@@ -627,7 +606,7 @@ acpi_attach(device_t dev)
 
     /* Pick the first valid sleep state for the sleep button default. */
     sc->acpi_sleep_button_sx = ACPI_S_STATES_MAX + 1;
-    for (state = ACPI_STATE_S1; state < ACPI_STATE_S5; state++)
+    for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++)
        if (ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) {
            sc->acpi_sleep_button_sx = state;
            break;
@@ -638,18 +617,8 @@ acpi_attach(device_t dev)
     /*
      * Scan the namespace and attach/initialise children.
      */
-#ifdef ACPI_DEBUGGER
-    debugpoint = kgetenv("debug.acpi.debugger");
-    if (debugpoint) {
-       if (!strcmp(debugpoint, "probe"))
-           acpi_EnterDebugger();
-       kfreeenv(debugpoint);
-    }
-#endif
 
-    /* Register our shutdown handlers */
-    EVENTHANDLER_REGISTER(shutdown_pre_sync, acpi_shutdown_pre_sync, sc,
-       SHUTDOWN_PRI_LAST);
+    /* Register our shutdown handler. */
     EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc,
        SHUTDOWN_PRI_LAST);
 
@@ -666,21 +635,11 @@ acpi_attach(device_t dev)
     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_ops, 0, UID_ROOT, GID_WHEEL, 0644,
                              "acpi");
     sc->acpi_dev_t->si_drv1 = sc;
 
-#ifdef ACPI_DEBUGGER
-    debugpoint = kgetenv("debug.acpi.debugger");
-    if (debugpoint) {
-       if (strcmp(debugpoint, "running") == 0)
-           acpi_EnterDebugger();
-       kfreeenv(debugpoint);
-    }
-#endif
-
     if ((error = acpi_machdep_init(dev)))
        goto out;
 
@@ -693,91 +652,114 @@ acpi_attach(device_t dev)
     error = 0;
 
  out:
-    ACPI_UNLOCK;
-
     cputimer_intr_pmfixup();
     return_VALUE (error);
 }
 
 static int
-acpi_shutdown(device_t dev)
+acpi_suspend(device_t dev)
 {
-    /* Allow children to shutdown first. */
-    bus_generic_shutdown(dev);
+    device_t child, *devlist;
+    int error, i, numdevs, pstate;
 
-    /* Disable all wake GPEs not appropriate for reboot/poweroff. */
-    acpi_wake_limit_walk(ACPI_STATE_S5);
-    return (0);
+    GIANT_REQUIRED;
+
+    /* First give child devices a chance to suspend. */
+    error = bus_generic_suspend(dev);
+    if (error)
+       return (error);
+
+    /*
+     * Now, set them into the appropriate power state, usually D3.  If the
+     * device has an _SxD method for the next sleep state, use that power
+     * state instead.
+     */
+    device_get_children(dev, &devlist, &numdevs);
+    for (i = 0; i < numdevs; i++) {
+       /* If the device is not attached, we've powered it down elsewhere. */
+       child = devlist[i];
+       if (!device_is_attached(child))
+           continue;
+
+       /*
+        * Default to D3 for all sleep states.  The _SxD method is optional
+        * so set the powerstate even if it's absent.
+        */
+       pstate = PCI_POWERSTATE_D3;
+       error = acpi_device_pwr_for_sleep(device_get_parent(child),
+           child, &pstate);
+       if ((error == 0 || error == ESRCH) && acpi_do_powerstate)
+           pci_set_powerstate(child, pstate);
+    }
+    kfree(devlist, M_TEMP);
+    error = 0;
+
+    return (error);
 }
 
-static void
-acpi_quirks_set(void)
+static int
+acpi_resume(device_t dev)
 {
-    ACPI_TABLE_HEADER *rsdt;
-    struct acpi_quirks *quirk;
-    char *env, *tmp;
-    int len;
+    ACPI_HANDLE handle;
+    int i, numdevs;
+    device_t child, *devlist;
+
+    GIANT_REQUIRED;
 
     /*
-     * If the user loaded a custom table or disabled "quirks", leave
-     * the settings alone.
+     * Put all devices in D0 before resuming them.  Call _S0D on each one
+     * since some systems expect this.
      */
-    len = 0;
-    if ((env = kgetenv("acpi_dsdt_load")) != NULL) {
-       /* XXX No strcasecmp but this is good enough. */
-       if (*env == 'Y' || *env == 'y')
-           goto out;
-       kfreeenv(env);
-    }
-    if ((env = kgetenv("debug.acpi.disabled")) != NULL) {
-       if (strstr("quirks", env) != NULL)
-           goto out;
-       len = strlen(env);
+    device_get_children(dev, &devlist, &numdevs);
+    for (i = 0; i < numdevs; i++) {
+       child = devlist[i];
+       handle = acpi_get_handle(child);
+       if (handle)
+           AcpiEvaluateObject(handle, "_S0D", NULL, NULL);
+       if (device_is_attached(child) && acpi_do_powerstate)
+           pci_set_powerstate(child, PCI_POWERSTATE_D0);
     }
+    kfree(devlist, M_TEMP);
+
+    return (bus_generic_resume(dev));
+}
+
+static int
+acpi_shutdown(device_t dev)
+{
+
+    GIANT_REQUIRED;
+
+    /* Allow children to shutdown first. */
+    bus_generic_shutdown(dev);
 
     /*
-     * Search through our quirk table and concatenate the disabled
-     * values with whatever we find.
+     * Enable any GPEs that are able to power-on the system (i.e., RTC).
+     * Also, disable any that are not valid for this state (most).
      */
-    if ((rsdt = acpi_map_rsdt_header()) == NULL)
-       goto out;
-    for (quirk = acpi_quirks_table; quirk->OemId; quirk++) {
-       if (!strncmp(rsdt->OemId, quirk->OemId, strlen(quirk->OemId)) &&
-           (rsdt->OemRevision == quirk->OemRevision ||
-           quirk->OemRevision == ACPI_OEM_REV_ANY)) {
-               len += strlen(quirk->value) + 2;
-               if ((tmp = kmalloc(len, M_TEMP, M_NOWAIT)) == NULL)
-                   goto out;
-               ksprintf(tmp, "%s %s", env ? env : "", quirk->value);
-               ksetenv("debug.acpi.disabled", tmp);
-               kfree(tmp, M_TEMP);
-               break;
-       }
-    }
-    AcpiOsUnmapMemory(rsdt, sizeof(*rsdt));
+    acpi_wake_prep_walk(ACPI_STATE_S5);
 
-out:
-    if (env)
-       kfreeenv(env);
+    return (0);
 }
 
 /*
  * Handle a new device being added
  */
 static device_t
-acpi_add_child(device_t bus, device_t parent, int order,
-               const char *name, int unit)
+acpi_add_child(device_t bus, device_t parent, int order, const char *name, int unit)
 {
     struct acpi_device *ad;
     device_t           child;
 
-    ad = kmalloc(sizeof(*ad), M_ACPIDEV, M_INTWAIT | M_ZERO);
+    if ((ad = kmalloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL)
+       return (NULL);
 
     resource_list_init(&ad->ad_rl);
-
     child = device_add_child_ordered(parent, order, name, unit);
     if (child != NULL)
        device_set_ivars(child, ad);
+    else
+       kfree(ad, M_ACPIDEV);
     return (child);
 }
 
@@ -793,11 +775,52 @@ acpi_print_child(device_t bus, device_t child)
     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");
+    if (device_get_flags(child))
+       retval += kprintf(" flags %#x", device_get_flags(child));
     retval += bus_print_child_footer(bus, child);
 
     return (retval);
 }
 
+/*
+ * If this device is an ACPI child but no one claimed it, attempt
+ * to power it off.  We'll power it back up when a driver is added.
+ *
+ * XXX Disabled for now since many necessary devices (like fdc and
+ * ATA) don't claim the devices we created for them but still expect
+ * them to be powered up.
+ */
+static void
+acpi_probe_nomatch(device_t bus, device_t child)
+{
+
+    /* pci_set_powerstate(child, PCI_POWERSTATE_D3); */
+}
+
+/*
+ * If a new driver has a chance to probe a child, first power it up.
+ *
+ * XXX Disabled for now (see acpi_probe_nomatch for details).
+ */
+static void
+acpi_driver_added(device_t dev, driver_t *driver)
+{
+    device_t child, *devlist;
+    int i, numdevs;
+
+    DEVICE_IDENTIFY(driver, dev);
+    device_get_children(dev, &devlist, &numdevs);
+    for (i = 0; i < numdevs; i++) {
+       child = devlist[i];
+       if (device_get_state(child) == DS_NOTPRESENT) {
+           /* pci_set_powerstate(child, PCI_POWERSTATE_D0); */
+           if (device_probe_and_attach(child) != 0)
+               ; /* pci_set_powerstate(child, PCI_POWERSTATE_D3); */
+       }
+    }
+    kfree(devlist, M_TEMP);
+}
+
 /* Location hint for devctl(8) */
 static int
 acpi_child_location_str_method(device_t cbdev, device_t child, char *buf,
@@ -806,9 +829,9 @@ acpi_child_location_str_method(device_t cbdev, device_t child, char *buf,
     struct acpi_device *dinfo = device_get_ivars(child);
 
     if (dinfo->ad_handle)
-       ksnprintf(buf, buflen, "path=%s", acpi_name(dinfo->ad_handle));
+       ksnprintf(buf, buflen, "handle=%s", acpi_name(dinfo->ad_handle));
     else
-       ksnprintf(buf, buflen, "magic=unknown");
+       ksnprintf(buf, buflen, "unknown");
     return (0);
 }
 
@@ -825,16 +848,14 @@ acpi_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf,
 
     error = AcpiGetObjectInfo(dinfo->ad_handle, &adbuf);
     adinfo = (ACPI_DEVICE_INFO *) adbuf.Pointer;
-
     if (error)
-       ksnprintf(buf, buflen, "Unknown");
+       ksnprintf(buf, buflen, "unknown");
     else
        ksnprintf(buf, buflen, "_HID=%s _UID=%lu",
-               (adinfo->Valid & ACPI_VALID_HID) ?
-               adinfo->HardwareId.Value : "UNKNOWN",
-               (adinfo->Valid & ACPI_VALID_UID) ?
-               strtoul(adinfo->UniqueId.Value, &end, 10) : 0);
-
+                (adinfo->Valid & ACPI_VALID_HID) ?
+                adinfo->HardwareId.Value : "none",
+                (adinfo->Valid & ACPI_VALID_UID) ?
+                strtoul(adinfo->UniqueId.Value, &end, 10) : 0);
     if (adinfo)
        AcpiOsFree(adinfo);
 
@@ -860,11 +881,14 @@ acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
        *(ACPI_HANDLE *)result = ad->ad_handle;
        break;
     case ACPI_IVAR_MAGIC:
-       *(int *)result = ad->ad_magic;
+       *(uintptr_t *)result = ad->ad_magic;
        break;
     case ACPI_IVAR_PRIVATE:
        *(void **)result = ad->ad_private;
        break;
+    case ACPI_IVAR_FLAGS:
+       *(int *)result = ad->ad_flags;
+       break;
     case ISA_IVAR_VENDORID:
     case ISA_IVAR_SERIAL:
     case ISA_IVAR_COMPATID:
@@ -895,11 +919,14 @@ acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
        ad->ad_handle = (ACPI_HANDLE)value;
        break;
     case ACPI_IVAR_MAGIC:
-       ad->ad_magic = (int)value;
+       ad->ad_magic = (uintptr_t)value;
        break;
     case ACPI_IVAR_PRIVATE:
        ad->ad_private = (void *)value;
        break;
+    case ACPI_IVAR_FLAGS:
+       ad->ad_flags = (int)value;
+       break;
     default:
        panic("bad ivar write request (%d)", index);
        return (ENOENT);
@@ -920,69 +947,151 @@ acpi_get_rlist(device_t dev, device_t child)
     return (&ad->ad_rl);
 }
 
+/*
+ * Pre-allocate/manage all memory and IO resources.  Since rman can't handle
+ * duplicates, we merge any in the sysresource attach routine.
+ */
+static int
+acpi_sysres_alloc(device_t dev)
+{
+    struct resource *res;
+    struct resource_list *rl;
+    struct resource_list_entry *rle;
+    struct rman *rm;
+    char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
+    device_t *children;
+    int child_count, i;
+    /*
+     * Probe/attach any sysresource devices.  This would be unnecessary if we
+     * had multi-pass probe/attach.
+     */
+    if (device_get_children(dev, &children, &child_count) != 0)
+       return (ENXIO);
+    for (i = 0; i < child_count; i++) {
+       if (ACPI_ID_PROBE(dev, children[i], sysres_ids) != NULL)
+           device_probe_and_attach(children[i]);
+    }
+    kfree(children, M_TEMP);
+
+    rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
+    if(!rl)
+       return 0;
+    SLIST_FOREACH(rle, rl, link) {
+       if (rle->res != NULL) {
+           device_printf(dev, "duplicate resource for %lx\n", rle->start);
+           continue;
+       }
+
+       /* Only memory and IO resources are valid here. */
+       switch (rle->type) {
+       case SYS_RES_IOPORT:
+           rm = &acpi_rman_io;
+           break;
+       case SYS_RES_MEMORY:
+           rm = &acpi_rman_mem;
+           break;
+       default:
+           continue;
+       }
+
+       /* Pre-allocate resource and add to our rman pool. */
+       res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, rle->type,
+           &rle->rid, rle->start, rle->start + rle->count - 1, rle->count, 0);
+       if (res != NULL) {
+           rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
+           rle->res = res;
+       } else
+           device_printf(dev, "reservation of %lx, %lx (%d) failed\n",
+               rle->start, rle->count, rle->type);
+    }
+    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)
 {
+    ACPI_RESOURCE ares;
     struct acpi_device *ad = device_get_ivars(child);
     struct resource_list *rl = &ad->ad_rl;
     struct resource_list_entry *rle;
     struct resource *res;
     struct rman *rm;
-    int needactivate;
+
+    res = NULL;
+
+    /* We only handle memory and IO resources through rman. */
+    switch (type) {
+    case SYS_RES_IOPORT:
+       rm = &acpi_rman_io;
+       break;
+    case SYS_RES_MEMORY:
+       rm = &acpi_rman_mem;
+       break;
+    default:
+       rm = NULL;
+    }
+
+    ACPI_SERIAL_BEGIN(acpi);
 
     /*
      * If this is an allocation of the "default" range for a given RID, and
      * we know what the resources for this device are (i.e., they're on the
      * child's resource list), use those start/end values.
      */
-    if (start == 0UL && end == ~0UL) {
+    if (bus == device_get_parent(child) && start == 0UL && end == ~0UL) {
        rle = resource_list_find(rl, type, *rid);
        if (rle == NULL)
-           return (NULL);
+           goto out;
        start = rle->start;
        end = rle->end;
        count = rle->count;
     }
 
-    /* If we don't manage this address, pass the request up to the parent. */
-    rle = acpi_sysres_find(type, start);
-    if (rle == NULL) {
-       return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
-           start, end, count, flags));
-    }
+    /*
+     * If this is an allocation of a specific range, see if we can satisfy
+     * the request from our system resource regions.  If we can't, pass the
+     * request up to the parent.
+     */
+    if (start + count - 1 == end && rm != NULL)
+       res = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+           child);
+    if (res == NULL) {
+       res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
+           start, end, count, flags);
+    } else {
+       rman_set_rid(res, *rid);
 
-    /* We only handle memory and IO resources through rman. */
-    switch (type) {
-    case SYS_RES_IOPORT:
-       rm = &acpi_rman_io;
-       break;
-    case SYS_RES_MEMORY:
-       rm = &acpi_rman_mem;
-       break;
-    default:
-       panic("acpi_alloc_resource: invalid res type %d", type);
+       /* If requested, activate the resource using the parent's method. */
+       if (flags & RF_ACTIVE)
+           if (bus_activate_resource(child, type, *rid, res) != 0) {
+               rman_release_resource(res);
+               res = NULL;
+               goto out;
+           }
     }
 
-    /* If we do know it, allocate it from the local pool. */
-    needactivate = flags & RF_ACTIVE;
-    flags &= ~RF_ACTIVE;
-    res = rman_reserve_resource(rm, start, end, count, flags, child);
-    if (res == NULL)
-       return (NULL);
-
-    /* Copy the bus tag from the pre-allocated resource. */
-    rman_set_bustag(res, rman_get_bustag(rle->res));
-    if (type == SYS_RES_IOPORT)
-       rman_set_bushandle(res, res->r_start);
-
-    /* If requested, activate the resource using the parent's method. */
-    if (needactivate)
-       if (bus_activate_resource(child, type, *rid, res) != 0) {
-           rman_release_resource(res);
-           return (NULL);
+    if (res != NULL && device_get_parent(child) == bus)
+       switch (type) {
+       case SYS_RES_IRQ:
+           /*
+            * Since bus_config_intr() takes immediate effect, we cannot
+            * configure the interrupt associated with a device when we
+            * parse the resources but have to defer it until a driver
+            * actually allocates the interrupt via bus_alloc_resource().
+            *
+            * XXX: Should we handle the lookup failing?
+            */
+kprintf("%s(): %d\n", __FUNCTION__, __LINE__);
+           if (ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares)))
+               acpi_config_intr(child, &ares);
+           else
+               kprintf("irq resource not found\n");
+           break;
        }
 
+out:
+    ACPI_SERIAL_END(acpi);
     return (res);
 }
 
@@ -990,63 +1099,99 @@ static int
 acpi_release_resource(device_t bus, device_t child, int type, int rid,
     struct resource *r)
 {
+    struct rman *rm;
     int ret;
 
+    /* We only handle memory and IO resources through rman. */
+    switch (type) {
+    case SYS_RES_IOPORT:
+       rm = &acpi_rman_io;
+       break;
+    case SYS_RES_MEMORY:
+       rm = &acpi_rman_mem;
+       break;
+    default:
+       rm = NULL;
+    }
+
+    ACPI_SERIAL_BEGIN(acpi);
+
     /*
-     * If we know about this address, deactivate it and release it to the
-     * local pool.  If we don't, pass this request up to the parent.
+     * If this resource belongs to one of our internal managers,
+     * deactivate it and release it to the local pool.  If it doesn't,
+     * pass this request up to the parent.
      */
-    if (acpi_sysres_find(type, rman_get_start(r)) == NULL) {
+    if (rm != NULL && rman_is_region_manager(r, rm)) {
        if (rman_get_flags(r) & RF_ACTIVE) {
            ret = bus_deactivate_resource(child, type, rid, r);
            if (ret != 0)
-               return (ret);
+               goto out;
        }
        ret = rman_release_resource(r);
     } else
        ret = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, type, rid, r);
 
+out:
+    ACPI_SERIAL_END(acpi);
     return (ret);
 }
 
+static void
+acpi_delete_resource(device_t bus, device_t child, int type, int rid)
+{
+    struct resource_list *rl;
+
+    rl = acpi_get_rlist(bus, child);
+    resource_list_delete(rl, type, rid);
+}
+
 /* Allocate an IO port or memory resource, given its GAS. */
-struct resource *
-acpi_bus_alloc_gas(device_t dev, int *rid, const ACPI_GENERIC_ADDRESS *gas,
-    u_int flags)
+int
+acpi_bus_alloc_gas(device_t dev, int *type, int *rid, ACPI_GENERIC_ADDRESS *gas,
+    struct resource **res, u_int flags)
 {
-    int type;
+    int error, res_type;
 
-    if (gas == NULL || gas->BitWidth < 8)
-       return (NULL);
+    error = ENOMEM;
+    if (type == NULL || rid == NULL || gas == NULL || res == NULL)
+       return (EINVAL);
 
+    /* We only support memory and IO spaces. */
     switch (gas->SpaceId) {
     case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-       type = SYS_RES_MEMORY;
+       res_type = SYS_RES_MEMORY;
        break;
     case ACPI_ADR_SPACE_SYSTEM_IO:
-       type = SYS_RES_IOPORT;
+       res_type = SYS_RES_IOPORT;
        break;
     default:
-       return (NULL);
+       return (EOPNOTSUPP);
     }
 
-    bus_set_resource(dev, type, *rid, gas->Address, gas->BitWidth / 8);
-    return (bus_alloc_resource_any(dev, type, rid, RF_ACTIVE | flags));
-}
+    /*
+     * If the register width is less than 8, assume the BIOS author means
+     * it is a bit field and just allocate a byte.
+     */
+    if (gas->BitWidth && gas->BitWidth < 8)
+       gas->BitWidth = 8;
 
-/*
- * 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))
+    /* Validate the address after we're sure we support the space. */
+    if (gas->Address == 0 || gas->BitWidth == 0)
+       return (EINVAL);
+
+    bus_set_resource(dev, res_type, *rid, gas->Address,
+       gas->BitWidth / 8);
+    *res = bus_alloc_resource_any(dev, res_type, rid, RF_ACTIVE | flags);
+    if (*res != NULL) {
+       *type = res_type;
+       error = 0;
+    } else
+       bus_delete_resource(dev, res_type, *rid);
 
+    return (error);
+}
+
+/* Probe _HID and _CID for compatible ISA PNP ids. */
 static uint32_t
 acpi_isa_get_logicalid(device_t dev)
 {
@@ -1055,7 +1200,6 @@ acpi_isa_get_logicalid(device_t dev)
     ACPI_HANDLE                h;
     ACPI_STATUS                error;
     u_int32_t          pnpid;
-    ACPI_LOCK_DECL;
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
@@ -1063,8 +1207,6 @@ acpi_isa_get_logicalid(device_t dev)
     buf.Pointer = NULL;
     buf.Length = ACPI_ALLOCATE_BUFFER;
 
-    ACPI_LOCK;
-    
     /* Fetch and validate the HID. */
     if ((h = acpi_get_handle(dev)) == NULL)
        goto out;
@@ -1079,7 +1221,6 @@ acpi_isa_get_logicalid(device_t dev)
 out:
     if (buf.Pointer != NULL)
        AcpiOsFree(buf.Pointer);
-    ACPI_UNLOCK;
     return_VALUE (pnpid);
 }
 
@@ -1092,7 +1233,6 @@ acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
     ACPI_STATUS                error;
     uint32_t           *pnpid;
     int                        valid, i;
-    ACPI_LOCK_DECL;
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
@@ -1101,8 +1241,6 @@ acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
     buf.Pointer = NULL;
     buf.Length = ACPI_ALLOCATE_BUFFER;
 
-    ACPI_LOCK;
-    
     /* Fetch and validate the CID */
     if ((h = acpi_get_handle(dev)) == NULL)
        goto out;
@@ -1125,7 +1263,6 @@ acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
 out:
     if (buf.Pointer != NULL)
        AcpiOsFree(buf.Pointer);
-    ACPI_UNLOCK;
     return_VALUE (valid);
 }
 
@@ -1147,6 +1284,172 @@ acpi_device_id_probe(device_t bus, device_t dev, char **ids)
     return (NULL);
 }
 
+static ACPI_STATUS
+acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname,
+    ACPI_OBJECT_LIST *parameters, ACPI_BUFFER *ret)
+{
+    ACPI_HANDLE h;
+
+    if (dev == NULL)
+       h = ACPI_ROOT_OBJECT;
+    else if ((h = acpi_get_handle(dev)) == NULL)
+       return (AE_BAD_PARAMETER);
+    return (AcpiEvaluateObject(h, pathname, parameters, ret));
+}
+
+static int
+acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
+{
+    struct acpi_softc *sc;
+    ACPI_HANDLE handle;
+    ACPI_STATUS status;
+    char sxd[8];
+    int error;
+
+    sc = device_get_softc(bus);
+    handle = acpi_get_handle(dev);
+
+    /*
+     * XXX If we find these devices, don't try to power them down.
+     * The serial and IRDA ports on my T23 hang the system when
+     * set to D3 and it appears that such legacy devices may
+     * need special handling in their drivers.
+     */
+    if (handle == NULL ||
+       acpi_MatchHid(handle, "PNP0500") ||
+       acpi_MatchHid(handle, "PNP0501") ||
+       acpi_MatchHid(handle, "PNP0502") ||
+       acpi_MatchHid(handle, "PNP0510") ||
+       acpi_MatchHid(handle, "PNP0511"))
+       return (ENXIO);
+
+    /*
+     * Override next state with the value from _SxD, if present.  If no
+     * dstate argument was provided, don't fetch the return value.
+     */
+    ksnprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate);
+    if (dstate)
+       status = acpi_GetInteger(handle, sxd, dstate);
+    else
+       status = AcpiEvaluateObject(handle, sxd, NULL, NULL);
+
+    switch (status) {
+    case AE_OK:
+       error = 0;
+       break;
+    case AE_NOT_FOUND:
+       error = ESRCH;
+       break;
+    default:
+       error = ENXIO;
+       break;
+    }
+
+    return (error);
+}
+
+/* Callback arg for our implementation of walking the namespace. */
+struct acpi_device_scan_ctx {
+    acpi_scan_cb_t     user_fn;
+    void               *arg;
+    ACPI_HANDLE                parent;
+};
+
+static ACPI_STATUS
+acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, void *arg, void **retval)
+{
+    struct acpi_device_scan_ctx *ctx;
+    device_t dev, old_dev;
+    ACPI_STATUS status;
+    ACPI_OBJECT_TYPE type;
+
+    /*
+     * Skip this device if we think we'll have trouble with it or it is
+     * the parent where the scan began.
+     */
+    ctx = (struct acpi_device_scan_ctx *)arg;
+    if (acpi_avoid(h) || h == ctx->parent)
+       return (AE_OK);
+
+    /* If this is not a valid device type (e.g., a method), skip it. */
+    if (ACPI_FAILURE(AcpiGetType(h, &type)))
+       return (AE_OK);
+    if (type != ACPI_TYPE_DEVICE && type != ACPI_TYPE_PROCESSOR &&
+       type != ACPI_TYPE_THERMAL && type != ACPI_TYPE_POWER)
+       return (AE_OK);
+
+    /*
+     * Call the user function with the current device.  If it is unchanged
+     * afterwards, return.  Otherwise, we update the handle to the new dev.
+     */
+    old_dev = acpi_get_device(h);
+    dev = old_dev;
+    status = ctx->user_fn(h, &dev, level, ctx->arg);
+    if (ACPI_FAILURE(status) || old_dev == dev)
+       return (status);
+
+    /* Remove the old child and its connection to the handle. */
+    if (old_dev != NULL) {
+       device_delete_child(device_get_parent(old_dev), old_dev);
+       AcpiDetachData(h, acpi_fake_objhandler);
+    }
+
+    /* Recreate the handle association if the user created a device. */
+    if (dev != NULL)
+       AcpiAttachData(h, acpi_fake_objhandler, dev);
+
+    return (AE_OK);
+}
+
+static ACPI_STATUS
+acpi_device_scan_children(device_t bus, device_t dev, int max_depth,
+    acpi_scan_cb_t user_fn, void *arg)
+{
+    ACPI_HANDLE h;
+    struct acpi_device_scan_ctx ctx;
+
+    if (acpi_disabled("children"))
+       return (AE_OK);
+
+    if (dev == NULL)
+       h = ACPI_ROOT_OBJECT;
+    else if ((h = acpi_get_handle(dev)) == NULL)
+       return (AE_BAD_PARAMETER);
+    ctx.user_fn = user_fn;
+    ctx.arg = arg;
+    ctx.parent = h;
+    return (AcpiWalkNamespace(ACPI_TYPE_ANY, h, max_depth,
+       acpi_device_scan_cb, &ctx, NULL));
+}
+
+/*
+ * Even though ACPI devices are not PCI, we use the PCI approach for setting
+ * device power states since it's close enough to ACPI.
+ */
+static int
+acpi_set_powerstate_method(device_t bus, device_t child, int state)
+{
+    ACPI_HANDLE h;
+    ACPI_STATUS status;
+    int error;
+
+    error = 0;
+    h = acpi_get_handle(child);
+    if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
+       return (EINVAL);
+    if (h == NULL)
+       return (0);
+
+    /* Ignore errors if the power methods aren't present. */
+    status = acpi_pwr_switch_consumer(h, state);
+    if (ACPI_FAILURE(status) && status != AE_NOT_FOUND
+       && status != AE_BAD_PARAMETER)
+       device_printf(bus, "failed to set ACPI power state D%d on %s: %s\n",
+           state, acpi_name(h), AcpiFormatException(status));
+
+    return (error);
+}
+
 static int
 acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids)
 {
@@ -1180,25 +1483,26 @@ acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids)
     }
 
  out:
+    if (result == 0 && ids->ip_desc)
+       device_set_desc(child, ids->ip_desc);
+
     return_VALUE (result);
 }
 
 /*
- * Scan relevant portions of the ACPI namespace and attach child devices.
+ * Scan all 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.
+ * We should only expect to find devices in the \_PR, \_TZ, \_SI, and
+ * \_SB scopes, and \_PR and \_TZ became obsolete in the ACPI 2.0 spec.
+ * However, in violation of the spec, some systems place their PCI link
+ * devices in \, so we have to walk the whole namespace.  We check the
+ * type of namespace nodes, so this should be ok.
  */
 static void
 acpi_probe_children(device_t bus)
 {
-    ACPI_HANDLE        parent;
-    ACPI_STATUS        status;
-    int                i;
-    static char        *scopes[] = {"\\_PR_", "\\_TZ_", "\\_SI", "\\_SB_", NULL};
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-    ACPI_ASSERTLOCK;
 
     /*
      * Scan the namespace and insert placeholders for all the devices that
@@ -1210,21 +1514,16 @@ acpi_probe_children(device_t bus)
      * 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);
-       }
-    }
+    AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100, acpi_probe_child,
+       bus, NULL);
 
+    /* Pre-allocate resources for our rman from any sysresource devices. */
+    acpi_sysres_alloc(bus);
     /* Create any static children by calling device identify methods. */
     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
     bus_generic_probe(bus);
 
-    /*
-     * Scan all of the child devices we have created and let them probe/attach.
-     */
+    /* Probe/attach all children, created staticly and from the namespace. */
     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "first bus_generic_attach\n"));
     bus_generic_attach(bus);
 
@@ -1242,26 +1541,29 @@ acpi_probe_children(device_t bus)
     return_VOID;
 }
 
-static int
-acpi_probe_order(ACPI_HANDLE handle, int level, int *order)
+/*
+ * Determine the probe order for a given device.
+ */
+static void
+acpi_probe_order(ACPI_HANDLE handle, int *order)
 {
-    int ret;
+    ACPI_OBJECT_TYPE type;
 
-    ret = 0;
-    /* IO port and memory system resource holders are first. */
-    if (acpi_MatchHid(handle, "PNP0C01") || acpi_MatchHid(handle, "PNP0C02")) {
+    /*
+     * 1. I/O port and memory system resource holders
+     * 2. Embedded controllers (to handle early accesses)
+     * 3. PCI Link Devices
+     * 100000. CPUs
+     */
+    AcpiGetType(handle, &type);
+    if (acpi_MatchHid(handle, "PNP0C01") || acpi_MatchHid(handle, "PNP0C02"))
        *order = 1;
-       ret = 1;
-    }
-
-    /* The embedded controller is needed to handle accesses early. */
-    if (acpi_MatchHid(handle, "PNP0C09")) {
+    else if (acpi_MatchHid(handle, "PNP0C09"))
        *order = 2;
-       ret = 1;
-    }
-
-    *order = (level + 1) * 10;
-    return (ret);
+    else if (acpi_MatchHid(handle, "PNP0C0F"))
+       *order = 3;
+    else if (type == ACPI_TYPE_PROCESSOR)
+       *order = 100000;
 }
 
 /*
@@ -1271,22 +1573,22 @@ acpi_probe_order(ACPI_HANDLE handle, int level, int *order)
 static ACPI_STATUS
 acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
 {
-    ACPI_OBJECT_TYPE   type;
-    device_t           child, bus;
-    int                        order, probe_now;
+    ACPI_OBJECT_TYPE type;
+    ACPI_HANDLE h;
+    device_t bus, child;
+    int order;
+    char *handle_str, **search;
+    static char *scopes[] = {"\\_PR_", "\\_TZ_", "\\_SI_", "\\_SB_", NULL};
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
     /* Skip this device if we think we'll have trouble with it. */
-    if (acpi_avoid(handle)) {
-       ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "not scanning '%s'\n",
-                        acpi_name(handle)));
+    if (acpi_avoid(handle))
        return_ACPI_STATUS (AE_OK);
-    }
 
     bus = (device_t)context;
     if (ACPI_SUCCESS(AcpiGetType(handle, &type))) {
-       switch(type) {
+       switch (type) {
        case ACPI_TYPE_DEVICE:
        case ACPI_TYPE_PROCESSOR:
        case ACPI_TYPE_THERMAL:
@@ -1294,13 +1596,29 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
            if (acpi_disabled("children"))
                break;
 
+           /*
+            * Since we scan from \, be sure to skip system scope objects.
+            * At least \_SB and \_TZ are detected as devices (ACPI-CA bug?)
+            */
+           handle_str = acpi_name(handle);
+           for (search = scopes; *search != NULL; search++) {
+               if (strcmp(handle_str, *search) == 0)
+                   break;
+           }
+           if (*search != NULL)
+               break;
+
            /* 
-            * Create a placeholder device for this node.  Sort the placeholder
-            * so that the probe/attach passes will run breadth-first.
+            * Create a placeholder device for this node.  Sort the
+            * placeholder so that the probe/attach passes will run
+            * breadth-first.  Orders less than ACPI_DEV_BASE_ORDER
+            * are reserved for special objects (i.e., system
+            * resources).  CPU devices have a very high order to
+            * ensure they are probed after other devices.
             */
-           ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n",
-                            acpi_name(handle)));
-           probe_now = acpi_probe_order(handle, level, &order);
+           ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n", handle_str));
+           order = level * 10 + 100;
+           acpi_probe_order(handle, &order);
            child = BUS_ADD_CHILD(bus, bus, order, NULL, -1);
            if (child == NULL)
                break;
@@ -1309,16 +1627,26 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
            acpi_set_handle(child, handle);
            AcpiAttachData(handle, acpi_fake_objhandler, child);
 
-           /* Check if the device can generate wake events. */
-           if (ACPI_SUCCESS(AcpiEvaluateObject(handle, "_PRW", NULL, NULL)))
-               device_set_flags(child, ACPI_FLAG_WAKE_CAPABLE);
-
            /*
             * 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).
+            *
+            * XXX PCI link devices sometimes report "present" but not
+            * "functional" (i.e. if disabled).  Go ahead and probe them
+            * anyway since we may enable them later.
             */
            if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) {
+               /* Never disable PCI link devices. */
+               if (acpi_MatchHid(handle, "PNP0C0F"))
+                   break;
+               /*
+                * Docking stations should remain enabled since the system
+                * may be undocked at boot.
+                */
+               if (ACPI_SUCCESS(AcpiGetHandle(handle, "_DCK", &h)))
+                   break;
+
                device_disable(child);
                break;
            }
@@ -1331,10 +1659,6 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
             * device not to have any resources.
             */
            acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL);
-
-           /* If order was overridden, probe/attach now rather than later. */
-           if (probe_now)
-               device_probe_and_attach(child);
            break;
        }
     }
@@ -1342,25 +1666,6 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
     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);
-}
-
 /*
  * AcpiAttachData() requires an object handler but never uses it.  This is a
  * placeholder object handler so we can store a device_t in an ACPI_HANDLE.
@@ -1373,14 +1678,15 @@ acpi_fake_objhandler(ACPI_HANDLE h, UINT32 fn, void *data)
 static void
 acpi_shutdown_final(void *arg, int howto)
 {
-    ACPI_STATUS        status;
-    ACPI_ASSERTLOCK;
+    struct acpi_softc *sc;
+    ACPI_STATUS status;
 
     /*
-     * If powering off, run the actual shutdown code on each processor.
-     * It will only perform the shutdown on the BSP.  Some chipsets do
-     * not power off the system correctly if called from an AP.
+     * XXX Shutdown code should only run on the BSP (cpuid 0).
+     * Some chipsets do not power off the system correctly if called from
+     * an AP.
      */
+    sc = arg;
     if ((howto & RB_POWEROFF) != 0) {
        status = AcpiEnterSleepStatePrep(ACPI_STATE_S5);
        if (ACPI_FAILURE(status)) {
@@ -1389,45 +1695,41 @@ acpi_shutdown_final(void *arg, int howto)
            return;
        }
        kprintf("Powering system off using ACPI\n");
-       acpi_shutdown_poweroff(NULL);
-    } else {
+       ACPI_DISABLE_IRQS();
+       status = AcpiEnterSleepState(ACPI_STATE_S5);
+       if (ACPI_FAILURE(status)) {
+           kprintf("ACPI power-off failed - %s\n", AcpiFormatException(status));
+       } else {
+           DELAY(1000000);
+           kprintf("ACPI power-off failed - timeout\n");
+       }
+    } else if ((howto & RB_HALT) == 0 &&
+       (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) &&
+       sc->acpi_handle_reboot) {
+       /* Reboot using the reset register. */
+       status = AcpiWrite(
+           AcpiGbl_FADT.ResetValue, &AcpiGbl_FADT.ResetRegister);
+       if (ACPI_FAILURE(status)) {
+           kprintf("ACPI reset failed - %s\n", AcpiFormatException(status));
+       } else {
+           DELAY(1000000);
+           kprintf("ACPI reset failed - timeout\n");
+       }
+    } else if (sc->acpi_do_disable && panicstr == NULL) {
+       /*
+        * Only disable ACPI if the user requested.  On some systems, writing
+        * the disable value to SMI_CMD hangs the system.
+        */
        kprintf("Shutting down ACPI\n");
        AcpiTerminate();
     }
 }
 
-/*
- * Since this function may be called with locks held or in an unknown
- * context, it cannot allocate memory, acquire locks, sleep, etc.
- */
-static void
-acpi_shutdown_poweroff(void *arg)
-{
-    ACPI_STATUS        status;
-
-    ACPI_ASSERTLOCK;
-
-    /* Only attempt to power off if this is the BSP (cpuid 0). */
-    if (mdcpu->mi.gd_cpuid != 0)
-       return;
-
-    ACPI_DISABLE_IRQS();
-    status = AcpiEnterSleepState(ACPI_STATE_S5);
-    if (ACPI_FAILURE(status)) {
-       kprintf("ACPI power-off failed - %s\n", AcpiFormatException(status));
-    } else {
-       DELAY(1000000);
-       kprintf("ACPI power-off failed - timeout\n");
-    }
-}
-
 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.Flags & ACPI_FADT_POWER_BUTTON) == 0) {
        AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
@@ -1461,8 +1763,6 @@ acpi_DeviceIsPresent(device_t dev)
     ACPI_STATUS                error;
     int                        ret;
 
-    ACPI_ASSERTLOCK;
-    
     ret = FALSE;
     if ((h = acpi_get_handle(dev)) == NULL)
        return (FALSE);
@@ -1478,7 +1778,7 @@ acpi_DeviceIsPresent(device_t dev)
        ret = TRUE;
 
     /* Return true for 'present' and 'functioning' */
-    if ((devinfo->CurrentStatus & 0x9) == 0x9)
+    if (ACPI_DEVICE_PRESENT(devinfo->CurrentStatus))
        ret = TRUE;
 
     AcpiOsFree(buf.Pointer);
@@ -1497,8 +1797,6 @@ acpi_BatteryIsPresent(device_t dev)
     ACPI_STATUS                error;
     int                        ret;
 
-    ACPI_ASSERTLOCK;
-    
     ret = FALSE;
     if ((h = acpi_get_handle(dev)) == NULL)
        return (FALSE);
@@ -1513,8 +1811,8 @@ acpi_BatteryIsPresent(device_t dev)
     if ((devinfo->Valid & ACPI_VALID_STA) == 0)
        ret = TRUE;
 
-    /* Return true for 'present' and 'functioning' */
-    if ((devinfo->CurrentStatus & 0x19) == 0x19)
+    /* Return true for 'present', 'battery present', and 'functioning' */
+    if (ACPI_BATTERY_PRESENT(devinfo->CurrentStatus))
        ret = TRUE;
 
     AcpiOsFree(buf.Pointer);
@@ -1525,15 +1823,13 @@ acpi_BatteryIsPresent(device_t dev)
  * Match a HID string against a handle
  */
 BOOLEAN
-acpi_MatchHid(ACPI_HANDLE h, char *hid) 
+acpi_MatchHid(ACPI_HANDLE h, const char *hid)
 {
     ACPI_DEVICE_INFO   *devinfo;
     ACPI_BUFFER                buf;
     ACPI_STATUS                error;
     int                        ret, i;
 
-    ACPI_ASSERTLOCK;
-
     ret = FALSE;
     if (hid == NULL || h == NULL)
        return (ret);
@@ -1570,8 +1866,6 @@ 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);
@@ -1579,6 +1873,7 @@ acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
            *result = r;
            return (AE_OK);
        }
+       /* XXX Return error here? */
        if (status != AE_NOT_FOUND)
            return (AE_OK);
        if (ACPI_FAILURE(AcpiGetParent(parent, &r)))
@@ -1595,10 +1890,10 @@ acpi_TimerDelta(uint32_t end, uint32_t start)
 
     if (end >= start)
        delta = end - start;
-    else if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
-       delta = ((0x00FFFFFF - start) + end + 1) & 0x00FFFFFF;
-    else
+    else if (AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER)
        delta = ((0xFFFFFFFF - start) + end + 1);
+    else
+       delta = ((0x00FFFFFF - start) + end + 1) & 0x00FFFFFF;
     return (delta);
 }
 
@@ -1610,7 +1905,8 @@ acpi_AllocBuffer(int size)
 {
     ACPI_BUFFER        *buf;
 
-    buf = kmalloc(size + sizeof(*buf), M_ACPIDEV, M_INTWAIT);
+    if ((buf = kmalloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
+       return (NULL);
     buf->Length = size;
     buf->Pointer = (void *)(buf + 1);
     return (buf);
@@ -1622,8 +1918,6 @@ acpi_SetInteger(ACPI_HANDLE handle, char *path, UINT32 number)
     ACPI_OBJECT arg1;
     ACPI_OBJECT_LIST args;
 
-    ACPI_ASSERTLOCK;
-
     arg1.Type = ACPI_TYPE_INTEGER;
     arg1.Integer.Value = number;
     args.Count = 1;
@@ -1642,8 +1936,6 @@ acpi_GetInteger(ACPI_HANDLE handle, char *path, UINT32 *number)
     ACPI_BUFFER        buf;
     ACPI_OBJECT        param;
 
-    ACPI_ASSERTLOCK;
-
     if (handle == NULL)
        handle = ACPI_ROOT_OBJECT;
 
@@ -1718,7 +2010,7 @@ acpi_ForeachPackageObject(ACPI_OBJECT *pkg,
 {
     ACPI_OBJECT        *comp;
     int                i;
-    
+
     if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE)
        return (AE_BAD_PARAMETER);
 
@@ -1743,7 +2035,7 @@ acpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp)
     rp = (ACPI_RESOURCE *)buf->Pointer;
     i = index;
     while (i-- > 0) {
-       /* Range check */       
+       /* Range check */
        if (rp > (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
            return (AE_BAD_PARAMETER);
 
@@ -1773,7 +2065,7 @@ 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;
@@ -1785,7 +2077,7 @@ acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
     }
     if (res == NULL)
        return (AE_OK);
-    
+
     /*
      * Scan the current buffer looking for the terminator.
      * This will either find the terminator or hit the end
@@ -1824,64 +2116,247 @@ acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
        buf->Pointer = newp;
        buf->Length += buf->Length;
     }
-    
-    /* Insert the new resource. */
-    bcopy(res, rp, res->Length + ACPI_RS_SIZE_NO_DATA);
-    
-    /* And add the terminator. */
-    rp = ACPI_NEXT_RESOURCE(rp);
-    rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
-    rp->Length = 0;
 
-    return (AE_OK);
+    /* Insert the new resource. */
+    bcopy(res, rp, res->Length + ACPI_RS_SIZE_NO_DATA);
+
+    /* And add the terminator. */
+    rp = ACPI_NEXT_RESOURCE(rp);
+    rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
+    rp->Length = 0;
+
+    return (AE_OK);
+}
+
+/*
+ * Set interrupt model.
+ */
+ACPI_STATUS
+acpi_SetIntrModel(int model)
+{
+
+    return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model));
+}
+
+/*
+ * DEPRECATED.  This interface has serious deficiencies and will be
+ * removed.
+ *
+ * Immediately enter the sleep state.  In the old model, acpiconf(8) ran
+ * rc.suspend and rc.resume so we don't have to notify devd(8) to do this.
+ */
+ACPI_STATUS
+acpi_SetSleepState(struct acpi_softc *sc, int state)
+{
+    static int once;
+
+    if (!once) {
+       kprintf(
+"warning: acpi_SetSleepState() deprecated, need to update your software\n");
+       once = 1;
+    }
+    return (acpi_EnterSleepState(sc, state));
+}
+
+static void
+acpi_sleep_force(void *arg)
+{
+    struct acpi_softc *sc;
+
+    kprintf("acpi: suspend request timed out, forcing sleep now\n");
+    sc = arg;
+    if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate)))
+       kprintf("acpi: force sleep state S%d failed\n", sc->acpi_next_sstate);
+}
+
+/*
+ * Request that the system enter the given suspend state.  All /dev/apm
+ * devices and devd(8) will be notified.  Userland then has a chance to
+ * save state and acknowledge the request.  The system sleeps once all
+ * acks are in.
+ */
+int
+acpi_ReqSleepState(struct acpi_softc *sc, int state)
+{
+    struct apm_clone_data *clone;
+
+    if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5)
+       return (EINVAL);
+
+    /* S5 (soft-off) should be entered directly with no waiting. */
+    if (state == ACPI_STATE_S5) {
+       if (ACPI_SUCCESS(acpi_EnterSleepState(sc, state)))
+           return (0);
+       else
+           return (ENXIO);
+    }
+
+#if !defined(__i386__)
+    /* This platform does not support acpi suspend/resume. */
+    return (EOPNOTSUPP);
+#endif
+
+    /* If a suspend request is already in progress, just return. */
+    ACPI_LOCK(acpi);
+    if (sc->acpi_next_sstate != 0) {
+       ACPI_UNLOCK(acpi);
+       return (0);
+    }
+
+    /* Record the pending state and notify all apm devices. */
+    sc->acpi_next_sstate = state;
+#if 0
+    STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) {
+       clone->notify_status = APM_EV_NONE;
+       if ((clone->flags & ACPI_EVF_DEVD) == 0) {
+           selwakeuppri(&clone->sel_read, PZERO);
+           KNOTE_UNLOCKED(&clone->sel_read.si_note, 0);
+       }
+    }
+#endif
+
+    /* If devd(8) is not running, immediately enter the sleep state. */
+    if (devctl_process_running() == FALSE) {
+       ACPI_UNLOCK(acpi);
+       if (ACPI_SUCCESS(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) {
+           return (0);
+       } else {
+           return (ENXIO);
+       }
+    }
+
+    /* Now notify devd(8) also. */
+    acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state);
+
+    /*
+     * Set a timeout to fire if userland doesn't ack the suspend request
+     * in time.  This way we still eventually go to sleep if we were
+     * overheating or running low on battery, even if userland is hung.
+     * We cancel this timeout once all userland acks are in or the
+     * suspend request is aborted.
+     */
+    callout_reset(&sc->susp_force_to, 10 * hz, acpi_sleep_force, sc);
+    ACPI_UNLOCK(acpi);
+    return (0);
 }
 
 /*
- * Set interrupt model.
+ * Acknowledge (or reject) a pending sleep state.  The caller has
+ * prepared for suspend and is now ready for it to proceed.  If the
+ * error argument is non-zero, it indicates suspend should be cancelled
+ * and gives an errno value describing why.  Once all votes are in,
+ * we suspend the system.
  */
-ACPI_STATUS
-acpi_SetIntrModel(int model)
+int
+acpi_AckSleepState(struct apm_clone_data *clone, int error)
 {
-    return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model));
-}
+    struct acpi_softc *sc;
+    int ret, sleeping;
 
-#define ACPI_MINIMUM_AWAKETIME 5
+#if !defined(__i386__)
+    /* This platform does not support acpi suspend/resume. */
+    return (EOPNOTSUPP);
+#endif
+
+    /* If no pending sleep state, return an error. */
+    ACPI_LOCK(acpi);
+    sc = clone->acpi_sc;
+    if (sc->acpi_next_sstate == 0) {
+       ACPI_UNLOCK(acpi);
+       return (ENXIO);
+    }
+
+    /* Caller wants to abort suspend process. */
+    if (error) {
+       sc->acpi_next_sstate = 0;
+       callout_stop(&sc->susp_force_to);
+       kprintf("acpi: listener on %s cancelled the pending suspend\n",
+           devtoname(clone->cdev));
+       ACPI_UNLOCK(acpi);
+       return (0);
+    }
+
+    /*
+     * Mark this device as acking the suspend request.  Then, walk through
+     * all devices, seeing if they agree yet.  We only count devices that
+     * are writable since read-only devices couldn't ack the request.
+     */
+    clone->notify_status = APM_EV_ACKED;
+    sleeping = TRUE;
+    STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) {
+       if ((clone->flags & ACPI_EVF_WRITE) != 0 &&
+           clone->notify_status != APM_EV_ACKED) {
+           sleeping = FALSE;
+           break;
+       }
+    }
+
+    /* If all devices have voted "yes", we will suspend now. */
+    if (sleeping)
+       callout_stop(&sc->susp_force_to);
+    ACPI_UNLOCK(acpi);
+    ret = 0;
+    if (sleeping) {
+       if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate)))
+               ret = ENODEV;
+    }
+
+    return (ret);
+}
 
 static void
 acpi_sleep_enable(void *arg)
 {
+
     ((struct acpi_softc *)arg)->acpi_sleep_disabled = 0;
 }
 
+enum acpi_sleep_state {
+    ACPI_SS_NONE,
+    ACPI_SS_GPE_SET,
+    ACPI_SS_DEV_SUSPEND,
+    ACPI_SS_SLP_PREP,
+    ACPI_SS_SLEPT,
+};
+
 /*
- * Set the system sleep state
+ * Enter the desired system sleep state.
  *
  * Currently we support S1-S5 but S4 is only S4BIOS
  */
-ACPI_STATUS
-acpi_SetSleepState(struct acpi_softc *sc, int state)
+static ACPI_STATUS
+acpi_EnterSleepState(struct acpi_softc *sc, int state)
 {
-    ACPI_STATUS        status = AE_OK;
+    ACPI_STATUS        status;
     UINT8      TypeA;
     UINT8      TypeB;
+    enum acpi_sleep_state slp_state;
 
     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);
+    /* Re-entry once we're suspending is not allowed. */
+    status = AE_OK;
+    ACPI_LOCK(acpi);
+    if (sc->acpi_sleep_disabled) {
+       ACPI_UNLOCK(acpi);
+       kprintf("acpi: suspend request ignored (not ready yet)\n");
+       return (AE_ERROR);
+    }
+    sc->acpi_sleep_disabled = 1;
+    ACPI_UNLOCK(acpi);
 
+    /*
+     * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
+     * drivers need this.
+     */
+    //get_mplock();
+    slp_state = ACPI_SS_NONE;
     switch (state) {
     case ACPI_STATE_S1:
     case ACPI_STATE_S2:
     case ACPI_STATE_S3:
     case ACPI_STATE_S4:
-       status = AcpiGetSleepTypeData((UINT8)state, &TypeA, &TypeB);
+       status = AcpiGetSleepTypeData(state, &TypeA, &TypeB);
        if (status == AE_NOT_FOUND) {
            device_printf(sc->acpi_dev,
                          "Sleep state S%d not supported by BIOS\n", state);
@@ -1893,23 +2368,28 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
        }
 
        sc->acpi_sstate = state;
-       sc->acpi_sleep_disabled = 1;
 
-       /* Disable all wake GPEs not appropriate for this state. */
-       acpi_wake_limit_walk(state);
+       /* Enable any GPEs as appropriate and requested by the user. */
+       acpi_wake_prep_walk(state);
+       slp_state = ACPI_SS_GPE_SET;
 
-       /* Inform all devices that we are going to sleep. */
+       /*
+        * Inform all devices that we are going to sleep.  If at least one
+        * device fails, DEVICE_SUSPEND() automatically resumes the tree.
+        *
+        * 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.
+        */
        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);
+           device_printf(sc->acpi_dev, "device_suspend failed\n");
+           break;
        }
+       slp_state = ACPI_SS_DEV_SUSPEND;
+
+       /* If testing device suspend only, back out of everything here. */
+       if (acpi_susp_bounce)
+           break;
 
        status = AcpiEnterSleepStatePrep(state);
        if (ACPI_FAILURE(status)) {
@@ -1917,31 +2397,27 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
                          AcpiFormatException(status));
            break;
        }
+       slp_state = ACPI_SS_SLP_PREP;
 
        if (sc->acpi_sleep_delay > 0)
            DELAY(sc->acpi_sleep_delay * 1000000);
 
        if (state != ACPI_STATE_S1) {
            acpi_sleep_machdep(sc, state);
-#if 0
-           /* AcpiEnterSleepState() may be incomplete, unlock if locked. */
-           AcpiOsReleaseLock(AcpiGbl_HardwareLock, 1);
-#endif
+
            /* Re-enable ACPI hardware on wakeup from sleep state 4. */
            if (state == ACPI_STATE_S4)
                AcpiEnable();
        } else {
-           status = AcpiEnterSleepState((UINT8)state);
+           ACPI_DISABLE_IRQS();
+           status = AcpiEnterSleepState(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);
+       slp_state = ACPI_SS_SLEPT;
        break;
     case ACPI_STATE_S5:
        /*
@@ -1956,11 +2432,31 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
        break;
     }
 
-    /* Disable a second sleep request for a short period */
-    if (sc->acpi_sleep_disabled)
-       callout_reset(&sc->acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME,
-                     acpi_sleep_enable, sc);
+    /*
+     * Back out state according to how far along we got in the suspend
+     * process.  This handles both the error and success cases.
+     */
+    sc->acpi_next_sstate = 0;
+    if (slp_state >= ACPI_SS_GPE_SET) {
+       acpi_wake_prep_walk(state);
+       sc->acpi_sstate = ACPI_STATE_S0;
+    }
+    if (slp_state >= ACPI_SS_SLP_PREP)
+       AcpiLeaveSleepState(state);
+    if (slp_state >= ACPI_SS_DEV_SUSPEND)
+       DEVICE_RESUME(root_bus);
+    if (slp_state >= ACPI_SS_SLEPT)
+       acpi_enable_fixed_events(sc);
+
+    /* Allow another sleep request after a while. */
+    /* XXX: needs timeout */
+    if (state != ACPI_STATE_S5)
+             acpi_sleep_enable(sc);
 
+    /* Run /etc/rc.resume after we are back. */
+    acpi_UserNotify("Resume", ACPI_ROOT_OBJECT, state);
+
+    //rel_mplock();
     return_ACPI_STATUS (status);
 }
 
@@ -1970,10 +2466,6 @@ acpi_wake_init(device_t dev, int type)
 {
     struct acpi_prw_data prw;
 
-    /* Check that the device can wake the system. */
-    if ((device_get_flags(dev) & ACPI_FLAG_WAKE_CAPABLE) == 0)
-       return (ENXIO);
-
     /* Evaluate _PRW to find the GPE. */
     if (acpi_parse_prw(acpi_get_handle(dev), &prw) != 0)
        return (ENXIO);
@@ -1992,153 +2484,126 @@ int
 acpi_wake_set_enable(device_t dev, int enable)
 {
     struct acpi_prw_data prw;
-    ACPI_HANDLE handle;
     ACPI_STATUS status;
     int flags;
 
-    /* Make sure the device supports waking the system. */
-    flags = device_get_flags(dev);
-    handle = acpi_get_handle(dev);
-    if ((flags & ACPI_FLAG_WAKE_CAPABLE) == 0 || handle == NULL)
-       return (ENXIO);
-
-    /* Evaluate _PRW to find the GPE. */
-    if (acpi_parse_prw(handle, &prw) != 0)
+    /* Make sure the device supports waking the system and get the GPE. */
+    if (acpi_parse_prw(acpi_get_handle(dev), &prw) != 0)
        return (ENXIO);
 
+    flags = acpi_get_flags(dev);
     if (enable) {
        status = AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
        if (ACPI_FAILURE(status)) {
            device_printf(dev, "enable wake failed\n");
            return (ENXIO);
        }
-       device_set_flags(dev, flags | ACPI_FLAG_WAKE_ENABLED);
+       acpi_set_flags(dev, flags | ACPI_FLAG_WAKE_ENABLED);
     } else {
        status = AcpiDisableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
        if (ACPI_FAILURE(status)) {
            device_printf(dev, "disable wake failed\n");
            return (ENXIO);
        }
-       device_set_flags(dev, flags & ~ACPI_FLAG_WAKE_ENABLED);
+       acpi_set_flags(dev, flags & ~ACPI_FLAG_WAKE_ENABLED);
     }
 
     return (0);
 }
 
-/* Configure a device's GPE appropriately for the new sleep state. */
-int
-acpi_wake_sleep_prep(device_t dev, int sstate)
+static int
+acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate)
 {
     struct acpi_prw_data prw;
-    ACPI_HANDLE handle;
-    int flags;
-
-    /* Check that this is an ACPI device and get its GPE. */
-    flags = device_get_flags(dev);
-    handle = acpi_get_handle(dev);
-    if ((flags & ACPI_FLAG_WAKE_CAPABLE) == 0 || handle == NULL)
-       return (ENXIO);
+    device_t dev;
 
-    /* Evaluate _PRW to find the GPE. */
+    /* Check that this is a wake-capable device and get its GPE. */
     if (acpi_parse_prw(handle, &prw) != 0)
        return (ENXIO);
+    dev = acpi_get_device(handle);
 
     /*
-     * TBD: All Power Resources referenced by elements 2 through N
-     *      of the _PRW object are put into the ON state.
-     */
-
-    /*
-     * If the user requested that this device wake the system and the next
-     * sleep state is valid for this GPE, enable it and the device's wake
-     * capability.  The sleep state must be less than (i.e., higher power)
-     * or equal to the value specified by _PRW.  Return early, leaving
-     * the appropriate power resources enabled.
+     * The destination sleep state must be less than (i.e., higher power)
+     * or equal to the value specified by _PRW.  If this GPE cannot be
+     * enabled for the next sleep state, then disable it.  If it can and
+     * the user requested it be enabled, turn on any required power resources
+     * and set _PSW.
      */
-    if ((flags & ACPI_FLAG_WAKE_ENABLED) != 0 &&
-       sstate <= prw.lowest_wake) {
+    if (sstate > prw.lowest_wake) {
+       AcpiDisableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
        if (bootverbose)
-           device_printf(dev, "wake_prep enabled gpe %#x for state %d\n",
-               prw.gpe_bit, sstate);
-       AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
+           device_printf(dev, "wake_prep disabled wake for %s (S%d)\n",
+               acpi_name(handle), sstate);
+    } else if (dev && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) {
+       acpi_pwr_wake_enable(handle, 1);
        acpi_SetInteger(handle, "_PSW", 1);
-       return (0);
+       if (bootverbose)
+           device_printf(dev, "wake_prep enabled for %s (S%d)\n",
+               acpi_name(handle), sstate);
     }
 
-    /*
-     * If the device wake was disabled or this sleep state is too low for
-     * this device, disable its wake capability and GPE.
-     */
-    AcpiDisableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
-    acpi_SetInteger(handle, "_PSW", 0);
-    if (bootverbose)
-       device_printf(dev, "wake_prep disabled gpe %#x for state %d\n",
-           prw.gpe_bit, sstate);
-
-    /*
-     * TBD: All Power Resources referenced by elements 2 through N
-     *      of the _PRW object are put into the OFF state.
-     */
-
     return (0);
 }
 
-/* Re-enable GPEs after wake. */
-int
-acpi_wake_run_prep(device_t dev)
+static int
+acpi_wake_run_prep(ACPI_HANDLE handle, int sstate)
 {
     struct acpi_prw_data prw;
-    ACPI_HANDLE handle;
-    int flags;
-
-    /* Check that this is an ACPI device and get its GPE. */
-    flags = device_get_flags(dev);
-    handle = acpi_get_handle(dev);
-    if ((flags & ACPI_FLAG_WAKE_CAPABLE) == 0 || handle == NULL)
-       return (ENXIO);
+    device_t dev;
 
-    /* Evaluate _PRW to find the GPE. */
+    /*
+     * Check that this is a wake-capable device and get its GPE.  Return
+     * now if the user didn't enable this device for wake.
+     */
     if (acpi_parse_prw(handle, &prw) != 0)
        return (ENXIO);
+    dev = acpi_get_device(handle);
+    if (dev == NULL || (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) == 0)
+       return (0);
 
     /*
-     * TBD: Be sure all Power Resources referenced by elements 2 through N
-     *      of the _PRW object are in the ON state.
+     * If this GPE couldn't be enabled for the previous sleep state, it was
+     * disabled before going to sleep so re-enable it.  If it was enabled,
+     * clear _PSW and turn off any power resources it used.
      */
-
-    /* Disable wake capability and if the user requested, enable the GPE. */
-    acpi_SetInteger(handle, "_PSW", 0);
-    if ((flags & ACPI_FLAG_WAKE_ENABLED) != 0)
+    if (sstate > prw.lowest_wake) {
        AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
+       if (bootverbose)
+           device_printf(dev, "run_prep re-enabled %s\n", acpi_name(handle));
+    } else {
+       acpi_SetInteger(handle, "_PSW", 0);
+       acpi_pwr_wake_enable(handle, 0);
+       if (bootverbose)
+           device_printf(dev, "run_prep cleaned up for %s\n",
+               acpi_name(handle));
+    }
+
     return (0);
 }
 
 static ACPI_STATUS
-acpi_wake_limit(ACPI_HANDLE h, UINT32 level, void *context, void **status)
+acpi_wake_prep(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
 {
-    struct acpi_prw_data prw;
-    int *sstate;
-
-    /* It's ok not to have _PRW if the device can't wake the system. */
-    if (acpi_parse_prw(h, &prw) != 0)
-       return (AE_OK);
-
-    sstate = (int *)context;
-    if (*sstate > prw.lowest_wake)
-       AcpiDisableGpe(prw.gpe_handle, prw.gpe_bit, ACPI_NOT_ISR);
+    int sstate;
 
+    /* If suspending, run the sleep prep function, otherwise wake. */
+    sstate = *(int *)context;
+    if (AcpiGbl_SystemAwakeAndRunning)
+       acpi_wake_sleep_prep(handle, sstate);
+    else
+       acpi_wake_run_prep(handle, sstate);
     return (AE_OK);
 }
 
-/* Walk all system devices, disabling them if necessary for sstate. */
+/* Walk the tree rooted at acpi0 to prep devices for suspend/resume. */
 static int
-acpi_wake_limit_walk(int sstate)
+acpi_wake_prep_walk(int sstate)
 {
     ACPI_HANDLE sb_handle;
 
     if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle)))
-       AcpiWalkNamespace(ACPI_TYPE_ANY, sb_handle, 100,
-           acpi_wake_limit, &sstate, NULL);
+       AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100,
+           acpi_wake_prep, &sstate, NULL);
     return (0);
 }
 
@@ -2149,30 +2614,34 @@ acpi_wake_sysctl_walk(device_t dev)
     int error, i, numdevs;
     device_t *devlist;
     device_t child;
+    ACPI_STATUS status;
 
     error = device_get_children(dev, &devlist, &numdevs);
-    if (error != 0 || numdevs == 0)
+    if (error != 0 || numdevs == 0) {
+       if (numdevs == 0)
+           kfree(devlist, M_TEMP);
        return (error);
+    }
+#ifdef notye
     for (i = 0; i < numdevs; i++) {
        child = devlist[i];
+       acpi_wake_sysctl_walk(child);
        if (!device_is_attached(child))
            continue;
-       if (device_get_flags(child) & ACPI_FLAG_WAKE_CAPABLE) {
-#ifdef dfly_notyet
+       status = AcpiEvaluateObject(acpi_get_handle(child), "_PRW", NULL, NULL);
+       if (ACPI_SUCCESS(status)) {
            SYSCTL_ADD_PROC(device_get_sysctl_ctx(child),
                SYSCTL_CHILDREN(device_get_sysctl_tree(child)), OID_AUTO,
                "wake", CTLTYPE_INT | CTLFLAG_RW, child, 0,
                acpi_wake_set_sysctl, "I", "Device set to wake the system");
-#endif /* dfly_notyet */
        }
-       acpi_wake_sysctl_walk(child);
     }
+#endif
     kfree(devlist, M_TEMP);
 
     return (0);
 }
 
-#ifdef dfly_notyet
 /* Enable or disable wake from userland. */
 static int
 acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS)
@@ -2181,7 +2650,7 @@ acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS)
     device_t dev;
 
     dev = (device_t)arg1;
-    enable = (device_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) ? 1 : 0;
+    enable = (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) ? 1 : 0;
 
     error = sysctl_handle_int(oidp, &enable, 0, req);
     if (error != 0 || req->newptr == NULL)
@@ -2191,16 +2660,15 @@ acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS)
 
     return (acpi_wake_set_enable(dev, enable));
 }
-#endif /* dfly_notyet */
 
 /* Parse a device's _PRW into a structure. */
-static int
+int
 acpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw)
 {
     ACPI_STATUS                        status;
     ACPI_BUFFER                        prw_buffer;
     ACPI_OBJECT                        *res, *res2;
-    int error;
+    int                                error, i, power_count;
 
     if (h == NULL || prw == NULL)
        return (EINVAL);
@@ -2273,8 +2741,15 @@ acpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw)
        goto out;
     }
 
-    /* XXX No power resource handling yet. */
-    prw->power_res = NULL;
+    /* Elements 2 to N of the _PRW object are power resources. */
+    power_count = res->Package.Count - 2;
+    if (power_count > ACPI_PRW_MAX_POWERRES) {
+       kprintf("ACPI device %s has too many power resources\n", acpi_name(h));
+       power_count = 0;
+    }
+    prw->power_res_count = power_count;
+    for (i = 0; i < power_count; i++)
+       prw->power_res[i] = res->Package.Elements[i];
 
 out:
     if (prw_buffer.Pointer != NULL)
@@ -2283,50 +2758,6 @@ out:
 }
 
 /*
- * 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
  */
 
@@ -2335,26 +2766,30 @@ acpi_Disable(struct acpi_softc *sc)
 static void
 acpi_system_eventhandler_sleep(void *arg, int state)
 {
-    ACPI_LOCK_DECL;
+    int ret;
+
     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;
+    /* Check if button action is disabled. */
+    if (state == ACPI_S_STATES_MAX + 1)
+       return;
+
+    /* Request that the system prepare to enter the given suspend state. */
+    ret = acpi_ReqSleepState((struct acpi_softc *)arg, state);
+    if (ret != 0)
+       kprintf("acpi: request to enter state S%d failed (err %d)\n",
+           state, ret);
+
     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_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
 
-    ACPI_LOCK;
-    ACPI_UNLOCK;
+    /* Currently, nothing to do for wakeup. */
 
     return_VOID;
 }
@@ -2411,27 +2846,21 @@ acpi_event_sleep_button_wake(void *context)
 }
 
 /*
- * XXX This is kinda ugly, and should not be here.
+ * XXX This static buffer is suboptimal.  There is no locking so only
+ * use this for single-threaded callers.
  */
-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];
+    ACPI_BUFFER buf;
+    static char data[256];
 
-    if (ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf.buffer)))
-       return (buf.buffer.Pointer);
+    buf.Length = sizeof(data);
+    buf.Pointer = data;
 
-    return ("(unknown path)");
+    if (handle && ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf)))
+       return (data);
+    return ("(unknown)");
 }
 
 /*
@@ -2447,19 +2876,18 @@ acpi_avoid(ACPI_HANDLE handle)
     np = acpi_name(handle);
     if (*np == '\\')
        np++;
-    if ((env = kgetenv("debug.acpi.avoid.paths")) == NULL &&
-       (env = kgetenv("debug.acpi.avoid")) == NULL)
+    if ((env = kgetenv("debug.acpi.avoid")) == NULL)
        return (0);
 
     /* Scan the avoid list checking for a match */
     cp = env;
     for (;;) {
-       while ((*cp != 0) && isspace(*cp))
+       while (*cp != 0 && isspace(*cp))
            cp++;
        if (*cp == 0)
            break;
        len = 0;
-       while ((cp[len] != 0) && !isspace(cp[len]))
+       while (cp[len] != 0 && !isspace(cp[len]))
            len++;
        if (!strncmp(cp, np, len)) {
            kfreeenv(env);
@@ -2473,9 +2901,7 @@ acpi_avoid(ACPI_HANDLE handle)
 }
 
 /*
- * Debugging/bug-avoidance.  Disable ACPI subsystem components.   Note that
- * some components may be disabled by default and can only be enabled
- * via acpi_enabled() (debug.acpi.enabled).
+ * Debugging/bug-avoidance.  Disable ACPI subsystem components.
  */
 int
 acpi_disabled(char *subsys)
@@ -2519,31 +2945,31 @@ acpi_disabled(char *subsys)
 int
 acpi_enabled(char *subsys)
 {
-    char       *cp, *env;
-    int                len;
+    char        *cp, *env;
+    int         len;
 
     if ((env = kgetenv("debug.acpi.enabled")) == NULL)
-       return (0);
+        return (0);
     if (strcmp(env, "all") == 0) {
-       kfreeenv(env);
-       return (1);
+        kfreeenv(env);
+        return (1);
     }
 
     /* Scan the enable 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) == 0) {
-           kfreeenv(env);
-           return (1);
-       }
-       cp += len;
+        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) == 0) {
+            kfreeenv(env);
+            return (1);
+        }
+        cp += len;
     }
     kfreeenv(env);
 
@@ -2568,42 +2994,43 @@ struct acpi_ioctl_hook
 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;
 
-    hp = kmalloc(sizeof(*hp), M_ACPIDEV, M_INTWAIT);
+    if ((hp = kmalloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL)
+       return (ENOMEM);
     hp->cmd = cmd;
     hp->fn = fn;
     hp->arg = arg;
+
+    ACPI_LOCK(acpi);
     if (acpi_ioctl_hooks_initted == 0) {
        TAILQ_INIT(&acpi_ioctl_hooks);
        acpi_ioctl_hooks_initted = 1;
     }
     TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
+    ACPI_UNLOCK(acpi);
+
     return (0);
 }
 
-/*
- * Deregister an ioctl handler.
- */
-void   
+void
 acpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn)
 {
     struct acpi_ioctl_hook     *hp;
 
+    ACPI_LOCK(acpi);
     TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
-       if ((hp->cmd == cmd) && (hp->fn == fn))
+       if (hp->cmd == cmd && hp->fn == fn)
            break;
 
     if (hp != NULL) {
        TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
        kfree(hp, M_ACPIDEV);
     }
+    ACPI_UNLOCK(acpi);
 }
 
 static int
@@ -2623,88 +3050,77 @@ acpiioctl(struct dev_ioctl_args *ap)
 {
     struct acpi_softc          *sc;
     struct acpi_ioctl_hook     *hp;
-    int                                error, xerror, state;
-    ACPI_LOCK_DECL;
-
-    ACPI_LOCK;
+    int                                error, state;
 
-    error = state = 0;
+    error = 0;
+    hp = NULL;
     sc = ap->a_head.a_dev->si_drv1;
 
     /*
      * Scan the list of registered ioctls, looking for handlers.
      */
-    if (acpi_ioctl_hooks_initted) {
+    ACPI_LOCK(acpi);
+    if (acpi_ioctl_hooks_initted)
        TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
-           if (hp->cmd == ap->a_cmd) {
-               xerror = hp->fn(ap->a_cmd, ap->a_data, hp->arg);
-               if (xerror != 0)
-                   error = xerror;
-               goto out;
-           }
+           if (hp->cmd == ap->a_cmd)
+               break;
        }
-    }
+    ACPI_UNLOCK(acpi);
+    if (hp)
+       return (hp->fn(ap->a_cmd, ap->a_data, hp->arg));
 
     /*
      * Core ioctls are not permitted for non-writable user.
      * Currently, other ioctls just fetch information.
      * Not changing system behavior.
      */
-    if((ap->a_fflag & FWRITE) == 0) {
-       error = EPERM;
-       goto out;
-    }
+    if ((ap->a_fflag & FWRITE) == 0)
+       return (EPERM);
 
     /* Core system ioctls. */
     switch (ap->a_cmd) {
-    case ACPIIO_ENABLE:
-       if (ACPI_FAILURE(acpi_Enable(sc)))
+    case ACPIIO_REQSLPSTATE:
+       state = *(int *)ap->a_data;
+       if (state != ACPI_STATE_S5)
+           error = acpi_ReqSleepState(sc, state);
+       else {
+           kprintf("power off via acpi ioctl not supported\n");
            error = ENXIO;
+       }
        break;
-    case ACPIIO_DISABLE:
-       if (ACPI_FAILURE(acpi_Disable(sc)))
-           error = ENXIO;
+    case ACPIIO_ACKSLPSTATE:
+       error = *(int *)ap->a_data;
+       error = acpi_AckSleepState(sc->acpi_clone, error);
        break;
-    case ACPIIO_SETSLPSTATE:
-       if (!sc->acpi_enabled) {
-           error = ENXIO;
-           break;
-       }
+    case ACPIIO_SETSLPSTATE:   /* DEPRECATED */
+       error = EINVAL;
        state = *(int *)ap->a_data;
-       if (state >= ACPI_STATE_S0  && state <= ACPI_S_STATES_MAX) {
-           if (ACPI_FAILURE(acpi_SetSleepState(sc, state)))
-               error = EINVAL;
-       } else {
-           error = EINVAL;
-       }
+       if (state >= ACPI_STATE_S0 && state <= ACPI_S_STATES_MAX)
+           if (ACPI_SUCCESS(acpi_SetSleepState(sc, state)))
+               error = 0;
        break;
     default:
-       if (error == 0)
-           error = EINVAL;
+       error = ENXIO;
        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;
+    struct sbuf sb;
     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))) {
-           ksprintf(sleep_state, "S%d ", state);
-           strcat(buf, sleep_state);
-       }
-    }
-    error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+    sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
+    for (state = ACPI_STATE_S1; state < ACPI_S_STATES_MAX + 1; state++)
+       if (ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB)))
+           sbuf_printf(&sb, "S%d ", state);
+    sbuf_trim(&sb);
+    sbuf_finish(&sb);
+    error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
+    sbuf_delete(&sb);
     return (error);
 }
 
@@ -2716,27 +3132,21 @@ acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
     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]));
-    }
+    if (old_state > ACPI_S_STATES_MAX + 1)
+       strlcpy(sleep_state, "unknown", sizeof(sleep_state));
+    else
+       strlcpy(sleep_state, sleep_state_names[old_state], sizeof(sleep_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)
+       for (; new_state <= ACPI_S_STATES_MAX + 1; new_state++)
+           if (strcmp(sleep_state, sleep_state_names[new_state]) == 0)
                break;
-       }
        if (new_state <= ACPI_S_STATES_MAX + 1) {
            if (new_state != old_state)
                *(u_int *)oidp->oid_arg1 = new_state;
-       } else {
+       } else
            error = EINVAL;
-       }
     }
 
     return (error);
@@ -2808,6 +3218,8 @@ static struct debugtag    dbg_layer[] = {
 };
 
 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},
@@ -2889,14 +3301,10 @@ acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
     }
 }
 
-/*
- * Warning: also called in early boot, before any allocators
- * are working.
- */
 static void
 acpi_set_debugging(void *junk)
 {
-    char *layer, *level;
+    char       *layer, *level;
 
     if (cold) {
        AcpiDbgLayer = 0;
@@ -2923,8 +3331,9 @@ acpi_set_debugging(void *junk)
     }
     kprintf("\n");
 }
-SYSINIT(acpi_debugging, SI_BOOT1_TUNABLES, SI_ORDER_ANY,
-       acpi_set_debugging, NULL);
+
+SYSINIT(acpi_debugging, SI_BOOT1_TUNABLES, SI_ORDER_ANY, acpi_set_debugging,
+       NULL);
 
 static int
 acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
@@ -2944,6 +3353,7 @@ acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
     }
 
     /* Get old values if this is a get request. */
+    ACPI_SERIAL_BEGIN(acpi);
     if (*dbg == 0) {
        sbuf_cpy(&sb, "NONE");
     } else if (req->newptr == NULL) {
@@ -2962,17 +3372,19 @@ acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
     /* If the user is setting a string, parse it. */
     if (error == 0 && req->newptr != NULL) {
        *dbg = 0;
-       ksetenv(oidp->oid_arg1, req->newptr);
+       setenv((char *)oidp->oid_arg1, (char *)req->newptr);
        acpi_set_debugging(NULL);
     }
+    ACPI_SERIAL_END(acpi);
 
     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
+#endif /* ACPI_DEBUG */
 
 static int
 acpi_pm_func(u_long cmd, void *arg, ...)
@@ -2993,7 +3405,7 @@ acpi_pm_func(u_long cmd, void *arg, ...)
 
                va_start(ap, arg);
                state = va_arg(ap, int);
-               va_end(ap);     
+               va_end(ap);
 
                switch (state) {
                case POWER_SLEEP_STATE_STANDBY:
@@ -3010,7 +3422,8 @@ acpi_pm_func(u_long cmd, void *arg, ...)
                        goto out;
                }
 
-               acpi_SetSleepState(sc, acpi_state);
+               if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state)))
+                       error = ENXIO;
                break;
        default:
                error = EINVAL;
index 7327309..6fc7b7b 100644 (file)
  * 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.27 2004/06/13 22:52:30 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_acad.c,v 1.8 2007/10/23 03:04:48 y0netan1 Exp $
+ * $FreeBSD: src/sys/dev/acpica/acpi_acad.c,v 1.39 2009/06/05 18:44:36 jkim Exp
  */
 
+#include <sys/cdefs.h>
+
 #include "opt_acpi.h"
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
+
 #include <sys/rman.h>
+#include <sys/ioccom.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/conf.h>
 #include <sys/power.h>
 
 #include "acpi.h"
+
 #include <dev/acpica5/acpivar.h>
 #include <dev/acpica5/acpiio.h>
+#include <bus/isa/isavar.h>
+#include <bus/isa/pnpvar.h>
  
 /* Hooks for the ACPI CA debugging infrastructure */
 #define _COMPONENT     ACPI_AC_ADAPTER
@@ -48,13 +53,10 @@ 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 *);
@@ -64,6 +66,7 @@ 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 void    acpi_acad_ac_only(void *arg);
 
 static device_method_t acpi_acad_methods[] = {
     /* Device interface */
@@ -83,6 +86,10 @@ static devclass_t acpi_acad_devclass;
 DRIVER_MODULE(acpi_acad, acpi, acpi_acad_driver, acpi_acad_devclass, 0, 0);
 MODULE_DEPEND(acpi_acad, acpi, 1, 1, 1);
 
+ACPI_SERIAL_DECL(acad, "ACPI AC adapter");
+
+SYSINIT(acad, SI_SUB_KTHREAD_IDLE, SI_ORDER_FIRST, acpi_acad_ac_only, NULL);
+
 static void
 acpi_acad_get_status(void *context)
 {
@@ -94,22 +101,20 @@ acpi_acad_get_status(void *context)
     dev = context;
     sc = device_get_softc(dev);
     h = acpi_get_handle(dev);
-    if (ACPI_FAILURE(acpi_GetInteger(h, "_PSR", &newstatus))) {
-       sc->status = -1;
-       return;
-    }
+    newstatus = -1;
+    acpi_GetInteger(h, "_PSR", &newstatus);
 
-    if (sc->status != newstatus) {
+    /* If status is valid and has changed, notify the system. */
+    ACPI_SERIAL_BEGIN(acad);
+    if (newstatus != -1 && 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);
+       power_profile_set_state(newstatus ? 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);
+           "%s Line\n", newstatus ? "On" : "Off");
+       acpi_UserNotify("ACAD", h, newstatus);
     }
+    ACPI_SERIAL_END(acad);
 }
 
 static void
@@ -119,8 +124,8 @@ acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
 
     dev = (device_t)context;
     switch (notify) {
-    case ACPI_DEVICE_CHECK_PNP:
-    case ACPI_DEVICE_CHECK_EXISTENCE:
+    case ACPI_NOTIFY_BUS_CHECK:
+    case ACPI_NOTIFY_DEVICE_CHECK:
     case ACPI_POWERSOURCE_STAT_CHANGE:
        /* Temporarily.  It is better to notify policy manager */
        AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_acad_get_status, context);
@@ -134,12 +139,14 @@ acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
 static int
 acpi_acad_probe(device_t dev)
 {
-    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("acad") &&
-       acpi_MatchHid(acpi_get_handle(dev), "ACPI0003")) {
-       device_set_desc(dev, "AC Adapter");
-       return (0);
-    }
-    return (ENXIO);
+    static char *acad_ids[] = { "ACPI0003", NULL };
+
+    if (acpi_disabled("acad") ||
+       ACPI_ID_PROBE(device_get_parent(dev), dev, acad_ids) == NULL)
+       return (ENXIO);
+
+    device_set_desc(dev, "AC Adapter");
+    return (0);
 }
 
 static int
@@ -151,8 +158,6 @@ acpi_acad_attach(device_t dev)
     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);
@@ -169,15 +174,12 @@ acpi_acad_attach(device_t dev)
 
     /* 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.
+     * Install both system and device notify handlers since the Casio
+     * FIVA needs them.
      */
-    AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
-                            acpi_acad_notify_handler, dev);
-    AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY,
+    AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
                             acpi_acad_notify_handler, dev);
     AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_acad_init_acline, dev);
 
@@ -192,8 +194,6 @@ acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
 
     dev = (device_t)arg;
     sc = device_get_softc(dev);
-    if (sc == NULL)
-       return (ENXIO);
 
     /*
      * No security check required: information retrieval only.  If
@@ -229,31 +229,38 @@ acpi_acad_init_acline(void *arg)
 {
     struct acpi_acad_softc *sc;
     device_t   dev;
-    int                retry, status;
+    int                retry;
 
     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)
+       if (sc->status != -1)
            break;
-       AcpiOsSleep(10);
+       AcpiOsSleep(10000);
     }
 
-    sc->initializing = 0;
     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
                "acline initialization done, tried %d times\n", retry + 1);
 }
 
 /*
+ * If no AC line devices detected after boot, create an "online" event
+ * so that userland code can adjust power settings accordingly.  The default
+ * power profile is "performance" so we don't need to repeat that here.
+ */
+static void
+acpi_acad_ac_only(void __unused *arg)
+{
+
+    if (devclass_get_count(acpi_acad_devclass) == 0)
+       acpi_UserNotify("ACAD", ACPI_ROOT_OBJECT, 1);
+}
+
+/*
  * Public interfaces.
  */
 int
@@ -266,8 +273,6 @@ acpi_acad_get_acline(int *status)
     if (dev == NULL)
        return (ENXIO);
     sc = device_get_softc(dev);
-    if (sc == NULL)
-       return (ENXIO);
 
     acpi_acad_get_status(dev);
     *status = sc->status;
index 1778dc0..2878421 100644 (file)
@@ -22,8 +22,7 @@
  * 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/acpi_support/acpi_asus.c,v 1.24.2.4.2.1 2008/10/02 02:57:24 kensmith Exp $
+ * $FreeBSD: src/sys/dev/acpi_support/acpi_asus.c,v 1.42 2009/06/05 18:44:36 jkim Exp
  */
 
 #include <sys/cdefs.h>
 #include "opt_acpi.h"
 #include <sys/param.h>
 #include <sys/kernel.h>
-#include <sys/bus.h>
-#include <machine/cpufunc.h>
 #include <sys/module.h>
-#include <sys/sensors.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <sys/lock.h>
+#include <sys/bus.h>
 #include <sys/sbuf.h>
-#include <sys/thread2.h>
-#include <machine/clock.h>
 
 #include "acpi.h"
 #include "accommon.h"
 #include "acpivar.h"
-#include "acpi_if.h"
+
+#if defined(__FreeBSD__)
+#include <dev/led/led.h>
+#endif
 
 /* Methods */
 #define ACPI_ASUS_METHOD_BRN   1
 #define ACPI_ASUS_METHOD_DISP  2
 #define ACPI_ASUS_METHOD_LCD   3
+#define ACPI_ASUS_METHOD_CAMERA        4
+#define ACPI_ASUS_METHOD_CARDRD        5
+#define ACPI_ASUS_METHOD_WLAN  6
 
 #define _COMPONENT     ACPI_OEM
 ACPI_MODULE_NAME("ASUS")
 
 struct acpi_asus_model {
        char    *name;
-
        char    *bled_set;
+       char    *dled_set;
+       char    *gled_set;
        char    *mled_set;
        char    *tled_set;
        char    *wled_set;
@@ -86,6 +85,20 @@ struct acpi_asus_model {
 
        char    *disp_get;
        char    *disp_set;
+
+       char    *cam_get;
+       char    *cam_set;
+
+       char    *crd_get;
+       char    *crd_set;
+
+       char    *wlan_get;
+       char    *wlan_set;
+
+       void    (*n_func)(ACPI_HANDLE, UINT32, void *);
+
+       char    *lcdd;
+       void    (*lcdd_n_func)(ACPI_HANDLE, UINT32, void *);
 };
 
 struct acpi_asus_led {
@@ -95,6 +108,8 @@ struct acpi_asus_led {
        int             state;
        enum {
                ACPI_ASUS_LED_BLED,
+               ACPI_ASUS_LED_DLED,
+               ACPI_ASUS_LED_GLED,
                ACPI_ASUS_LED_MLED,
                ACPI_ASUS_LED_TLED,
                ACPI_ASUS_LED_WLED,
@@ -104,21 +119,31 @@ struct acpi_asus_led {
 struct acpi_asus_softc {
        device_t                dev;
        ACPI_HANDLE             handle;
+       ACPI_HANDLE             lcdd_handle;
 
        struct acpi_asus_model  *model;
        struct sysctl_ctx_list  sysctl_ctx;
        struct sysctl_oid       *sysctl_tree;
-
+#if defined(__FreeBSD__)
        struct acpi_asus_led    s_bled;
+       struct acpi_asus_led    s_dled;
+       struct acpi_asus_led    s_gled;
        struct acpi_asus_led    s_mled;
        struct acpi_asus_led    s_tled;
        struct acpi_asus_led    s_wled;
+#endif
 
        int                     s_brn;
        int                     s_disp;
        int                     s_lcd;
+       int                     s_cam;
+       int                     s_crd;
+       int                     s_wlan;
 };
 
+static void    acpi_asus_lcdd_notify(ACPI_HANDLE h, UINT32 notify,
+    void *context);
+
 /*
  * We can identify Asus laptops from the string they return
  * as a result of calling the ATK0100 'INIT' method.
@@ -155,16 +180,39 @@ static struct acpi_asus_model acpi_asus_models[] = {
                .disp_set       = "SDSP"
        },
        {
+               .name           = "A3E",
+               .mled_set       = "MLED",
+               .wled_set       = "WLED",
+               .lcd_get        = "\\_SB.PCI0.SBRG.EC0.RPIN(0x67)",
+               .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .brn_get        = "GPLV",
+               .brn_set        = "SPLV",
+               .disp_get       = "\\_SB.PCI0.P0P2.VGA.GETD",
+               .disp_set       = "SDSP"
+       },
+       {
+               .name           = "A3F",
+               .mled_set       = "MLED",
+               .wled_set       = "WLED",
+               .bled_set       = "BLED",
+               .lcd_get        = "\\_SB.PCI0.SBRG.EC0.RPIN(0x11)",
+               .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .brn_get        = "GPLV",
+               .brn_set        = "SPLV",
+               .disp_get       = "\\SSTE",
+               .disp_set       = "SDSP"
+       },
+       {
                .name           = "A3N",
                .mled_set       = "MLED",
                .bled_set       = "BLED",
                .wled_set       = "WLED",
-               .lcd_get        = NULL,
+               .lcd_get        = "\\BKLT",
                .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .brn_get        = "GPLV",
                .brn_set        = "SPLV",
-               .brn_get        = "SDSP",
-               .disp_set       = "SDSP",
-               .disp_get       = "\\_SB.PCI0.P0P3.VGA.GETD"
+               .disp_get       = "\\_SB.PCI0.P0P3.VGA.GETD",
+               .disp_set       = "SDSP"
        },
        {
                .name           = "A4D",
@@ -191,6 +239,20 @@ static struct acpi_asus_model acpi_asus_models[] = {
                .disp_set       = "SDSP"
        },
        {
+               .name           = "A8SR",
+               .bled_set       = "BLED",
+               .mled_set       = "MLED",
+               .wled_set       = "WLED",
+               .lcd_get        = NULL,
+               .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .brn_get        = "GPLV",
+               .brn_set        = "SPLV",
+               .disp_get       = "\\_SB.PCI0.P0P1.VGA.GETD",
+               .disp_set       = "SDSP",
+               .lcdd           = "\\_SB.PCI0.P0P1.VGA.LCDD",
+               .lcdd_n_func    = acpi_asus_lcdd_notify
+       },
+       {
                .name           = "D1x",
                .mled_set       = "MLED",
                .lcd_get        = "\\GP11",
@@ -201,6 +263,21 @@ static struct acpi_asus_model acpi_asus_models[] = {
                .disp_set       = "SDSP"
        },
        {
+               .name           = "G2K",
+               .bled_set       = "BLED",
+               .dled_set       = "DLED",
+               .gled_set       = "GLED",
+               .mled_set       = "MLED",
+               .tled_set       = "TLED",
+               .wled_set       = "WLED",
+               .brn_get        = "GPLV",
+               .brn_set        = "SPLV",
+               .lcd_get        = "\\_SB.PCI0.SBRG.EC0.RPIN",
+               .lcd_set        = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .disp_get       = "\\_SB.PCI0.PCE2.VGA.GETD",
+               .disp_set       = "SDSP",
+       },
+       {
                .name           = "L2D",
                .mled_set       = "MLED",
                .wled_set       = "WLED",
@@ -262,7 +339,7 @@ static struct acpi_asus_model acpi_asus_models[] = {
        },
        {
                .name           = "L8L"
-               /* Only has hotkeys, apparantly */
+               /* Only has hotkeys, apparently */
        },
        {
                .name           = "M1A",
@@ -363,6 +440,8 @@ static struct acpi_asus_model acpi_samsung_models[] = {
        { .name = NULL }
 };
 
+static void    acpi_asus_eeepc_notify(ACPI_HANDLE h, UINT32 notify, void *context);
+
 /*
  * EeePC have an Asus ASUS010 gadget interface,
  * but they can't be probed quite the same way as Asus laptops.
@@ -371,7 +450,14 @@ static struct acpi_asus_model acpi_eeepc_models[] = {
        {
                .name           = "EEE",
                .brn_get        = "\\_SB.ATKD.PBLG",
-               .brn_set        = "\\_SB.ATKD.PBLS"
+               .brn_set        = "\\_SB.ATKD.PBLS",
+               .cam_get        = "\\_SB.ATKD.CAMG",
+               .cam_set        = "\\_SB.ATKD.CAMS",
+               .crd_set        = "\\_SB.ATKD.CRDS",
+               .crd_get        = "\\_SB.ATKD.CRDG",
+               .wlan_get       = "\\_SB.ATKD.WLDG",
+               .wlan_set       = "\\_SB.ATKD.WLDS",
+               .n_func         = acpi_asus_eeepc_notify
        },
 
        { .name = NULL }
@@ -381,31 +467,59 @@ static struct {
        char    *name;
        char    *description;
        int     method;
+       int     flags;
 } acpi_asus_sysctls[] = {
        {
                .name           = "lcd_backlight",
                .method         = ACPI_ASUS_METHOD_LCD,
-               .description    = "state of the lcd backlight"
+               .description    = "state of the lcd backlight",
+               .flags          = CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY
        },
        {
                .name           = "lcd_brightness",
                .method         = ACPI_ASUS_METHOD_BRN,
-               .description    = "brightness of the lcd panel"
+               .description    = "brightness of the lcd panel",
+               .flags          = CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY
        },
        {
                .name           = "video_output",
                .method         = ACPI_ASUS_METHOD_DISP,
-               .description    = "display output state"
+               .description    = "display output state",
+               .flags          = CTLTYPE_INT | CTLFLAG_RW
+       },
+       {
+               .name           = "camera",
+               .method         = ACPI_ASUS_METHOD_CAMERA,
+               .description    = "internal camera state",  
+               .flags          = CTLTYPE_INT | CTLFLAG_RW
+       },
+       {
+               .name           = "cardreader",
+               .method         = ACPI_ASUS_METHOD_CARDRD,
+               .description    = "internal card reader state",
+               .flags          = CTLTYPE_INT | CTLFLAG_RW
+       },
+       {
+               .name           = "wlan",
+               .method         = ACPI_ASUS_METHOD_WLAN,
+               .description    = "wireless lan state",
+               .flags          = CTLTYPE_INT | CTLFLAG_RW
        },
 
        { .name = NULL }
 };
 
+ACPI_SERIAL_DECL(asus, "ACPI ASUS extras");
+
+/* Function prototypes */
 static int     acpi_asus_probe(device_t dev);
 static int     acpi_asus_attach(device_t dev);
 static int     acpi_asus_detach(device_t dev);
 
-static struct lock asuslock;
+#if defined(__FreeBSD__)
+static void    acpi_asus_led(struct acpi_asus_led *led, int state);
+static void    acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused);
+#endif
 
 static int     acpi_asus_sysctl(SYSCTL_HANDLER_ARGS);
 static int     acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method);
@@ -415,27 +529,24 @@ static int        acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int val)
 static void    acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context);
 
 static device_method_t acpi_asus_methods[] = {
-       /* Device interface */
-       DEVMETHOD(device_probe, acpi_asus_probe),
+       DEVMETHOD(device_probe,  acpi_asus_probe),
        DEVMETHOD(device_attach, acpi_asus_attach),
        DEVMETHOD(device_detach, acpi_asus_detach),
-       {0, 0}
+
+       { 0, 0 }
 };
 
-static driver_t        acpi_asus_driver = {
+static driver_t acpi_asus_driver = {
        "acpi_asus",
        acpi_asus_methods,
-       sizeof(struct acpi_asus_softc),
+       sizeof(struct acpi_asus_softc)
 };
 
 static devclass_t acpi_asus_devclass;
 
-DRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver,
-    acpi_asus_devclass, 0, 0);
+DRIVER_MODULE(acpi_asus, acpi, acpi_asus_driver, acpi_asus_devclass, 0, 0);
 MODULE_DEPEND(acpi_asus, acpi, 1, 1, 1);
 
-static char            *asus_ids[] = { "ATK0100", "ASUS010", NULL };
-
 static int
 acpi_asus_probe(device_t dev)
 {
@@ -445,22 +556,23 @@ acpi_asus_probe(device_t dev)
        ACPI_BUFFER             Buf;
        ACPI_OBJECT             Arg, *Obj;
        ACPI_OBJECT_LIST        Args;
+       static char             *asus_ids[] = { "ATK0100", "ASUS010", NULL };
        char *rstr;
 
        ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
-       if (acpi_disabled("asus")) return (ENXIO);
+       if (acpi_disabled("asus"))
+               return (ENXIO);
+       ACPI_SERIAL_INIT(asus);
        rstr = ACPI_ID_PROBE(device_get_parent(dev), dev, asus_ids);
        if (rstr == NULL) {
                return (ENXIO);
        }
 
-
        sc = device_get_softc(dev);
        sc->dev = dev;
        sc->handle = acpi_get_handle(dev);
 
-
        Arg.Type = ACPI_TYPE_INTEGER;
        Arg.Integer.Value = 0;
 
@@ -481,7 +593,7 @@ acpi_asus_probe(device_t dev)
                ACPI_STATUS             status;
                ACPI_TABLE_HEADER       th;
 
-               status = AcpiGetTableHeader(ACPI_SIG_DSDT, 1, &th);
+               status = AcpiGetTableHeader(ACPI_SIG_DSDT, 0, &th);
                if (ACPI_FAILURE(status)) {
                        device_printf(dev, "Unsupported (Samsung?) laptop\n");
                        AcpiOsFree(Buf.Pointer);
@@ -495,7 +607,7 @@ acpi_asus_probe(device_t dev)
                        return (0);
                }
 
-               /* if EeePC */
+               /* EeePC */
                if (strncmp("ASUS010", rstr, 7) == 0) {
                        sc->model = &acpi_eeepc_models[0];
                        device_set_desc(dev, "ASUS EeePC");
@@ -504,7 +616,7 @@ acpi_asus_probe(device_t dev)
                }
        }
 
-       sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+       sb = sbuf_new_auto();
        if (sb == NULL)
                return (ENOMEM);
 
@@ -526,7 +638,7 @@ good:
                        AcpiOsFree(Buf.Pointer);
                        return (0);
                }
-
+               
                /*
                 * Some models look exactly the same as other models, but have
                 * their own ids.  If we spot these, set them up with the same
@@ -545,6 +657,9 @@ good:
                else if (strncmp(model->name, "A2x", 3) == 0 &&
                    strncmp(Obj->String.Pointer, "A2", 2) == 0)
                        goto good;
+               else if (strncmp(model->name, "A3F", 3) == 0 &&
+                   strncmp(Obj->String.Pointer, "A6F", 3) == 0)
+                       goto good;
                else if (strncmp(model->name, "D1x", 3) == 0 &&
                    strncmp(Obj->String.Pointer, "D1", 2) == 0)
                        goto good;
@@ -610,40 +725,6 @@ good:
 }
 
 static int
-acpi_asus_detach(device_t dev)
-{
-       struct acpi_asus_softc  *sc;
-
-       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
-       sc = device_get_softc(dev);
-
-
-       /* Turn the lights off */
-       /* We don't have LED support, sadly... :( */
-/*     if (sc->model->bled_set)
-               led_destroy(sc->s_bled.cdev);
-
-       if (sc->model->mled_set)
-               led_destroy(sc->s_mled.cdev);
-
-       if (sc->model->tled_set)
-               led_destroy(sc->s_tled.cdev);
-
-       if (sc->model->wled_set)
-               led_destroy(sc->s_wled.cdev);
-*/
-       /* Remove notify handler */
-       AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
-           acpi_asus_notify);
-
-       /* Free sysctl tree */
-       sysctl_ctx_free(&sc->sysctl_ctx);
-
-       return (0);
-}
-
-static int
 acpi_asus_attach(device_t dev)
 {
        struct acpi_asus_softc  *sc;
@@ -668,21 +749,36 @@ acpi_asus_attach(device_t dev)
                SYSCTL_ADD_PROC(&sc->sysctl_ctx,
                    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
                    acpi_asus_sysctls[i].name,
-                   CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
+                   acpi_asus_sysctls[i].flags,
                    sc, i, acpi_asus_sysctl, "I",
                    acpi_asus_sysctls[i].description);
        }
 
+#if defined(__FreeBSD__)
        /* Attach leds */
-
-   /*Currently we don't have LEDs control. Just comment this for now...*/
-/*
        if (sc->model->bled_set) {
                sc->s_bled.busy = 0;
                sc->s_bled.sc = sc;
                sc->s_bled.type = ACPI_ASUS_LED_BLED;
                sc->s_bled.cdev =
-                   led_create((led_t *)acpi_asus_led, &sc->s_bled, "bled");
+                   led_create_state((led_t *)acpi_asus_led, &sc->s_bled,
+                       "bled", 1);
+       }
+
+       if (sc->model->dled_set) {
+               sc->s_dled.busy = 0;
+               sc->s_dled.sc = sc;
+               sc->s_dled.type = ACPI_ASUS_LED_DLED;
+               sc->s_dled.cdev =
+                   led_create((led_t *)acpi_asus_led, &sc->s_dled, "dled");
+       }
+
+       if (sc->model->gled_set) {
+               sc->s_gled.busy = 0;
+               sc->s_gled.sc = sc;
+               sc->s_gled.type = ACPI_ASUS_LED_GLED;
+               sc->s_gled.cdev =
+                   led_create((led_t *)acpi_asus_led, &sc->s_gled, "gled");
        }
 
        if (sc->model->mled_set) {
@@ -698,7 +794,8 @@ acpi_asus_attach(device_t dev)
                sc->s_tled.sc = sc;
                sc->s_tled.type = ACPI_ASUS_LED_TLED;
                sc->s_tled.cdev =
-                   led_create((led_t *)acpi_asus_led, &sc->s_tled, "tled");
+                   led_create_state((led_t *)acpi_asus_led, &sc->s_tled,
+                       "tled", 1);
        }
 
        if (sc->model->wled_set) {
@@ -706,22 +803,149 @@ acpi_asus_attach(device_t dev)
                sc->s_wled.sc = sc;
                sc->s_wled.type = ACPI_ASUS_LED_WLED;
                sc->s_wled.cdev =
-                   led_create((led_t *)acpi_asus_led, &sc->s_wled, "wled");
+                   led_create_state((led_t *)acpi_asus_led, &sc->s_wled,
+                       "wled", 1);
        }
-*/
+#endif
 
        /* Activate hotkeys */
        AcpiEvaluateObject(sc->handle, "BSTS", NULL, NULL);
 
        /* Handle notifies */
+       if (sc->model->n_func == NULL)
+               sc->model->n_func = acpi_asus_notify;
+
        AcpiInstallNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
-           acpi_asus_notify, dev);
+           sc->model->n_func, dev);
+
+       /* Find and hook the 'LCDD' object */
+       if (sc->model->lcdd != NULL && sc->model->lcdd_n_func != NULL) {
+               ACPI_STATUS res;
+
+               sc->lcdd_handle = NULL;
+               res = AcpiGetHandle((sc->model->lcdd[0] == '\\' ?
+                   NULL : sc->handle), sc->model->lcdd, &(sc->lcdd_handle));
+               if (ACPI_SUCCESS(res)) {
+                       AcpiInstallNotifyHandler((sc->lcdd_handle),
+                           ACPI_DEVICE_NOTIFY, sc->model->lcdd_n_func, dev);
+               } else {
+                       kprintf("%s: unable to find LCD device '%s'\n",
+                           __func__, sc->model->lcdd);
+               }
+       }
+
+       return (0);
+}
+
+static int
+acpi_asus_detach(device_t dev)
+{
+       struct acpi_asus_softc  *sc;
 
-    lockinit(&asuslock, "asus", 0, 0);
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = device_get_softc(dev);
+#if defined(__FreeBSD)
+       /* Turn the lights off */
+       if (sc->model->bled_set)
+               led_destroy(sc->s_bled.cdev);
+
+       if (sc->model->dled_set)
+               led_destroy(sc->s_dled.cdev);
+
+       if (sc->model->gled_set)
+               led_destroy(sc->s_gled.cdev);
+
+       if (sc->model->mled_set)
+               led_destroy(sc->s_mled.cdev);
+
+       if (sc->model->tled_set)
+               led_destroy(sc->s_tled.cdev);
+
+       if (sc->model->wled_set)
+               led_destroy(sc->s_wled.cdev);
+#endif
+
+       /* Remove notify handler */
+       AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
+           acpi_asus_notify);
+       
+       if (sc->lcdd_handle) {
+               KASSERT(sc->model->lcdd_n_func != NULL,
+                   ("model->lcdd_n_func is NULL, but lcdd_handle is non-zero"));
+               AcpiRemoveNotifyHandler((sc->lcdd_handle),
+                   ACPI_DEVICE_NOTIFY, sc->model->lcdd_n_func);
+       }
+
+       /* Free sysctl tree */
+       sysctl_ctx_free(&sc->sysctl_ctx);
 
        return (0);
 }
 
+#if defined(__FreeBSD__)
+static void
+acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused)
+{
+       struct acpi_asus_softc  *sc;
+       char                    *method;
+       int                     state;
+       
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = led->sc;
+
+       switch (led->type) {
+       case ACPI_ASUS_LED_BLED:
+               method = sc->model->bled_set;
+               state = led->state;
+               break;
+       case ACPI_ASUS_LED_DLED:
+               method = sc->model->dled_set;
+               state = led->state;
+               break;
+       case ACPI_ASUS_LED_GLED:
+               method = sc->model->gled_set;
+               state = led->state + 1; /* 1: off, 2: on */
+               break;
+       case ACPI_ASUS_LED_MLED:
+               method = sc->model->mled_set;
+               state = !led->state;    /* inverted */
+               break;
+       case ACPI_ASUS_LED_TLED:
+               method = sc->model->tled_set;
+               state = led->state;
+               break;
+       case ACPI_ASUS_LED_WLED:
+               method = sc->model->wled_set;
+               state = led->state;
+               break;
+       default:
+               kprintf("acpi_asus_led: invalid LED type %d\n",
+                   (int)led->type);
+               return;
+       }
+
+       acpi_SetInteger(sc->handle, method, state);
+       led->busy = 0;
+}
+       
+static void
+acpi_asus_led(struct acpi_asus_led *led, int state)
+{
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       if (led->busy)
+               return;
+
+       led->busy = 1;
+       led->state = state;
+
+       AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)acpi_asus_led_task, led);
+}
+#endif
+
 static int
 acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
 {
@@ -730,14 +954,14 @@ acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
        int                     error = 0;
        int                     function;
        int                     method;
-
+       
        ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
        sc = (struct acpi_asus_softc *)oidp->oid_arg1;
        function = oidp->oid_arg2;
        method = acpi_asus_sysctls[function].method;
 
-       lockmgr(&asuslock, LK_EXCLUSIVE);
+       ACPI_SERIAL_BEGIN(asus);
        arg = acpi_asus_sysctl_get(sc, method);
        error = sysctl_handle_int(oidp, &arg, 0, req);
 
@@ -749,7 +973,7 @@ acpi_asus_sysctl(SYSCTL_HANDLER_ARGS)
        error = acpi_asus_sysctl_set(sc, method, arg);
 
 out:
-       lockmgr(&asuslock, LK_RELEASE);
+       ACPI_SERIAL_END(asus);
        return (error);
 }
 
@@ -759,7 +983,7 @@ acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
        int val = 0;
 
        ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-       KKASSERT(lockstatus(&asuslock, NULL)!=0); /* was ACPI_SERIAL_ASSERT(asus); may be I lost something? */
+       ACPI_SERIAL_ASSERT(asus);
 
        switch (method) {
        case ACPI_ASUS_METHOD_BRN:
@@ -771,6 +995,15 @@ acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
        case ACPI_ASUS_METHOD_LCD:
                val = sc->s_lcd;
                break;
+       case ACPI_ASUS_METHOD_CAMERA:
+               val = sc->s_cam;
+               break;
+       case ACPI_ASUS_METHOD_CARDRD:
+               val = sc->s_crd;
+               break;
+       case ACPI_ASUS_METHOD_WLAN:
+               val = sc->s_wlan;
+               break;
        }
 
        return (val);
@@ -779,12 +1012,17 @@ acpi_asus_sysctl_get(struct acpi_asus_softc *sc, int method)
 static int
 acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int arg)
 {
-       ACPI_STATUS     status = AE_OK;
+       ACPI_STATUS             status = AE_OK;
+       ACPI_OBJECT_LIST        acpiargs;
+       ACPI_OBJECT             acpiarg[1];
 
        ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+       ACPI_SERIAL_ASSERT(asus);
 
-
-       KKASSERT(lockstatus(&asuslock, NULL)!=0); /* was ACPI_SERIAL_ASSERT(asus); another miss? */
+       acpiargs.Count = 1;
+       acpiargs.Pointer = acpiarg;
+       acpiarg[0].Type = ACPI_TYPE_INTEGER;
+       acpiarg[0].Integer.Value = arg;
 
        switch (method) {
        case ACPI_ASUS_METHOD_BRN:
@@ -833,6 +1071,36 @@ acpi_asus_sysctl_set(struct acpi_asus_softc *sc, int method, int arg)
                        sc->s_lcd = arg;
 
                break;
+       case ACPI_ASUS_METHOD_CAMERA:
+               if (arg < 0 || arg > 1)
+                       return (EINVAL);
+
+               status = AcpiEvaluateObject(sc->handle,
+                   sc->model->cam_set, &acpiargs, NULL);
+
+               if (ACPI_SUCCESS(status))
+                       sc->s_cam = arg;
+               break;
+       case ACPI_ASUS_METHOD_CARDRD:
+               if (arg < 0 || arg > 1)
+                       return (EINVAL);
+
+               status = AcpiEvaluateObject(sc->handle,
+                   sc->model->crd_set, &acpiargs, NULL);
+
+               if (ACPI_SUCCESS(status))
+                       sc->s_crd = arg;
+               break;
+       case ACPI_ASUS_METHOD_WLAN:
+               if (arg < 0 || arg > 1)
+                       return (EINVAL);
+
+               status = AcpiEvaluateObject(sc->handle,
+                   sc->model->wlan_set, &acpiargs, NULL);
+
+               if (ACPI_SUCCESS(status))
+                       sc->s_wlan = arg;
+               break;
        }
 
        return (0);
@@ -875,37 +1143,80 @@ acpi_asus_sysctl_init(struct acpi_asus_softc *sc, int method)
                }
                return (FALSE);
        case ACPI_ASUS_METHOD_LCD:
-               if (sc->model->lcd_get &&
-                   strncmp(sc->model->name, "L3H", 3) != 0) {
+               if (sc->model->lcd_get) {
+                       if (strncmp(sc->model->name, "G2K", 3) == 0) {
+                               ACPI_BUFFER             Buf;
+                               ACPI_OBJECT             Arg, Obj;
+                               ACPI_OBJECT_LIST        Args;
+
+                               Arg.Type = ACPI_TYPE_INTEGER;
+                               Arg.Integer.Value = 0x11;
+                               Args.Count = 1;
+                               Args.Pointer = &Arg;
+                               Buf.Length = sizeof(Obj);
+                               Buf.Pointer = &Obj;
+
+                               status = AcpiEvaluateObject(sc->handle,
+                                   sc->model->lcd_get, &Args, &Buf);
+                               if (ACPI_SUCCESS(status) &&
+                                   Obj.Type == ACPI_TYPE_INTEGER) {
+                                       sc->s_lcd = Obj.Integer.Value;
+                                       return (TRUE);
+                               }
+                       } else if (strncmp(sc->model->name, "L3H", 3) == 0) {
+                               ACPI_BUFFER             Buf;
+                               ACPI_OBJECT             Arg[2], Obj;
+                               ACPI_OBJECT_LIST        Args;
+
+                               /* L3H is a bit special */
+                               Arg[0].Type = ACPI_TYPE_INTEGER;
+                               Arg[0].Integer.Value = 0x02;
+                               Arg[1].Type = ACPI_TYPE_INTEGER;
+                               Arg[1].Integer.Value = 0x03;
+
+                               Args.Count = 2;
+                               Args.Pointer = Arg;
+
+                               Buf.Length = sizeof(Obj);
+                               Buf.Pointer = &Obj;
+
+                               status = AcpiEvaluateObject(sc->handle,
+                                   sc->model->lcd_get, &Args, &Buf);
+                               if (ACPI_SUCCESS(status) &&
+                                   Obj.Type == ACPI_TYPE_INTEGER) {
+                                       sc->s_lcd = Obj.Integer.Value >> 8;
+                                       return (TRUE);
+                               }
+                       } else {
+                               status = acpi_GetInteger(sc->handle,
+                                   sc->model->lcd_get, &sc->s_lcd);
+                               if (ACPI_SUCCESS(status))
+                                       return (TRUE);
+                       }
+               }
+               return (FALSE);
+       case ACPI_ASUS_METHOD_CAMERA:
+               if (sc->model->cam_get) {
                        status = acpi_GetInteger(sc->handle,
-                           sc->model->lcd_get, &sc->s_lcd);
+                           sc->model->cam_get, &sc->s_cam);
                        if (ACPI_SUCCESS(status))
                                return (TRUE);
                }
-               else if (sc->model->lcd_get) {
-                       ACPI_BUFFER             Buf;
-                       ACPI_OBJECT             Arg[2], Obj;
-                       ACPI_OBJECT_LIST        Args;
-
-                       /* L3H is a bit special */
-                       Arg[0].Type = ACPI_TYPE_INTEGER;
-                       Arg[0].Integer.Value = 0x02;
-                       Arg[1].Type = ACPI_TYPE_INTEGER;
-                       Arg[1].Integer.Value = 0x03;
-
-                       Args.Count = 2;
-                       Args.Pointer = Arg;
-
-                       Buf.Length = sizeof(Obj);
-                       Buf.Pointer = &Obj;
-
-                       status = AcpiEvaluateObject(sc->handle,
-                           sc->model->lcd_get, &Args, &Buf);
-                       if (ACPI_SUCCESS(status) &&
-                           Obj.Type == ACPI_TYPE_INTEGER) {
-                               sc->s_lcd = Obj.Integer.Value >> 8;
+               return (FALSE);
+       case ACPI_ASUS_METHOD_CARDRD:
+               if (sc->model->crd_get) {
+                       status = acpi_GetInteger(sc->handle,
+                           sc->model->crd_get, &sc->s_crd);
+                       if (ACPI_SUCCESS(status))
+                               return (TRUE);
+               }
+               return (FALSE);
+       case ACPI_ASUS_METHOD_WLAN:
+               if (sc->model->wlan_get) {
+                       status = acpi_GetInteger(sc->handle,
+                           sc->model->wlan_get, &sc->s_wlan);
+                       if (ACPI_SUCCESS(status))
                                return (TRUE);
-                       }
                }
                return (FALSE);
        }
@@ -923,7 +1234,7 @@ acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
        sc = device_get_softc((device_t)context);
        acpi_sc = acpi_device_get_parent_softc(sc->dev);
 
-       lockmgr(&asuslock, LK_EXCLUSIVE);
+       ACPI_SERIAL_BEGIN(asus);
        if ((notify & ~0x10) <= 15) {
                sc->s_brn = notify & ~0x10;
                ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
@@ -936,9 +1247,63 @@ acpi_asus_notify(ACPI_HANDLE h, UINT32 notify, void *context)
        } else if (notify == 0x34) {
                sc->s_lcd = 0;
                ACPI_VPRINT(sc->dev, acpi_sc, "LCD turned off\n");
+       } else if (notify == 0x86) {
+               acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn-1);
+               ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
+       } else if (notify == 0x87) {
+               acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn+1);
+               ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
        } else {
                /* Notify devd(8) */
                acpi_UserNotify("ASUS", h, notify);
        }
-       lockmgr(&asuslock, LK_RELEASE);
+       ACPI_SERIAL_END(asus);
+}
+
+static void
+acpi_asus_lcdd_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+       struct acpi_asus_softc  *sc;
+       struct acpi_softc       *acpi_sc;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = device_get_softc((device_t)context);
+       acpi_sc = acpi_device_get_parent_softc(sc->dev);
+
+       ACPI_SERIAL_BEGIN(asus);
+       switch (notify) {
+       case 0x87:
+               acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn-1);
+               ACPI_VPRINT(sc->dev, acpi_sc, "Brightness decreased\n");
+               break;
+       case 0x86:
+               acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn+1);
+               ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n");
+               break;
+       }
+       ACPI_SERIAL_END(asus);
+}
+
+static void
+acpi_asus_eeepc_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+       struct acpi_asus_softc  *sc;
+       struct acpi_softc       *acpi_sc;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = device_get_softc((device_t)context);
+       acpi_sc = acpi_device_get_parent_softc(sc->dev);
+
+       ACPI_SERIAL_BEGIN(asus);
+       if ((notify & ~0x20) <= 15) {
+               sc->s_brn = notify & ~0x20;
+               ACPI_VPRINT(sc->dev, acpi_sc,
+                   "Brightness increased/decreased\n");
+       } else {
+               /* Notify devd(8) */
+               acpi_UserNotify("ASUS-Eee", h, notify);
+       }
+       ACPI_SERIAL_END(asus);
 }
index 0122c81..93a58a9 100644 (file)
  * 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.26 2007/11/20 18:35:36 jkim Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_battery.c,v 1.4 2008/09/29 06:59:45 hasso Exp $
+ * $FreeBSD: src/sys/dev/acpica/acpi_battery.c,v 1.30 2009/08/20 19:17:53 jhb
  */
 
+#include <sys/cdefs.h>
+
 #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 <sys/thread2.h>
 
 #include "acpi.h"
+
 #include <dev/acpica5/acpivar.h>
 #include <dev/acpica5/acpiio.h>
 
@@ -49,6 +50,8 @@ static struct acpi_battinfo   acpi_battery_battinfo;
 static struct  sysctl_ctx_list acpi_battery_sysctl_ctx;
 static struct  sysctl_oid      *acpi_battery_sysctl_tree;
 
+ACPI_SERIAL_DECL(battery, "ACPI generic battery");
+
 static void acpi_reset_battinfo(struct acpi_battinfo *info);
 static void acpi_battery_clean_str(char *str, int len);
 static device_t acpi_battery_find_dev(u_int logical_unit);
@@ -63,16 +66,17 @@ acpi_battery_register(device_t dev)
     int error;
 
     error = 0;
-    crit_enter();
+    ACPI_SERIAL_BEGIN(battery);
     if (!acpi_batteries_initted)
        error = acpi_battery_init();
-    crit_exit();
+    ACPI_SERIAL_END(battery);
     return (error);
 }
 
 int
 acpi_battery_remove(device_t dev)
 {
+
     return (0);
 }
 
@@ -90,6 +94,7 @@ acpi_battery_get_units(void)
 int
 acpi_battery_get_info_expire(void)
 {
+
     return (acpi_battery_info_expire);
 }
 
@@ -193,7 +198,7 @@ acpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *battinfo)
         * is 0 (due to some error reading the battery), skip this
         * conversion.
         */
-       if (bif->units == ACPI_BIF_UNITS_MA && bif->dvol != 0) {
+       if (bif->units == ACPI_BIF_UNITS_MA && bif->dvol != 0 && dev == NULL) {
            bst[i].rate = (bst[i].rate * bif->dvol) / 1000;
            bst[i].cap = (bst[i].cap * bif->dvol) / 1000;
            bif->lfcap = (bif->lfcap * bif->dvol) / 1000;
@@ -434,6 +439,8 @@ acpi_battery_init(void)
     device_t            dev;
     int                         error;
 
+    ACPI_SERIAL_ASSERT(battery);
+
     error = ENXIO;
     dev = devclass_get_device(devclass_find("acpi"), 0);
     if (dev == NULL)
index 567b76b..1ccc1e4 100644 (file)
  * 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.27 2004/06/13 22:52:30 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_button.c,v 1.5 2007/10/23 03:04:48 y0netan1 Exp $
+ * $FreeBSD: src/sys/dev/acpica/acpi_button.c,v 1.33 2009/06/05 18:44:36 jkim Exp
  */
 
+#include <sys/cdefs.h>
+
 #include "opt_acpi.h"
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -37,6 +37,7 @@
 
 #include "acpi.h"
 #include "accommon.h"
+
 #include <dev/acpica5/acpivar.h>
 
 /* Hooks for the ACPI CA debugging infrastructure */
@@ -66,6 +67,11 @@ static ACPI_STATUS
 static void    acpi_button_notify_sleep(void *arg);
 static void    acpi_button_notify_wakeup(void *arg);
 
+static char *btn_ids[] = {
+    "PNP0C0C", "ACPI_FPB", "PNP0C0E", "ACPI_FSB",
+    NULL
+};
+
 static device_method_t acpi_button_methods[] = {
     /* Device interface */
     DEVMETHOD(device_probe,    acpi_button_probe),
@@ -91,34 +97,31 @@ MODULE_DEPEND(acpi_button, acpi, 1, 1, 1);
 static int
 acpi_button_probe(device_t dev)
 {
-    struct acpi_button_softc   *sc;
-    ACPI_HANDLE h;
-    int ret = ENXIO;
+    struct acpi_button_softc *sc;
+    char *str;
+
+    if (acpi_disabled("button") ||
+       (str = ACPI_ID_PROBE(device_get_parent(dev), dev, btn_ids)) == NULL)
+       return (ENXIO);
 
-    h = acpi_get_handle(dev);
     sc = device_get_softc(dev);
-    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) {
-       if (acpi_MatchHid(h, "PNP0C0C")) {
-           device_set_desc(dev, "Power Button");
-           sc->button_type = ACPI_POWER_BUTTON;
-           ret = 0;
-       } else if (acpi_MatchHid(h, "ACPI_FPB")) {
-           device_set_desc(dev, "Power Button (fixed)");
-           sc->button_type = ACPI_POWER_BUTTON;
-           sc->fixed = 1;
-           ret = 0;
-       } else if (acpi_MatchHid(h, "PNP0C0E")) {
-           device_set_desc(dev, "Sleep Button");
-           sc->button_type = ACPI_SLEEP_BUTTON;
-           ret = 0;
-       } else if (acpi_MatchHid(h, "ACPI_FSB")) {
-           device_set_desc(dev, "Sleep Button (fixed)");
-           sc->button_type = ACPI_SLEEP_BUTTON;
-           sc->fixed = 1;
-           ret = 0;
-       }
+    if (strcmp(str, "PNP0C0C") == 0) {
+       device_set_desc(dev, "Power Button");
+       sc->button_type = ACPI_POWER_BUTTON;
+    } else if (strcmp(str, "ACPI_FPB") == 0) {
+       device_set_desc(dev, "Power Button (fixed)");
+       sc->button_type = ACPI_POWER_BUTTON;
+       sc->fixed = 1;
+    } else if (strcmp(str, "PNP0C0E") == 0) {
+       device_set_desc(dev, "Sleep Button");
+       sc->button_type = ACPI_SLEEP_BUTTON;
+    } else if (strcmp(str, "ACPI_FSB") == 0) {
+       device_set_desc(dev, "Sleep Button (fixed)");
+       sc->button_type = ACPI_SLEEP_BUTTON;
+       sc->fixed = 1;
     }
-    return (ret);
+
+    return (0);
 }
 
 static int
@@ -170,17 +173,12 @@ acpi_button_attach(device_t dev)
 static int
 acpi_button_suspend(device_t dev)
 {
-    struct acpi_softc           *acpi_sc;
-
-    acpi_sc = acpi_device_get_parent_softc(dev);
-    acpi_wake_sleep_prep(dev, acpi_sc->acpi_sstate);
     return (0);
 }
 
 static int
 acpi_button_resume(device_t dev)
 {
-    acpi_wake_run_prep(dev);
     return (0);
 }
 
index cf2ffce..a69b4bc 100644 (file)
  * 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.46 2007/03/22 18:16:40 jkim Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_cmbat.c,v 1.12 2008/09/29 06:59:45 hasso Exp $
+ * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_cmbat.c,v 1.46.8.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
+#include <sys/cdefs.h>
+
 #include "opt_acpi.h"
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/bus.h>
+#include <sys/ioccom.h>
+
 #include <sys/rman.h>
 #include <sys/malloc.h>
-#include <sys/thread2.h>
 
 #include "acpi.h"
 #include <dev/acpica5/acpivar.h>
@@ -67,6 +68,8 @@ struct acpi_cmbat_softc {
     struct timespec bst_lastupdated;
 };
 
+ACPI_SERIAL_DECL(cmbat, "ACPI cmbat");
+
 static int             acpi_cmbat_probe(device_t dev);
 static int             acpi_cmbat_attach(device_t dev);
 static int             acpi_cmbat_detach(device_t dev);
@@ -205,6 +208,8 @@ acpi_cmbat_info_expired(struct timespec *lastupdated)
 {
     struct timespec    curtime;
 
+    ACPI_SERIAL_ASSERT(cmbat);
+
     if (lastupdated == NULL)
        return (TRUE);
     if (!timespecisset(lastupdated))
@@ -219,6 +224,9 @@ acpi_cmbat_info_expired(struct timespec *lastupdated)
 static void
 acpi_cmbat_info_updated(struct timespec *lastupdated)
 {
+
+    ACPI_SERIAL_ASSERT(cmbat);
+
     if (lastupdated != NULL)
        getnanotime(lastupdated);
 }
@@ -233,6 +241,8 @@ acpi_cmbat_get_bst(void *arg)
     ACPI_BUFFER        bst_buffer;
     device_t dev;
 
+    ACPI_SERIAL_ASSERT(cmbat);
+
     dev = arg;
     sc = device_get_softc(dev);
     h = acpi_get_handle(dev);
@@ -285,9 +295,10 @@ end:
 static void
 acpi_cmbat_get_bif_task(void *arg)
 {
-    crit_enter();
+
+    ACPI_SERIAL_BEGIN(cmbat);
     acpi_cmbat_get_bif(arg);
-    crit_exit();
+    ACPI_SERIAL_END(cmbat);
 }
 
 static void
@@ -300,6 +311,8 @@ acpi_cmbat_get_bif(void *arg)
     ACPI_BUFFER        bif_buffer;
     device_t dev;
 
+    ACPI_SERIAL_ASSERT(cmbat);
+
     dev = arg;
     sc = device_get_softc(dev);
     h = acpi_get_handle(dev);
@@ -366,7 +379,7 @@ acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp)
      * the info has changed.  Many systems apparently take a long time to
      * process a _BIF call so we avoid it if possible.
      */
-    crit_enter();
+    ACPI_SERIAL_BEGIN(cmbat);
     bifp->units = sc->bif.units;
     bifp->dcap = sc->bif.dcap;
     bifp->lfcap = sc->bif.lfcap;
@@ -380,7 +393,7 @@ acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp)
     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));
-    crit_exit();
+    ACPI_SERIAL_END(cmbat);
 
     return (0);
 }
@@ -392,7 +405,7 @@ acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
 
     sc = device_get_softc(dev);
 
-    crit_enter();
+    ACPI_SERIAL_BEGIN(cmbat);
     if (acpi_BatteryIsPresent(dev)) {
        acpi_cmbat_get_bst(dev);
        bstp->state = sc->bst.state;
@@ -401,7 +414,7 @@ acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
        bstp->volt = sc->bst.volt;
     } else
        bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
-    crit_exit();
+    ACPI_SERIAL_END(cmbat);
 
     return (0);
 }
@@ -423,7 +436,7 @@ acpi_cmbat_init_battery(void *arg)
      * embedded controller isn't always ready just after boot, we may have
      * to wait a while.
      */
-    for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10)) {
+    for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) {
        /* batteries on DOCK can be ejected w/ DOCK during retrying */
        if (!device_is_attached(dev))
            return;
@@ -435,7 +448,7 @@ acpi_cmbat_init_battery(void *arg)
         * Only query the battery if this is the first try or the specific
         * type of info is still invalid.
         */
-       crit_enter();
+       ACPI_SERIAL_BEGIN(cmbat);
        if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) {
            timespecclear(&sc->bst_lastupdated);
            acpi_cmbat_get_bst(dev);
@@ -445,7 +458,7 @@ acpi_cmbat_init_battery(void *arg)
 
        valid = acpi_battery_bst_valid(&sc->bst) &&
            acpi_battery_bif_valid(&sc->bif);
-       crit_exit();
+       ACPI_SERIAL_END(cmbat);
 
        if (valid)
            break;
index feb8df9..21b9b92 100644 (file)
@@ -47,7 +47,6 @@
 #include <sys/rman.h>
 
 #include "acpi.h"
-#include "accommon.h"
 #include "acpivar.h"
 #include "acpi_cpu.h"
 
@@ -518,7 +517,7 @@ acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc)
        gas.Address = sc->cpu_p_blk + 4;
 
        cx_ptr->rid = sc->cpu_parent->cpux_next_rid;
-       cx_ptr->p_lvlx = acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->rid, &gas,
+       acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->type, &cx_ptr->rid, &gas, &cx_ptr->p_lvlx,
                                            RF_SHAREABLE);
        if (cx_ptr->p_lvlx != NULL) {
            sc->cpu_parent->cpux_next_rid++;
@@ -536,8 +535,8 @@ acpi_cpu_generic_cx_probe(struct acpi_cpu_softc *sc)
        gas.Address = sc->cpu_p_blk + 5;
 
        cx_ptr->rid = sc->cpu_parent->cpux_next_rid;
-       cx_ptr->p_lvlx = acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->rid, &gas,
-                                           RF_SHAREABLE);
+       acpi_bus_alloc_gas(sc->cpu_dev, &cx_ptr->type, &cx_ptr->rid, &gas,
+                                           &cx_ptr->p_lvlx, RF_SHAREABLE);
        if (cx_ptr->p_lvlx != NULL) {
            sc->cpu_parent->cpux_next_rid++;
            cx_ptr->type = ACPI_STATE_C3;
@@ -642,7 +641,7 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
 
        /* Allocate the control register for C2 or C3. */
        cx_ptr->rid = sc->cpu_parent->cpux_next_rid;
-       acpi_PkgGas(sc->cpu_dev, pkg, 0, &cx_ptr->rid, &cx_ptr->p_lvlx,
+       acpi_PkgGas(sc->cpu_dev, pkg, 0, &cx_ptr->type, &cx_ptr->rid, &cx_ptr->p_lvlx,
                    RF_SHAREABLE);
        if (cx_ptr->p_lvlx) {
            sc->cpu_parent->cpux_next_rid++;
@@ -1017,7 +1016,7 @@ acpi_cpu_quirks(void)
            if (val) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                    "acpi_cpu: PIIX4: reset BRLD_EN_BM\n"));
-               AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 0);
+               AcpiReadBitRegister(ACPI_BITREG_BUS_MASTER_RLD, 0);
            }
            break;
        default:
index d1252f4..5e436c8 100644 (file)
@@ -351,9 +351,9 @@ acpi_pst_attach(device_t dev)
                return error;
        }
        if (bootverbose) {
-               device_printf(dev, "control reg %jd %jx\n",
-                             (intmax_t)sc->pst_creg.pr_gas.SpaceId,
-                             (intmax_t)sc->pst_creg.pr_gas.Address);
+               device_printf(dev, "control reg %d %llx\n",
+                             sc->pst_creg.pr_gas.SpaceId,
+                             sc->pst_creg.pr_gas.Address);
        }
 
        /* Save and try allocating status register */
@@ -1065,7 +1065,7 @@ acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
                        struct acpi_pst_res *res)
 {
        struct acpi_pst_softc *sc = device_get_softc(dev);
-       int error;
+       int error, type;
 
        /* Save GAS */
        error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
@@ -1074,7 +1074,7 @@ acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
 
        /* Allocate resource, if possible */
        res->pr_rid = sc->pst_parent->cpux_next_rid;
-       res->pr_res = acpi_bus_alloc_gas(dev, &res->pr_rid, &res->pr_gas, 0);
+       acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
        if (res->pr_res != NULL) {
                sc->pst_parent->cpux_next_rid++;
                res->pr_bt = rman_get_bustag(res->pr_res);
index 6fd4096..d5a7c86 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003 Nate Lawson
+ * Copyright (c) 2003-2007 Nate Lawson
  * Copyright (c) 2000 Michael Smith
  * Copyright (c) 2000 BSDi
  * All rights reserved.
  * 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.52 2004/06/13 22:52:30 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_ec.c,v 1.14 2008/08/27 16:35:19 hasso Exp $
+ * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_ec.c,v 1.76.2.1.6.1 2009/04/15 03:14:26 kensmith 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.52 2004/06/13 22:52:30 njl Exp $
-  * $DragonFly: src/sys/dev/acpica5/acpi_ec.c,v 1.14 2008/08/27 16:35:19 hasso Exp $
-  *
-  */
+
+#include <sys/cdefs.h>
 
 #include "opt_acpi.h"
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
-#include <sys/thread.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
-#include <sys/lock.h>
 #include <sys/rman.h>
 
 #include "acpi.h"
-#include "accommon.h"
 #include <dev/acpica5/acpivar.h>
+#include "acutils.h"
 
-/*
- * Hooks for the ACPI CA debugging infrastructure
- */
+/* Hooks for the ACPI CA debugging infrastructure */
 #define _COMPONENT     ACPI_EC
 ACPI_MODULE_NAME("EC")
 
+#define rebooting 0
+#define PZERO 0
 /*
  * EC_COMMAND:
  * -----------
@@ -175,14 +61,14 @@ typedef UINT8                              EC_COMMAND;
 #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|   
+ * |7|6|5|4|3|2|1|0|
  * +-+-+-+-+-+-+-+-+
  *  | | | | | | | |
  *  | | | | | | | +- Output Buffer Full?
@@ -192,15 +78,15 @@ typedef UINT8                              EC_COMMAND;
  *  | | | +--------- Burst Mode Enabled?
  *  | | +----------- SCI Event?
  *  | +------------- SMI Event?
- *  +--------------- <Reserved>
+ *  +--------------- <reserved>
  *
  */
 typedef UINT8                          EC_STATUS;
 
 #define EC_FLAG_OUTPUT_BUFFER          ((EC_STATUS) 0x01)
 #define EC_FLAG_INPUT_BUFFER           ((EC_STATUS) 0x02)
+#define EC_FLAG_DATA_IS_CMD            ((EC_STATUS) 0x08)
 #define EC_FLAG_BURST_MODE             ((EC_STATUS) 0x10)
-#define EC_FLAG_SCI                    ((EC_STATUS) 0x20)
 
 /*
  * EC_EVENT:
@@ -212,6 +98,10 @@ typedef UINT8                               EC_EVENT;
 #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)
+#define EC_EVENT_SMI                   ((EC_EVENT) 0x40)
+
+/* Data byte returned after burst enable indicating it was successful. */
+#define EC_BURST_ACK                   0x90
 
 /*
  * Register access primitives
@@ -237,7 +127,7 @@ struct acpi_ec_params {
 };
 
 /* Indicate that this device has already been probed via ECDT. */
-#define DEV_ECDT(x)            (acpi_get_magic(x) == (int)&acpi_ec_devclass)
+#define DEV_ECDT(x)    (acpi_get_magic(x) == (uintptr_t)&acpi_ec_devclass)
 
 /*
  * Driver softc.
@@ -248,8 +138,7 @@ struct acpi_ec_softc {
     int                        ec_uid;
     ACPI_HANDLE                ec_gpehandle;
     UINT8              ec_gpebit;
-    UINT8              ec_csrvalue;
-    
+
     int                        ec_data_rid;
     struct resource    *ec_data_res;
     bus_space_tag_t    ec_data_tag;
@@ -262,21 +151,24 @@ struct acpi_ec_softc {
 
     int                        ec_glk;
     int                        ec_glkhandle;
-    struct lock                ec_lock;
+    int                        ec_burstactive;
+    int                        ec_sci_pend;
+    u_int              ec_gencount;
+    int                        ec_suspending;
 };
 
 /*
- * XXX
+ * XXX njl
  * 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
 
-/* Default interval in microseconds for the status polling loop. */
-#define EC_POLL_DELAY  10
+/* Default delay in microseconds between each run of the status polling loop. */
+#define EC_POLL_DELAY  5
 
-/* Total time in ms spent in the poll loop waiting for a response. */
-#define EC_POLL_TIMEOUT        100
+/* Total time in ms spent waiting for a response from EC. */
+#define EC_TIMEOUT     750
 
 #define EVENT_READY(event, status)                     \
        (((event) == EC_EVENT_OUTPUT_BUFFER_FULL &&     \
@@ -284,43 +176,57 @@ struct acpi_ec_softc {
         ((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);
+ACPI_SERIAL_DECL(ec, "ACPI embedded controller");
+
+SYSCTL_DECL(_debug_acpi);
+SYSCTL_NODE(_debug_acpi, OID_AUTO, ec, CTLFLAG_RD, NULL, "EC debugging");
 
-static __inline ACPI_STATUS
+static int     ec_burst_mode;
+TUNABLE_INT("debug.acpi.ec.burst", &ec_burst_mode);
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, burst, CTLFLAG_RW, &ec_burst_mode, 0,
+    "Enable use of burst mode (faster for nearly all systems)");
+static int     ec_polled_mode;
+TUNABLE_INT("debug.acpi.ec.polled", &ec_polled_mode);
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, polled, CTLFLAG_RW, &ec_polled_mode, 0,
+    "Force use of polled mode (only if interrupt mode doesn't work)");
+static int     ec_timeout = EC_TIMEOUT;
+TUNABLE_INT("debug.acpi.ec.timeout", &ec_timeout);
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, timeout, CTLFLAG_RW, &ec_timeout,
+    EC_TIMEOUT, "Total time spent waiting for a response (poll+sleep)");
+
+static ACPI_STATUS
 EcLock(struct acpi_ec_softc *sc)
 {
-    ACPI_STATUS        status = AE_OK;
-
-    /* Always acquire this EC's mutex. */
-    lockmgr(&sc->ec_lock, LK_EXCLUSIVE|LK_RETRY);
+    ACPI_STATUS        status;
 
-    /* If _GLK is non-zero, also acquire the global lock. */
+    /* If _GLK is non-zero, acquire the global lock. */
+    status = AE_OK;
     if (sc->ec_glk) {
        status = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->ec_glkhandle);
        if (ACPI_FAILURE(status))
-           lockmgr(&sc->ec_lock, LK_RELEASE);
+           return (status);
     }
-
+    ACPI_SERIAL_BEGIN(ec);
     return (status);
 }
 
-static __inline void
+static void
 EcUnlock(struct acpi_ec_softc *sc)
 {
+    ACPI_SERIAL_END(ec);
     if (sc->ec_glk)
        AcpiReleaseGlobalLock(sc->ec_glkhandle);
-    lockmgr(&sc->ec_lock, LK_RELEASE);
 }
 
 static uint32_t                EcGpeHandler(void *Context);
-static ACPI_STATUS     EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, 
+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     EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event,
+                               u_int gen_count);
 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);
@@ -328,6 +234,9 @@ 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 int             acpi_ec_suspend(device_t dev);
+static int             acpi_ec_resume(device_t dev);
+static int             acpi_ec_shutdown(device_t dev);
 static int             acpi_ec_read_method(device_t dev, u_int addr,
                                ACPI_INTEGER *val, int width);
 static int             acpi_ec_write_method(device_t dev, u_int addr,
@@ -337,10 +246,13 @@ static device_method_t acpi_ec_methods[] = {
     /* Device interface */
     DEVMETHOD(device_probe,    acpi_ec_probe),
     DEVMETHOD(device_attach,   acpi_ec_attach),
+    DEVMETHOD(device_suspend,  acpi_ec_suspend),
+    DEVMETHOD(device_resume,   acpi_ec_resume),
+    DEVMETHOD(device_shutdown, acpi_ec_shutdown),
 
     /* Embedded controller interface */
-    DEVMETHOD(acpi_ec_read,     acpi_ec_read_method),
-    DEVMETHOD(acpi_ec_write,    acpi_ec_write_method),
+    DEVMETHOD(acpi_ec_read,    acpi_ec_read_method),
+    DEVMETHOD(acpi_ec_write,   acpi_ec_write_method),
 
     {0, 0}
 };
@@ -356,10 +268,12 @@ DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
 MODULE_DEPEND(acpi_ec, acpi, 1, 1, 1);
 
 /*
- * Look for an ECDT and if we find one, set up default GPE and 
+ * 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.
+ *
+ * TODO: Some old Gateway laptops need us to fake up an ECDT or
+ * otherwise attach early so that _REG methods can run.
  */
 void
 acpi_ec_ecdt_probe(device_t parent)
@@ -375,7 +289,8 @@ acpi_ec_ecdt_probe(device_t parent)
     /* Find and validate the ECDT. */
     status = AcpiGetTable(ACPI_SIG_ECDT, 1, (ACPI_TABLE_HEADER **)&ecdt);
     if (ACPI_FAILURE(status) ||
-       ecdt->Control.BitWidth != 8 || ecdt->Data.BitWidth != 8) {
+       ecdt->Control.BitWidth != 8 ||
+       ecdt->Data.BitWidth != 8) {
        return;
     }
 
@@ -414,7 +329,7 @@ acpi_ec_ecdt_probe(device_t parent)
     params->uid = ecdt->Uid;
     acpi_GetInteger(h, "_GLK", &params->glk);
     acpi_set_private(child, params);
-    acpi_set_magic(child, (int)&acpi_ec_devclass);
+    acpi_set_magic(child, (uintptr_t)&acpi_ec_devclass);
 
     /* Finish the attach process. */
     if (device_probe_and_attach(child) != 0)
@@ -432,6 +347,7 @@ acpi_ec_probe(device_t dev)
     char       desc[64];
     int                ret;
     struct acpi_ec_params *params;
+    static char *ec_ids[] = { "PNP0C09", NULL };
 
     /* Check that this is a device and that EC is not disabled. */
     if (acpi_get_type(dev) != ACPI_TYPE_DEVICE || acpi_disabled("ec"))
@@ -449,7 +365,8 @@ acpi_ec_probe(device_t dev)
     if (DEV_ECDT(dev)) {
        params = acpi_get_private(dev);
        ret = 0;
-    } else if (acpi_MatchHid(acpi_get_handle(dev), "PNP0C09")) {
+    } else if (!acpi_disabled("ec") &&
+       ACPI_ID_PROBE(device_get_parent(dev), dev, ec_ids)) {
        params = kmalloc(sizeof(struct acpi_ec_params), M_TEMP,
                        M_WAITOK | M_ZERO);
        h = acpi_get_handle(dev);
@@ -475,11 +392,11 @@ acpi_ec_probe(device_t dev)
        if (ACPI_FAILURE(status)) {
            device_printf(dev, "can't evaluate _GPE - %s\n",
                          AcpiFormatException(status));
-           return (ENXIO);
+           goto out;
        }
        obj = (ACPI_OBJECT *)buf.Pointer;
        if (obj == NULL)
-           return (ENXIO);
+           goto out;
 
        switch (obj->Type) {
        case ACPI_TYPE_INTEGER:
@@ -544,13 +461,13 @@ acpi_ec_attach(device_t dev)
     params = acpi_get_private(dev);
     sc->ec_dev = dev;
     sc->ec_handle = acpi_get_handle(dev);
-    lockinit(&sc->ec_lock, "eclock", 0, 0);
 
     /* Retrieve previously probed values via device ivars. */
     sc->ec_glk = params->glk;
     sc->ec_gpebit = params->gpe_bit;
     sc->ec_gpehandle = params->gpe_handle;
     sc->ec_uid = params->uid;
+    sc->ec_suspending = FALSE;
     kfree(params, M_TEMP);
 
     /* Attach bus resources for data and command/status ports. */
@@ -587,7 +504,7 @@ acpi_ec_attach(device_t dev)
        goto error;
     }
 
-    /* 
+    /*
      * Install address space handler
      */
     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching address space handler\n"));
@@ -622,15 +539,45 @@ error:
     AcpiRemoveAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
        EcSpaceHandler);
     if (sc->ec_csr_res)
-       bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_csr_rid, 
+       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 (ENXIO);
 }
 
+static int
+acpi_ec_suspend(device_t dev)
+{
+    struct acpi_ec_softc       *sc;
+
+    sc = device_get_softc(dev);
+    sc->ec_suspending = TRUE;
+    return (0);
+}
+
+static int
+acpi_ec_resume(device_t dev)
+{
+    struct acpi_ec_softc       *sc;
+
+    sc = device_get_softc(dev);
+    sc->ec_suspending = FALSE;
+    return (0);
+}
+
+static int
+acpi_ec_shutdown(device_t dev)
+{
+    struct acpi_ec_softc       *sc;
+
+    /* Disable the GPE so we don't get EC events during shutdown. */
+    sc = device_get_softc(dev);
+    AcpiDisableGpe(sc->ec_gpehandle, sc->ec_gpebit, ACPI_NOT_ISR);
+    return (0);
+}
+
 /* Methods to allow other devices (e.g., smbat) to read/write EC space. */
 static int
 acpi_ec_read_method(device_t dev, u_int addr, ACPI_INTEGER *val, int width)
@@ -641,7 +588,7 @@ acpi_ec_read_method(device_t dev, u_int addr, ACPI_INTEGER *val, int width)
     sc = device_get_softc(dev);
     status = EcSpaceHandler(ACPI_READ, addr, width * 8, val, sc, NULL);
     if (ACPI_FAILURE(status))
-        return (ENXIO);
+       return (ENXIO);
     return (0);
 }
 
@@ -654,7 +601,7 @@ acpi_ec_write_method(device_t dev, u_int addr, ACPI_INTEGER val, int width)
     sc = device_get_softc(dev);
     status = EcSpaceHandler(ACPI_WRITE, addr, width * 8, &val, sc, NULL);
     if (ACPI_FAILURE(status))
-        return (ENXIO);
+       return (ENXIO);
     return (0);
 }
 
@@ -664,93 +611,99 @@ 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"));
 
+    /* Serialize user access with EcSpaceHandler(). */
     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));
+       device_printf(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.
+     * interrupt source since we are edge-triggered.  To prevent the GPE
+     * that may arise from running the query from causing another query
+     * to be queued, we clear the pending flag only after running it.
      */
     Status = EcCommand(sc, EC_COMMAND_QUERY);
+    sc->ec_sci_pend = FALSE;
     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;
+       device_printf(sc->ec_dev, "GPE query failed: %s\n",
+           AcpiFormatException(Status));
+       return;
     }
     Data = EC_GET_DATA(sc);
+
+    /*
+     * We have to unlock before running the _Qxx method below since that
+     * method may attempt to read/write from EC address space, causing
+     * recursive acquisition of the lock.
+     */
     EcUnlock(sc);
 
     /* Ignore the value for "no outstanding event". (13.3.5) */
+#if 0
+    CTR2(KTR_ACPI, "ec query ok,%s running _Q%02X", Data ? "" : " not", Data);
+#endif
     if (Data == 0)
-       goto re_enable;
+       return;
 
     /* Evaluate _Qxx to respond to the controller. */
-    ksprintf(qxx, "_Q%02x", Data);
-    strupr(qxx);
+    ksnprintf(qxx, sizeof(qxx), "_Q%02X", Data);
+    AcpiUtStrupr(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));
+       device_printf(sc->ec_dev, "evaluation of query method %s failed: %s\n",
+           qxx, AcpiFormatException(Status));
     }
-
-re_enable:
-    /* Re-enable the GPE event so we'll get future requests. */
-    Status = AcpiEnableGpe(sc->ec_gpehandle, sc->ec_gpebit, ACPI_NOT_ISR);
-    if (ACPI_FAILURE(Status))
-       kprintf("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.
+ * The GPE handler is called when IBE/OBF or SCI events occur.  We are
+ * called from an unknown lock context.
  */
 static uint32_t
 EcGpeHandler(void *Context)
 {
     struct acpi_ec_softc *sc = Context;
     ACPI_STATUS                       Status;
+    EC_STATUS                 EcStatus;
 
     KASSERT(Context != NULL, ("EcGpeHandler called with NULL"));
+#if 0
+    CTR0(KTR_ACPI, "ec gpe handler start");
+#endif
+    /*
+     * Notify EcWaitEvent() that the status register is now fresh.  If we
+     * didn't do this, it wouldn't be possible to distinguish an old IBE
+     * from a new one, for example when doing a write transaction (writing
+     * address and then data values.)
+     */
+    atomic_add_int(&sc->ec_gencount, 1);
+    wakeup(&sc->ec_gencount);
 
-    /* Disable further GPEs while we handle this one. */
-    AcpiDisableGpe(sc->ec_gpehandle, sc->ec_gpebit, ACPI_ISR);
-
-    /* Schedule the GPE query handler. */
-    Status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler,
-               Context);
-    if (ACPI_FAILURE(Status)) {
-       kprintf("Queuing GPE query handler failed.\n");
-       Status = AcpiEnableGpe(sc->ec_gpehandle, sc->ec_gpebit, ACPI_ISR);
-       if (ACPI_FAILURE(Status))
-           kprintf("EcGpeHandler: AcpiEnableEvent failed\n");
+    /*
+     * If the EC_SCI bit of the status register is set, queue a query handler.
+     * It will run the query and _Qxx method later, under the lock.
+     */
+    EcStatus = EC_GET_CSR(sc);
+    if ((EcStatus & EC_EVENT_SCI) && !sc->ec_sci_pend) {
+#if 0
+       CTR0(KTR_ACPI, "ec gpe queueing query handler");
+#endif
+       Status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler, Context);
+       if (ACPI_SUCCESS(Status))
+           sc->ec_sci_pend = TRUE;
+       else
+           kprintf("EcGpeHandler: queuing GPE query handler failed\n");
     }
-
     return (0);
 }
 
@@ -794,12 +747,26 @@ EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width,
     EcAddr = Address;
     Status = AE_ERROR;
 
+    /*
+     * If booting, check if we need to run the query handler.  If so, we
+     * we call it directly here since our thread taskq is not active yet.
+     */
+    if (cold || rebooting) {
+       if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) {
+#if 0
+           CTR0(KTR_ACPI, "ec running gpe handler directly");
+#endif
+           EcGpeQueryHandler(sc);
+       }
+    }
+
+    /* Serialize with EcGpeQueryHandler() at transaction granularity. */
+    Status = EcLock(sc);
+    if (ACPI_FAILURE(Status))
+       return_ACPI_STATUS (Status);
+
     /* Perform the transaction(s), based on width. */
     for (i = 0; i < width; i += 8, EcAddr++) {
-       Status = EcLock(sc);
-       if (ACPI_FAILURE(Status))
-           break;
-
        switch (Function) {
        case ACPI_READ:
            Status = EcRead(sc, EcAddr, &EcData);
@@ -816,199 +783,286 @@ EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width,
            Status = AE_BAD_PARAMETER;
            break;
        }
-       EcUnlock(sc);
        if (ACPI_FAILURE(Status))
            break;
     }
 
+    EcUnlock(sc);
     return_ACPI_STATUS (Status);
 }
 
 static ACPI_STATUS
-EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
+EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event)
 {
-    EC_STATUS  EcStatus;
-    ACPI_STATUS        Status;
-    int                count, i, period, retval, slp_ival;
-    static int EcDbgMaxDelay;
+    ACPI_STATUS status;
+    EC_STATUS ec_status;
 
-    /* mtx_assert(&sc->ec_mtx, MA_OWNED); */
-    Status = AE_NO_HARDWARE_RESPONSE;
+    status = AE_NO_HARDWARE_RESPONSE;
+    ec_status = EC_GET_CSR(sc);
+    if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
+#if 0
+       CTR1(KTR_ACPI, "ec burst disabled in waitevent (%s)", msg);
+#endif
+       sc->ec_burstactive = FALSE;
+    }
+    if (EVENT_READY(event, ec_status)) {
+#if 0
+       CTR2(KTR_ACPI, "ec %s wait ready, status %#x", msg, ec_status);
+#endif
+       status = AE_OK;
+    }
+    return (status);
+}
 
-    /* 
-     * 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);
+static ACPI_STATUS
+EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count)
+{
+    ACPI_STATUS        Status;
+    int                count, i, slp_ival;
 
+    ACPI_SERIAL_ASSERT(ec);
+    Status = AE_NO_HARDWARE_RESPONSE;
+    int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending;
     /*
-     * Poll the EC status register for up to 1 ms in chunks of 10 us
-     * to detect completion of the last command.
+     * The main CPU should be much faster than the EC.  So the status should
+     * be "not ready" when we start waiting.  But if the main CPU is really
+     * slow, it's possible we see the current "ready" response.  Since that
+     * can't be distinguished from the previous response in polled mode,
+     * this is a potential issue.  We really should have interrupts enabled
+     * during boot so there is no ambiguity in polled mode.
+     *
+     * If this occurs, we add an additional delay before actually entering
+     * the status checking loop, hopefully to allow the EC to go to work
+     * and produce a non-stale status.
      */
-    for (i = 0; i < 1000 / EC_POLL_DELAY; i++) {
-       EcStatus = EC_GET_CSR(sc);
-       if (EVENT_READY(Event, EcStatus)) {
-           Status = AE_OK;
-           break;
+    if (need_poll) {
+       static int      once;
+
+       if (EcCheckStatus(sc, "pre-check", Event) == AE_OK) {
+           if (!once) {
+               device_printf(sc->ec_dev,
+                   "warning: EC done before starting event wait\n");
+               once = 1;
+           }
+           AcpiOsStall(10);
        }
-       AcpiOsStall(EC_POLL_DELAY);
     }
-    period = i * EC_POLL_DELAY;
 
-    /*
-     * If we still don't have a response and we're up and running, wait up
-     * to ec_poll_timeout ms for completion, sleeping for chunks of 10 ms.
-     */
-    slp_ival = 0;
-    if (Status != AE_OK) {
-       retval = ENXIO;
-       count = ec_poll_timeout / 10;
+    /* Wait for event by polling or GPE (interrupt). */
+    if (need_poll) {
+       count = (ec_timeout * 1000) / EC_POLL_DELAY;
        if (count == 0)
            count = 1;
-       slp_ival = hz / 100;
-       if (slp_ival == 0)
-           slp_ival = 1;
        for (i = 0; i < count; i++) {
-           if (retval != 0)
-               EcStatus = EC_GET_CSR(sc);
-           else
-               EcStatus = sc->ec_csrvalue;
-           if (EVENT_READY(Event, EcStatus)) {
-               Status = AE_OK;
+           Status = EcCheckStatus(sc, "poll", Event);
+           if (Status == AE_OK)
                break;
+           AcpiOsStall(EC_POLL_DELAY);
+       }
+    } else {
+       slp_ival = hz / 1000;
+       if (slp_ival != 0) {
+           count = ec_timeout;
+       } else {
+           /* hz has less than 1 ms resolution so scale timeout. */
+           slp_ival = 1;
+           count = ec_timeout / (1000 / hz);
+       }
+
+       /*
+        * Wait for the GPE to signal the status changed, checking the
+        * status register each time we get one.  It's possible to get a
+        * GPE for an event we're not interested in here (i.e., SCI for
+        * EC query).
+        */
+       for (i = 0; i < count; i++) {
+           if (gen_count != sc->ec_gencount) {
+               /*
+                * Record new generation count.  It's possible the GPE was
+                * just to notify us that a query is needed and we need to
+                * wait for a second GPE to signal the completion of the
+                * event we are actually waiting for.
+                */
+               gen_count = sc->ec_gencount;
+               Status = EcCheckStatus(sc, "sleep", Event);
+               if (Status == AE_OK)
+                   break;
            }
-           if (!cold)
-               retval = tsleep(&sc->ec_csrvalue, 0, "ecpoll", slp_ival);
-           else
-               AcpiOsStall(10000);
+           tsleep(&sc->ec_gencount, PZERO, "ecgpe", slp_ival);
        }
-    }
 
-    /* Calculate new delay and print it if it exceeds the max. */
-    if (slp_ival > 0)
-       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);
+       /*
+        * We finished waiting for the GPE and it never arrived.  Try to
+        * read the register once and trust whatever value we got.  This is
+        * the best we can do at this point.  Then, force polled mode on
+        * since this system doesn't appear to generate GPEs.
+        */
+       if (Status != AE_OK) {
+           Status = EcCheckStatus(sc, "sleep_end", Event);
+           device_printf(sc->ec_dev,
+               "wait timed out (%sresponse), forcing polled mode\n",
+               Status == AE_OK ? "" : "no ");
+           ec_polled_mode = TRUE;
+       }
     }
-
+#if 0
+    if (Status != AE_OK)
+           CTR0(KTR_ACPI, "error: ec wait timed out");
+#endif
     return (Status);
-}    
+}
 
 static ACPI_STATUS
 EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd)
 {
-    ACPI_STATUS        Status;
-    EC_EVENT   Event;
+    ACPI_STATUS        status;
+    EC_EVENT   event;
+    EC_STATUS  ec_status;
+    u_int      gen_count;
 
-    /*mtx_assert(&sc->ec_mtx, MA_OWNED);*/
+    ACPI_SERIAL_ASSERT(ec);
+
+    /* Don't use burst mode if user disabled it. */
+    if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE)
+       return (AE_ERROR);
 
     /* 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;
+       event = EC_EVENT_INPUT_BUFFER_EMPTY;
        break;
     case EC_COMMAND_QUERY:
     case EC_COMMAND_BURST_ENABLE:
-       Event = EC_EVENT_OUTPUT_BUFFER_FULL;
+       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);
+       device_printf(sc->ec_dev, "EcCommand: invalid command %#x\n", cmd);
        return (AE_BAD_PARAMETER);
     }
 
     /* Run the command and wait for the chosen event. */
+#if 0
+    CTR1(KTR_ACPI, "ec running command %#x", cmd);
+#endif
+    gen_count = sc->ec_gencount;
     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);
+    status = EcWaitEvent(sc, event, gen_count);
+    if (ACPI_SUCCESS(status)) {
+       /* If we succeeded, burst flag should now be present. */
+       if (cmd == EC_COMMAND_BURST_ENABLE) {
+           ec_status = EC_GET_CSR(sc);
+           if ((ec_status & EC_FLAG_BURST_MODE) == 0)
+               status = AE_ERROR;
+       }
+    } else
+       device_printf(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);*/
+    ACPI_STATUS        status;
+    UINT8 data;
+    u_int gen_count;
 
-#ifdef notyet
+    ACPI_SERIAL_ASSERT(ec);
+#if 0
+    CTR1(KTR_ACPI, "ec read from %#x", Address);
+#endif
     /* If we can't start burst mode, continue anyway. */
-    EcCommand(sc, EC_COMMAND_BURST_ENABLE);
+    status = EcCommand(sc, EC_COMMAND_BURST_ENABLE);
+    if (status == AE_OK) {
+       data = EC_GET_DATA(sc);
+       if (data == EC_BURST_ACK) {
+#if 0
+           CTR0(KTR_ACPI, "ec burst enabled");
 #endif
+           sc->ec_burstactive = TRUE;
+       }
+    }
 
-    Status = EcCommand(sc, EC_COMMAND_READ);
-    if (ACPI_FAILURE(Status))
-       return (Status);
+    status = EcCommand(sc, EC_COMMAND_READ);
+    if (ACPI_FAILURE(status))
+       return (status);
 
+    gen_count = sc->ec_gencount;
     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);
+    status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count);
+    if (ACPI_FAILURE(status)) {
+       device_printf(sc->ec_dev, "EcRead: failed waiting to get 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);
-    }
+       sc->ec_burstactive = FALSE;
+       status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
+       if (ACPI_FAILURE(status))
+           return (status);
+#if 0
+       CTR0(KTR_ACPI, "ec disabled burst ok");
 #endif
+    }
 
     return (AE_OK);
-}    
+}
 
 static ACPI_STATUS
 EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
 {
-    ACPI_STATUS        Status;
+    ACPI_STATUS        status;
+    UINT8 data;
+    u_int gen_count;
 
-    /*mtx_assert(&sc->ec_mtx, MA_OWNED);*/
+    ACPI_SERIAL_ASSERT(ec);
+#if 0
+    CTR2(KTR_ACPI, "ec write to %#x, data %#x", Address, *Data);
+#endif
 
-#ifdef notyet
     /* If we can't start burst mode, continue anyway. */
-    EcCommand(sc, EC_COMMAND_BURST_ENABLE);
+    status = EcCommand(sc, EC_COMMAND_BURST_ENABLE);
+    if (status == AE_OK) {
+       data = EC_GET_DATA(sc);
+       if (data == EC_BURST_ACK) {
+#if 0
+           CTR0(KTR_ACPI, "ec burst enabled");
 #endif
+           sc->ec_burstactive = TRUE;
+       }
+    }
 
-    Status = EcCommand(sc, EC_COMMAND_WRITE);
-    if (ACPI_FAILURE(Status))
-       return (Status);
+    status = EcCommand(sc, EC_COMMAND_WRITE);
+    if (ACPI_FAILURE(status))
+       return (status);
 
+    gen_count = sc->ec_gencount;
     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);
+    status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count);
+    if (ACPI_FAILURE(status)) {
+       device_printf(sc->ec_dev, "EcRead: failed waiting for sent address\n");
+       return (status);
     }
 
+    gen_count = sc->ec_gencount;
     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);
+    status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count);
+    if (ACPI_FAILURE(status)) {
+       device_printf(sc->ec_dev, "EcWrite: failed waiting for sent data\n");
+       return (status);
     }
 
-#ifdef notyet
     if (sc->ec_burstactive) {
-       Status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
-       if (ACPI_FAILURE(Status))
-           return (Status);
-    }
+       sc->ec_burstactive = FALSE;
+       status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
+       if (ACPI_FAILURE(status))
+           return (status);
+#if 0
+       CTR0(KTR_ACPI, "ec disabled burst ok");
 #endif
+    }
 
     return (AE_OK);
 }
index 9889a93..9ed7e8c 100644 (file)
@@ -177,7 +177,7 @@ acpi_hpet_probe(device_t dev)
 {
        ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
 
-       if (!acpi_enabled("hpet"))
+       if (acpi_disabled("hpet"))
                return ENXIO;
 
        if (!DEV_HPET(dev) &&
index 9eedf3f..1062287 100644 (file)
@@ -23,7 +23,7 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $DragonFly: src/sys/dev/acpica5/acpi_if.m,v 1.3 2008/09/29 06:59:45 hasso Exp $
+# $FreeBSD: src/sys/dev/acpica/acpi_if.m,v 1.8.8.1 2009/04/15 03:14:26 kensmith Exp $
 #
 
 #include <sys/bus.h>
@@ -86,6 +86,79 @@ METHOD char * id_probe {
 } DEFAULT acpi_generic_id_probe;
 
 #
+# Evaluate an ACPI method or object, given its path.
+#
+# device_t bus:  parent bus for the device
+#
+# device_t dev:  evaluate the object relative to this device's handle.
+#   Specify NULL to begin the search at the ACPI root.
+#
+# ACPI_STRING pathname:  absolute or relative path to this object
+#
+# ACPI_OBJECT_LIST *parameters:  array of arguments to pass to the object.
+#   Specify NULL if there are none.
+#
+# ACPI_BUFFER *ret:  the result (if any) of the evaluation
+#   Specify NULL if there is none.
+#
+# Returns:  AE_OK or an error value
+#
+METHOD ACPI_STATUS evaluate_object {
+       device_t        bus;
+       device_t        dev;
+       ACPI_STRING     pathname;
+       ACPI_OBJECT_LIST *parameters;
+       ACPI_BUFFER     *ret;
+};
+
+#
+# Get the highest power state (D0-D3) that is usable for a device when
+# suspending/resuming.  If a bus calls this when suspending a device, it
+# must also call it when resuming.
+#
+# device_t bus:  parent bus for the device
+#
+# device_t dev:  check this device's appropriate power state
+#
+# int *dstate:  if successful, contains the highest valid sleep state
+#
+# Returns:  0 on success, ESRCH if device has no special state, or
+#   some other error value.
+#
+METHOD int pwr_for_sleep {
+       device_t        bus;
+       device_t        dev;
+       int             *dstate;
+};
+
+#
+# Rescan a subtree and optionally reattach devices to handles.  Users
+# specify a callback that is called for each ACPI_HANDLE of type Device
+# that is a child of "dev".
+#
+# device_t bus:  parent bus for the device
+#
+# device_t dev:  begin the scan starting with this device's handle.
+#   Specify NULL to begin the scan at the ACPI root.
+#
+# int max_depth:  number of levels to traverse (i.e., 1 means just the
+#   immediate children.
+#
+# acpi_scan_cb_t user_fn:  called for each child handle
+#
+# void *arg:  argument to pass to the callback function
+#
+# Returns:  AE_OK or an error value, based on the callback return value
+#
+METHOD ACPI_STATUS scan_children {
+       device_t        bus;
+       device_t        dev;
+       int             max_depth;
+       acpi_scan_cb_t  user_fn;
+       void            *arg;
+};
+
+#
 # Query a given driver for its supported feature(s).  This should be
 # called by the parent bus before the driver is probed.
 #
@@ -149,4 +222,3 @@ METHOD int batt_get_status {
        device_t        dev;
        struct acpi_bst *bst;
 };
-
index d1fde8c..27a5192 100644 (file)
  * 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.8 2004/06/13 22:52:30 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_isab.c,v 1.4 2007/10/23 03:04:48 y0netan1 Exp $
+ * $FreeBSD: src/sys/dev/acpica/acpi_isab.c,v 1.11 2009/06/05 18:44:36 jkim
  */
 
+#include <sys/cdefs.h>
+
 /*
  * ISA Bridge driver for Generic ISA Bus Devices.  See section 10.7 of the
  * ACPI 2.0a specification for details on this device.
@@ -41,7 +41,8 @@
 
 #include "acpi.h"
 #include "accommon.h"
-#include "acpivar.h"
+
+#include <dev/acpica5/acpivar.h>
 #include <bus/isa/isavar.h>
 
 /* Hooks for the ACPI CA debugging infrastructure. */
@@ -91,17 +92,15 @@ MODULE_DEPEND(acpi_isab, acpi, 1, 1, 1);
 static int
 acpi_isab_probe(device_t dev)
 {
-       ACPI_HANDLE h;
-
-       h = acpi_get_handle(dev);
-       if (acpi_get_type(dev) == ACPI_TYPE_DEVICE &&
-           !acpi_disabled("isa") &&
-           devclass_get_device(isab_devclass, 0) == dev &&
-           (acpi_MatchHid(h, "PNP0A05") || acpi_MatchHid(h, "PNP0A06"))) {
-               device_set_desc(dev, "ACPI Generic ISA bridge");
-               return (0);
-       }
-       return (ENXIO);
+       static char *isa_ids[] = { "PNP0A05", "PNP0A06", NULL };
+
+       if (acpi_disabled("isab") ||
+           ACPI_ID_PROBE(device_get_parent(dev), dev, isa_ids) == NULL ||
+           devclass_get_device(isab_devclass, 0) != dev)
+               return (ENXIO);
+
+       device_set_desc(dev, "ACPI Generic ISA bridge");
+       return (0);
 }
 
 static int
index 9cfea99..9633839 100644 (file)
  * 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.23 2004/06/13 22:52:30 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_lid.c,v 1.5 2007/10/23 03:04:48 y0netan1 Exp $
+ * $FreeBSD: src/sys/dev/acpica/acpi_lid.c,v 1.30 2009/06/05 18:44:36 jkim Exp $
  */
 
+#include <sys/cdefs.h>
+
 #include "opt_acpi.h"
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -39,6 +39,7 @@
 
 #include "acpi.h"
 #include "accommon.h"
+
 #include <dev/acpica5/acpivar.h>
 
 /* Hooks for the ACPI CA debugging infrastructure */
@@ -51,6 +52,8 @@ struct acpi_lid_softc {
     int                lid_status;     /* open or closed */
 };
 
+ACPI_SERIAL_DECL(lid, "ACPI lid");
+
 static int     acpi_lid_probe(device_t dev);
 static int     acpi_lid_attach(device_t dev);
 static int     acpi_lid_suspend(device_t dev);
@@ -82,13 +85,16 @@ MODULE_DEPEND(acpi_lid, acpi, 1, 1, 1);
 static int
 acpi_lid_probe(device_t dev)
 {
-    if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("lid") &&
-       acpi_MatchHid(acpi_get_handle(dev), "PNP0C0D")) {
+    static char *lid_ids[] = { "PNP0C0D", NULL };
 
-       device_set_desc(dev, "Control Method Lid Switch");
-       return (0);
-    }
-    return (ENXIO);
+    ACPI_SERIAL_INIT(lid);
+
+    if (acpi_disabled("lid") ||
+       ACPI_ID_PROBE(device_get_parent(dev), dev, lid_ids) == NULL)
+       return (ENXIO);
+
+    device_set_desc(dev, "Control Method Lid Switch");
+    return (0);
 }
 
 static int
@@ -114,23 +120,18 @@ acpi_lid_attach(device_t dev)
     acpi_wake_init(dev, ACPI_GPE_TYPE_WAKE_RUN);
     acpi_wake_set_enable(dev, 1);
 
-    return_VALUE (0);
+    return (0);
 }
 
 static int
 acpi_lid_suspend(device_t dev)
 {
-    struct acpi_softc          *acpi_sc;
-
-    acpi_sc = acpi_device_get_parent_softc(dev);
-    acpi_wake_sleep_prep(dev, acpi_sc->acpi_sstate);
     return (0);
 }
 
 static int
 acpi_lid_resume(device_t dev)
 {
-    acpi_wake_run_prep(dev);
     return (0);
 }
 
@@ -144,6 +145,7 @@ acpi_lid_notify_status_changed(void *arg)
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
     sc = (struct acpi_lid_softc *)arg;
+    ACPI_SERIAL_BEGIN(lid);
 
     /*
      * Evaluate _LID and check the return value, update lid status.
@@ -152,11 +154,11 @@ acpi_lid_notify_status_changed(void *arg)
      */
     status = acpi_GetInteger(sc->lid_handle, "_LID", &sc->lid_status);
     if (ACPI_FAILURE(status))
-       return_VOID;
+       goto out;
 
     acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
     if (acpi_sc == NULL)
-        return_VOID;
+       goto out;
 
     ACPI_VPRINT(sc->lid_dev, acpi_sc, "Lid %s\n",
                sc->lid_status ? "opened" : "closed");
@@ -168,6 +170,8 @@ acpi_lid_notify_status_changed(void *arg)
     else
        EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);
 
+out:
+    ACPI_SERIAL_END(lid);
     return_VOID;
 }
 
@@ -184,7 +188,8 @@ acpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
     sc = (struct acpi_lid_softc *)context;
     switch (notify) {
     case ACPI_NOTIFY_STATUS_CHANGED:
-       AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_lid_notify_status_changed, sc);
+       AcpiOsExecute(OSL_NOTIFY_HANDLER,
+                     acpi_lid_notify_status_changed, sc);
        break;
     default:
        device_printf(sc->lid_dev, "unknown notify %#x\n", notify);
index 1b12384..4123c44 100644 (file)
  * 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.3 2004/04/09 06:40:03 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_package.c,v 1.4 2008/09/05 10:28:35 hasso Exp $
+ * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_package.c,v 1.9.8.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
+#include <sys/cdefs.h>
+
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/sbuf.h>
+
 #include <sys/rman.h>
 
 #include "acpi.h"
@@ -100,33 +101,30 @@ acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size)
 }
 
 int
-acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *rid,
-       struct resource **dst, u_int flags)
+acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid,
+    struct resource **dst, u_int flags)
 {
     ACPI_GENERIC_ADDRESS gas;
-    int error;
+    ACPI_OBJECT *obj;
 
-    error = acpi_PkgRawGas(res, idx, &gas);
-    if (error)
-       return (error);
+    obj = &res->Package.Elements[idx];
+    if (obj == NULL || obj->Type != ACPI_TYPE_BUFFER ||
+       obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3)
+       return (EINVAL);
 
-    *dst = acpi_bus_alloc_gas(dev, rid, &gas, flags);
-    if (*dst == NULL)
-       return (ENXIO);
+    memcpy(&gas, obj->Buffer.Pointer + 3, sizeof(gas));
 
-    return (0);
+    return (acpi_bus_alloc_gas(dev, type, rid, &gas, dst, flags));
 }
 
 int
 acpi_PkgRawGas(ACPI_OBJECT *res, int idx, ACPI_GENERIC_ADDRESS *gas)
 {
-    ACPI_OBJECT                *obj;
-
+    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);
-
+        obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3)
+        return (EINVAL);
     memcpy(gas, obj->Buffer.Pointer + 3, sizeof(*gas));
     return (0);
 }
index 5f8e162..895d6e0 100644 (file)
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
- * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@kfreebsd.org>
  * Copyright (c) 2000, BSDi
  * All rights reserved.
  *
  * 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.16 2004/05/29 04:32:50 njl Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_pci.c,v 1.5 2006/09/05 00:55:36 dillon Exp $
+ * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_pci.c,v 1.31.2.1.6.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
-#include "opt_bus.h"
+#include <sys/cdefs.h>
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -39,7 +37,6 @@
 #include <sys/module.h>
 
 #include "acpi.h"
-#include "accommon.h"
 #include "acpivar.h"
 
 #include <sys/pciio.h>
@@ -57,73 +54,84 @@ ACPI_MODULE_NAME("PCI")
 struct acpi_pci_devinfo {
        struct pci_devinfo      ap_dinfo;
        ACPI_HANDLE             ap_handle;
+       int                     ap_flags;
 };
 
-static int     acpi_pci_probe(device_t dev);
+ACPI_SERIAL_DECL(pci_powerstate, "ACPI PCI power methods");
+
+/* Be sure that ACPI and PCI power states are equivalent. */
+CTASSERT(ACPI_STATE_D0 == PCI_POWERSTATE_D0);
+CTASSERT(ACPI_STATE_D1 == PCI_POWERSTATE_D1);
+CTASSERT(ACPI_STATE_D2 == PCI_POWERSTATE_D2);
+CTASSERT(ACPI_STATE_D3 == PCI_POWERSTATE_D3);
+
 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);
+static int     acpi_pci_suspend(device_t dev);
+static int     acpi_pci_resume(device_t dev);
 static int     acpi_pci_child_location_str_method(device_t cbdev,
                    device_t child, char *buf, size_t buflen);
-
-
-static int     acpi_pci_set_powerstate_method(device_t dev, device_t child,
-                   int state);
+static int     acpi_pci_probe(device_t dev);
+static int     acpi_pci_read_ivar(device_t dev, device_t child, int which,
+                   uintptr_t *result);
+static int     acpi_pci_write_ivar(device_t dev, device_t child, int which,
+                   uintptr_t value);
 static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level,
                    void *context, void **status);
+static int     acpi_pci_set_powerstate_method(device_t dev, device_t child,
+                   int state);
+static void    acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child);
 
 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,        bus_generic_resume),
+        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
+        DEVMETHOD(device_suspend,       acpi_pci_suspend),
+        DEVMETHOD(device_resume,        acpi_pci_resume),
 
        /* Bus interface */
-       DEVMETHOD(bus_print_child,      pci_print_child),
-       DEVMETHOD(bus_probe_nomatch,    pci_probe_nomatch),
+       DEVMETHOD(bus_print_child,      pci_print_child),
+        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_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_write_ivar,       acpi_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_child_location_str, acpi_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),
-       DEVMETHOD(pci_get_powerstate,   pci_get_powerstate_method),
        DEVMETHOD(pci_set_powerstate,   acpi_pci_set_powerstate_method),
-       DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
+        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),
+        DEVMETHOD(pci_get_powerstate,   pci_get_powerstate_method),
+        DEVMETHOD(pci_set_powerstate,   acpi_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 */
+        "pci",
+        acpi_pci_methods,
+        0,                      /* no softc */
 };
 
 static devclass_t pci_devclass;
 
 DRIVER_MODULE(acpi_pci, pcib, acpi_pci_driver, pci_devclass, 0, 0);
 MODULE_DEPEND(acpi_pci, acpi, 1, 1, 1);
+MODULE_DEPEND(acpi_pci, pci, 1, 1, 1);
 MODULE_VERSION(acpi_pci, 1);
 
 static int
@@ -131,16 +139,36 @@ acpi_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
 {
     struct acpi_pci_devinfo *dinfo;
 
+    dinfo = device_get_ivars(child);
     switch (which) {
     case ACPI_IVAR_HANDLE:
-       dinfo = device_get_ivars(child);
        *result = (uintptr_t)dinfo->ap_handle;
        return (0);
+    case ACPI_IVAR_FLAGS:
+       *result = (uintptr_t)dinfo->ap_flags;
+       return (0);
     }
     return (pci_read_ivar(dev, child, which, result));
 }
 
 static int
+acpi_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+    struct acpi_pci_devinfo *dinfo;
+
+    dinfo = device_get_ivars(child);
+    switch (which) {
+    case ACPI_IVAR_HANDLE:
+       dinfo->ap_handle = (ACPI_HANDLE)value;
+       return (0);
+    case ACPI_IVAR_FLAGS:
+       dinfo->ap_flags = (int)value;
+       return (0);
+    }
+    return (pci_write_ivar(dev, child, which, value));
+}
+
+static int
 acpi_pci_child_location_str_method(device_t cbdev, device_t child, char *buf,
     size_t buflen)
 {
@@ -149,7 +177,7 @@ acpi_pci_child_location_str_method(device_t cbdev, device_t child, char *buf,
     pci_child_location_str_method(cbdev, child, buf, buflen);
 
     if (dinfo->ap_handle) {
-       strlcat(buf, " path=", buflen);
+       strlcat(buf, " handle=", buflen);
        strlcat(buf, acpi_name(dinfo->ap_handle), buflen);
     }
     return (0);
@@ -163,24 +191,11 @@ acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
 {
        ACPI_HANDLE h;
        ACPI_STATUS status;
-       int acpi_state, old_state, error;
-
-       switch (state) {
-       case PCI_POWERSTATE_D0:
-               acpi_state = ACPI_STATE_D0;
-               break;
-       case PCI_POWERSTATE_D1:
-               acpi_state = ACPI_STATE_D1;
-               break;
-       case PCI_POWERSTATE_D2:
-               acpi_state = ACPI_STATE_D2;
-               break;
-       case PCI_POWERSTATE_D3:
-               acpi_state = ACPI_STATE_D3;
-               break;
-       default:
+       int old_state, error;
+
+       error = 0;
+       if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
                return (EINVAL);
-       }
 
        /*
         * We set the state using PCI Power Management outside of setting
@@ -191,25 +206,70 @@ acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
         * it can enable any needed Power Resources before changing the PCI
         * power state.
         */
+       ACPI_SERIAL_BEGIN(pci_powerstate);
        old_state = pci_get_powerstate(child);
        if (old_state < state) {
                error = pci_set_powerstate_method(dev, child, state);
                if (error)
-                       return (error);
+                       goto out;
        }
        h = acpi_get_handle(child);
-       if (h != NULL) {
-               status = acpi_pwr_switch_consumer(h, acpi_state);
-               if (ACPI_FAILURE(status))
-                       device_printf(dev,
-                           "Failed to set ACPI power state D%d on %s: %s\n",
-                           acpi_state, device_get_nameunit(child),
-                           AcpiFormatException(status));
-       }
+       status = acpi_pwr_switch_consumer(h, state);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+               device_printf(dev,
+                   "Failed to set ACPI power state D%d on %s: %s\n",
+                   state, acpi_name(h), AcpiFormatException(status));
        if (old_state > state)
-               return (pci_set_powerstate_method(dev, child, state));
-       else
-               return (0);
+               error = pci_set_powerstate_method(dev, child, state);
+
+out:
+       ACPI_SERIAL_END(pci_powerstate);
+       return (error);
+}
+
+static void
+acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child)
+{
+       ACPI_STATUS status;
+       device_t child;
+
+       /*
+        * Lookup and remove the unused device that acpi0 creates when it walks
+        * the namespace creating devices.
+        */
+       child = acpi_get_device(handle);
+       if (child != NULL) {
+               if (device_is_alive(child)) {
+                       /*
+                        * The TabletPC TC1000 has a second PCI-ISA bridge
+                        * that has a _HID for an acpi_sysresource device.
+                        * In that case, leave ACPI-CA's device data pointing
+                        * at the ACPI-enumerated device.
+                        */
+                       device_printf(child,
+                           "Conflicts with PCI device %d:%d:%d\n",
+                           pci_get_bus(pci_child), pci_get_slot(pci_child),
+                           pci_get_function(pci_child));
+                       return;
+               }
+               KASSERT(device_get_parent(child) ==
+                   devclass_get_device(devclass_find("acpi"), 0),
+                   ("%s: child (%s)'s parent is not acpi0", __func__,
+                   acpi_name(handle)));
+               device_delete_child(device_get_parent(child), child);
+       }
+
+       /*
+        * Update ACPI-CA to use the PCI enumerated device_t for this handle.
+        */
+       status = AcpiDetachData(handle, acpi_fake_objhandler);
+       if (ACPI_FAILURE(status))
+               kprintf("WARNING: Unable to detach object data from %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(status));
+       status = AcpiAttachData(handle, acpi_fake_objhandler, pci_child);
+       if (ACPI_FAILURE(status))
+               kprintf("WARNING: Unable to attach object data to %s - %s\n",
+                   acpi_name(handle), AcpiFormatException(status));
 }
 
 static ACPI_STATUS
@@ -225,8 +285,8 @@ acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,
 
        if (ACPI_FAILURE(acpi_GetInteger(handle, "_ADR", &address)))
                return_ACPI_STATUS (AE_OK);
-       slot = address >> 16;
-       func = address & 0xffff;
+       slot = ACPI_ADR_PCI_SLOT(address);
+       func = ACPI_ADR_PCI_FUNC(address);
        if (device_get_children((device_t)context, &devlist, &devcount) != 0)
                return_ACPI_STATUS (AE_OK);
        for (i = 0; i < devcount; i++) {
@@ -234,8 +294,8 @@ acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,
                if (dinfo->ap_dinfo.cfg.func == func &&
                    dinfo->ap_dinfo.cfg.slot == slot) {
                        dinfo->ap_handle = handle;
-                       kfree(devlist, M_TEMP);
-                       return_ACPI_STATUS (AE_OK);
+                       acpi_pci_update_device(handle, devlist[i]);
+                       break;
                }
        }
        kfree(devlist, M_TEMP);
@@ -245,7 +305,8 @@ acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,
 static int
 acpi_pci_probe(device_t dev)
 {
-       if (pcib_get_bus(device_get_parent(dev)) < 0)
+
+       if (pcib_get_bus(dev) < 0)
                return (ENXIO);
        if (acpi_get_handle(dev) == NULL)
                return (ENXIO);
@@ -260,15 +321,15 @@ acpi_pci_attach(device_t dev)
 
        /*
         * 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.
+        * busses on systems with multiple PCI domains, we can't use
+        * the unit number to decide which bus we are probing. We ask
+        * the parent pcib what our domain and bus numbers are.
         */
-       busno = pcib_get_bus(device_get_parent(dev));
+       busno = pcib_get_bus(dev);
+       domain = pcib_get_domain(dev);
        if (bootverbose)
-               device_printf(dev, "physical bus=%d\n", busno);
-
-       domain = pcib_get_domain(device_get_parent(dev));
+              device_printf(dev, "domain=%d, physical bus=%d\n",
+                    domain, busno);
 
        /*
         * First, PCI devices are added as in the normal PCI bus driver.
@@ -286,3 +347,79 @@ acpi_pci_attach(device_t dev)
 
        return (bus_generic_attach(dev));
 }
+
+int
+acpi_pci_suspend(device_t dev)
+{
+        int dstate, error, i, numdevs;
+        device_t acpi_dev, child, *devlist;
+        struct pci_devinfo *dinfo;
+        /*
+         * Save the PCI configuration space for each child and set the
+         * device in the appropriate power state for this sleep state.
+         */
+        acpi_dev = NULL;
+       acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
+        device_get_children(dev, &devlist, &numdevs);
+        for (i = 0; i < numdevs; i++) {
+                child = devlist[i];
+                dinfo = (struct pci_devinfo *) device_get_ivars(child);
+                pci_cfg_save(child, dinfo, 0);
+        }
+        /* Suspend devices before potentially powering them down. */
+        error = bus_generic_suspend(dev);
+        if (error) {
+                kfree(devlist, M_TEMP);
+                return (error);
+        }
+        /*
+         * Always set the device to D3.  If ACPI suggests a different
+         * power state, use it instead.  If ACPI is not present, the
+         * firmware is responsible for managing device power.  Skip
+         * children who aren't attached since they are powered down
+         * separately.  Only manage type 0 devices for now.
+         */
+        for (i = 0; acpi_dev && i < numdevs; i++) {
+                child = devlist[i];
+                dinfo = (struct pci_devinfo *) device_get_ivars(child);
+                if (device_is_attached(child) && dinfo->cfg.hdrtype == 0) {
+                        dstate = PCI_POWERSTATE_D3;
+                        ACPI_PWR_FOR_SLEEP(acpi_dev, child, &dstate);
+                        pci_set_powerstate(child, dstate);
+                }
+        }
+        kfree(devlist, M_TEMP);
+        return (0);
+}
+
+int
+acpi_pci_resume(device_t dev)
+{
+        int i, numdevs;
+        device_t acpi_dev, child, *devlist;
+        struct pci_devinfo *dinfo;
+        /*
+         * Set each child to D0 and restore its PCI configuration space.
+         */
+        acpi_dev = NULL;
+       acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
+        device_get_children(dev, &devlist, &numdevs);
+        for (i = 0; i < numdevs; i++) {
+                /*
+                 * Notify ACPI we're going to D0 but ignore the result.  If
+                 * ACPI is not present, the firmware is responsible for
+                 * managing device power.  Only manage type 0 devices for now.
+                 */
+                child = devlist[i];
+                dinfo = (struct pci_devinfo *) device_get_ivars(child);
+                if (acpi_dev && device_is_attached(child) &&
+                    dinfo->cfg.hdrtype == 0) {
+                       ACPI_PWR_FOR_SLEEP(acpi_dev, child, NULL);
+                        pci_set_powerstate(child, PCI_POWERSTATE_D0);
+                }
+                /* Now the device is powered up, restore its config space. */
+                pci_cfg_restore(child, dinfo);
+        }
+        kfree(devlist, M_TEMP);
+        return (bus_generic_resume(dev));
+}
index 42e0ca8..24c9d12 100644 (file)
@@ -1,5 +1,5 @@
-/*-
- * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+/*
+ * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.kfreebsd.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * 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.16 2004/06/14 18:54:14 jhb Exp $
- * $DragonFly: src/sys/dev/acpica5/acpi_pci_link.c,v 1.7 2006/12/22 23:26:14 swildner Exp $
+ * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_pci_link.c,v 1.56.2.1.6.1 2009/04/15 03:14:26 kensmith Exp $");
  */
 
+#define MPASS(ex)               MPASS4(ex, #ex, __FILE__, __LINE__)
+#define MPASS4(ex, what, file, line)                                    \
+        KASSERT((ex), ("Assertion %s failed at %s:%d", what, file, line))
+
+#include <sys/cdefs.h>
+
 #include "opt_acpi.h"
 #include <sys/param.h>
-#include <sys/kernel.h>
 #include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
 
 #include "acpi.h"
-#include "accommon.h"
 #include <dev/acpica5/acpivar.h>
 #include <dev/acpica5/acpi_pcibvar.h>
 
+#include <bus/pci/i386/pci_cfgreg.h>
+#include <bus/pci/pcireg.h>
+#include <bus/pci/pcivar.h>
+#include "pcib_if.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;
+ACPI_SERIAL_DECL(pci_link, "ACPI PCI link");
+
+#define NUM_ISA_INTERRUPTS     16
+#define NUM_ACPI_INTERRUPTS    256
+
+/*
+ * An ACPI PCI link device may contain multiple links.  Each link has its
+ * own ACPI resource.  _PRT entries specify which link is being used via
+ * the Source Index.
+ *
+ * XXX: A note about Source Indices and DPFs:  Currently we assume that
+ * the DPF start and end tags are not counted towards the index that
+ * Source Index corresponds to.  Also, we assume that when DPFs are in use
+ * they various sets overlap in terms of Indices.  Here's an example
+ * resource list indicating these assumptions:
+ *
+ * Resource            Index
+ * --------            -----
+ * I/O Port            0
+ * Start DPF           -
+ * IRQ                 1
+ * MemIO               2
+ * Start DPF           -
+ * IRQ                 1
+ * MemIO               2
+ * End DPF             -
+ * DMA Channel         3
+ *
+ * The XXX is because I'm not sure if this is a valid assumption to make.
+ */
+
+/* States during DPF processing. */
+#define        DPF_OUTSIDE     0
+#define        DPF_FIRST       1
+#define        DPF_IGNORE      2
+
+struct link;
+
+struct acpi_pci_link_softc {
+       int     pl_num_links;
+       int     pl_crs_bad;
+       struct link *pl_links;
+       device_t pl_dev;
 };
 
-TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
-static struct acpi_pci_link_entries acpi_pci_link_entries;
+struct link {
+       struct acpi_pci_link_softc *l_sc;
+       uint8_t l_bios_irq;
+       uint8_t l_irq;
+       uint8_t l_initial_irq;
+       int     l_res_index;
+       int     l_num_irqs;
+       int     *l_irqs;
+       int     l_references;
+       int     l_routed:1;
+       int     l_isa_irq:1;
+       ACPI_RESOURCE l_prs_template;
+};
 
-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;
+struct link_count_request {
+       int     in_dpf;
+       int     count;
 };
 
-TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
-static struct acpi_prt_entries acpi_prt_entries;
+struct link_res_request {
+       struct acpi_pci_link_softc *sc;
+       int     in_dpf;
+       int     res_index;
+       int     link_index;
+};
+
+MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures");
 
-static int     irq_penalty[MAX_ACPI_INTERRUPTS];
+static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS];
+static int pci_link_bios_isa_irqs;
 
-#define ACPI_STA_PRESENT       0x00000001
-#define ACPI_STA_ENABLE                0x00000002
-#define ACPI_STA_SHOWINUI      0x00000004
-#define ACPI_STA_FUNCTIONAL    0x00000008
+static char *pci_link_ids[] = { "PNP0C0F", NULL };
 
 /*
- * PCI link object management
+ * Fetch the short name associated with an ACPI handle and save it in the
+ * passed in buffer.
  */
-
-static void
-acpi_pci_link_dump_polarity(UINT32 Polarity)
+static ACPI_STATUS
+acpi_short_name(ACPI_HANDLE handle, char *buffer, size_t buflen)
 {
+       ACPI_BUFFER buf;
 
-       switch (Polarity) {
-       case ACPI_ACTIVE_HIGH:
-               kprintf("high,");
-               break;
-       case ACPI_ACTIVE_LOW:
-               kprintf("low,");
-               break;
-       default:
-               kprintf("unknown,");
-               break;
-       }
+       buf.Length = buflen;
+       buf.Pointer = buffer;
+       return (AcpiGetName(handle, ACPI_SINGLE_NAME, &buf));
 }
 
-static void
-acpi_pci_link_dump_trigger(UINT32 Triggering)
+static int
+acpi_pci_link_probe(device_t dev)
 {
+       char descr[28], name[12];
 
-       switch (Triggering) {
-       case ACPI_EDGE_SENSITIVE:
-               kprintf("edge,");
-               break;
-       case ACPI_LEVEL_SENSITIVE:
-               kprintf("level,");
-               break;
-       default:
-               kprintf("unknown,");
-               break;
-       }
+       /*
+        * We explicitly do not check _STA since not all systems set it to
+        * sensible values.
+        */
+       if (acpi_disabled("pci_link") ||
+           ACPI_ID_PROBE(device_get_parent(dev), dev, pci_link_ids) == NULL)
+               return (ENXIO);
+
+       if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), name,
+           sizeof(name)))) {
+               ksnprintf(descr, sizeof(descr), "ACPI PCI Link %s", name);
+               device_set_desc_copy(dev, descr);
+       } else
+               device_set_desc(dev, "ACPI PCI Link");
+       device_quiet(dev);
+       return (0);
 }
 
-static void
-acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
+static ACPI_STATUS
+acpi_count_irq_resources(ACPI_RESOURCE *res, void *context)
 {
-
-       switch (SharedExclusive) {
-       case ACPI_EXCLUSIVE:
-               kprintf("exclusive");
+       struct link_count_request *req;
+
+       req = (struct link_count_request *)context;
+       switch (res->Type) {
+       case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+               switch (req->in_dpf) {
+               case DPF_OUTSIDE:
+                       /* We've started the first DPF. */
+                       req->in_dpf = DPF_FIRST;
+                       break;
+               case DPF_FIRST:
+                       /* We've started the second DPF. */
+                       req->in_dpf = DPF_IGNORE;
+                       break;
+               }
                break;
-       case ACPI_SHARED:
-               kprintf("sharable");
+       case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+               /* We are finished with DPF parsing. */
+               KASSERT(req->in_dpf != DPF_OUTSIDE,
+                   ("%s: end dpf when not parsing a dpf", __func__));
+               req->in_dpf = DPF_OUTSIDE;
                break;
-       default:
-               kprintf("unknown");
-               break;
-       }
-}
-
-static void
-acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
-{
-       UINT8                   i;
-       ACPI_RESOURCE_IRQ       *Irq;
-       ACPI_RESOURCE_EXTENDED_IRQ      *ExtIrq;
-
-       if (entry == NULL || entry->pci_link == NULL)
-               return;
-
-       kprintf("%s irq %3d: ", acpi_name(entry->pci_link->handle),
-           entry->pci_link->current_irq);
-
-       kprintf("[");
-       for (i = 0; i < entry->pci_link->number_of_interrupts; i++)
-               kprintf("%3d", entry->pci_link->interrupts[i]);
-       kprintf("] ");
-
-       switch (entry->pci_link->possible_resources.Type) {
        case ACPI_RESOURCE_TYPE_IRQ:
-               Irq = &entry->pci_link->possible_resources.Data.Irq;
-               acpi_pci_link_dump_polarity(Irq->Polarity);
-               acpi_pci_link_dump_trigger(Irq->Triggering);
-               acpi_pci_link_dump_sharemode(Irq->Sharable);
-               break;
        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-               ExtIrq = &entry->pci_link->possible_resources.Data.ExtendedIrq;
-               acpi_pci_link_dump_polarity(ExtIrq->Polarity);
-               acpi_pci_link_dump_trigger(ExtIrq->Triggering);
-               acpi_pci_link_dump_sharemode(ExtIrq->Sharable);
-               break;
+               /*
+                * Don't count resources if we are in a DPF set that we are
+                * ignoring.
+                */
+               if (req->in_dpf != DPF_IGNORE)
+                       req->count++;
        }
-
-       kprintf(" %d.%d.%d\n", entry->busno,
-           (int)((entry->prt.Address & 0xffff0000) >> 16),
-           (int)entry->prt.Pin);
+       return (AE_OK);
 }
 
 static ACPI_STATUS
-acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
+link_add_crs(ACPI_RESOURCE *res, void *context)
 {
-       ACPI_DEVICE_INFO        *devinfo;
-       ACPI_BUFFER             buf;
-       ACPI_STATUS             error;
-
-       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
-       if (handle == NULL || sta == NULL) {
-               kprintf("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)) {
-               kprintf("couldn't get object info %s - %s\n",
-                   acpi_name(handle), AcpiFormatException(error));
-               return_ACPI_STATUS (error);
-       }
+       struct link_res_request *req;
+       struct link *link;
+
+       ACPI_SERIAL_ASSERT(pci_link);
+       req = (struct link_res_request *)context;
+       switch (res->Type) {
+       case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+               switch (req->in_dpf) {
+               case DPF_OUTSIDE:
+                       /* We've started the first DPF. */
+                       req->in_dpf = DPF_FIRST;
+                       break;
+               case DPF_FIRST:
+                       /* We've started the second DPF. */
+                       panic(
+               "%s: Multiple dependent functions within a current resource",
+                           __func__);
+                       break;
+               }
+               break;
+       case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+               /* We are finished with DPF parsing. */
+               KASSERT(req->in_dpf != DPF_OUTSIDE,
+                   ("%s: end dpf when not parsing a dpf", __func__));
+               req->in_dpf = DPF_OUTSIDE;
+               break;
+       case ACPI_RESOURCE_TYPE_IRQ:
+       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+               KASSERT(req->link_index < req->sc->pl_num_links,
+                   ("%s: array boundary violation", __func__));
+               link = &req->sc->pl_links[req->link_index];
+               link->l_res_index = req->res_index;
+               req->link_index++;
+               req->res_index++;
 
-       devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
-       if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
-           strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
-               kprintf("invalid hardware ID - %s\n", acpi_name(handle));
-               AcpiOsFree(buf.Pointer);
-               return_ACPI_STATUS (AE_TYPE);
-       }
+               /*
+                * Only use the current value if there's one IRQ.  Some
+                * systems return multiple IRQs (which is nonsense for _CRS)
+                * when the link hasn't been programmed.
+                */
+               if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
+                       if (res->Data.Irq.InterruptCount == 1)
+                               link->l_irq = res->Data.Irq.Interrupts[0];
+               } else if (res->Data.ExtendedIrq.InterruptCount == 1)
+                       link->l_irq = res->Data.ExtendedIrq.Interrupts[0];
 
-       if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
-               *sta = devinfo->CurrentStatus;
-       } else {
-               kprintf("invalid status - %s\n", acpi_name(handle));
-               *sta = 0;
+               /*
+                * An IRQ of zero means that the link isn't routed.
+                */
+               if (link->l_irq == 0)
+                       link->l_irq = PCI_INVALID_IRQ;
+               break;
+       default:
+               req->res_index++;
        }
-
-       AcpiOsFree(buf.Pointer);
-       return_ACPI_STATUS (AE_OK);
+       return (AE_OK);
 }
 
+/*
+ * Populate the set of possible IRQs for each device.
+ */
 static ACPI_STATUS
-acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
-    UINT8 *number_of_interrupts, UINT8 interrupts[])
+link_add_prs(ACPI_RESOURCE *res, void *context)
 {
-       UINT8                   count;
-       UINT8                   i;
-       UINT32                  InterruptCount;
-       UINT32                  *Interrupts32;
-       UINT8                   *Interrupts8;
-
-       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
-       if (resources == NULL || number_of_interrupts == NULL) {
-               kprintf("invalid argument\n");
-               return_ACPI_STATUS (AE_BAD_PARAMETER);
-       }
-
-       *number_of_interrupts = 0;
-       InterruptCount = 0;
-       Interrupts8 = NULL;
-       Interrupts32 = NULL;
-
-       if (resources->Type == ACPI_RESOURCE_TYPE_START_DEPENDENT)
-               resources = ACPI_NEXT_RESOURCE(resources);
-
-       if (resources->Type != ACPI_RESOURCE_TYPE_IRQ &&
-           resources->Type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
-               kprintf("Resource is not an IRQ entry - %d\n", resources->Type);
-               return_ACPI_STATUS (AE_TYPE);
-       }
-
-       switch (resources->Type) {
-       case ACPI_RESOURCE_TYPE_IRQ:
-               InterruptCount = resources->Data.Irq.InterruptCount;
-               Interrupts8 = resources->Data.Irq.Interrupts;
+       struct link_res_request *req;
+       struct link *link;
+       UINT8 *irqs = NULL;
+       UINT32 *ext_irqs = NULL;
+       int i, is_ext_irq = 1;
+
+       ACPI_SERIAL_ASSERT(pci_link);
+       req = (struct link_res_request *)context;
+       switch (res->Type) {
+       case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+               switch (req->in_dpf) {
+               case DPF_OUTSIDE:
+                       /* We've started the first DPF. */
+                       req->in_dpf = DPF_FIRST;
+                       break;
+               case DPF_FIRST:
+                       /* We've started the second DPF. */
+                       req->in_dpf = DPF_IGNORE;
+                       break;
+               }
                break;
-       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-                InterruptCount =
-                   resources->Data.ExtendedIrq.InterruptCount;
-                Interrupts32 = resources->Data.ExtendedIrq.Interrupts;
+       case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+               /* We are finished with DPF parsing. */
+               KASSERT(req->in_dpf != DPF_OUTSIDE,
+                   ("%s: end dpf when not parsing a dpf", __func__));
+               req->in_dpf = DPF_OUTSIDE;
                break;
-       }
-       
-       if (InterruptCount == 0) {
-               kprintf("Blank IRQ resource\n");
-               return_ACPI_STATUS (AE_NULL_ENTRY);
-       }
-
-       count = 0;
-       for (i = 0; i < InterruptCount; i++) {
-               UINT32 intr;
-
-               if (i >= MAX_POSSIBLE_INTERRUPTS) {
-                       kprintf("too many IRQs (%d)\n", i);
+       case ACPI_RESOURCE_TYPE_IRQ:
+               is_ext_irq = 0;
+               /* fall through */
+       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+               /*
+                * Don't parse resources if we are in a DPF set that we are
+                * ignoring.
+                */
+               if (req->in_dpf == DPF_IGNORE)
                        break;
+
+               KASSERT(req->link_index < req->sc->pl_num_links,
+                   ("%s: array boundary violation", __func__));
+               link = &req->sc->pl_links[req->link_index];
+               if (link->l_res_index == -1) {
+                       KASSERT(req->sc->pl_crs_bad,
+                           ("res_index should be set"));
+                       link->l_res_index = req->res_index;
                }
+               req->link_index++;
+               req->res_index++;
 
-               KKASSERT(Interrupts8 != NULL || Interrupts32 != NULL);
-               if (Interrupts8 != NULL)
-                       intr = Interrupts8[i];
-               else
-                       intr = Interrupts32[i];
+               /*
+                * Stash a copy of the resource for later use when doing
+                * _SRS.
+                */
+               bcopy(res, &link->l_prs_template, sizeof(ACPI_RESOURCE));
+               if (is_ext_irq) {
+                       link->l_num_irqs =
+                           res->Data.ExtendedIrq.InterruptCount;
+                       ext_irqs = res->Data.ExtendedIrq.Interrupts;
+               } else {
+                       link->l_num_irqs = res->Data.Irq.InterruptCount;
+                       irqs = res->Data.Irq.Interrupts;
+               }
+               if (link->l_num_irqs == 0)
+                       break;
 
-               if (intr == 0) {
-                       kprintf("invalid IRQ %d\n", intr);
-                       continue;
+               /*
+                * Save a list of the valid IRQs.  Also, if all of the
+                * valid IRQs are ISA IRQs, then mark this link as
+                * routed via an ISA interrupt.
+                */
+               link->l_isa_irq = TRUE;
+
+               link->l_irqs = kmalloc(sizeof(int) * link->l_num_irqs,
+                   M_PCI_LINK, M_WAITOK | M_ZERO);
+               for (i = 0; i < link->l_num_irqs; i++) {
+                       if (is_ext_irq) {
+                               link->l_irqs[i] = ext_irqs[i];
+                               if (ext_irqs[i] >= NUM_ISA_INTERRUPTS)
+                                       link->l_isa_irq = FALSE;
+                       } else {
+                               link->l_irqs[i] = irqs[i];
+                               if (irqs[i] >= NUM_ISA_INTERRUPTS)
+                                       link->l_isa_irq = FALSE;
+                       }
                }
-               interrupts[count] = intr;
-               count++;
+               break;
+       default:
+               if (req->in_dpf == DPF_IGNORE)
+                       break;
+               if (req->sc->pl_crs_bad)
+                       device_printf(req->sc->pl_dev,
+                   "Warning: possible resource %d will be lost during _SRS\n",
+                           req->res_index);
+               req->res_index++;
        }
-       *number_of_interrupts = count;
-
-       return_ACPI_STATUS (AE_OK);
+       return (AE_OK);
 }
 
-static ACPI_STATUS
-acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
+static int
+link_valid_irq(struct link *link, int 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) {
-               kprintf("invalid argument\n");
-               return_ACPI_STATUS (AE_BAD_PARAMETER);
-       }
+       int i;
 
-       *irq = 0;
-       buf.Pointer = NULL;
-       buf.Length = ACPI_ALLOCATE_BUFFER;
-       error = AcpiGetCurrentResources(link->handle, &buf);
-       if (ACPI_FAILURE(error)) {
-               kprintf("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) {
-               kprintf("couldn't allocate memory - %s\n",
-                   acpi_name(link->handle));
-               return_ACPI_STATUS (AE_NO_MEMORY);
-       }
+       ACPI_SERIAL_ASSERT(pci_link);
 
-       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)) {
-               kprintf("couldn't get current IRQ from "
-                   "interrupt link %s - %s\n",
-                   acpi_name(link->handle), AcpiFormatException(error));
-               return_ACPI_STATUS (error);
-       }
+       /* Invalid interrupts are never valid. */
+       if (!PCI_INTERRUPT_VALID(irq))
+               return (FALSE);
 
-       if (number_of_interrupts == 0) {
-               kprintf("PCI interrupt link device _CRS data is corrupted - "
-                   "%s\n", acpi_name(link->handle));
-               return_ACPI_STATUS (AE_NULL_ENTRY);
-       }
+       /* Any interrupt in the list of possible interrupts is valid. */
+       for (i = 0; i < link->l_num_irqs; i++)
+               if (link->l_irqs[i] == irq)
+                        return (TRUE);
 
-       *irq = interrupts[0];
+       /*
+        * For links routed via an ISA interrupt, if the SCI is routed via
+        * an ISA interrupt, the SCI is always treated as a valid IRQ.
+        */
+       if (link->l_isa_irq && AcpiGbl_FADT.SciInterrupt == irq &&
+           irq < NUM_ISA_INTERRUPTS)
+               return (TRUE);
 
-       return_ACPI_STATUS (AE_OK);
+       /* If the interrupt wasn't found in the list it is not valid. */
+       return (FALSE);
 }
 
-static ACPI_STATUS
-acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
+static void
+acpi_pci_link_dump(struct acpi_pci_link_softc *sc, int header, const char *tag)
 {
-       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);
-               }
+       struct link *link;
+       char buf[16];
+       int i, j;
+
+       ACPI_SERIAL_ASSERT(pci_link);
+       if (header) {
+               ksnprintf(buf, sizeof(buf), "%s:",
+                   device_get_nameunit(sc->pl_dev));
+               kprintf("%-16.16s  Index  IRQ  Rtd  Ref  IRQs\n", buf);
        }
-
-       link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
-       if (link == NULL) {
-               kprintf("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)) {
-               kprintf("couldn't get current IRQ from "
-                   "interrupt link %s - %s\n",
-                   acpi_name(handle), AcpiFormatException(error));
-       }
-
-       link->initial_irq = link->current_irq;
-
-       error = AcpiGetPossibleResources(handle, &buf);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't get interrupt link device _PRS "
-                   "data %s - %s\n",
-                   acpi_name(handle), AcpiFormatException(error));
-               goto out;
-       }
-       if (buf.Pointer == NULL) {
-               kprintf("_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)) {
-               kprintf("couldn't get possible IRQs from "
-                   "interrupt link %s - %s\n",
-                   acpi_name(handle), AcpiFormatException(error));
-               goto out;
-       }
-
-       if (link->number_of_interrupts == 0) {
-               kprintf("interrupt link device _PRS data is corrupted - %s\n",
-                   acpi_name(handle));
-               error = AE_NULL_ENTRY;
-               goto out;
+       for (i = 0; i < sc->pl_num_links; i++) {
+               link = &sc->pl_links[i];
+               kprintf("  %-14.14s  %5d  %3d   %c   %3d ", i == 0 ? tag : "", i,
+                   link->l_irq, link->l_routed ? 'Y' : 'N',
+                   link->l_references);
+               if (link->l_num_irqs == 0)
+                       kprintf(" none");
+               else for (j = 0; j < link->l_num_irqs; j++)
+                       kprintf(" %d", link->l_irqs[j]);
+               kprintf("\n");
        }
-
-       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)
+static int
+acpi_pci_link_attach(device_t dev)
 {
-       ACPI_HANDLE             handle;
-       ACPI_STATUS             error;
-       UINT32                  sta;
-       struct acpi_prt_entry   *entry;
+       struct acpi_pci_link_softc *sc;
+       struct link_count_request creq;
+       struct link_res_request rreq;
+       ACPI_STATUS status;
+       int i;
 
-       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
-       if (prt == NULL || prt->Source == NULL || prt->Source[0] == '\0') {
-               kprintf("couldn't handle this routing table - hardwired\n");
-               return_ACPI_STATUS (AE_BAD_PARAMETER);
-       }
+       sc = device_get_softc(dev);
+       sc->pl_dev = dev;
+       ACPI_SERIAL_BEGIN(pci_link);
 
-       error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't get handle - %s\n",
-                   AcpiFormatException(error));
-               return_ACPI_STATUS (error);
+       /*
+        * Count the number of current resources so we know how big of
+        * a link array to allocate.  On some systems, _CRS is broken,
+        * so for those systems try to derive the count from _PRS instead.
+        */
+       creq.in_dpf = DPF_OUTSIDE;
+       creq.count = 0;
+       status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
+           acpi_count_irq_resources, &creq);
+       sc->pl_crs_bad = ACPI_FAILURE(status);
+       if (sc->pl_crs_bad) {
+               creq.in_dpf = DPF_OUTSIDE;
+               creq.count = 0;
+               status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
+                   acpi_count_irq_resources, &creq);
+               if (ACPI_FAILURE(status)) {
+                       device_printf(dev,
+                           "Unable to parse _CRS or _PRS: %s\n",
+                           AcpiFormatException(status));
+                       ACPI_SERIAL_END(pci_link);
+                       return (ENXIO);
+               }
        }
-
-       error = acpi_pci_link_get_object_status(handle, &sta);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't get object status %s - %s\n",
-                   acpi_name(handle), AcpiFormatException(error));
-               return_ACPI_STATUS (error);
+       sc->pl_num_links = creq.count;
+       if (creq.count == 0) {
+               ACPI_SERIAL_END(pci_link);
+               return (0);
        }
-
-       if ((sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL)) == 0) {
-               kprintf("interrupt link is not functional - %s\n",
-                   acpi_name(handle));
-               return_ACPI_STATUS (AE_ERROR);
+       sc->pl_links = kmalloc(sizeof(struct link) * sc->pl_num_links,
+           M_PCI_LINK, M_WAITOK | M_ZERO);
+
+       /* Initialize the child links. */
+       for (i = 0; i < sc->pl_num_links; i++) {
+               sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
+               sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ;
+               sc->pl_links[i].l_sc = sc;
+               sc->pl_links[i].l_isa_irq = FALSE;
+               sc->pl_links[i].l_res_index = -1;
        }
 
-       TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
-               if (entry->busno == busno &&
-                   entry->prt.Address == prt->Address &&
-                   entry->prt.Pin == prt->Pin) {
-                       kprintf("interrupt link entry already exists - %s\n",
-                           acpi_name(handle));
-                       return_ACPI_STATUS (AE_ALREADY_EXISTS);
+       /* Try to read the current settings from _CRS if it is valid. */
+       if (!sc->pl_crs_bad) {
+               rreq.in_dpf = DPF_OUTSIDE;
+               rreq.link_index = 0;
+               rreq.res_index = 0;
+               rreq.sc = sc;
+               status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
+                   link_add_crs, &rreq);
+               if (ACPI_FAILURE(status)) {
+                       device_printf(dev, "Unable to parse _CRS: %s\n",
+                           AcpiFormatException(status));
+                       goto fail;
                }
        }
 
-       entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
-       if (entry == NULL) {
-               kprintf("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)) {
-               kprintf("couldn't add _PRT entry to link %s - %s\n",
-                   acpi_name(handle), AcpiFormatException(error));
-               goto out;
+       /*
+        * Try to read the possible settings from _PRS.  Note that if the
+        * _CRS is toast, we depend on having a working _PRS.  However, if
+        * _CRS works, then it is ok for _PRS to be missing.
+        */
+       rreq.in_dpf = DPF_OUTSIDE;
+       rreq.link_index = 0;
+       rreq.res_index = 0;
+       rreq.sc = sc;
+       status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
+           link_add_prs, &rreq);
+       if (ACPI_FAILURE(status) &&
+           (status != AE_NOT_FOUND || sc->pl_crs_bad)) {
+               device_printf(dev, "Unable to parse _PRS: %s\n",
+                   AcpiFormatException(status));
+               goto fail;
        }
+       if (bootverbose)
+               acpi_pci_link_dump(sc, 1, "Initial Probe");
+
+       /* Verify initial IRQs if we have _PRS. */
+       if (status != AE_NOT_FOUND)
+               for (i = 0; i < sc->pl_num_links; i++)
+                       if (!link_valid_irq(&sc->pl_links[i],
+                           sc->pl_links[i].l_irq))
+                               sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
+       if (bootverbose)
+               acpi_pci_link_dump(sc, 0, "Validation");
+
+       /* Save initial IRQs. */
+       for (i = 0; i < sc->pl_num_links; i++)
+               sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq;
 
-       TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
-       error = AE_OK;
-
-out:
-       if (error != AE_OK && entry != NULL)
-               AcpiOsFree(entry);
-
-       return_ACPI_STATUS (error);
+       /*
+        * Try to disable this link.  If successful, set the current IRQ to
+        * zero and flags to indicate this link is not routed.  If we can't
+        * run _DIS (i.e., the method doesn't exist), assume the initial
+        * IRQ was routed by the BIOS.
+        */
+       if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL,
+           NULL)))
+               for (i = 0; i < sc->pl_num_links; i++)
+                       sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
+       else
+               for (i = 0; i < sc->pl_num_links; i++)
+                       if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq))
+                               sc->pl_links[i].l_routed = TRUE;
+       if (bootverbose)
+               acpi_pci_link_dump(sc, 0, "After Disable");
+       ACPI_SERIAL_END(pci_link);
+       return (0);
+fail:
+       ACPI_SERIAL_END(pci_link);
+       for (i = 0; i < sc->pl_num_links; i++)
+               if (sc->pl_links[i].l_irqs != NULL)
+                       kfree(sc->pl_links[i].l_irqs, M_PCI_LINK);
+       kfree(sc->pl_links, M_PCI_LINK);
+       return (ENXIO);
 }
 
-static int
-acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
+/* XXX: Note that this is identical to pci_pir_search_irq(). */
+static uint8_t
+acpi_pci_link_search_irq(int bus, int device, int pin)
 {
-       UINT8                   i;
-
-       if (irq == 0)
-               return (0);
+       uint32_t value;
+       uint8_t func, maxfunc;
+
+       /* See if we have a valid device at function 0. */
+       value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1);
+       if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
+               return (PCI_INVALID_IRQ);
+       if (value & PCIM_MFDEV)
+               maxfunc = PCI_FUNCMAX;
+       else
+               maxfunc = 0;
+
+       /* Scan all possible functions at this device. */
+       for (func = 0; func <= maxfunc; func++) {
+               value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4);
+               if (value == 0xffffffff)
+                       continue;
+               value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1);
 
-       for (i = 0; i < link->number_of_interrupts; i++) {
-               if (link->interrupts[i] == irq)
-                       return (1);
+               /*
+                * See if it uses the pin in question.  Note that the passed
+                * in pin uses 0 for A, .. 3 for D whereas the intpin
+                * register uses 0 for no interrupt, 1 for A, .. 4 for D.
+                */
+               if (value != pin + 1)
+                       continue;
+               value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1);
+               if (bootverbose)
+                       kprintf(
+               "ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n",
+                           bus, device, pin + 'A', func, value);
+               if (value != PCI_INVALID_IRQ)
+                       return (value);
        }
-
-       /* allow initial IRQ as valid one. */
-       if (link->initial_irq == irq)
-               return (1);
-
-       return (0);
+       return (PCI_INVALID_IRQ);
 }
 
-static ACPI_STATUS
-acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
+/*
+ * Find the link structure that corresponds to the resource index passed in
+ * via 'source_index'.
+ */
+static struct link *
+acpi_pci_link_lookup(device_t dev, int source_index)
 {
-       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)) {
-               kprintf("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)) {
-               kprintf("couldn't get current IRQ from "
-                   "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.Type) {
-       case ACPI_RESOURCE_TYPE_IRQ:
-               resbuf.Type = ACPI_RESOURCE_TYPE_IRQ;
-               resbuf.Length = sizeof(ACPI_RESOURCE_IRQ);
-
-               /* structure copy other fields */
-               resbuf.Data.Irq = link->possible_resources.Data.Irq;
-               resbuf.Data.Irq.InterruptCount = 1;
-               resbuf.Data.Irq.Interrupts[0] = irq;
-               break;
-       case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-               resbuf.Type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
-               resbuf.Length = sizeof(ACPI_RESOURCE_EXTENDED_IRQ);
-
-               /* structure copy other fields */
-               resbuf.Data.ExtendedIrq =
-                   link->possible_resources.Data.ExtendedIrq;
-               resbuf.Data.ExtendedIrq.InterruptCount = 1;
-               resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
-               break;
-       default:
-               kprintf("Resource is not an IRQ entry %s - %d\n",
-                   acpi_name(link->handle), link->possible_resources.Type);
-               return_ACPI_STATUS (AE_TYPE);
-       }
-
-       error = acpi_AppendBufferResource(&crsbuf, &resbuf);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't setup buffer by "
-                   "acpi_AppendBufferResource - %s\n",
-                   acpi_name(link->handle));
-               return_ACPI_STATUS (error);
-       }
-       if (crsbuf.Pointer == NULL) {
-               kprintf("appended buffer for %s is corrupted\n",
-                   acpi_name(link->handle));
-               return_ACPI_STATUS (AE_NO_MEMORY);
-       }
-
-       error = AcpiSetCurrentResources(link->handle, &crsbuf);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't set link device _SRS %s - %s\n",
-                   acpi_name(link->handle), AcpiFormatException(error));
-               return_ACPI_STATUS (error);
-       }
+       struct acpi_pci_link_softc *sc;
+       int i;
+
+       ACPI_SERIAL_ASSERT(pci_link);
+       sc = device_get_softc(dev);
+       for (i = 0; i < sc->pl_num_links; i++)
+               if (sc->pl_links[i].l_res_index == source_index)
+                       return (&sc->pl_links[i]);
+       return (NULL);
+}
 
-       AcpiOsFree(crsbuf.Pointer);
-       link->current_irq = 0;
+void
+acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
+    int pin)
+{
+       struct link *link;
+       uint8_t bios_irq;
+       uintptr_t bus;
 
-       error = acpi_pci_link_get_object_status(link->handle, &sta);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't get object status %s - %s\n",
-                   acpi_name(link->handle), AcpiFormatException(error));
-               return_ACPI_STATUS (error);
+       /*
+        * Look up the PCI bus for the specified PCI bridge device.  Note
+        * that the PCI bridge device might not have any children yet.
+        * However, looking up its bus number doesn't require a valid child
+        * device, so we just pass NULL.
+        */
+       if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_BUS, &bus) != 0) {
+               device_printf(pcib, "Unable to read PCI bus number");
+               panic("PCI bridge without a bus number");
        }
 
-       if ((sta & ACPI_STA_ENABLE) == 0) {
-               kprintf("interrupt link %s is disabled\n",
-                   acpi_name(link->handle));
-               return_ACPI_STATUS (AE_ERROR);
+       /* Bump the reference count. */
+       ACPI_SERIAL_BEGIN(pci_link);
+       link = acpi_pci_link_lookup(dev, index);
+       if (link == NULL) {
+               device_printf(dev, "apparently invalid index %d\n", index);
+               ACPI_SERIAL_END(pci_link);
+               return;
        }
+       link->l_references++;
+       if (link->l_routed)
+               pci_link_interrupt_weights[link->l_irq]++;
 
-       error = acpi_pci_link_get_current_irq(link, &link->current_irq);
-       if (ACPI_FAILURE(error)) {
-               kprintf("couldn't get current IRQ from "
-                   "interrupt link %s - %s\n",
-                   acpi_name(link->handle), AcpiFormatException(error));
-               return_ACPI_STATUS (error);
+       /*
+        * The BIOS only routes interrupts via ISA IRQs using the ATPICs
+        * (8259As).  Thus, if this link is routed via an ISA IRQ, go
+        * look to see if the BIOS routed an IRQ for this link at the
+        * indicated (bus, slot, pin).  If so, we prefer that IRQ for
+        * this link and add that IRQ to our list of known-good IRQs.
+        * This provides a good work-around for link devices whose _CRS
+        * method is either broken or bogus.  We only use the value
+        * returned by _CRS if we can't find a valid IRQ via this method
+        * in fact.
+        *
+        * If this link is not routed via an ISA IRQ (because we are using
+        * APIC for example), then don't bother looking up the BIOS IRQ
+        * as if we find one it won't be valid anyway.
+        */
+       if (!link->l_isa_irq) {
+               ACPI_SERIAL_END(pci_link);
+               return;
        }
 
-       if (link->current_irq == irq) {
-               error = AE_OK;
-       } else {
-               kprintf("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;
+       /* Try to find a BIOS IRQ setting from any matching devices. */
+       bios_irq = acpi_pci_link_search_irq(bus, slot, pin);
+       if (!PCI_INTERRUPT_VALID(bios_irq)) {
+               ACPI_SERIAL_END(pci_link);
+               return;
        }
 
-       return_ACPI_STATUS (error);
+       /* Validate the BIOS IRQ. */
+       if (!link_valid_irq(link, bios_irq)) {
+               device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
+                   bios_irq, (int)bus, slot, pin + 'A');
+       } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
+               link->l_bios_irq = bios_irq;
+               if (bios_irq < NUM_ISA_INTERRUPTS)
+                       pci_link_bios_isa_irqs |= (1 << bios_irq);
+               if (bios_irq != link->l_initial_irq &&
+                   PCI_INTERRUPT_VALID(link->l_initial_irq))
+                       device_printf(dev,
+                           "BIOS IRQ %u does not match initial IRQ %u\n",
+                           bios_irq, link->l_initial_irq);
+       } else if (bios_irq != link->l_bios_irq)
+               device_printf(dev,
+           "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
+                   bios_irq, (int)bus, slot, pin + 'A',
+                   link->l_bios_irq);
+       ACPI_SERIAL_END(pci_link);
 }
 
-/*
- * Auto arbitration for boot-disabled devices
- */
-
-static void
-acpi_pci_link_bootdisabled_dump(void)
+static ACPI_STATUS
+acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf)
 {
-       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;
+       ACPI_RESOURCE *resource, *end, newres, *resptr;
+       ACPI_BUFFER crsbuf;
+       ACPI_STATUS status;
+       struct link *link;
+       int i, in_dpf;
+
+       /* Fetch the _CRS. */
+       ACPI_SERIAL_ASSERT(pci_link);
+       crsbuf.Pointer = NULL;
+       crsbuf.Length = ACPI_ALLOCATE_BUFFER;
+       status = AcpiGetCurrentResources(acpi_get_handle(sc->pl_dev), &crsbuf);
+       if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL)
+               status = AE_NO_MEMORY;
+       if (ACPI_FAILURE(status)) {
+               if (bootverbose)
+                       device_printf(sc->pl_dev,
+                           "Unable to fetch current resources: %s\n",
+                           AcpiFormatException(status));
+               return (status);
+       }
 
-               kprintf("%s:\n", acpi_name(link->handle));
-               kprintf("       interrupts:     ");
-               for (i = 0; i < link->number_of_interrupts; i++) {
-                       irq = link->sorted_irq[i];
-                       kprintf("%6d", irq);
+       /* Fill in IRQ resources via link structures. */
+       srsbuf->Pointer = NULL;
+       link = sc->pl_links;
+       i = 0;
+       in_dpf = DPF_OUTSIDE;
+       resource = (ACPI_RESOURCE *)crsbuf.Pointer;
+       end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length);
+       for (;;) {
+               switch (resource->Type) {
+               case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+                       switch (in_dpf) {
+                       case DPF_OUTSIDE:
+                               /* We've started the first DPF. */
+                               in_dpf = DPF_FIRST;
+                               break;
+                       case DPF_FIRST:
+                               /* We've started the second DPF. */
+                               panic(
+               "%s: Multiple dependent functions within a current resource",
+                                   __func__);
+                               break;
+                       }
+                       resptr = NULL;
+                       break;
+               case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+                       /* We are finished with DPF parsing. */
+                       KASSERT(in_dpf != DPF_OUTSIDE,
+                           ("%s: end dpf when not parsing a dpf", __func__));
+                       in_dpf = DPF_OUTSIDE;
+                       resptr = NULL;
+                       break;
+               case ACPI_RESOURCE_TYPE_IRQ:
+                       MPASS(i < sc->pl_num_links);
+                       MPASS(link->l_prs_template.Type == ACPI_RESOURCE_TYPE_IRQ);
+                       newres = link->l_prs_template;
+                       resptr = &newres;
+                       resptr->Data.Irq.InterruptCount = 1;
+                       if (PCI_INTERRUPT_VALID(link->l_irq)) {
+                               KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
+               ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
+                                   __func__, link->l_irq));
+                               resptr->Data.Irq.Interrupts[0] = link->l_irq;
+                       } else
+                               resptr->Data.Irq.Interrupts[0] = 0;
+                       link++;
+                       i++;
+                       break;
+               case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+                       MPASS(i < sc->pl_num_links);
+                       MPASS(link->l_prs_template.Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ);
+                       newres = link->l_prs_template;
+                       resptr = &newres;
+                       resptr->Data.ExtendedIrq.InterruptCount = 1;
+                       if (PCI_INTERRUPT_VALID(link->l_irq))
+                               resptr->Data.ExtendedIrq.Interrupts[0] =
+                                   link->l_irq;
+                       else
+                               resptr->Data.ExtendedIrq.Interrupts[0] = 0;
+                       link++;
+                       i++;
+                       break;
+               default:
+                       resptr = resource;
                }
-               kprintf("\n");
-               kprintf("       penalty:        ");
-               for (i = 0; i < link->number_of_interrupts; i++) {
-                       irq = link->sorted_irq[i];
-                       kprintf("%6d", irq_penalty[irq]);
+               if (resptr != NULL) {
+                       status = acpi_AppendBufferResource(srsbuf, resptr);
+                       if (ACPI_FAILURE(status)) {
+                               device_printf(sc->pl_dev,
+                                   "Unable to build resources: %s\n",
+                                   AcpiFormatException(status));
+                               if (srsbuf->Pointer != NULL)
+                                       AcpiOsFree(srsbuf->Pointer);
+                               AcpiOsFree(crsbuf.Pointer);
+                               return (status);
+                       }
                }
-               kprintf("\n");
-               kprintf("       references:     %d\n", link->references);
-               kprintf("       priority:       %d\n", link->priority);
+               if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
+                       break;
+               resource = ACPI_NEXT_RESOURCE(resource);
+               if (resource >= end)
+                       break;
        }
+       AcpiOsFree(crsbuf.Pointer);
+       return (AE_OK);
 }
 
-static void
-acpi_pci_link_init_irq_penalty(void)
+static ACPI_STATUS
+acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc,
+    ACPI_BUFFER *srsbuf)
 {
-       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;
+       ACPI_RESOURCE newres;
+       ACPI_STATUS status;
+       struct link *link;
+       int i;
+
+       /* Start off with an empty buffer. */
+       srsbuf->Pointer = NULL;
+       link = sc->pl_links;
+       for (i = 0; i < sc->pl_num_links; i++) {
+
+               /* Add a new IRQ resource from each link. */
+               link = &sc->pl_links[i];
+               newres = link->l_prs_template;
+               if (newres.Type == ACPI_RESOURCE_TYPE_IRQ) {
+
+                       /* Build an IRQ resource. */
+                       newres.Data.Irq.InterruptCount = 1;
+                       if (PCI_INTERRUPT_VALID(link->l_irq)) {
+                               KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
+               ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
+                                   __func__, link->l_irq));
+                               newres.Data.Irq.Interrupts[0] = link->l_irq;
+                       } else
+                               newres.Data.Irq.Interrupts[0] = 0;
+               } else {
+
+                       /* Build an ExtIRQ resuorce. */
+                       newres.Data.ExtendedIrq.InterruptCount = 1;
+                       if (PCI_INTERRUPT_VALID(link->l_irq))
+                               newres.Data.ExtendedIrq.Interrupts[0] =
+                                   link->l_irq;
+                       else
+                               newres.Data.ExtendedIrq.Interrupts[0] = 0;
                }
 
-               /* 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;
+               /* Add the new resource to the end of the _SRS buffer. */
+               status = acpi_AppendBufferResource(srsbuf, &newres);
+               if (ACPI_FAILURE(status)) {
+                       device_printf(sc->pl_dev,
+                           "Unable to build resources: %s\n",
+                           AcpiFormatException(status));
+                       if (srsbuf->Pointer != NULL)
+                               AcpiOsFree(srsbuf->Pointer);
+                       return (status);
                }
        }
+       return (AE_OK);
 }
 
-static int
-link_exclusive(ACPI_RESOURCE *res)
-{
-       if (res == NULL ||
-           (res->Type != ACPI_RESOURCE_TYPE_IRQ &&
-           res->Type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ))
-               return (0);
-
-       if ((res->Type == ACPI_RESOURCE_TYPE_IRQ &&
-           res->Data.Irq.Sharable == ACPI_EXCLUSIVE) ||
-           (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ &&
-           res->Data.ExtendedIrq.Sharable == ACPI_EXCLUSIVE))
-               return (1);
-
-       return (0);
-}
-
-static void
-acpi_pci_link_update_irq_penalty(device_t dev, int busno)
+static ACPI_STATUS
+acpi_pci_link_route_irqs(device_t dev)
 {
-       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;
-
-               /* Impossible? */
-               link = entry->pci_link;
-               if (link == NULL)
-                       continue;
-
-               if (link->current_irq != 0) {
-                       /* not boot-disabled link, we will use this IRQ. */
-                       irq_penalty[link->current_irq] += 100;
-                       continue;
-               }
+       struct acpi_pci_link_softc *sc;
+       ACPI_RESOURCE *resource, *end;
+       ACPI_BUFFER srsbuf;
+       ACPI_STATUS status;
+       struct link *link;
+       int i;
+
+       ACPI_SERIAL_ASSERT(pci_link);
+       sc = device_get_softc(dev);
+       if (sc->pl_crs_bad)
+               status = acpi_pci_link_srs_from_links(sc, &srsbuf);
+       else
+               status = acpi_pci_link_srs_from_crs(sc, &srsbuf);
+
+       /* Write out new resources via _SRS. */
+       status = AcpiSetCurrentResources(acpi_get_handle(dev), &srsbuf);
+       if (ACPI_FAILURE(status)) {
+               device_printf(dev, "Unable to route IRQs: %s\n",
+                   AcpiFormatException(status));
+               AcpiOsFree(srsbuf.Pointer);
+               return (status);
+       }
 
-               /* 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 (link_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;
+       /*
+        * Perform acpi_config_intr() on each IRQ resource if it was just
+        * routed for the first time.
+        */
+       link = sc->pl_links;
+       i = 0;
+       resource = (ACPI_RESOURCE *)srsbuf.Pointer;
+       end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length);
+       for (;;) {
+               if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
+                       break;
+               switch (resource->Type) {
+               case ACPI_RESOURCE_TYPE_IRQ:
+               case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+                       MPASS(i < sc->pl_num_links);
+
+                       /*
+                        * Only configure the interrupt and update the
+                        * weights if this link has a valid IRQ and was
+                        * previously unrouted.
+                        */
+                       if (!link->l_routed &&
+                           PCI_INTERRUPT_VALID(link->l_irq)) {
+                               link->l_routed = TRUE;
+                               acpi_config_intr(dev, resource);
+                               pci_link_interrupt_weights[link->l_irq] +=
+                                   link->l_references;
                        }
+                       link++;
+                       i++;
+                       break;
                }
-
-               /* initialize `sorted' possible IRQs. */
-               bcopy(link->interrupts, link->sorted_irq,
-                   sizeof(link->sorted_irq));
+               resource = ACPI_NEXT_RESOURCE(resource);
+               if (resource >= end)
+                       break;
        }
+       AcpiOsFree(srsbuf.Pointer);
+       return (AE_OK);
 }
 
-static void
-acpi_pci_link_set_bootdisabled_priority(void)
+static int
+acpi_pci_link_resume(device_t dev)
 {