summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>2000-10-28 06:59:48 +0000
committermsmith <msmith@FreeBSD.org>2000-10-28 06:59:48 +0000
commita69e8faa90e4070a65302cf076ac04b9186fa622 (patch)
treea28f70dd99f84e0e7c0aeb156ae5ff36e60bd789 /sys
parent64e150eaa441bc8b9ecc4f649c022b7d522e487f (diff)
downloadFreeBSD-src-a69e8faa90e4070a65302cf076ac04b9186fa622.zip
FreeBSD-src-a69e8faa90e4070a65302cf076ac04b9186fa622.tar.gz
Initial FreeBSD OSPM (operating system power management) modules for
ACPICA. Most of these are still works in progress. Support exists for: - Fixed feature and control method power, lid and sleep buttons. - Detection of ISA PnP devices using ACPI namespace. - Detection of PCI root busses using ACPI namespace. - CPU throttling and sleep states (incomplete) - Thermal monitoring and cooling control (incomplete) - Interface to platform embedded controllers (mostly complete) - ACPI timer (incomplete) - Simple userland control of sleep states. - Shutdown and poweroff.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/acpica/acpi.c1124
-rw-r--r--sys/dev/acpica/acpi_apic.c159
-rw-r--r--sys/dev/acpica/acpi_button.c182
-rw-r--r--sys/dev/acpica/acpi_ec.c710
-rw-r--r--sys/dev/acpica/acpi_ecreg.h196
-rw-r--r--sys/dev/acpica/acpi_isa.c442
-rw-r--r--sys/dev/acpica/acpi_lid.c152
-rw-r--r--sys/dev/acpica/acpi_pcib.c236
-rw-r--r--sys/dev/acpica/acpi_pcib_acpi.c236
-rw-r--r--sys/dev/acpica/acpi_processor.c640
-rw-r--r--sys/dev/acpica/acpi_resource.c343
-rw-r--r--sys/dev/acpica/acpi_thermal.c102
-rw-r--r--sys/dev/acpica/acpi_timer.c117
-rw-r--r--sys/dev/acpica/acpiio.h33
-rw-r--r--sys/dev/acpica/acpivar.h221
15 files changed, 4893 insertions, 0 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
new file mode 100644
index 0000000..651a7737
--- /dev/null
+++ b/sys/dev/acpica/acpi.c
@@ -0,0 +1,1124 @@
+/*-
+ * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/ioccom.h>
+#include <sys/reboot.h>
+#include <sys/sysctl.h>
+#include <sys/ctype.h>
+
+#include <machine/clock.h>
+
+#include <machine/resource.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+#include <dev/acpica/acpiio.h>
+
+#include <pci/pcivar.h>
+#include "pcib_if.h"
+
+MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
+
+/*
+ * Character device
+ */
+
+static d_open_t acpiopen;
+static d_close_t acpiclose;
+static d_ioctl_t acpiioctl;
+
+#define CDEV_MAJOR 152
+static struct cdevsw acpi_cdevsw = {
+ acpiopen,
+ acpiclose,
+ noread,
+ nowrite,
+ acpiioctl,
+ nopoll,
+ nommap,
+ nostrategy,
+ "acpi",
+ CDEV_MAJOR,
+ nodump,
+ nopsize,
+ 0,
+ -1
+};
+
+static void acpi_identify(driver_t *driver, device_t parent);
+static int acpi_probe(device_t dev);
+static int acpi_attach(device_t dev);
+static device_t acpi_add_child(device_t bus, int order, const char *name, int unit);
+static int acpi_print_resources(struct resource_list *rl, const char *name, int type,
+ const char *format);
+static int acpi_print_child(device_t bus, device_t child);
+static int acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result);
+static int acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value);
+static int acpi_set_resource(device_t dev, device_t child, int type, int rid, u_long start,
+ u_long count);
+static int acpi_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp,
+ u_long *countp);
+static struct resource *acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags);
+static int acpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r);
+
+static void acpi_probe_children(device_t bus);
+static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status);
+
+static void acpi_shutdown_pre_sync(void *arg, int howto);
+static void acpi_shutdown_final(void *arg, int howto);
+
+#ifdef ACPI_DEBUG
+static void acpi_set_debugging(void);
+#endif
+
+static void acpi_system_eventhandler_sleep(void *arg, int state);
+static void acpi_system_eventhandler_wakeup(void *arg, int state);
+
+static device_method_t acpi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_identify),
+ DEVMETHOD(device_probe, acpi_probe),
+ DEVMETHOD(device_attach, acpi_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_add_child, acpi_add_child),
+ DEVMETHOD(bus_print_child, acpi_print_child),
+ DEVMETHOD(bus_read_ivar, acpi_read_ivar),
+ DEVMETHOD(bus_write_ivar, acpi_write_ivar),
+ DEVMETHOD(bus_set_resource, acpi_set_resource),
+ DEVMETHOD(bus_get_resource, acpi_get_resource),
+ DEVMETHOD(bus_alloc_resource, acpi_alloc_resource),
+ DEVMETHOD(bus_release_resource, acpi_release_resource),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ {0, 0}
+};
+
+static driver_t acpi_driver = {
+ "acpi",
+ acpi_methods,
+ sizeof(struct acpi_softc),
+};
+
+devclass_t acpi_devclass;
+DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, 0, 0);
+
+SYSCTL_INT(_debug, OID_AUTO, acpi_debug_layer, CTLFLAG_RW, &AcpiDbgLayer, 0, "");
+SYSCTL_INT(_debug, OID_AUTO, acpi_debug_level, CTLFLAG_RW, &AcpiDbgLevel, 0, "");
+
+/*
+ * Detect ACPI, perform early initialisation
+ */
+static void
+acpi_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+ void *rsdp;
+ int error;
+#ifdef ENABLE_DEBUGGER
+ char *debugpoint = getenv("debug.acpi.debugger");
+#endif
+
+ /*
+ * Make sure we're not being doubly invoked.
+ */
+ if (device_find_child(parent, "acpi", 0) != NULL)
+ return;
+
+#ifdef ACPI_DEBUG
+ acpi_set_debugging();
+#endif
+
+ /*
+ * Start up ACPICA
+ */
+#ifdef ENABLE_DEBUGGER
+ if (debugpoint && !strcmp(debugpoint, "init"))
+ acpi_EnterDebugger();
+#endif
+ if ((error = AcpiInitializeSubsystem()) != AE_OK) {
+ printf("ACPI: initialisation failed: %s\n", acpi_strerror(error));
+ return;
+ }
+#ifdef ENABLE_DEBUGGER
+ if (debugpoint && !strcmp(debugpoint, "tables"))
+ acpi_EnterDebugger();
+#endif
+ if (((error = AcpiFindRootPointer(&rsdp)) != AE_OK) ||
+ ((error = AcpiLoadTables(rsdp)) != AE_OK)) {
+ printf("ACPI: table load failed: %s\n", acpi_strerror(error));
+ return;
+ }
+
+ /*
+ * Attach the actual ACPI device.
+ */
+ if ((child = BUS_ADD_CHILD(parent, 0, "acpi", 0)) == NULL) {
+ device_printf(parent, "ACPI: could not attach\n");
+ return;
+ }
+}
+
+/*
+ * 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;
+
+ if ((error = AcpiGetTableHeader(ACPI_TABLE_RSDT, 1, &th)) != AE_OK) {
+ device_printf(dev, "couldn't get RSDT header: %s\n", acpi_strerror(error));
+ return(ENXIO);
+ }
+ sprintf(buf, "%.6s %.8s", th.OemId, th.OemTableId);
+ device_set_desc_copy(dev, buf);
+
+ return(0);
+}
+
+static int
+acpi_attach(device_t dev)
+{
+ struct acpi_softc *sc;
+ int error;
+#ifdef ENABLE_DEBUGGER
+ char *debugpoint = getenv("debug.acpi.debugger");
+#endif
+
+
+ sc = device_get_softc(dev);
+ bzero(sc, sizeof(*sc));
+ sc->acpi_dev = dev;
+
+#ifdef ENABLE_DEBUGGER
+ if (debugpoint && !strcmp(debugpoint, "spaces"))
+ acpi_EnterDebugger();
+#endif
+
+ /*
+ * Install the default address space handlers.
+ */
+ if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+ ADDRESS_SPACE_SYSTEM_MEMORY,
+ ACPI_DEFAULT_HANDLER,
+ NULL, NULL)) != AE_OK) {
+ device_printf(dev, "could not initialise SystemMemory handler: %s\n", acpi_strerror(error));
+ return(ENXIO);
+ }
+ if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+ ADDRESS_SPACE_SYSTEM_IO,
+ ACPI_DEFAULT_HANDLER,
+ NULL, NULL)) != AE_OK) {
+ device_printf(dev, "could not initialise SystemIO handler: %s\n", acpi_strerror(error));
+ return(ENXIO);
+ }
+ if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+ ADDRESS_SPACE_PCI_CONFIG,
+ ACPI_DEFAULT_HANDLER,
+ NULL, NULL)) != AE_OK) {
+ device_printf(dev, "could not initialise PciConfig handler: %s\n", acpi_strerror(error));
+ return(ENXIO);
+ }
+
+ /*
+ * Bring ACPI fully online.
+ *
+ * Note that we request that device _STA and _INI methods not be run (ACPI_NO_DEVICE_INIT)
+ * and the final object initialisation pass be skipped (ACPI_NO_OBJECT_INIT).
+ *
+ * XXX We need to arrange for the object init pass after we have attached all our
+ * child devices.
+ */
+#ifdef ENABLE_DEBUGGER
+ if (debugpoint && !strcmp(debugpoint, "enable"))
+ acpi_EnterDebugger();
+#endif
+ if ((error = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT)) != AE_OK) {
+ device_printf(dev, "could not enable ACPI: %s\n", acpi_strerror(error));
+ return(ENXIO);
+ }
+
+ /*
+ * Dispatch the default sleep state to devices.
+ * TBD: should be configured from userland policy manager.
+ */
+ sc->acpi_power_button_sx = ACPI_POWER_BUTTON_DEFAULT_SX;
+ sc->acpi_sleep_button_sx = ACPI_SLEEP_BUTTON_DEFAULT_SX;
+ sc->acpi_lid_switch_sx = ACPI_LID_SWITCH_DEFAULT_SX;
+
+ /* Enable and clear fixed events and install handlers. */
+ if (AcpiGbl_FACP != NULL && AcpiGbl_FACP->PwrButton == 0) {
+ AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, ACPI_EVENT_FIXED);
+ AcpiClearEvent(ACPI_EVENT_POWER_BUTTON, ACPI_EVENT_FIXED);
+ AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, acpi_eventhandler_power_button_for_sleep, sc);
+ device_printf(dev, "power button is handled as a fixed feature programming model.\n");
+ }
+ if (AcpiGbl_FACP != NULL && AcpiGbl_FACP->SleepButton == 0) {
+ AcpiEnableEvent(ACPI_EVENT_SLEEP_BUTTON, ACPI_EVENT_FIXED);
+ AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON, ACPI_EVENT_FIXED);
+ AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, acpi_eventhandler_sleep_button_for_sleep, sc);
+ device_printf(dev, "sleep button is handled as a fixed feature programming model.\n");
+ }
+
+ /*
+ * Scan the namespace and attach/initialise children.
+ */
+#ifdef ENABLE_DEBUGGER
+ if (debugpoint && !strcmp(debugpoint, "probe"))
+ acpi_EnterDebugger();
+#endif
+ acpi_probe_children(dev);
+
+ /*
+ * Register our shutdown handlers
+ */
+ EVENTHANDLER_REGISTER(shutdown_pre_sync, acpi_shutdown_pre_sync, sc, SHUTDOWN_PRI_LAST);
+ EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc, SHUTDOWN_PRI_LAST);
+
+ /*
+ * Register our acpi event handlers.
+ * XXX should be configurable eg. via userland policy manager.
+ */
+ EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep, sc, ACPI_EVENT_PRI_LAST);
+ EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup, sc, ACPI_EVENT_PRI_LAST);
+
+ /*
+ * Flag our initial states.
+ */
+ sc->acpi_enabled = 1;
+ sc->acpi_sstate = ACPI_STATE_S0;
+
+ /*
+ * Create the control device
+ */
+ sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, 0, 5, 0660, "acpi");
+ sc->acpi_dev_t->si_drv1 = sc;
+
+#ifdef ENABLE_DEBUGGER
+ if (debugpoint && !strcmp(debugpoint, "running"))
+ acpi_EnterDebugger();
+#endif
+ return(0);
+}
+
+/*
+ * Handle a new device being added
+ */
+static device_t
+acpi_add_child(device_t bus, int order, const char *name, int unit)
+{
+ struct acpi_device *ad;
+ device_t child;
+
+ if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT)) == NULL)
+ return(NULL);
+ bzero(ad, sizeof(*ad));
+
+ resource_list_init(&ad->ad_rl);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+ if (child != NULL)
+ device_set_ivars(child, ad);
+ return(child);
+}
+
+/*
+ * Print child device resource usage
+ */
+static int
+acpi_print_resources(struct resource_list *rl, const char *name, int type, const char *format)
+{
+ struct resource_list_entry *rle;
+ int printed, retval;
+
+ printed = 0;
+ retval = 0;
+
+ if (!SLIST_FIRST(rl))
+ return(0);
+
+ /* Yes, this is kinda cheating */
+ SLIST_FOREACH(rle, rl, link) {
+ if (rle->type == type) {
+ if (printed == 0)
+ retval += printf(" %s ", name);
+ else if (printed > 0)
+ retval += printf(",");
+ printed++;
+ retval += printf(format, rle->start);
+ if (rle->count > 1) {
+ retval += printf("-");
+ retval += printf(format, rle->start +
+ rle->count - 1);
+ }
+ }
+ }
+ return(retval);
+}
+
+static int
+acpi_print_child(device_t bus, device_t child)
+{
+ struct acpi_device *adev = device_get_ivars(child);
+ struct resource_list *rl = &adev->ad_rl;
+ int retval = 0;
+
+ retval += bus_print_child_header(bus, child);
+ retval += acpi_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx");
+ retval += acpi_print_resources(rl, "iomem", SYS_RES_MEMORY, "%#lx");
+ retval += acpi_print_resources(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += bus_print_child_footer(bus, child);
+
+ return(retval);
+}
+
+
+/*
+ * Handle per-device ivars
+ */
+static int
+acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
+{
+ struct acpi_device *ad;
+
+ if ((ad = device_get_ivars(child)) == NULL) {
+ printf("device has no ivars\n");
+ return(ENOENT);
+ }
+
+ switch(index) {
+ /* ACPI ivars */
+ case ACPI_IVAR_HANDLE:
+ *(ACPI_HANDLE *)result = ad->ad_handle;
+ break;
+ case ACPI_IVAR_MAGIC:
+ *(int *)result = ad->ad_magic;
+ break;
+ case ACPI_IVAR_PRIVATE:
+ *(void **)result = ad->ad_private;
+ break;
+
+ default:
+ panic("bad ivar read request (%d)\n", index);
+ return(ENOENT);
+ }
+ return(0);
+}
+
+static int
+acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
+{
+ struct acpi_device *ad;
+
+ if ((ad = device_get_ivars(child)) == NULL) {
+ printf("device has no ivars\n");
+ return(ENOENT);
+ }
+
+ switch(index) {
+ /* ACPI ivars */
+ case ACPI_IVAR_HANDLE:
+ ad->ad_handle = (ACPI_HANDLE)value;
+ break;
+ case ACPI_IVAR_MAGIC:
+ ad->ad_magic = (int )value;
+ break;
+ case ACPI_IVAR_PRIVATE:
+ ad->ad_private = (void *)value;
+ break;
+
+ default:
+ panic("bad ivar write request (%d)\n", index);
+ return(ENOENT);
+ }
+ return(0);
+}
+
+/*
+ * Handle child resource allocation/removal
+ */
+static int
+acpi_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count)
+{
+ struct acpi_device *ad = device_get_ivars(child);
+ struct resource_list *rl = &ad->ad_rl;
+
+ resource_list_add(rl, type, rid, start, start + count -1, count);
+
+ return(0);
+}
+
+static int
+acpi_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp)
+{
+ struct acpi_device *ad = device_get_ivars(child);
+ struct resource_list *rl = &ad->ad_rl;
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(rl, type, rid);
+ if (!rle)
+ return(ENOENT);
+
+ if (startp)
+ *startp = rle->start;
+ if (countp)
+ *countp = rle->count;
+
+ return(0);
+}
+
+static struct resource *
+acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct acpi_device *ad = device_get_ivars(child);
+ struct resource_list *rl = &ad->ad_rl;
+
+ return(resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags));
+}
+
+static int
+acpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r)
+{
+ struct acpi_device *ad = device_get_ivars(child);
+ struct resource_list *rl = &ad->ad_rl;
+
+ return(resource_list_release(rl, bus, child, type, rid, r));
+}
+
+/*
+ * Scan relevant portions of the ACPI namespace and attach child devices.
+ *
+ * Note that we only expect to find devices in the \_TZ_, \_SI_ and \_SB_ scopes,
+ * and \_TZ_ becomes obsolete in the ACPI 2.0 spec.
+ */
+static void
+acpi_probe_children(device_t bus)
+{
+ ACPI_HANDLE parent;
+ static char *scopes[] = {"\\_TZ_", "\\_SI", "\\_SB_", NULL};
+ int i;
+
+ /*
+ * Create any static children by calling device identify methods.
+ */
+ bus_generic_probe(bus);
+
+ /*
+ * Scan the namespace and insert placeholders for all the devices that
+ * we find.
+ *
+ * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because
+ * we want to create nodes for all devices, not just those that are currently
+ * present. (This assumes that we don't want to create/remove devices as they
+ * appear, which might be smarter.)
+ */
+ for (i = 0; scopes[i] != NULL; i++)
+ if ((AcpiGetHandle(ACPI_ROOT_OBJECT, scopes[i], &parent)) == AE_OK)
+ AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, acpi_probe_child, bus, NULL);
+
+ /*
+ * Scan all of the child devices we have created and let them probe/attach.
+ */
+ bus_generic_attach(bus);
+
+ /*
+ * Some of these children may have attached others as part of their attach
+ * process (eg. the root PCI bus driver), so rescan.
+ */
+ bus_generic_attach(bus);
+}
+
+/*
+ * Evaluate a child device and determine whether we might attach a device to
+ * it.
+ */
+static ACPI_STATUS
+acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+ ACPI_OBJECT_TYPE type;
+ device_t child, bus = (device_t)context;
+
+ if (AcpiGetType(handle, &type) == AE_OK) {
+ switch(type) {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_POWER:
+ /*
+ * Create a placeholder device for this node. Sort the placeholder
+ * so that the probe/attach passes will run breadth-first.
+ */
+ child = BUS_ADD_CHILD(bus, level * 10, NULL, -1);
+ acpi_set_handle(child, handle);
+ }
+ }
+ return(AE_OK);
+}
+
+static void
+acpi_shutdown_pre_sync(void *arg, int howto)
+{
+ /*
+ * disable all of 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.
+ */
+ acpi_Disable((struct acpi_softc *)arg);
+}
+
+static void
+acpi_shutdown_final(void *arg, int howto)
+{
+ ACPI_STATUS status;
+
+ if (howto == RB_POWEROFF) {
+ printf("Power system off using ACPI...\n");
+ if ((status = AcpiSetSystemSleepState(ACPI_STATE_S5)) != AE_OK) {
+ printf("ACPI power-off failed - %s\n", acpi_strerror(status));
+ } else {
+ DELAY(1000000);
+ printf("ACPI power-off failed - timeout\n");
+ }
+ }
+}
+
+/*
+ * Match a HID string against a device
+ */
+BOOLEAN
+acpi_MatchHid(device_t dev, char *hid)
+{
+ ACPI_HANDLE h;
+ ACPI_DEVICE_INFO devinfo;
+ ACPI_STATUS error;
+
+ if ((hid == NULL) || (strlen(hid) != 7))
+ return(FALSE);
+ if ((h = acpi_get_handle(dev)) == NULL)
+ return(FALSE);
+ if ((error = AcpiGetObjectInfo(h, &devinfo)) != AE_OK)
+ return(FALSE);
+ if ((devinfo.Valid & ACPI_VALID_HID) && !strncmp(hid, devinfo.HardwareId, 7))
+ return(TRUE);
+ return(FALSE);
+}
+
+/*
+ * Perform the tedious double-get procedure required for fetching something into
+ * an ACPI_BUFFER that has not been initialised.
+ */
+ACPI_STATUS
+acpi_GetIntoBuffer(ACPI_HANDLE handle, ACPI_STATUS (*func)(ACPI_HANDLE, ACPI_BUFFER *), ACPI_BUFFER *buf)
+{
+ ACPI_STATUS status;
+
+ buf->Length = 0;
+ buf->Pointer = NULL;
+
+ if ((status = func(handle, buf)) != AE_BUFFER_OVERFLOW)
+ return(status);
+ if ((buf->Pointer = AcpiOsCallocate(buf->Length)) == NULL)
+ return(AE_NO_MEMORY);
+ return(func(handle, buf));
+}
+
+/*
+ * Allocate a buffer with a preset data size.
+ */
+ACPI_BUFFER *
+acpi_AllocBuffer(int size)
+{
+ ACPI_BUFFER *buf;
+
+ if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
+ return(NULL);
+ buf->Length = size;
+ buf->Pointer = (void *)(buf + 1);
+ return(buf);
+}
+
+/*
+ * Set the system sleep state
+ *
+ * Currently we only support S1 and S5
+ */
+ACPI_STATUS
+acpi_SetSleepState(struct acpi_softc *sc, int state)
+{
+ ACPI_STATUS status = AE_OK;
+
+ switch (state) {
+ case ACPI_STATE_S0: /* XXX only for testing */
+ status = AcpiSetSystemSleepState((UINT8)state);
+ if (status != AE_OK) {
+ device_printf(sc->acpi_dev, "AcpiSetSystemSleepState failed - %s\n", acpi_strerror(status));
+ }
+ break;
+
+ case ACPI_STATE_S1:
+ /*
+ * Inform all devices that we are going to sleep.
+ */
+ if (DEVICE_SUSPEND(root_bus) != 0) {
+ /*
+ * Re-wake the system.
+ *
+ * XXX note that a better two-pass approach with a 'veto' pass
+ * followed by a "real thing" pass would be better, but the
+ * current bus interface does not provide for this.
+ */
+ DEVICE_RESUME(root_bus);
+ return(AE_ERROR);
+ }
+ sc->acpi_sstate = state;
+ status = AcpiSetSystemSleepState((UINT8)state);
+ if (status != AE_OK) {
+ device_printf(sc->acpi_dev, "AcpiSetSystemSleepState failed - %s\n", acpi_strerror(status));
+ }
+ DEVICE_RESUME(root_bus);
+ sc->acpi_sstate = ACPI_STATE_S0;
+ break;
+
+ case ACPI_STATE_S5:
+ /*
+ * Shut down cleanly and power off. This will call us back through the
+ * shutdown handlers.
+ */
+ shutdown_nice(RB_POWEROFF);
+ break;
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+ return(status);
+}
+
+/*
+ * Enable/Disable ACPI
+ */
+ACPI_STATUS
+acpi_Enable(struct acpi_softc *sc)
+{
+ ACPI_STATUS status;
+ u_int32_t flags;
+
+ 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(status);
+}
+
+ACPI_STATUS
+acpi_Disable(struct acpi_softc *sc)
+{
+ ACPI_STATUS status;
+
+ if (sc->acpi_enabled) {
+ status = AcpiDisable();
+ } else {
+ status = AE_OK;
+ }
+ if (status == AE_OK)
+ sc->acpi_enabled = 0;
+ return(status);
+}
+
+/*
+ * Returns true if the device is actually present and should
+ * be attached to. This requires the present, enabled, UI-visible
+ * and diagnostics-passed bits to be set.
+ */
+BOOLEAN
+acpi_DeviceIsPresent(device_t dev)
+{
+ ACPI_HANDLE h;
+ ACPI_DEVICE_INFO devinfo;
+ ACPI_STATUS error;
+
+ if ((h = acpi_get_handle(dev)) == NULL)
+ return(FALSE);
+ if ((error = AcpiGetObjectInfo(h, &devinfo)) != AE_OK)
+ return(FALSE);
+ if ((devinfo.Valid & ACPI_VALID_HID) && (devinfo.CurrentStatus & 0xf))
+ return(TRUE);
+ return(FALSE);
+}
+
+/*
+ * Evaluate a path that should return a number
+ */
+ACPI_STATUS
+acpi_EvaluateNumber(ACPI_HANDLE handle, char *path, int *number)
+{
+ ACPI_STATUS error;
+ ACPI_BUFFER buf;
+ int param[4];
+
+ if (handle == NULL)
+ handle = ACPI_ROOT_OBJECT;
+ buf.Pointer = &param[0];
+ buf.Length = sizeof(param);
+ if ((error = AcpiEvaluateObject(handle, path, NULL, &buf)) == AE_OK) {
+ if (param[0] == ACPI_TYPE_NUMBER) {
+ *number = param[1];
+ } else {
+ error = AE_TYPE;
+ }
+ }
+ return(error);
+}
+
+/*
+ * ACPI Event Handlers
+ */
+
+/* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
+
+static void
+acpi_system_eventhandler_sleep(void *arg, int state)
+{
+ if (state < ACPI_STATE_S0 || state > ACPI_STATE_S5) {
+ return;
+ }
+
+ acpi_SetSleepState((struct acpi_softc *)arg, state);
+}
+
+
+static void
+acpi_system_eventhandler_wakeup(void *arg, int state)
+{
+ /* Well, what to do? :-) */
+}
+
+/*
+ * ACPICA Event Handlers (FixedEvent, also called from button notify handler)
+ */
+UINT32
+acpi_eventhandler_power_button_for_sleep(void *context)
+{
+ struct acpi_softc *sc = (struct acpi_softc *)context;
+
+ EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_power_button_sx);
+ return(INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_eventhandler_power_button_for_wakeup(void *context)
+{
+ struct acpi_softc *sc = (struct acpi_softc *)context;
+
+ EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_power_button_sx);
+ return(INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_eventhandler_sleep_button_for_sleep(void *context)
+{
+ struct acpi_softc *sc = (struct acpi_softc *)context;
+
+ EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_sleep_button_sx);
+ return(INTERRUPT_HANDLED);
+}
+
+UINT32
+acpi_eventhandler_sleep_button_for_wakeup(void *context)
+{
+ struct acpi_softc *sc = (struct acpi_softc *)context;
+
+ EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_sleep_button_sx);
+ return(INTERRUPT_HANDLED);
+}
+
+/*
+ * XXX This is kinda ugly, and should not be here.
+ */
+struct acpi_staticbuf {
+ ACPI_BUFFER buffer;
+ char data[512];
+};
+
+char *
+acpi_strerror(ACPI_STATUS excep)
+{
+ static struct acpi_staticbuf buf;
+
+ buf.buffer.Length = 512;
+ buf.buffer.Pointer = &buf.data[0];
+
+ if (AcpiFormatException(excep, &buf.buffer) == AE_OK)
+ return(buf.buffer.Pointer);
+ return("(error formatting exception)");
+}
+
+char *
+acpi_name(ACPI_HANDLE handle)
+{
+ static struct acpi_staticbuf buf;
+
+ buf.buffer.Length = 512;
+ buf.buffer.Pointer = &buf.data[0];
+
+ if (AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf.buffer) == AE_OK)
+ return(buf.buffer.Pointer);
+ return("(unknown path)");
+}
+
+/*
+ * Debugging/bug-avoidance. Avoid trying to fetch info on various
+ * parts of the namespace.
+ */
+int
+acpi_avoid(ACPI_HANDLE handle)
+{
+ char *cp, *np;
+ int len;
+
+ np = acpi_name(handle);
+ if (*np == '\\')
+ np++;
+ if ((cp = getenv("debug.acpi.avoid")) == NULL)
+ return(0);
+
+ /* scan the avoid list checking for a match */
+ for (;;) {
+ while ((*cp != 0) && isspace(*cp))
+ cp++;
+ if (*cp == 0)
+ break;
+ len = 0;
+ while ((cp[len] != 0) && !isspace(cp[len]))
+ len++;
+ if (!strncmp(cp, np, len)) {
+ printf("avoiding '%s'\n", np);
+ return(1);
+ }
+ cp += len;
+ }
+ return(0);
+}
+
+/*
+ * Control interface.
+ *
+ * XXX this is provided as a temporary measure for
+ * backwards compatibility for now. A better
+ * interface will probably use sysctl or similar.
+ */
+static int
+acpiopen(dev_t dev, int flag, int fmt, struct proc * p)
+{
+ return(0);
+}
+
+static int
+acpiclose(dev_t dev, int flag, int fmt, struct proc * p)
+{
+ return(0);
+}
+
+static int
+acpiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc * p)
+{
+ int error, state;
+ struct acpi_softc *sc;
+
+ error = state = 0;
+ sc = dev->si_drv1;
+
+ switch (cmd) {
+ case ACPIIO_ENABLE:
+ if (ACPI_FAILURE(acpi_Enable(sc))) {
+ error = ENXIO;
+ }
+ break;
+
+ case ACPIIO_DISABLE:
+ if (ACPI_FAILURE(acpi_Disable(sc))) {
+ error = ENXIO;
+ }
+ break;
+
+ case ACPIIO_SETSLPSTATE:
+ if (!sc->acpi_enabled) {
+ error = ENXIO;
+ break;
+ }
+ state = *(int *)addr;
+ if (state >= ACPI_STATE_S0 && state <= ACPI_STATE_S5) {
+ acpi_SetSleepState(sc, state);
+ } else {
+ error = EINVAL;
+ }
+
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return(error);
+}
+
+#ifdef ACPI_DEBUG
+struct debugtag
+{
+ char *name;
+ UINT32 value;
+};
+
+static struct debugtag dbg_layer[] = {
+ {"GLOBAL", 0x00000001},
+ {"COMMON", 0x00000002},
+ {"PARSER", 0x00000004},
+ {"DISPATCHER", 0x00000008},
+ {"INTERPRETER", 0x00000010},
+ {"NAMESPACE", 0x00000020},
+ {"RESOURCE_MANAGER", 0x00000040},
+ {"TABLE_MANAGER", 0x00000080},
+ {"EVENT_HANDLING", 0x00000100},
+ {"HARDWARE", 0x00000200},
+ {"MISCELLANEOUS", 0x00000400},
+ {"OS_DEPENDENT", 0x00000800},
+ {"BUS_MANAGER", 0x00001000},
+ {"PROCESSOR_CONTROL", 0x00002000},
+ {"SYSTEM_CONTROL", 0x00004000},
+ {"THERMAL_CONTROL", 0x00008000},
+ {"POWER_CONTROL", 0x00010000},
+ {"EMBEDDED_CONTROLLER", 0x00020000},
+ {"BATTERY", 0x00040000},
+ {"DEBUGGER", 0x00100000},
+ {"ALL_COMPONENTS", 0x001FFFFF},
+ {NULL, 0}
+};
+
+static struct debugtag dbg_level[] = {
+ {"ACPI_OK", 0x00000001},
+ {"ACPI_INFO", 0x00000002},
+ {"ACPI_WARN", 0x00000004},
+ {"ACPI_ERROR", 0x00000008},
+ {"ACPI_FATAL", 0x00000010},
+ {"ACPI_DEBUG_OBJECT", 0x00000020},
+ {"ACPI_ALL", 0x0000003F},
+ {"TRACE_PARSE", 0x00000100},
+ {"TRACE_DISPATCH", 0x00000200},
+ {"TRACE_LOAD", 0x00000400},
+ {"TRACE_EXEC", 0x00000800},
+ {"TRACE_NAMES", 0x00001000},
+ {"TRACE_OPREGION", 0x00002000},
+ {"TRACE_BFIELD", 0x00004000},
+ {"TRACE_TRASH", 0x00008000},
+ {"TRACE_TABLES", 0x00010000},
+ {"TRACE_FUNCTIONS", 0x00020000},
+ {"TRACE_VALUES", 0x00040000},
+ {"TRACE_OBJECTS", 0x00080000},
+ {"TRACE_ALLOCATIONS", 0x00100000},
+ {"TRACE_RESOURCES", 0x00200000},
+ {"TRACE_IO", 0x00400000},
+ {"TRACE_INTERRUPTS", 0x00800000},
+ {"TRACE_USER_REQUESTS", 0x01000000},
+ {"TRACE_PACKAGE", 0x02000000},
+ {"TRACE_MUTEX", 0x04000000},
+ {"TRACE_ALL", 0x0FFFFF00},
+ {"VERBOSE_AML_DISASSEMBLE", 0x10000000},
+ {"VERBOSE_INFO", 0x20000000},
+ {"VERBOSE_TABLES", 0x40000000},
+ {"VERBOSE_EVENTS", 0x80000000},
+ {"VERBOSE_ALL", 0xF0000000},
+ {NULL, 0}
+};
+
+static void
+acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
+{
+ char *ep;
+ int i, l;
+
+ while (*cp) {
+ if (isspace(*cp)) {
+ cp++;
+ continue;
+ }
+ ep = cp;
+ while (*ep && !isspace(*ep))
+ ep++;
+ l = ep - cp;
+ for (i = 0; tag[i].name != NULL; i++) {
+ if (!strncmp(cp, tag[i].name, l)) {
+ *flag |= tag[i].value;
+ printf("ACPI_DEBUG: set '%s'\n", tag[i].name);
+ }
+ }
+ cp = ep;
+ }
+}
+
+static void
+acpi_set_debugging(void)
+{
+ char *cp;
+
+ if ((cp = getenv("debug.acpi.layer")) != NULL)
+ acpi_parse_debug(cp, &dbg_layer[0], &AcpiDbgLayer);
+ if ((cp = getenv("debug.acpi.level")) != NULL)
+ acpi_parse_debug(cp, &dbg_level[0], &AcpiDbgLevel);
+}
+#endif
diff --git a/sys/dev/acpica/acpi_apic.c b/sys/dev/acpica/acpi_apic.c
new file mode 100644
index 0000000..1a83b1d
--- /dev/null
+++ b/sys/dev/acpica/acpi_apic.c
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * XXX This is all pretty dubious, since we really want the APIC and co.
+ * up and running long before attaching interrupts, etc.
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#define APIC_MAGIC 0x43495041 /* "APIC" */
+
+struct acpi_apic_softc {
+ device_t apic_dev;
+ IO_APIC *apic_ioapic;
+};
+
+static void acpi_apic_identify(driver_t *driver, device_t bus);
+static int acpi_apic_probe(device_t dev);
+static int acpi_apic_attach(device_t dev);
+
+static device_method_t acpi_apic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_apic_identify),
+ DEVMETHOD(device_probe, acpi_apic_probe),
+ DEVMETHOD(device_attach, acpi_apic_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_apic_driver = {
+ "acpi_apic",
+ acpi_apic_methods,
+ sizeof(struct acpi_apic_softc),
+};
+
+devclass_t acpi_apic_devclass;
+DRIVER_MODULE(acpi_apic, acpi, acpi_apic_driver, acpi_apic_devclass, 0, 0);
+
+static void
+acpi_apic_identify(driver_t *driver, device_t bus)
+{
+ ACPI_BUFFER buf;
+ ACPI_STATUS status;
+ APIC_HEADER *hdr;
+ APIC_TABLE *tbl;
+ device_t child;
+ int len;
+ void *private;
+
+ /*
+ * Perform the tedious double-get to fetch the actual table.
+ */
+ buf.Length = 0;
+ buf.Pointer = NULL;
+ if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_BUFFER_OVERFLOW) {
+ if (status != AE_NOT_EXIST)
+ device_printf(bus, "error sizing APIC table - %s\n", acpi_strerror(status));
+ return;
+ }
+ if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL)
+ return;
+ if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_OK) {
+ device_printf(bus, "error fetching APIC table - %s\n", acpi_strerror(status));
+ return;
+ }
+
+ /*
+ * Scan the tables, create child devices for each I/O APIC found
+ */
+ tbl = (APIC_TABLE *)buf.Pointer;
+ len = tbl->header.Length - sizeof(APIC_TABLE);
+ hdr = (APIC_HEADER *)((char *)buf.Pointer + sizeof(APIC_TABLE));
+ while(len > 0) {
+ if (hdr->Length > len) {
+ device_printf(bus, "APIC header corrupt (claims %d bytes where only %d left in structure)\n",
+ hdr->Length, len);
+ break;
+ }
+ switch (hdr->Type) {
+ case APIC_IO:
+ if ((child = BUS_ADD_CHILD(bus, 0, "acpi_apic", -1)) == NULL) {
+ device_printf(bus, "could not create I/O APIC device");
+ break;
+ }
+ if ((private = AcpiOsAllocate(hdr->Length)) == NULL) {
+ device_printf(bus, "could not allocate memory for APIC child");
+ break;
+ }
+ bcopy(hdr, private, hdr->Length);
+ acpi_set_magic(child, APIC_MAGIC);
+ acpi_set_private(child, private);
+ device_set_desc(child, "I/O APIC");
+ break;
+ }
+ len -= hdr->Length;
+ hdr = (APIC_HEADER *)((char *)hdr + hdr->Length);
+ }
+
+ AcpiOsFree(buf.Pointer);
+}
+
+static int
+acpi_apic_probe(device_t dev)
+{
+ if (acpi_get_magic(dev) == APIC_MAGIC)
+ return(0);
+ return(ENXIO);
+}
+
+static int
+acpi_apic_attach(device_t dev)
+{
+ struct acpi_apic_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->apic_dev = dev;
+
+ /*
+ * Fetch our parameters.
+ */
+ sc->apic_ioapic = acpi_get_private(dev);
+ device_printf(dev, "I/O APIC ID %d at 0x%08x vectors 0%x\n",
+ sc->apic_ioapic->IoApicId, sc->apic_ioapic->IoApicAddress, sc->apic_ioapic->Vector);
+ return(0);
+}
diff --git a/sys/dev/acpica/acpi_button.c b/sys/dev/acpica/acpi_button.c
new file mode 100644
index 0000000..cc6b4c2
--- /dev/null
+++ b/sys/dev/acpica/acpi_button.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+struct acpi_button_softc {
+ device_t button_dev;
+ ACPI_HANDLE button_handle;
+#define ACPI_POWER_BUTTON 0
+#define ACPI_SLEEP_BUTTON 1
+ boolean_t button_type; /* Power or Sleep Button */
+};
+
+static int acpi_button_probe(device_t dev);
+static int acpi_button_attach(device_t dev);
+static void acpi_button_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context);
+static void acpi_button_notify_pressed_for_sleep(void *arg);
+static void acpi_button_notify_pressed_for_wakeup(void *arg);
+
+static device_method_t acpi_button_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, acpi_button_probe),
+ DEVMETHOD(device_attach, acpi_button_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_button_driver = {
+ "acpi_button",
+ acpi_button_methods,
+ sizeof(struct acpi_button_softc),
+};
+
+devclass_t acpi_button_devclass;
+DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 0, 0);
+
+static int
+acpi_button_probe(device_t dev)
+{
+ struct acpi_button_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (acpi_get_type(dev) == ACPI_TYPE_DEVICE) {
+ if (acpi_MatchHid(dev, "PNP0C0C")) {
+ device_set_desc(dev, "Control Method Power Button Device");
+ sc->button_type = ACPI_POWER_BUTTON;
+ return(0);
+ }
+ if (acpi_MatchHid(dev, "PNP0C0E")) {
+ device_set_desc(dev, "Control Method Sleep Button Device");
+ sc->button_type = ACPI_SLEEP_BUTTON;
+ return(0);
+ }
+ return(ENXIO);
+ }
+ return(ENXIO);
+}
+
+static int
+acpi_button_attach(device_t dev)
+{
+ struct acpi_button_softc *sc;
+ ACPI_STATUS status;
+
+ sc = device_get_softc(dev);
+ sc->button_dev = dev;
+ sc->button_handle = acpi_get_handle(dev);
+
+ if ((status = AcpiInstallNotifyHandler(sc->button_handle, ACPI_DEVICE_NOTIFY,
+ acpi_button_notify_handler, sc)) != AE_OK) {
+ device_printf(sc->button_dev, "couldn't install Notify handler - %s\n", acpi_strerror(status));
+ return(ENXIO);
+ }
+ return(0);
+}
+
+static void
+acpi_button_notify_pressed_for_sleep(void *arg)
+{
+ struct acpi_button_softc *sc;
+ struct acpi_softc *acpi_sc;
+
+ sc = (struct acpi_button_softc *)arg;
+ acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
+ if (acpi_sc == NULL) {
+ return;
+ }
+
+ switch (sc->button_type) {
+ case ACPI_POWER_BUTTON:
+ acpi_eventhandler_power_button_for_sleep((void *)acpi_sc);
+ break;
+ case ACPI_SLEEP_BUTTON:
+ acpi_eventhandler_sleep_button_for_sleep((void *)acpi_sc);
+ break;
+ default:
+ return; /* unknown button type */
+ }
+}
+
+static void
+acpi_button_notify_pressed_for_wakeup(void *arg)
+{
+ struct acpi_button_softc *sc;
+ struct acpi_softc *acpi_sc;
+
+ sc = (struct acpi_button_softc *)arg;
+ acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
+ if (acpi_sc == NULL) {
+ return;
+ }
+
+ switch (sc->button_type) {
+ case ACPI_POWER_BUTTON:
+ acpi_eventhandler_power_button_for_wakeup((void *)acpi_sc);
+ break;
+ case ACPI_SLEEP_BUTTON:
+ acpi_eventhandler_sleep_button_for_wakeup((void *)acpi_sc);
+ break;
+ default:
+ return; /* unknown button type */
+ }
+}
+
+/* XXX maybe not here */
+#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80
+#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02
+
+static void
+acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+ struct acpi_button_softc *sc = (struct acpi_button_softc *)context;
+
+ switch (notify) {
+ case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
+ AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_sleep, sc);
+ device_printf(sc->button_dev, "pressed for sleep, button type: %d\n", sc->button_type);
+ break;
+ case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
+ AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_wakeup, sc);
+ device_printf(sc->button_dev, "pressed for wakeup, button type: %d\n", sc->button_type);
+ break;
+ default:
+ return; /* unknown notification value */
+ }
+}
+
+
diff --git a/sys/dev/acpica/acpi_ec.c b/sys/dev/acpica/acpi_ec.c
new file mode 100644
index 0000000..ff4fa6c
--- /dev/null
+++ b/sys/dev/acpica/acpi_ec.c
@@ -0,0 +1,710 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+#include <dev/acpica/acpi_ecreg.h>
+
+struct acpi_ec_softc {
+ device_t ec_dev;
+ ACPI_HANDLE ec_handle;
+ ACPI_HANDLE ec_semaphore;
+ UINT32 ec_gpebit;
+
+ int ec_data_rid;
+ struct resource *ec_data_res;
+ bus_space_tag_t ec_data_tag;
+ bus_space_handle_t ec_data_handle;
+
+ int ec_csr_rid;
+ struct resource *ec_csr_res;
+ bus_space_tag_t ec_csr_tag;
+ bus_space_handle_t ec_csr_handle;
+
+ int ec_locked;
+};
+
+#define EC_LOCK_TIMEOUT 1000 /* 1ms */
+
+static __inline ACPI_STATUS
+EcLock(struct acpi_ec_softc *sc)
+{
+ ACPI_STATUS status;
+
+ status = AcpiOsWaitSemaphore((sc)->ec_semaphore, 1, EC_LOCK_TIMEOUT);
+ (sc)->ec_locked = 1;
+ return(status);
+}
+
+static __inline void
+EcUnlock(struct acpi_ec_softc *sc)
+{
+ (sc)->ec_locked = 0;
+ AcpiOsSignalSemaphore((sc)->ec_semaphore, 1);
+}
+
+static __inline int
+EcIsLocked(struct acpi_ec_softc *sc)
+{
+ return((sc)->ec_locked != 0);
+}
+
+typedef struct
+{
+ EC_COMMAND Command;
+ UINT8 Address;
+ UINT8 Data;
+} EC_REQUEST;
+
+static struct acpi_ec_softc acpi_ec_default; /* for the default EC handler */
+
+static void EcGpeHandler(void *Context);
+static ACPI_STATUS EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
+ void *Context, void **return_Context);
+static ACPI_STATUS EcSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value,
+ void *Context, void *RegionContext);
+static ACPI_STATUS EcDefaultSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value,
+ void *Context, void *RegionContext);
+
+static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
+static ACPI_STATUS EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
+static ACPI_STATUS EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
+static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
+static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
+
+static void acpi_ec_identify(driver_t driver, device_t bus);
+static int acpi_ec_probe(device_t dev);
+static int acpi_ec_attach(device_t dev);
+
+static device_method_t acpi_ec_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_ec_identify),
+ DEVMETHOD(device_probe, acpi_ec_probe),
+ DEVMETHOD(device_attach, acpi_ec_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_ec_driver = {
+ "acpi_ec",
+ acpi_ec_methods,
+ sizeof(struct acpi_ec_softc),
+};
+
+devclass_t acpi_ec_devclass;
+DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
+
+/*
+ * Look for an ECDT table and if we find one, set up a default EC
+ * space handler to catch possible attempts to access EC space before
+ * we have a real driver instance in place.
+ * We're not really an identify routine, but because we get called
+ * before most other things, this works out OK.
+ */
+static void
+acpi_ec_identify(driver_t driver, device_t bus)
+{
+ ACPI_STATUS Status;
+
+ /* XXX implement - need an ACPI 2.0 system to test this */
+
+ /*
+ * XXX install a do-nothing handler at the top of the namespace to catch
+ * bogus accesses being made due to apparent interpreter bugs.
+ */
+ acpi_ec_default.ec_dev = bus;
+ if ((Status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ADDRESS_SPACE_EC,
+ &EcDefaultSpaceHandler, &EcSpaceSetup,
+ &acpi_ec_default)) != AE_OK) {
+ device_printf(acpi_ec_default.ec_dev, "can't install default EC address space handler - %s\n",
+ acpi_strerror(Status));
+ }
+}
+
+/*
+ * We could setup resources in the probe routine in order to have them printed
+ * when the device is attached.
+ */
+static int
+acpi_ec_probe(device_t dev)
+{
+ if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
+ acpi_MatchHid(dev, "PNP0C09")) {
+
+ /*
+ * Set device description
+ */
+ device_set_desc(dev, "embedded controller");
+
+ return(0);
+ }
+ return(ENXIO);
+}
+
+static int
+acpi_ec_attach(device_t dev)
+{
+ struct acpi_ec_softc *sc;
+ ACPI_BUFFER *bufp;
+ UINT32 *param;
+ ACPI_STATUS Status;
+ struct acpi_object_list *args;
+
+ /*
+ * Fetch/initialise softc
+ */
+ sc = device_get_softc(dev);
+ sc->ec_dev = dev;
+ sc->ec_handle = acpi_get_handle(dev);
+
+ /*
+ * Evaluate resources
+ */
+ acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
+
+ /*
+ * Attach bus resources
+ */
+ sc->ec_data_rid = 0;
+ if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
+ 0, ~0, 1, RF_ACTIVE)) == NULL) {
+ device_printf(dev, "can't allocate data port\n");
+ return(ENXIO);
+ }
+ sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
+ sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
+
+ sc->ec_csr_rid = 1;
+ if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
+ 0, ~0, 1, RF_ACTIVE)) == NULL) {
+ device_printf(dev, "can't allocate command/status port\n");
+ return(ENXIO);
+ }
+ sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
+ sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
+
+ /*
+ * Create serialisation semaphore
+ */
+ if ((Status = AcpiOsCreateSemaphore(1, 1, &sc->ec_semaphore)) != AE_OK) {
+ device_printf(dev, "can't create semaphore - %s\n", acpi_strerror(Status));
+ return(ENXIO);
+ }
+
+ /*
+ * Install GPE handler
+ *
+ * Evaluate the _GPE method to find the GPE bit used by the EC to signal
+ * status (SCI).
+ */
+ if ((bufp = acpi_AllocBuffer(16)) == NULL)
+ return(ENOMEM);
+ if ((Status = AcpiEvaluateObject(sc->ec_handle, "_GPE", NULL, bufp)) != AE_OK) {
+ device_printf(dev, "can't evaluate _GPE method - %s\n", acpi_strerror(Status));
+ return(ENXIO);
+ }
+ param = (UINT32 *)bufp->Pointer;
+ if (param[0] != ACPI_TYPE_NUMBER) {
+ device_printf(dev, "_GPE method returned bad result\n");
+ return(ENXIO);
+ }
+ sc->ec_gpebit = param[1];
+ AcpiOsFree(bufp);
+
+ /*
+ * Install a handler for this EC's GPE bit. Note that EC SCIs are
+ * treated as both edge- and level-triggered interrupts; in other words
+ * we clear the status bit immediately after getting an EC-SCI, then
+ * again after we're done processing the event. This guarantees that
+ * events we cause while performing a transaction (e.g. IBE/OBF) get
+ * cleared before re-enabling the GPE.
+ */
+ if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
+ EcGpeHandler, sc)) != AE_OK) {
+ device_printf(dev, "can't install GPE handler - %s\n", acpi_strerror(Status));
+ return(ENXIO);
+ }
+
+ /*
+ * Install address space handler
+ */
+ if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ADDRESS_SPACE_EC,
+ &EcSpaceHandler, &EcSpaceSetup, sc)) != AE_OK) {
+ device_printf(dev, "can't install address space handler - %s\n", acpi_strerror(Status));
+ return(ENXIO);
+ }
+
+ /*
+ * Evaluate _REG to indicate that the region is now available.
+ */
+ if ((args = acpi_AllocObjectList(2)) == NULL)
+ return(ENOMEM);
+ args->object[0].Type = ACPI_TYPE_NUMBER;
+ args->object[0].Number.Value = ADDRESS_SPACE_EC;
+ args->object[1].Type = ACPI_TYPE_NUMBER;
+ args->object[1].Number.Value = 1;
+ Status = AcpiEvaluateObject(sc->ec_handle, "_REG", (ACPI_OBJECT_LIST *)args, NULL);
+ AcpiOsFree(args);
+ /*
+ * If evaluation failed for some reason other than that the method didn't
+ * exist, that's bad and we should not attach.
+ */
+ if ((Status != AE_OK) && (Status != AE_NOT_FOUND)) {
+ device_printf(dev, "can't evaluate _REG method - %s\n", acpi_strerror(Status));
+ return(ENXIO);
+ }
+
+ return(0);
+}
+
+static void
+EcGpeHandler(void *Context)
+{
+ struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context;
+ UINT8 Data;
+ ACPI_STATUS Status;
+ char qxx[5];
+
+ for (;;) {
+
+ /*
+ * Check EC_SCI.
+ *
+ * Bail out if the EC_SCI bit of the status register is not set.
+ * Note that this function should only be called when
+ * this bit is set (polling is used to detect IBE/OBF events).
+ *
+ * It is safe to do this without locking the controller, as it's
+ * OK to call EcQuery when there's no data ready; in the worst
+ * case we should just find nothing waiting for us and bail.
+ */
+ if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
+ break;
+
+ /*
+ * Find out why the EC is signalling us
+ */
+ Status = EcQuery(sc, &Data);
+
+ /*
+ * If we failed to get anything from the EC, give up
+ */
+ if (Status != AE_OK) {
+ device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
+ break;
+ }
+
+ /*
+ * Evaluate _Qxx to respond to the controller.
+ */
+ sprintf(qxx, "_Q%02x", Data);
+ strupr(qxx);
+ if ((Status - AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) {
+ device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
+ qxx, acpi_strerror(Status));
+ }
+ }
+}
+
+static ACPI_STATUS
+EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
+{
+ /*
+ * Just pass the context through, there's nothing to do here.
+ */
+ *RegionContext = Context;
+
+ return(AE_OK);
+}
+
+static ACPI_STATUS
+EcSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value, void *Context, void *RegionContext)
+{
+ struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context;
+ ACPI_STATUS Status = AE_OK;
+ EC_REQUEST EcRequest;
+
+ if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL))
+ return(AE_BAD_PARAMETER);
+
+ switch (Function) {
+ case ADDRESS_SPACE_READ:
+ EcRequest.Command = EC_COMMAND_READ;
+ EcRequest.Address = Address;
+ EcRequest.Data = 0;
+ break;
+
+ case ADDRESS_SPACE_WRITE:
+ EcRequest.Command = EC_COMMAND_WRITE;
+ EcRequest.Address = Address;
+ EcRequest.Data = (UINT8)(*Value);
+ break;
+
+ default:
+ device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
+ return(AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Perform the transaction.
+ */
+ if ((Status = EcTransaction(sc, &EcRequest)) == AE_OK)
+ (*Value) = (UINT32)EcRequest.Data;
+
+ return(Status);
+}
+
+static ACPI_STATUS
+EcDefaultSpaceHandler(UINT32 Function, UINT32 Address, UINT32 width, UINT32 *Value, void *Context, void *RegionContext)
+{
+ if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL))
+ return(AE_BAD_PARAMETER);
+
+ switch (Function) {
+ case ADDRESS_SPACE_READ:
+ printf("ACPI: Illegal EC read from 0x%x\n", Address);
+ *Value = 0;
+ break;
+ case ADDRESS_SPACE_WRITE:
+ printf("ACPI: Illegal EC write 0x%x to 0x%x\n", *Value, Address);
+ break;
+ default:
+ printf("ACPI: Illegal EC unknown operation");
+ break;
+ }
+ /* let things keep going */
+ return(AE_OK);
+}
+
+static ACPI_STATUS
+EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
+{
+ EC_STATUS EcStatus;
+ UINT32 i = 0;
+
+ if (!EcIsLocked(sc))
+ device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
+
+ /*
+ * Stall 1us:
+ * ----------
+ * Stall for 1 microsecond before reading the status register
+ * for the first time. This allows the EC to set the IBF/OBF
+ * bit to its proper state.
+ *
+ * XXX it is not clear why we read the CSR twice.
+ */
+ AcpiOsSleepUsec(1);
+ EcStatus = EC_GET_CSR(sc);
+
+ /*
+ * Wait For Event:
+ * ---------------
+ * Poll the EC status register to detect completion of the last
+ * command. Wait up to 10ms (in 100us chunks) for this to occur.
+ */
+ for (i = 0; i < 100; i++) {
+ EcStatus = EC_GET_CSR(sc);
+
+ if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
+ (EcStatus & EC_FLAG_OUTPUT_BUFFER))
+ return(AE_OK);
+
+ if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
+ !(EcStatus & EC_FLAG_INPUT_BUFFER))
+ return(AE_OK);
+
+ AcpiOsSleepUsec(100);
+ }
+
+ return(AE_ERROR);
+}
+
+static ACPI_STATUS
+EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
+{
+ ACPI_STATUS Status;
+
+ if ((Status = EcLock(sc)) != AE_OK)
+ return(Status);
+
+ EC_SET_CSR(sc, EC_COMMAND_QUERY);
+ Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
+ if (Status == AE_OK)
+ *Data = EC_GET_DATA(sc);
+
+ EcUnlock(sc);
+
+ if (Status != AE_OK)
+ device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
+ return(Status);
+}
+
+
+static ACPI_STATUS
+EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
+{
+ ACPI_STATUS Status;
+
+ /*
+ * Lock the EC
+ */
+ if ((Status = EcLock(sc)) != AE_OK)
+ return(Status);
+
+ /*
+ * Disable EC GPE:
+ * ---------------
+ * Disable EC interrupts (GPEs) from occuring during this transaction.
+ * This is done here as EcTransaction() is also called by the EC GPE
+ * handler -- where disabling/re-enabling the EC GPE is automatically
+ * handled by the ACPI Core Subsystem.
+ */
+ if (AcpiDisableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
+ device_printf(sc->ec_dev, "EcRequest: Unable to disable the EC GPE.\n");
+
+ /*
+ * Perform the transaction.
+ */
+ switch (EcRequest->Command) {
+ case EC_COMMAND_READ:
+ Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
+ break;
+
+ case EC_COMMAND_WRITE:
+ Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
+ break;
+
+ default:
+ Status = AE_SUPPORT;
+ break;
+ }
+
+ /*
+ * Clear & Re-Enable the EC GPE:
+ * -----------------------------
+ * 'Consume' any EC GPE events that we generated while performing
+ * the transaction (e.g. IBF/OBF). Clearing the GPE here shouldn't
+ * have an adverse affect on outstanding EC-SCI's, as the source
+ * (EC-SCI) will still be high and thus should trigger the GPE
+ * immediately after we re-enabling it.
+ */
+ if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
+ device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
+ if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
+ device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
+
+ /*
+ * Unlock the EC
+ */
+ EcUnlock(sc);
+
+ return(Status);
+}
+
+
+static ACPI_STATUS
+EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
+{
+ ACPI_STATUS Status;
+
+ if (!EcIsLocked(sc))
+ device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
+
+ /*EcBurstEnable(EmbeddedController);*/
+
+ EC_SET_CSR(sc, EC_COMMAND_READ);
+ if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
+ return(Status);
+ }
+
+ EC_SET_DATA(sc, Address);
+ if ((Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
+ device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
+ return(Status);
+ }
+
+ (*Data) = EC_GET_DATA(sc);
+
+ /*EcBurstDisable(EmbeddedController);*/
+
+ return(AE_OK);
+}
+
+static ACPI_STATUS
+EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
+{
+ ACPI_STATUS Status;
+
+ if (!EcIsLocked(sc))
+ device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
+
+ /*EcBurstEnable(EmbeddedController);*/
+
+ EC_SET_CSR(sc, EC_COMMAND_WRITE);
+ if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
+ return(Status);
+ }
+
+ EC_SET_DATA(sc, Address);
+ if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
+ return(Status);
+ }
+
+ EC_SET_DATA(sc, *Data);
+ if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
+ return(Status);
+ }
+
+ /*EcBurstDisable(EmbeddedController);*/
+
+ return(AE_OK);
+}
diff --git a/sys/dev/acpica/acpi_ecreg.h b/sys/dev/acpica/acpi_ecreg.h
new file mode 100644
index 0000000..344ff28
--- /dev/null
+++ b/sys/dev/acpica/acpi_ecreg.h
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+/*
+ * EC_COMMAND:
+ * -----------
+ */
+typedef UINT8 EC_COMMAND;
+
+#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00)
+#define EC_COMMAND_READ ((EC_COMMAND) 0x80)
+#define EC_COMMAND_WRITE ((EC_COMMAND) 0x81)
+#define EC_COMMAND_BURST_ENABLE ((EC_COMMAND) 0x82)
+#define EC_COMMAND_BURST_DISABLE ((EC_COMMAND) 0x83)
+#define EC_COMMAND_QUERY ((EC_COMMAND) 0x84)
+
+/*
+ * EC_STATUS:
+ * ----------
+ * The encoding of the EC status register is illustrated below.
+ * Note that a set bit (1) indicates the property is TRUE
+ * (e.g. if bit 0 is set then the output buffer is full).
+ * +-+-+-+-+-+-+-+-+
+ * |7|6|5|4|3|2|1|0|
+ * +-+-+-+-+-+-+-+-+
+ * | | | | | | | |
+ * | | | | | | | +- Output Buffer Full?
+ * | | | | | | +--- Input Buffer Full?
+ * | | | | | +----- <reserved>
+ * | | | | +------- Data Register is Command Byte?
+ * | | | +--------- Burst Mode Enabled?
+ * | | +----------- SCI Event?
+ * | +------------- SMI Event?
+ * +--------------- <Reserved>
+ *
+ */
+typedef UINT8 EC_STATUS;
+
+#define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01)
+#define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02)
+#define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10)
+#define EC_FLAG_SCI ((EC_STATUS) 0x20)
+
+/*
+ * EC_EVENT:
+ * ---------
+ */
+typedef UINT8 EC_EVENT;
+
+#define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00)
+#define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01)
+#define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02)
+#define EC_EVENT_SCI ((EC_EVENT) 0x20)
+
+/*
+ * Register access primitives
+ */
+#define EC_GET_DATA(sc) bus_space_read_1 (sc->ec_data_tag, sc->ec_data_handle, 0)
+#define EC_SET_DATA(sc, v) bus_space_write_1(sc->ec_data_tag, sc->ec_data_handle, 0, v)
+#define EC_GET_CSR(sc) bus_space_read_1 (sc->ec_csr_tag, sc->ec_csr_handle, 0)
+#define EC_SET_CSR(sc, v) bus_space_write_1(sc->ec_csr_tag, sc->ec_csr_handle, 0, v)
+
diff --git a/sys/dev/acpica/acpi_isa.c b/sys/dev/acpica/acpi_isa.c
new file mode 100644
index 0000000..3aa03c1
--- /dev/null
+++ b/sys/dev/acpica/acpi_isa.c
@@ -0,0 +1,442 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * ISA bus enumerator using PnP HIDs from ACPI space.
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+
+#include <isa/isavar.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#define PNP_HEXTONUM(c) ((c) >= 'a' \
+ ? (c) - 'a' + 10 \
+ : ((c) >= 'A' \
+ ? (c) - 'A' + 10 \
+ : (c) - '0'))
+#define PNP_EISAID(s) \
+ ((((s[0] - '@') & 0x1f) << 2) \
+ | (((s[1] - '@') & 0x18) >> 3) \
+ | (((s[1] - '@') & 0x07) << 13) \
+ | (((s[2] - '@') & 0x1f) << 8) \
+ | (PNP_HEXTONUM(s[4]) << 16) \
+ | (PNP_HEXTONUM(s[3]) << 20) \
+ | (PNP_HEXTONUM(s[6]) << 24) \
+ | (PNP_HEXTONUM(s[5]) << 28))
+
+static void acpi_isa_set_init(device_t dev, void **context);
+static void acpi_isa_set_done(device_t dev, void *context);
+static void acpi_isa_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
+static void acpi_isa_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
+ u_int32_t length, u_int32_t align);
+static void acpi_isa_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
+static void acpi_isa_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
+ u_int32_t length, u_int32_t align);
+static void acpi_isa_set_irq(device_t dev, void *context, u_int32_t irq);
+static void acpi_isa_set_drq(device_t dev, void *context, u_int32_t drq);
+static void acpi_isa_set_start_dependant(device_t dev, void *context, int preference);
+static void acpi_isa_set_end_dependant(device_t dev, void *context);
+
+static struct acpi_parse_resource_set acpi_isa_parse_set = {
+ acpi_isa_set_init,
+ acpi_isa_set_done,
+ acpi_isa_set_ioport,
+ acpi_isa_set_iorange,
+ acpi_isa_set_memory,
+ acpi_isa_set_memoryrange,
+ acpi_isa_set_irq,
+ acpi_isa_set_drq,
+ acpi_isa_set_start_dependant,
+ acpi_isa_set_end_dependant
+};
+
+#define MAXDEP 8
+
+struct acpi_isa_context {
+ int ai_config;
+ int ai_nconfigs;
+ struct isa_config ai_configs[MAXDEP + 1];
+ int ai_priorities[MAXDEP + 1];
+};
+
+static void acpi_isa_set_config(void *arg, struct isa_config *config, int enable);
+static void acpi_isa_identify(driver_t *driver, device_t bus);
+static ACPI_STATUS acpi_isa_identify_child(ACPI_HANDLE handle, UINT32 level,
+ void *context, void **status);
+
+static device_method_t acpi_isa_methods[] = {
+ DEVMETHOD(device_identify, acpi_isa_identify),
+ {0, 0}
+};
+
+static driver_t acpi_isa_driver = {
+ "acpi_isa",
+ acpi_isa_methods,
+ 1,
+};
+
+static devclass_t acpi_isa_devclass;
+DRIVER_MODULE(acpi_isa, isa, acpi_isa_driver, acpi_isa_devclass, 0, 0);
+
+/*
+ * This function is called to make the selected configuration
+ * active.
+ */
+static void
+acpi_isa_set_config(void *arg, struct isa_config *config, int enable)
+{
+}
+
+/*
+ * Interrogate ACPI for devices which might be attatched to an ISA
+ * bus.
+ *
+ * Note that it is difficult to determine whether a device in the ACPI
+ * namespace is or is not visible to the ISA bus, and thus we are a
+ * little too generous here and just export everything with _HID
+ * and _CRS.
+ */
+static void
+acpi_isa_identify(driver_t *driver, device_t bus)
+{
+ ACPI_HANDLE parent;
+ ACPI_STATUS status;
+
+ /*
+ * Look for the _SB_ scope, which will contain all the devices
+ * we are likely to support.
+ */
+ if ((status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent)) != AE_OK) {
+ device_printf(bus, "no ACPI _SB_ scope - %s\n", acpi_strerror(status));
+ return;
+ }
+
+ if ((status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, acpi_isa_identify_child, bus, NULL)) != AE_OK) {
+ device_printf(bus, "AcpiWalkNamespace on _SB_ failed - %s\n", acpi_strerror(status));
+ return;
+ }
+}
+
+/*
+ * Check a device to see whether it makes sense to try attaching it to an
+ * ISA bus, and if so, do so.
+ *
+ * Note that we *must* always return AE_OK, or the namespace walk will terminate.
+ *
+ * XXX Note also that this is picking up a *lot* of things that are not ISA devices.
+ * Should we consider lazy-binding this so that only the ID is saved and resources
+ * are not parsed until the device is claimed by a driver?
+ */
+static ACPI_STATUS
+acpi_isa_identify_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+ ACPI_DEVICE_INFO devinfo;
+ ACPI_BUFFER buf;
+ device_t child, bus = (device_t)context;
+ u_int32_t devid;
+
+ /*
+ * Try to get information about the device
+ */
+ if (AcpiGetObjectInfo(handle, &devinfo) != AE_OK)
+ return(AE_OK);
+
+ /*
+ * Reformat the _HID value into 32 bits.
+ */
+ if (!(devinfo.Valid & ACPI_VALID_HID))
+ return(AE_OK);
+
+ /*
+ * XXX Try to avoid passing stuff to ISA that it just isn't interested
+ * in. This is the *wrong* solution, and what needs to be done
+ * involves just sending ISA the PnP ID and a handle, and then
+ * lazy-parsing the resources if and only if a driver attaches.
+ * With the way that ISA currently works (using bus_probe_and_attach)
+ * this is very difficult. Maybe we need a device_configure method?
+ */
+ if (!(strncmp(devinfo.HardwareId, "PNP0C", 5)))
+ return(AE_OK);
+
+ devid = PNP_EISAID(devinfo.HardwareId);
+
+ /* XXX check _STA here? */
+ if (devinfo.Valid & ACPI_VALID_STA) {
+ }
+
+ /*
+ * Fetch our current settings.
+ *
+ * XXX Note that we may want to support alternate settings at some
+ * point as well.
+ */
+ if (acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf) != AE_OK)
+ return(AE_OK);
+
+ /*
+ * Add the device and parse our resources
+ */
+ child = BUS_ADD_CHILD(bus, ISA_ORDER_PNP, NULL, -1);
+ isa_set_vendorid(child, devid);
+ isa_set_logicalid(child, devid);
+ ISA_SET_CONFIG_CALLBACK(bus, child, acpi_isa_set_config, 0);
+ acpi_parse_resources(child, handle, &acpi_isa_parse_set);
+ AcpiOsFree(buf.Pointer);
+
+ if (!device_get_desc(child))
+ device_set_desc_copy(child, devinfo.HardwareId);
+
+ /*
+ * XXX Parse configuration data and _CID list to find compatible IDs
+ */
+ return(AE_OK);
+}
+
+static void
+acpi_isa_set_init(device_t dev, void **context)
+{
+ struct acpi_isa_context *cp;
+
+ cp = malloc(sizeof(*cp), M_DEVBUF, M_NOWAIT);
+ bzero(cp, sizeof(*cp));
+ cp->ai_nconfigs = 1;
+ *context = cp;
+}
+
+static void
+acpi_isa_set_done(device_t dev, void *context)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *config, *configs;
+ device_t parent;
+ int i, j;
+
+ if (cp == NULL)
+ return;
+ parent = device_get_parent(dev);
+
+ /* simple config without dependants */
+ if (cp->ai_nconfigs == 1) {
+ ISA_ADD_CONFIG(parent, dev, cp->ai_priorities[0], &cp->ai_configs[0]);
+ goto done;
+ }
+
+ /* Cycle through dependant configs merging primary details */
+ configs = &cp->ai_configs[0];
+ for(i = 1; i < cp->ai_nconfigs; i++) {
+ config = &configs[i];
+ for(j = 0; j < configs[0].ic_nmem; j++) {
+ if (config->ic_nmem == ISA_NMEM) {
+ device_printf(parent, "too many memory ranges\n");
+ free(configs, M_DEVBUF);
+ return;
+ }
+ config->ic_mem[config->ic_nmem] = configs[0].ic_mem[j];
+ config->ic_nmem++;
+ }
+ for(j = 0; j < configs[0].ic_nport; j++) {
+ if (config->ic_nport == ISA_NPORT) {
+ device_printf(parent, "too many port ranges\n");
+ free(configs, M_DEVBUF);
+ return;
+ }
+ config->ic_port[config->ic_nport] = configs[0].ic_port[j];
+ config->ic_nport++;
+ }
+ for(j = 0; j < configs[0].ic_nirq; j++) {
+ if (config->ic_nirq == ISA_NIRQ) {
+ device_printf(parent, "too many irq ranges\n");
+ free(configs, M_DEVBUF);
+ return;
+ }
+ config->ic_irqmask[config->ic_nirq] = configs[0].ic_irqmask[j];
+ config->ic_nirq++;
+ }
+ for(j = 0; j < configs[0].ic_ndrq; j++) {
+ if (config->ic_ndrq == ISA_NDRQ) {
+ device_printf(parent, "too many drq ranges\n");
+ free(configs, M_DEVBUF);
+ return;
+ }
+ config->ic_drqmask[config->ic_ndrq] = configs[0].ic_drqmask[j];
+ config->ic_ndrq++;
+ }
+ (void)ISA_ADD_CONFIG(parent, dev, cp->ai_priorities[i], &configs[i]);
+ }
+
+done:
+ free(cp, M_DEVBUF);
+}
+
+static void
+acpi_isa_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *ic = &cp->ai_configs[cp->ai_config];
+
+ if (cp == NULL)
+ return;
+ if (ic->ic_nport == ISA_NPORT) {
+ printf("too many ports\n");
+ return;
+ }
+ ic->ic_port[ic->ic_nport].ir_start = base;
+ ic->ic_port[ic->ic_nport].ir_end = base + length - 1;
+ ic->ic_port[ic->ic_nport].ir_size = length;
+ ic->ic_port[ic->ic_nport].ir_align = 1;
+ ic->ic_nport++;
+}
+
+static void
+acpi_isa_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *ic = &cp->ai_configs[cp->ai_config];
+
+ if (cp == NULL)
+ return;
+ if (ic->ic_nport == ISA_NPORT) {
+ printf("too many ports\n");
+ return;
+ }
+ ic->ic_port[ic->ic_nport].ir_start = low;
+ ic->ic_port[ic->ic_nport].ir_end = high + length - 1;
+ ic->ic_port[ic->ic_nport].ir_size = length;
+ ic->ic_port[ic->ic_nport].ir_align = imin(1, align);
+ ic->ic_nport++;
+}
+
+static void
+acpi_isa_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *ic = &cp->ai_configs[cp->ai_config];
+
+ if (cp == NULL)
+ return;
+ if (ic->ic_nmem == ISA_NMEM) {
+ printf("too many memory ranges\n");
+ return;
+ }
+ ic->ic_mem[ic->ic_nmem].ir_start = base;
+ ic->ic_mem[ic->ic_nmem].ir_end = base + length - 1;
+ ic->ic_mem[ic->ic_nmem].ir_size = length;
+ ic->ic_mem[ic->ic_nmem].ir_align = 1;
+ ic->ic_nmem++;
+}
+
+static void
+acpi_isa_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *ic = &cp->ai_configs[cp->ai_config];
+
+ if (cp == NULL)
+ return;
+ if (ic->ic_nmem == ISA_NMEM) {
+ printf("too many memory ranges\n");
+ return;
+ }
+ ic->ic_mem[ic->ic_nmem].ir_start = low;
+ ic->ic_mem[ic->ic_nmem].ir_end = high + length - 1;
+ ic->ic_mem[ic->ic_nmem].ir_size = length;
+ ic->ic_mem[ic->ic_nmem].ir_align = imin(1, align);
+ ic->ic_nmem++;
+}
+
+static void
+acpi_isa_set_irq(device_t dev, void *context, u_int32_t irq)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *ic = &cp->ai_configs[cp->ai_config];
+
+ if (cp == NULL)
+ return;
+ if (ic->ic_nirq == ISA_NIRQ) {
+ printf("too many IRQs\n");
+ return;
+ }
+ ic->ic_irqmask[ic->ic_nirq] = 1 << irq;
+ ic->ic_nirq++;
+}
+
+static void
+acpi_isa_set_drq(device_t dev, void *context, u_int32_t drq)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+ struct isa_config *ic = &cp->ai_configs[cp->ai_config];
+
+ if (cp == NULL)
+ return;
+ if (ic->ic_nirq == ISA_NDRQ) {
+ printf("too many DRQs\n");
+ return;
+ }
+ ic->ic_drqmask[ic->ic_ndrq] = drq;
+ ic->ic_ndrq++;
+}
+
+/*
+ * XXX the "too many dependant configs" logic here is wrong, and
+ * will spam the last dependant config.
+ */
+static void
+acpi_isa_set_start_dependant(device_t dev, void *context, int preference)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+
+ if (cp == NULL)
+ return;
+
+ if (cp->ai_nconfigs > MAXDEP) {
+ printf("too many dependant configs\n");
+ return;
+ }
+ cp->ai_config = cp->ai_nconfigs;
+ cp->ai_priorities[cp->ai_config] = preference;
+ cp->ai_nconfigs++;
+}
+
+static void
+acpi_isa_set_end_dependant(device_t dev, void *context)
+{
+ struct acpi_isa_context *cp = (struct acpi_isa_context *)context;
+
+ if (cp == NULL)
+ return;
+ cp->ai_config = 0;
+}
diff --git a/sys/dev/acpica/acpi_lid.c b/sys/dev/acpica/acpi_lid.c
new file mode 100644
index 0000000..b32cdc6
--- /dev/null
+++ b/sys/dev/acpica/acpi_lid.c
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Michael Smith <msmith@freebd.org>
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+struct acpi_lid_softc {
+ device_t lid_dev;
+ ACPI_HANDLE lid_handle;
+ int lid_status; /* open or closed */
+};
+
+static int acpi_lid_probe(device_t dev);
+static int acpi_lid_attach(device_t dev);
+static void acpi_lid_notify_status_changed(void *arg);
+static void acpi_lid_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context);
+
+static device_method_t acpi_lid_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, acpi_lid_probe),
+ DEVMETHOD(device_attach, acpi_lid_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_lid_driver = {
+ "acpi_lid",
+ acpi_lid_methods,
+ sizeof(struct acpi_lid_softc),
+};
+
+devclass_t acpi_lid_devclass;
+DRIVER_MODULE(acpi_lid, acpi, acpi_lid_driver, acpi_lid_devclass, 0, 0);
+
+static int
+acpi_lid_probe(device_t dev)
+{
+ if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
+ acpi_MatchHid(dev, "PNP0C0D")) {
+ device_set_desc(dev, "Control Method Lid Switch");
+ return(0);
+ }
+ return(ENXIO);
+}
+
+static int
+acpi_lid_attach(device_t dev)
+{
+ struct acpi_lid_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->lid_dev = dev;
+ sc->lid_handle = acpi_get_handle(dev);
+
+ /*
+ * Install notification handler
+ */
+ AcpiInstallNotifyHandler(sc->lid_handle, ACPI_DEVICE_NOTIFY, acpi_lid_notify_handler, sc);
+ return(0);
+}
+
+static void
+acpi_lid_notify_status_changed(void *arg)
+{
+ struct acpi_lid_softc *sc;
+ struct acpi_softc *acpi_sc;
+ ACPI_BUFFER Buffer;
+ ACPI_OBJECT Object;
+
+ sc = (struct acpi_lid_softc *)arg;
+
+ /*
+ * Evaluate _LID and check the return value
+ * Zero: The lid is closed
+ * Non-zero: The lid is open
+ */
+ Buffer.Length = sizeof(Object);
+ Buffer.Pointer = &Object;
+ if (AcpiEvaluateObject(sc->lid_handle, "_LID", NULL, &Buffer) != AE_OK)
+ return;
+ if (Object.Type != ACPI_TYPE_NUMBER)
+ return;
+
+ /*
+ * Update lid status
+ */
+ sc->lid_status = Object.Number.Value;
+ device_printf(sc->lid_dev, "Lid %s\n", sc->lid_status ? "opened" : "closed");
+
+ acpi_sc = acpi_device_get_parent_softc(sc->lid_dev);
+ if (acpi_sc == NULL) {
+ return;
+ }
+
+ if (sc->lid_status == 0) {
+ EVENTHANDLER_INVOKE(acpi_sleep_event, acpi_sc->acpi_lid_switch_sx);
+ } else {
+ EVENTHANDLER_INVOKE(acpi_wakeup_event, acpi_sc->acpi_lid_switch_sx);
+ }
+}
+
+/* XXX maybe not here */
+#define ACPI_NOTIFY_STATUS_CHANGED 0x80
+
+static void
+acpi_lid_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+ struct acpi_lid_softc *sc = (struct acpi_lid_softc *)context;
+
+ switch (notify) {
+ case ACPI_NOTIFY_STATUS_CHANGED:
+ AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_lid_notify_status_changed, sc);
+ break;
+ default:
+ return; /* unknown notification value */
+ }
+}
+
diff --git a/sys/dev/acpica/acpi_pcib.c b/sys/dev/acpica/acpi_pcib.c
new file mode 100644
index 0000000..43c2f3d
--- /dev/null
+++ b/sys/dev/acpica/acpi_pcib.c
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#include <machine/pci_cfgreg.h>
+#include <pci/pcivar.h>
+#include "pcib_if.h"
+
+struct acpi_pcib_softc {
+ device_t ap_dev;
+ ACPI_HANDLE ap_handle;
+
+ int ap_segment; /* analagous to Alpha 'hose' */
+ int ap_bus; /* bios-assigned bus number */
+};
+
+static int acpi_pcib_probe(device_t bus);
+static int acpi_pcib_attach(device_t bus);
+static int acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
+static int acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
+static int acpi_pcib_maxslots(device_t dev);
+static u_int32_t acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
+static void acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
+ u_int32_t data, int bytes);
+static int acpi_pcib_route_interrupt(device_t bus, int device, int pin);
+
+static device_method_t acpi_pcib_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, acpi_pcib_probe),
+ DEVMETHOD(device_attach, acpi_pcib_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, acpi_pcib_write_ivar),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, acpi_pcib_maxslots),
+ DEVMETHOD(pcib_read_config, acpi_pcib_read_config),
+ DEVMETHOD(pcib_write_config, acpi_pcib_write_config),
+ DEVMETHOD(pcib_route_interrupt, acpi_pcib_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t acpi_pcib_driver = {
+ "acpi_pcib",
+ acpi_pcib_methods,
+ sizeof(struct acpi_pcib_softc),
+};
+
+devclass_t acpi_pcib_devclass;
+DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_driver, acpi_pcib_devclass, 0, 0);
+
+static int
+acpi_pcib_probe(device_t dev)
+{
+
+ if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
+ acpi_MatchHid(dev, "PNP0A03")) {
+
+ /*
+ * Set device description
+ */
+ device_set_desc(dev, "Host-PCI bridge");
+ return(0);
+ }
+ return(ENXIO);
+}
+
+static int
+acpi_pcib_attach(device_t dev)
+{
+ struct acpi_pcib_softc *sc;
+ device_t child;
+ ACPI_STATUS status;
+
+ sc = device_get_softc(dev);
+ sc->ap_dev = dev;
+ sc->ap_handle = acpi_get_handle(dev);
+
+ /*
+ * Don't attach if we're not really there.
+ *
+ * XXX this isn't entirely correct, since we may be a PCI bus
+ * on a hot-plug docking station, etc.
+ */
+ if (!acpi_DeviceIsPresent(dev))
+ return(ENXIO);
+
+ /*
+ * Get our segment number by evaluating _SEG
+ * It's OK for this to not exist.
+ */
+ if ((status = acpi_EvaluateNumber(sc->ap_handle, "_SEG", &sc->ap_segment)) != AE_OK) {
+ if (status != AE_NOT_FOUND) {
+ device_printf(dev, "could not evaluate _SEG - %s\n", acpi_strerror(status));
+ return(ENXIO);
+ }
+ /* if it's not found, assume 0 */
+ sc->ap_segment = 0;
+ }
+
+ /*
+ * Get our base bus number by evaluating _BBN
+ * If this doesn't exist, we assume we're bus number 0.
+ *
+ * XXX note that it may also not exist in the case where we are
+ * meant to use a private configuration space mechanism for this bus,
+ * so we should dig out our resources and check to see if we have
+ * anything like that. How do we do this?
+ */
+ if ((status = acpi_EvaluateNumber(sc->ap_handle, "_BBN", &sc->ap_bus)) != AE_OK) {
+ if (status != AE_NOT_FOUND) {
+ device_printf(dev, "could not evaluate _BBN - %s\n", acpi_strerror(status));
+ return(ENXIO);
+ }
+ /* if it's not found, assume 0 */
+ sc->ap_bus = 0;
+ }
+
+ /*
+ * XXX we should check here to make sure that this bus number hasn't already
+ * been attached. It shouldn't really be an issue.
+ */
+ if ((child = device_add_child(dev, "pci", sc->ap_bus)) == NULL) {
+ device_printf(device_get_parent(dev), "couldn't attach pci bus");
+ return(ENXIO);
+ }
+ /*
+ * XXX If we have the requisite information, and if we don't think the
+ * default PCI configuration space handlers can deal with this bus,
+ * we should attach our own handler.
+ */
+ /* XXX invoke _REG on this for the PCI config space address space? */
+
+ /*
+ * Now go scan the bus.
+ *
+ * XXX is it possible to defer this and count on the nexus getting to it
+ * reliably after it's finished with ACPI? Should we really care?
+ */
+ return(bus_generic_attach(dev));
+}
+
+static int
+acpi_pcib_maxslots(device_t dev)
+{
+ return(31);
+}
+
+static int
+acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct acpi_pcib_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ *result = sc->ap_bus;
+ return(0);
+ }
+ return(ENOENT);
+}
+
+static int
+acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct acpi_pcib_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->ap_bus = value;
+ return(0);
+ }
+ return(ENOENT);
+}
+
+static u_int32_t
+acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes)
+{
+ return(pci_cfgregread(bus, slot, func, reg, bytes));
+}
+
+static void
+acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg, u_int32_t data, int bytes)
+{
+ pci_cfgregwrite(bus, slot, func, reg, data, bytes);
+}
+
+static int
+acpi_pcib_route_interrupt(device_t bus, int device, int pin)
+{
+ return(255); /* XXX implement */
+}
diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c
new file mode 100644
index 0000000..43c2f3d
--- /dev/null
+++ b/sys/dev/acpica/acpi_pcib_acpi.c
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#include <machine/pci_cfgreg.h>
+#include <pci/pcivar.h>
+#include "pcib_if.h"
+
+struct acpi_pcib_softc {
+ device_t ap_dev;
+ ACPI_HANDLE ap_handle;
+
+ int ap_segment; /* analagous to Alpha 'hose' */
+ int ap_bus; /* bios-assigned bus number */
+};
+
+static int acpi_pcib_probe(device_t bus);
+static int acpi_pcib_attach(device_t bus);
+static int acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result);
+static int acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value);
+static int acpi_pcib_maxslots(device_t dev);
+static u_int32_t acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes);
+static void acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
+ u_int32_t data, int bytes);
+static int acpi_pcib_route_interrupt(device_t bus, int device, int pin);
+
+static device_method_t acpi_pcib_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, acpi_pcib_probe),
+ DEVMETHOD(device_attach, acpi_pcib_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, acpi_pcib_write_ivar),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, acpi_pcib_maxslots),
+ DEVMETHOD(pcib_read_config, acpi_pcib_read_config),
+ DEVMETHOD(pcib_write_config, acpi_pcib_write_config),
+ DEVMETHOD(pcib_route_interrupt, acpi_pcib_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t acpi_pcib_driver = {
+ "acpi_pcib",
+ acpi_pcib_methods,
+ sizeof(struct acpi_pcib_softc),
+};
+
+devclass_t acpi_pcib_devclass;
+DRIVER_MODULE(acpi_pcib, acpi, acpi_pcib_driver, acpi_pcib_devclass, 0, 0);
+
+static int
+acpi_pcib_probe(device_t dev)
+{
+
+ if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
+ acpi_MatchHid(dev, "PNP0A03")) {
+
+ /*
+ * Set device description
+ */
+ device_set_desc(dev, "Host-PCI bridge");
+ return(0);
+ }
+ return(ENXIO);
+}
+
+static int
+acpi_pcib_attach(device_t dev)
+{
+ struct acpi_pcib_softc *sc;
+ device_t child;
+ ACPI_STATUS status;
+
+ sc = device_get_softc(dev);
+ sc->ap_dev = dev;
+ sc->ap_handle = acpi_get_handle(dev);
+
+ /*
+ * Don't attach if we're not really there.
+ *
+ * XXX this isn't entirely correct, since we may be a PCI bus
+ * on a hot-plug docking station, etc.
+ */
+ if (!acpi_DeviceIsPresent(dev))
+ return(ENXIO);
+
+ /*
+ * Get our segment number by evaluating _SEG
+ * It's OK for this to not exist.
+ */
+ if ((status = acpi_EvaluateNumber(sc->ap_handle, "_SEG", &sc->ap_segment)) != AE_OK) {
+ if (status != AE_NOT_FOUND) {
+ device_printf(dev, "could not evaluate _SEG - %s\n", acpi_strerror(status));
+ return(ENXIO);
+ }
+ /* if it's not found, assume 0 */
+ sc->ap_segment = 0;
+ }
+
+ /*
+ * Get our base bus number by evaluating _BBN
+ * If this doesn't exist, we assume we're bus number 0.
+ *
+ * XXX note that it may also not exist in the case where we are
+ * meant to use a private configuration space mechanism for this bus,
+ * so we should dig out our resources and check to see if we have
+ * anything like that. How do we do this?
+ */
+ if ((status = acpi_EvaluateNumber(sc->ap_handle, "_BBN", &sc->ap_bus)) != AE_OK) {
+ if (status != AE_NOT_FOUND) {
+ device_printf(dev, "could not evaluate _BBN - %s\n", acpi_strerror(status));
+ return(ENXIO);
+ }
+ /* if it's not found, assume 0 */
+ sc->ap_bus = 0;
+ }
+
+ /*
+ * XXX we should check here to make sure that this bus number hasn't already
+ * been attached. It shouldn't really be an issue.
+ */
+ if ((child = device_add_child(dev, "pci", sc->ap_bus)) == NULL) {
+ device_printf(device_get_parent(dev), "couldn't attach pci bus");
+ return(ENXIO);
+ }
+ /*
+ * XXX If we have the requisite information, and if we don't think the
+ * default PCI configuration space handlers can deal with this bus,
+ * we should attach our own handler.
+ */
+ /* XXX invoke _REG on this for the PCI config space address space? */
+
+ /*
+ * Now go scan the bus.
+ *
+ * XXX is it possible to defer this and count on the nexus getting to it
+ * reliably after it's finished with ACPI? Should we really care?
+ */
+ return(bus_generic_attach(dev));
+}
+
+static int
+acpi_pcib_maxslots(device_t dev)
+{
+ return(31);
+}
+
+static int
+acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct acpi_pcib_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ *result = sc->ap_bus;
+ return(0);
+ }
+ return(ENOENT);
+}
+
+static int
+acpi_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct acpi_pcib_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->ap_bus = value;
+ return(0);
+ }
+ return(ENOENT);
+}
+
+static u_int32_t
+acpi_pcib_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes)
+{
+ return(pci_cfgregread(bus, slot, func, reg, bytes));
+}
+
+static void
+acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg, u_int32_t data, int bytes)
+{
+ pci_cfgregwrite(bus, slot, func, reg, data, bytes);
+}
+
+static int
+acpi_pcib_route_interrupt(device_t bus, int device, int pin)
+{
+ return(255); /* XXX implement */
+}
diff --git a/sys/dev/acpica/acpi_processor.c b/sys/dev/acpica/acpi_processor.c
new file mode 100644
index 0000000..627c8f9
--- /dev/null
+++ b/sys/dev/acpica/acpi_processor.c
@@ -0,0 +1,640 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+
+/*
+ * Processor driver.
+ *
+ * XXX Note that the power state code here is almost certainly suboptimal.
+ * We should go raid the Linux code for their ideas and experience.
+ *
+ * Code style here is a hairy mix of BSD-like and Intel-like. Should be
+ * sanitised at some point.
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#define PR_MAX_POWER_STATES 4
+#define PR_MAX_PERFORMANCE_STATES 8
+#define PR_MAX_THROTTLING_STATES 8
+
+/*
+ * Processor Commands:
+ * -------------------
+ */
+#define PR_COMMAND_GET_INFO ((BM_COMMAND) 0x80)
+#define PR_COMMAND_SET_CX_STATE_INFO ((BM_COMMAND) 0x81)
+#define PR_COMMAND_GET_THROTTLING_STATE ((BM_COMMAND) 0x82)
+#define PR_COMMAND_SET_THROTTLING_STATE ((BM_COMMAND) 0x83)
+#define PR_COMMAND_GET_PERF_STATE ((BM_COMMAND) 0x84)
+#define PR_COMMAND_SET_PERF_STATE ((BM_COMMAND) 0x85)
+#define PR_COMMAND_GET_CURRENT_FREQ ((BM_COMMAND) 0x86)
+
+/*
+ * PR_POWER_STATE:
+ * ---------------
+ */
+typedef u_int32_t PR_POWER_STATE;
+
+#define PR_POWER_STATE_UNKNOWN ((PR_POWER_STATE) 0xFFFFFFFF)
+
+#define PR_POWER_STATE_C0 ((PR_POWER_STATE) 0x00000000)
+#define PR_POWER_STATE_C1 ((PR_POWER_STATE) 0x00000001)
+#define PR_POWER_STATE_C2 ((PR_POWER_STATE) 0x00000002)
+#define PR_POWER_STATE_C3 ((PR_POWER_STATE) 0x00000003)
+
+/*
+ * Processor Notifications:
+ * ------------------------
+ */
+#define PR_NOTIFY_PERF_STATES_CHANGE ((BM_NOTIFY) 0x80)
+#define PR_NOTIFY_POWER_STATES_CHANGE ((BM_NOTIFY) 0x81)
+
+
+typedef struct
+{
+ u_int32_t TimeThreshold;
+ u_int32_t CountThreshold;
+ u_int32_t Count;
+ PR_POWER_STATE TargetState;
+} PR_POLICY_VALUES;
+
+/*
+ * PR_CX_STATE_INFO:
+ * -----------------
+ */
+typedef struct
+{
+ u_int32_t Latency;
+ u_int64_t Utilization;
+ PR_POLICY_VALUES PromotionPolicy;
+ PR_POLICY_VALUES DemotionPolicy;
+} PR_CX_STATE_INFO;
+
+/*
+ * PR_POWER_INFO:
+ * --------------
+ */
+typedef struct
+{
+ u_int32_t Count;
+ PR_POWER_STATE ActiveState;
+ PR_CX_STATE_INFO Info[PR_MAX_POWER_STATES];
+} PR_POWER_INFO;
+
+/*
+ * PR_PERFORMANCE_INFO:
+ * --------------------
+ */
+typedef struct
+{
+ u_int32_t Count;
+ /* TODO... */
+} PR_PERFORMANCE_INFO;
+
+/*
+ * PR_THROTTLING_INFO:
+ * -------------------
+ */
+typedef struct
+{
+ u_int32_t Count;
+ u_int32_t Percentage[PR_MAX_THROTTLING_STATES];
+} PR_THROTTLING_INFO;
+
+struct acpi_pr_softc {
+ device_t pr_dev;
+ ACPI_HANDLE pr_handle;
+ PR_POWER_INFO pr_PowerStates;
+ PR_PERFORMANCE_INFO pr_PerformanceStates;
+ PR_THROTTLING_INFO pr_ThrottlingStates;
+ eventhandler_tag pr_idleevent;
+
+ /* local APIC data */
+ PROCESSOR_APIC pr_lapic;
+};
+
+#define PR_MAGIC 0x20555043 /* "CPU " */
+
+static void acpi_pr_identify(driver_t *driver, device_t bus);
+static ACPI_STATUS acpi_pr_identify_cpu(ACPI_HANDLE handle, UINT32 level, void *context, void **status);
+static int acpi_pr_probe(device_t dev);
+static int acpi_pr_attach(device_t dev);
+
+static void acpi_pr_FindLapic(device_t dev, ACPI_HANDLE handle, PROCESSOR_APIC *lapic);
+static ACPI_STATUS acpi_pr_CalculatePowerStates(struct acpi_pr_softc *sc);
+static ACPI_STATUS acpi_pr_CalculatePerformanceStates(struct acpi_pr_softc *sc);
+static ACPI_STATUS acpi_pr_CalculateThrottlingStates(struct acpi_pr_softc *sc);
+static void acpi_pr_IdleHandler(void *arg, int count);
+static ACPI_STATUS acpi_pr_PolicyInitialize(struct acpi_pr_softc *sc);
+
+static device_method_t acpi_pr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_pr_identify),
+ DEVMETHOD(device_probe, acpi_pr_probe),
+ DEVMETHOD(device_attach, acpi_pr_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_pr_driver = {
+ "acpi_pr",
+ acpi_pr_methods,
+ sizeof(struct acpi_pr_softc),
+};
+
+devclass_t acpi_pr_devclass;
+DRIVER_MODULE(acpi_pr, acpi, acpi_pr_driver, acpi_pr_devclass, 0, 0);
+
+/*
+ * Scan the \_PR_ scope for processor objects, and attach them accordingly.
+ *
+ * XXX note that we should find the local APIC address and obtain a resource
+ * that we can hand to child devices for access to it...
+ */
+static void
+acpi_pr_identify(driver_t *driver, device_t bus)
+{
+ ACPI_HANDLE handle;
+
+ if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_PR_", &handle) == AE_OK)
+ AcpiWalkNamespace(ACPI_TYPE_PROCESSOR, handle, 2, acpi_pr_identify_cpu, bus, NULL);
+}
+
+/*
+ * Create a child device for CPUs
+ */
+static ACPI_STATUS
+acpi_pr_identify_cpu(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+ device_t bus = (device_t)context;
+ device_t child;
+ PROCESSOR_APIC lapic;
+
+
+ acpi_pr_FindLapic(bus, handle, &lapic);
+
+ if (lapic.ProcessorEnabled) {
+ if ((child = BUS_ADD_CHILD(bus, 0, "acpi_pr", -1)) == NULL) {
+ device_printf(bus, "could not create CPU device\n");
+ return(AE_OK);
+ }
+ acpi_set_handle(child, handle);
+ acpi_set_magic(child, PR_MAGIC);
+ device_set_desc(child, "processor device");
+ }
+
+ return(AE_OK);
+}
+
+static int
+acpi_pr_probe(device_t dev)
+{
+ if (acpi_get_magic(dev) == PR_MAGIC)
+ return(0);
+ return(ENXIO);
+}
+
+static int
+acpi_pr_attach(device_t dev)
+{
+ struct acpi_pr_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->pr_dev = dev;
+ sc->pr_handle = acpi_get_handle(dev);
+ acpi_pr_FindLapic(dev, sc->pr_handle, &sc->pr_lapic);
+
+ /*
+ * If the APIC information is valid, print it
+ */
+ if (sc->pr_lapic.LocalApicId != (UINT8)0xff)
+ device_printf(dev, "local APIC ID %d\n", sc->pr_lapic.LocalApicId);
+
+ /*
+ * Fetch operational parameters.
+ */
+ if (acpi_pr_CalculatePowerStates(sc) == AE_OK) {
+ acpi_pr_PolicyInitialize(sc);
+ }
+ acpi_pr_CalculatePerformanceStates(sc);
+ acpi_pr_CalculateThrottlingStates(sc);
+
+ /* XXX call MD cpu-identification here? */
+
+ return(0);
+}
+
+/*
+ * Find the Local Apic information for this CPU
+ */
+static void
+acpi_pr_FindLapic(device_t dev, ACPI_HANDLE handle, PROCESSOR_APIC *lapic)
+{
+ ACPI_BUFFER buf;
+ ACPI_STATUS status;
+ APIC_HEADER *hdr;
+ APIC_TABLE *tbl;
+ PROCESSOR_APIC *pap;
+ int len, cpuno;
+
+ /*
+ * Assume that we're not going to suceed in finding/parsing the APIC table.
+ * In this case, CPU 0 is valid, and any other CPU is invalid.
+ */
+ lapic->LocalApicId = 0xff;
+ lapic->ProcessorEnabled = 0;
+ if ((status = AcpiGetProcessorId(handle, &cpuno)) != AE_OK) {
+ device_printf(dev, "error fetching CPU device ID - %s\n", acpi_strerror(status));
+ return;
+ }
+ lapic->ProcessorEnabled = (cpuno == 0);
+
+ /*
+ * Perform the tedious double-get to fetch the actual APIC table, and suck it in.
+ */
+ buf.Length = 0;
+ buf.Pointer = NULL;
+ if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_BUFFER_OVERFLOW) {
+ if (status != AE_NOT_EXIST)
+ device_printf(dev, "error sizing APIC table - %s\n", acpi_strerror(status));
+ return;
+ }
+ if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL)
+ return;
+ if ((status = AcpiGetTable(ACPI_TABLE_APIC, 1, &buf)) != AE_OK) {
+ device_printf(dev, "error fetching APIC table - %s\n", acpi_strerror(status));
+ return;
+ }
+
+ /*
+ * Scan the tables looking for this CPU index.
+ */
+ tbl = (APIC_TABLE *)buf.Pointer;
+ len = tbl->header.Length - sizeof(APIC_TABLE);
+ hdr = (APIC_HEADER *)((char *)buf.Pointer + sizeof(APIC_TABLE));
+ while(len > 0) {
+ if (hdr->Length > len) {
+ device_printf(dev, "APIC header corrupt (claims %d bytes where only %d left in structure)\n",
+ hdr->Length, len);
+ break;
+ }
+ /*
+ * If we have found a processor APIC definition with
+ * matching CPU index, copy it out and return.
+ */
+ if (hdr->Type == APIC_PROC) {
+ pap = (PROCESSOR_APIC *)hdr;
+ if (pap->ProcessorApicId == cpuno) {
+ bcopy(pap, lapic, sizeof(*pap));
+ break;
+ }
+ }
+ len -= hdr->Length;
+ hdr = (APIC_HEADER *)((char *)hdr + hdr->Length);
+ }
+ AcpiOsFree(buf.Pointer);
+}
+
+static ACPI_STATUS
+acpi_pr_CalculatePowerStates(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS Status = AE_OK;
+ ACPI_BUFFER Buffer;
+ ACPI_CX_STATE *State = NULL;
+ u_int32_t StateCount = 0;
+ u_int32_t i = 0;
+
+ /*
+ * Set Latency Defaults:
+ * ---------------------
+ * Default state latency to ACPI_UINT32_MAX -- meaning that this state
+ * should not be used by policy. This value is overriden by states
+ * that are present and have usable latencies (e.g. <= 1000us for C3).
+ */
+ for (i = 0; i < PR_MAX_POWER_STATES; i++)
+ sc->pr_PowerStates.Info[i].Latency = ACPI_UINT32_MAX;
+
+ /*
+ * Get Power State Latencies:
+ * --------------------------
+ *
+ * XXX Note that ACPICA will never give us back C2 if it costs more than 100us,
+ * or C3 if it costs more than 1000us, so some of this code is redundant.
+ */
+ Status = acpi_GetIntoBuffer(sc->pr_handle, AcpiGetProcessorCxInfo, &Buffer);
+ if (Status != AE_OK) {
+ device_printf(sc->pr_dev, "could not fetch ProcessorCxInfo - %s\n", acpi_strerror(Status));
+ return(Status);
+ }
+
+ State = (ACPI_CX_STATE*)(Buffer.Pointer);
+ if (State != NULL) {
+ device_printf(sc->pr_dev, "supported power states:");
+ StateCount = Buffer.Length / sizeof(ACPI_CX_STATE);
+ for (i = 0; i < StateCount; i++) {
+ /* XXX C3 isn't supportable in MP configurations, how to best handle this? */
+ if ((State[i].StateNumber < PR_MAX_POWER_STATES) && (State[i].Latency <= 1000)) {
+ printf(" C%d (%dus)", i, State[i].Latency);
+ sc->pr_PowerStates.Info[State[i].StateNumber].Latency = State[i].Latency;
+ }
+ }
+ printf("\n");
+ }
+ sc->pr_PowerStates.Count = PR_MAX_POWER_STATES;
+ sc->pr_PowerStates.ActiveState = PR_POWER_STATE_C1;
+
+ AcpiOsFree(Buffer.Pointer);
+ return(Status);
+}
+
+static ACPI_STATUS
+acpi_pr_CalculatePerformanceStates(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS Status = AE_OK;
+
+ /* TODO... */
+
+ return(Status);
+}
+
+static ACPI_STATUS
+acpi_pr_CalculateThrottlingStates(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS Status = AE_OK;
+ ACPI_BUFFER Buffer;
+ ACPI_CPU_THROTTLING_STATE *State = NULL;
+ u_int32_t StateCount = 0;
+ u_int32_t i = 0;
+
+ /*
+ * Get Throttling States:
+ * ----------------------
+ */
+ Status = acpi_GetIntoBuffer(sc->pr_handle, AcpiGetProcessorThrottlingInfo, &Buffer);
+ if (Status != AE_OK) {
+ device_printf(sc->pr_dev, "could not fetch ThrottlingInfo - %s\n", acpi_strerror(Status));
+ return(Status);
+ }
+
+ State = (ACPI_CPU_THROTTLING_STATE*)(Buffer.Pointer);
+ if (State != NULL) {
+ StateCount = Buffer.Length / sizeof(ACPI_CPU_THROTTLING_STATE);
+ device_printf(sc->pr_dev, "supported throttling states:");
+ for (i = 0; i < StateCount; i++) {
+ if (State[i].StateNumber < PR_MAX_THROTTLING_STATES) {
+ /* TODO: Verify that state is *really* supported by this chipset/processor (e.g. errata). */
+ sc->pr_ThrottlingStates.Percentage[State[i].StateNumber] = State[i].PercentOfClock;
+ sc->pr_ThrottlingStates.Count++;
+ printf(" %d%%", State[i].PercentOfClock);
+ }
+ }
+ printf("\n");
+ }
+
+ AcpiOsFree(Buffer.Pointer);
+ return(Status);
+}
+
+static ACPI_STATUS
+acpi_pr_PolicyInitialize(struct acpi_pr_softc *sc)
+{
+ ACPI_STATUS status;
+
+ if ((status = AcpiSetProcessorSleepState(sc->pr_handle, sc->pr_PowerStates.ActiveState)) != AE_OK) {
+ device_printf(sc->pr_dev, "could not set Active sleep state - %s\n", acpi_strerror(status));
+ return(status);
+ }
+
+ /* XXX need to hook ourselves to be called when things go idle */
+/* sc->pr_idleevent = EVENTHANDLER_FAST_REGISTER(idle_event, acpi_pr_IdleHandler, sc, IDLE_PRI_FIRST); */
+ return(AE_OK);
+}
+
+static void
+acpi_pr_IdleHandler(void *arg, int count)
+{
+ struct acpi_pr_softc *sc = (struct acpi_pr_softc *)arg;
+ ACPI_STATUS Status = AE_OK;
+ PR_CX_STATE_INFO *CxState = NULL;
+ PR_POWER_STATE ActiveState = PR_POWER_STATE_UNKNOWN;
+ PR_POWER_STATE NextState = PR_POWER_STATE_UNKNOWN;
+ u_int32_t PmTimerTicks = 0;
+
+ ActiveState = NextState = sc->pr_PowerStates.ActiveState;
+ CxState = &(sc->pr_PowerStates.Info[ActiveState]);
+ CxState->Utilization++;
+
+ /*
+ * Invoke Cx State:
+ * ----------------
+ */
+ if ((Status = AcpiProcessorSleep(sc->pr_handle, &PmTimerTicks)) != AE_OK) {
+ device_printf(sc->pr_dev, "AcpiProcessorSleep() failed - %s\n", acpi_strerror(Status));
+ /*
+ * Something went wrong with the sleep attempt, so give up on trying to do this.
+ */
+/* EVENTHANDLER_FAST_DEREGISTER(idle_event, sc->pr_idleevent);*/
+ device_printf(sc->pr_dev, "disabling CPU power saving\n");
+ return;
+ }
+
+ /*
+ * Check For State Promotion:
+ * --------------------------
+ * Only need to check for promotion on C1 and C2, and then only
+ * when the state has a non-zero count threshold and target state.
+ */
+ if (CxState->PromotionPolicy.CountThreshold && CxState->PromotionPolicy.TargetState &&
+ ((ActiveState == PR_POWER_STATE_C1) || (ActiveState == PR_POWER_STATE_C2))) {
+ /*
+ * Check the amount of time we spent in the Cx state against our
+ * promotion policy. If successful (asleep longer than our threshold)
+ * increment our count and see if a promotion is in order.
+ */
+ if (PmTimerTicks > (CxState->PromotionPolicy.TimeThreshold)) {
+ CxState->PromotionPolicy.Count++;
+ CxState->DemotionPolicy.Count = 0;
+
+ if (CxState->PromotionPolicy.Count >= CxState->PromotionPolicy.CountThreshold)
+ NextState = CxState->PromotionPolicy.TargetState;
+ }
+ }
+
+ /*
+ * Check For State Demotion:
+ * -------------------------
+ * Only need to check for demotion on C2 and C3, and then only
+ * when the state has a non-zero count threshold and target state.
+ */
+ if (CxState->DemotionPolicy.CountThreshold && CxState->DemotionPolicy.TargetState &&
+ ((ActiveState == PR_POWER_STATE_C2) || (ActiveState == PR_POWER_STATE_C3))) {
+ /*
+ * Check the amount of time we spent in the Cx state against our
+ * demotion policy. If unsuccessful (asleep shorter than our threshold)
+ * increment our count and see if a demotion is in order.
+ */
+ if (PmTimerTicks < (CxState->DemotionPolicy.TimeThreshold)) {
+ CxState->DemotionPolicy.Count++;
+ CxState->PromotionPolicy.Count = 0;
+
+ if (CxState->DemotionPolicy.Count >= CxState->DemotionPolicy.CountThreshold)
+ NextState = CxState->DemotionPolicy.TargetState;
+ }
+ }
+
+ /*
+ * New Cx State?
+ * -------------
+ * If so, clean up from the previous Cx state (if necessary).
+ */
+ if (NextState != sc->pr_PowerStates.ActiveState) {
+ if ((Status = AcpiSetProcessorSleepState(sc->pr_handle, NextState)) != AE_OK) {
+ device_printf(sc->pr_dev, "AcpiSetProcessorSleepState() returned error [0x%08X]\n", Status);
+ } else {
+ CxState->PromotionPolicy.Count = 0;
+ CxState->DemotionPolicy.Count = 0;
+ sc->pr_PowerStates.ActiveState = NextState;
+ }
+ }
+}
diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
new file mode 100644
index 0000000..3581ff7
--- /dev/null
+++ b/sys/dev/acpica/acpi_resource.c
@@ -0,0 +1,343 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+/*
+ * Fetch a device's resources and associate them with the device.
+ *
+ * Note that it might be nice to also locate ACPI-specific resource items, such
+ * as GPE bits.
+ */
+ACPI_STATUS
+acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set)
+{
+ ACPI_BUFFER buf;
+ RESOURCE *res;
+ char *curr, *last;
+ ACPI_STATUS status;
+ int i;
+ void *context;
+
+ /*
+ * Fetch the device resources
+ */
+ if (((status = acpi_GetIntoBuffer(handle, AcpiGetPossibleResources, &buf)) != AE_OK) &&
+ ((status = acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf)) != AE_OK)) {
+ device_printf(dev, "can't fetch ACPI resources - %s\n", acpi_strerror(status));
+ return(status);
+ }
+
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "got %d bytes of resources\n", buf.Length);
+#endif
+ set->set_init(dev, &context);
+
+ /*
+ * Iterate through the resources
+ */
+ curr = buf.Pointer;
+ last = (char *)buf.Pointer + buf.Length;
+ while (curr < last) {
+ res = (RESOURCE *)curr;
+ curr += res->Length;
+
+ /*
+ * Handle the individual resource types
+ */
+ switch(res->Id) {
+ case EndTag:
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "EndTag\n");
+#endif
+ curr = last;
+ break;
+
+ case FixedIo:
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "FixedIo 0x%x/%d\n", res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength);
+#endif
+ set->set_ioport(dev, context, res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength);
+ break;
+
+ case Io:
+ if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Io 0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
+#endif
+ set->set_ioport(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
+ } else {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Io 0x%x-0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
+ res->Data.Io.RangeLength);
+#endif
+ set->set_iorange(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
+ res->Data.Io.RangeLength, res->Data.Io.Alignment);
+ }
+ break;
+
+ case FixedMemory32:
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "FixedMemory32 0x%x/%d\n", res->Data.FixedMemory32.RangeBaseAddress,
+ res->Data.FixedMemory32.RangeLength);
+#endif
+ set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
+ res->Data.FixedMemory32.RangeLength);
+ break;
+
+ case Memory32:
+ if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Memory32 0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
+ res->Data.Memory32.RangeLength);
+#endif
+ set->set_memory(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.RangeLength);
+ } else {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Memory32 0x%x-0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
+ res->Data.Memory32.MaxBaseAddress, res->Data.Memory32.RangeLength);
+#endif
+ set->set_memoryrange(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.MaxBaseAddress,
+ res->Data.Memory32.RangeLength, res->Data.Memory32.Alignment);
+ }
+ break;
+
+ case Memory24:
+ if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Memory24 0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
+ res->Data.Memory24.RangeLength);
+#endif
+ set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.RangeLength);
+ } else {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Memory24 0x%x-0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
+ res->Data.Memory24.MaxBaseAddress, res->Data.Memory24.RangeLength);
+#endif
+ set->set_memoryrange(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.MaxBaseAddress,
+ res->Data.Memory24.RangeLength, res->Data.Memory24.Alignment);
+ }
+ break;
+
+ case Irq:
+ for (i = 0; i < res->Data.Irq.NumberOfInterrupts; i++) {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Irq %d\n", res->Data.Irq.Interrupts[i]);
+#endif
+ set->set_irq(dev, context, res->Data.Irq.Interrupts[i]);
+ }
+ break;
+
+ case Dma:
+ for (i = 0; i < res->Data.Dma.NumberOfChannels; i++) {
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "Drq %d\n", res->Data.Dma.Channels[i]);
+#endif
+ set->set_drq(dev, context, res->Data.Dma.Channels[i]);
+ }
+ break;
+
+ case StartDependentFunctions:
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "start dependant functions");
+#endif
+ set->set_start_dependant(dev, context, res->Data.StartDependentFunctions.CompatibilityPriority);
+ break;
+
+ case EndDependentFunctions:
+#ifdef ACPI_RES_DEBUG
+ device_printf(dev, "end dependant functions");
+#endif
+ set->set_end_dependant(dev, context);
+ break;
+
+ case Address32:
+ device_printf(dev, "unimplemented Address32 resource\n");
+ break;
+
+ case Address16:
+ device_printf(dev, "unimplemented Address16 resource\n");
+ break;
+
+ case ExtendedIrq:
+ device_printf(dev, "unimplemented ExtendedIrq resource\n");
+ break;
+
+ case VendorSpecific:
+ device_printf(dev, "unimplemented VendorSpecific resource\n");
+ break;
+ default:
+ break;
+ }
+ }
+ AcpiOsFree(buf.Pointer);
+ set->set_done(dev, context);
+ return(AE_OK);
+}
+
+static void acpi_res_set_init(device_t dev, void **context);
+static void acpi_res_set_done(device_t dev, void *context);
+static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
+static void acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
+ u_int32_t length, u_int32_t align);
+static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
+static void acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
+ u_int32_t length, u_int32_t align);
+static void acpi_res_set_irq(device_t dev, void *context, u_int32_t irq);
+static void acpi_res_set_drq(device_t dev, void *context, u_int32_t drq);
+static void acpi_res_set_start_dependant(device_t dev, void *context, int preference);
+static void acpi_res_set_end_dependant(device_t dev, void *context);
+
+struct acpi_parse_resource_set acpi_res_parse_set = {
+ acpi_res_set_init,
+ acpi_res_set_done,
+ acpi_res_set_ioport,
+ acpi_res_set_iorange,
+ acpi_res_set_memory,
+ acpi_res_set_memoryrange,
+ acpi_res_set_irq,
+ acpi_res_set_drq,
+ acpi_res_set_start_dependant,
+ acpi_res_set_end_dependant
+};
+
+struct acpi_res_context {
+ int ar_nio;
+ int ar_nmem;
+ int ar_nirq;
+};
+
+static void
+acpi_res_set_init(device_t dev, void **context)
+{
+ struct acpi_res_context *cp;
+
+ if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
+ bzero(cp, sizeof(*cp));
+ *context = cp;
+ }
+}
+
+static void
+acpi_res_set_done(device_t dev, void *context)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ AcpiOsFree(cp);
+}
+
+static void
+acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
+}
+
+static void
+acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ device_printf(dev, "I/O range not supported\n");
+}
+
+static void
+acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
+}
+
+static void
+acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ device_printf(dev, "memory range not supported\n");
+}
+
+static void
+acpi_res_set_irq(device_t dev, void *context, u_int32_t irq)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq, 1);
+}
+
+static void
+acpi_res_set_drq(device_t dev, void *context, u_int32_t drq)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ device_printf(dev, "DRQ not supported\n");
+}
+
+static void
+acpi_res_set_start_dependant(device_t dev, void *context, int preference)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+ device_printf(dev, "dependant functions not supported");
+}
+
+static void
+acpi_res_set_end_dependant(device_t dev, void *context)
+{
+ struct acpi_res_context *cp = (struct acpi_res_context *)context;
+
+ if (cp == NULL)
+ return;
+}
diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c
new file mode 100644
index 0000000..45398fe
--- /dev/null
+++ b/sys/dev/acpica/acpi_thermal.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#define TZ_KELVTOC(x) (((x) - 2732) / 10), (((x) - 2732) % 10)
+
+struct acpi_tz_softc {
+ device_t tz_dev;
+ ACPI_HANDLE tz_handle;
+};
+
+static int acpi_tz_probe(device_t dev);
+static int acpi_tz_attach(device_t dev);
+
+static device_method_t acpi_tz_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, acpi_tz_probe),
+ DEVMETHOD(device_attach, acpi_tz_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_tz_driver = {
+ "acpi_tz",
+ acpi_tz_methods,
+ sizeof(struct acpi_tz_softc),
+};
+
+devclass_t acpi_tz_devclass;
+DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
+
+static int
+acpi_tz_probe(device_t dev)
+{
+ if (acpi_get_type(dev) == ACPI_TYPE_THERMAL) {
+ device_set_desc(dev, "thermal zone");
+ return(0);
+ }
+ return(ENXIO);
+}
+
+static int
+acpi_tz_attach(device_t dev)
+{
+ struct acpi_tz_softc *sc;
+ UINT32 param[4];
+ ACPI_BUFFER buf;
+ ACPI_STATUS status;
+
+ sc = device_get_softc(dev);
+ sc->tz_dev = dev;
+ sc->tz_handle = acpi_get_handle(dev);
+
+ buf.Pointer = &param[0];
+ buf.Length = sizeof(param);
+ if ((status = AcpiEvaluateObject(sc->tz_handle, "_TMP", NULL, &buf)) != AE_OK) {
+ device_printf(sc->tz_dev, "can't fetch temperature - %s\n", acpi_strerror(status));
+ return(ENXIO);
+ }
+ if (param[0] != ACPI_TYPE_NUMBER) {
+ device_printf(sc->tz_dev, "%s._TMP does not evaluate to ACPI_TYPE_NUMBER\n",
+ acpi_name(sc->tz_handle));
+ return(ENXIO);
+ }
+ device_printf(sc->tz_dev, "current temperature %d.%dC\n", TZ_KELVTOC(param[1]));
+
+ return(0);
+}
diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c
new file mode 100644
index 0000000..e232f8b
--- /dev/null
+++ b/sys/dev/acpica/acpi_timer.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+#define ACPITIMER_MAGIC 0x524d4954 /* "TIMR" */
+
+struct acpi_timer_softc {
+ device_t tm_dev;
+};
+
+static void acpi_timer_identify(driver_t *driver, device_t parent);
+static int acpi_timer_probe(device_t dev);
+static int acpi_timer_attach(device_t dev);
+
+static device_method_t acpi_timer_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_timer_identify),
+ DEVMETHOD(device_probe, acpi_timer_probe),
+ DEVMETHOD(device_attach, acpi_timer_attach),
+
+ {0, 0}
+};
+
+static driver_t acpi_timer_driver = {
+ "acpi_timer",
+ acpi_timer_methods,
+ sizeof(struct acpi_timer_softc),
+};
+
+devclass_t acpi_timer_devclass;
+DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0);
+
+static void
+acpi_timer_identify(driver_t *driver, device_t parent)
+{
+ static FIXED_ACPI_DESCRIPTION_TABLE facp;
+ ACPI_BUFFER buf;
+ ACPI_STATUS status;
+ device_t dev;
+ char desc[40];
+
+ buf.Pointer = &facp;
+ buf.Length = sizeof(facp);
+ if ((status = AcpiGetTable(ACPI_TABLE_FACP, 1, &buf)) != AE_OK) {
+ device_printf(parent, "can't locate FACP - %s\n", acpi_strerror(status));
+ return;
+ }
+ if (buf.Length != sizeof(facp)) {
+ device_printf(parent, "invalid FACP\n");
+ return;
+ }
+
+ if ((dev = BUS_ADD_CHILD(parent, 0, "acpi_timer", 0)) == NULL) {
+ device_printf(parent, "could not add acpi_timer0\n");
+ return;
+ }
+ if (acpi_set_magic(dev, ACPITIMER_MAGIC)) {
+ device_printf(dev, "could not set magic\n");
+ return;
+ }
+
+ sprintf(desc, "%d-bit timer at 3.579545MHz", facp.TmrValExt ? 32 : 24);
+ device_set_desc_copy(dev, desc);
+}
+
+static int
+acpi_timer_probe(device_t dev)
+{
+ if (acpi_get_magic(dev) == ACPITIMER_MAGIC)
+ return(0);
+ return(ENXIO);
+}
+
+static int
+acpi_timer_attach(device_t dev)
+{
+ struct acpi_timer_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->tm_dev = dev;
+
+ return(0);
+}
diff --git a/sys/dev/acpica/acpiio.h b/sys/dev/acpica/acpiio.h
new file mode 100644
index 0000000..75c59fc
--- /dev/null
+++ b/sys/dev/acpica/acpiio.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 1999 Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
+ * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define ACPIIO_ENABLE _IO('P', 1)
+#define ACPIIO_DISABLE _IO('P', 2)
+#define ACPIIO_SETSLPSTATE _IOW('P', 3, int)
+
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
new file mode 100644
index 0000000..f415bae
--- /dev/null
+++ b/sys/dev/acpica/acpivar.h
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "bus_if.h"
+#include <sys/eventhandler.h>
+
+extern devclass_t acpi_devclass;
+
+struct acpi_softc {
+ device_t acpi_dev;
+ dev_t acpi_dev_t;
+
+ struct resource *acpi_irq;
+ int acpi_irq_rid;
+ void *acpi_irq_handle;
+
+ int acpi_enabled;
+ int acpi_sstate;
+
+#define ACPI_POWER_BUTTON_DEFAULT_SX ACPI_STATE_S5;
+#define ACPI_SLEEP_BUTTON_DEFAULT_SX ACPI_STATE_S1;
+#define ACPI_LID_SWITCH_DEFAULT_SX ACPI_STATE_S1;
+ int acpi_power_button_sx;
+ int acpi_sleep_button_sx;
+ int acpi_lid_switch_sx;
+};
+
+struct acpi_device {
+ /* ACPI ivars */
+ ACPI_HANDLE ad_handle;
+ int ad_magic;
+ void *ad_private;
+
+ /* resources */
+ struct resource_list ad_rl;
+};
+
+/*
+ * This is a cheap and nasty way to get around the horrid counted list
+ * argument format that AcpiEvalateMethod uses.
+ */
+#define ACPI_OBJECTLIST_MAX 16
+struct acpi_object_list {
+ UINT32 count;
+ ACPI_OBJECT *pointer[ACPI_OBJECTLIST_MAX];
+ ACPI_OBJECT object[ACPI_OBJECTLIST_MAX];
+};
+
+static __inline struct acpi_object_list *
+acpi_AllocObjectList(int nobj) {
+ struct acpi_object_list *l;
+ int i;
+
+ if (nobj > ACPI_OBJECTLIST_MAX)
+ return(NULL);
+ if ((l = AcpiOsAllocate(sizeof(*l))) == NULL)
+ return(NULL);
+ bzero(l, sizeof(*l));
+ for (i = 0; i < ACPI_OBJECTLIST_MAX; i++)
+ l->pointer[i] = &l->object[i];
+ l->count = nobj;
+ return(l);
+}
+
+#define ACPI_IVAR_HANDLE 0x100
+#define ACPI_IVAR_MAGIC 0x101
+#define ACPI_IVAR_PRIVATE 0x102
+
+static __inline ACPI_HANDLE
+acpi_get_handle(device_t dev) {
+ ACPI_HANDLE h;
+
+ if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, (uintptr_t *)&h))
+ return(NULL);
+ return(h);
+}
+
+static __inline int
+acpi_set_handle(device_t dev, ACPI_HANDLE h) {
+ return(BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, (uintptr_t)h));
+}
+
+static __inline int
+acpi_get_magic(device_t dev) {
+ int m;
+
+ if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, (uintptr_t *)&m))
+ return(0);
+ return(m);
+}
+
+static __inline int
+acpi_set_magic(device_t dev, int m) {
+ return(BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, (uintptr_t)m));
+}
+
+static __inline void *
+acpi_get_private(device_t dev) {
+ void *p;
+
+ if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, (uintptr_t *)&p))
+ return(NULL);
+ return(p);
+}
+
+static __inline int
+acpi_set_private(device_t dev, void *p) {
+ return(BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, (uintptr_t)p));
+}
+
+static __inline ACPI_OBJECT_TYPE
+acpi_get_type(device_t dev) {
+ ACPI_HANDLE h;
+ ACPI_OBJECT_TYPE t;
+
+ if ((h = acpi_get_handle(dev)) == NULL)
+ return(ACPI_TYPE_NOT_FOUND);
+ if (AcpiGetType(h, &t) != AE_OK)
+ return(ACPI_TYPE_NOT_FOUND);
+ return(t);
+}
+
+#ifdef ENABLE_DEBUGGER
+extern void acpi_EnterDebugger(void);
+#endif
+
+extern BOOLEAN acpi_MatchHid(device_t dev, char *hid);
+extern ACPI_STATUS acpi_GetIntoBuffer(ACPI_HANDLE handle,
+ ACPI_STATUS (*func)(ACPI_HANDLE, ACPI_BUFFER *),
+ ACPI_BUFFER *buf);
+extern ACPI_BUFFER *acpi_AllocBuffer(int size);
+extern ACPI_STATUS acpi_SetSleepState(struct acpi_softc *sc, int state);
+extern ACPI_STATUS acpi_Enable(struct acpi_softc *sc);
+extern ACPI_STATUS acpi_Disable(struct acpi_softc *sc);
+extern BOOLEAN acpi_DeviceIsPresent(device_t dev);
+extern ACPI_STATUS acpi_EvaluateNumber(ACPI_HANDLE handle, char *path, int *number);
+
+struct acpi_parse_resource_set {
+ void (* set_init)(device_t dev, void **context);
+ void (* set_done)(device_t dev, void *context);
+ void (* set_ioport)(device_t dev, void *context, u_int32_t base, u_int32_t length);
+ void (* set_iorange)(device_t dev, void *context, u_int32_t low, u_int32_t high,
+ u_int32_t length, u_int32_t align);
+ void (* set_memory)(device_t dev, void *context, u_int32_t base, u_int32_t length);
+ void (* set_memoryrange)(device_t dev, void *context, u_int32_t low, u_int32_t high,
+ u_int32_t length, u_int32_t align);
+ void (* set_irq)(device_t dev, void *context, u_int32_t irq);
+ void (* set_drq)(device_t dev, void *context, u_int32_t drq);
+ void (* set_start_dependant)(device_t dev, void *context, int preference);
+ void (* set_end_dependant)(device_t dev, void *context);
+};
+
+extern struct acpi_parse_resource_set acpi_res_parse_set;
+extern ACPI_STATUS acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
+ struct acpi_parse_resource_set *set);
+
+/* XXX this is ugly */
+extern char *acpi_strerror(ACPI_STATUS excep);
+
+/*
+ * ACPI event handling
+ */
+extern UINT32 acpi_eventhandler_power_button_for_sleep(void *context);
+extern UINT32 acpi_eventhandler_power_button_for_wakeup(void *context);
+extern UINT32 acpi_eventhandler_sleep_button_for_sleep(void *context);
+extern UINT32 acpi_eventhandler_sleep_button_for_wakeup(void *context);
+
+#define ACPI_EVENT_PRI_FIRST 0
+#define ACPI_EVENT_PRI_DEFAULT 10000
+#define ACPI_EVENT_PRI_LAST 20000
+
+typedef void (*acpi_event_handler_t) __P((void *, int));
+
+EVENTHANDLER_DECLARE(acpi_sleep_event, acpi_event_handler_t);
+EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t);
+
+/*
+ * Misc.
+ */
+static __inline struct acpi_softc *
+acpi_device_get_parent_softc(device_t child)
+{
+ device_t parent;
+
+ parent = device_get_parent(child);
+ if (parent == NULL) {
+ return(NULL);
+ }
+ return(device_get_softc(parent));
+}
+
+extern char *acpi_name(ACPI_HANDLE handle);
+extern int acpi_avoid(ACPI_HANDLE handle);
+
OpenPOWER on IntegriCloud