diff options
-rw-r--r-- | sys/dev/acpica/acpi.c | 133 | ||||
-rw-r--r-- | sys/dev/acpica/acpi_button.c | 22 | ||||
-rw-r--r-- | sys/dev/acpica/acpi_lid.c | 21 | ||||
-rw-r--r-- | sys/dev/acpica/acpivar.h | 3 |
4 files changed, 174 insertions, 5 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 7d24c2b..b292bcc 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1328,6 +1328,9 @@ acpi_SetSleepState(struct acpi_softc *sc, int state) break; } + sc->acpi_sstate = state; + sc->acpi_sleep_disabled = 1; + /* * Inform all devices that we are going to sleep. */ @@ -1349,14 +1352,13 @@ acpi_SetSleepState(struct acpi_softc *sc, int state) break; } - sc->acpi_sstate = state; - sc->acpi_sleep_disabled = 1; - if (state != ACPI_STATE_S1) { acpi_sleep_machdep(sc, state); - /* AcpiEnterSleepState() maybe incompleted, unlock here. */ - AcpiUtReleaseMutex(ACPI_MTX_HARDWARE); + /* AcpiEnterSleepState() maybe incompleted, unlock here if locked. */ + if (AcpiGbl_AcpiMutexInfo[ACPI_MTX_HARDWARE].OwnerId != ACPI_MUTEX_NOT_ACQUIRED) { + AcpiUtReleaseMutex(ACPI_MTX_HARDWARE); + } /* Re-enable ACPI hardware on wakeup from sleep state 4. */ if (state == ACPI_STATE_S4) { @@ -1613,6 +1615,127 @@ acpi_disabled(char *subsys) } /* + * Device wake capability enable/disable. + */ +void +acpi_device_enable_wake_capability(ACPI_HANDLE h, int enable) +{ + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg; + + /* + * TBD: All Power Resources referenced by elements 2 through N + * of the _PRW object are put into the ON state. + */ + + /* + * enable/disable device wake function. + */ + + ArgList.Count = 1; + ArgList.Pointer = &Arg; + + Arg.Type = ACPI_TYPE_INTEGER; + Arg.Integer.Value = enable; + + (void)AcpiEvaluateObject(h, "_PSW", &ArgList, NULL); +} + +void +acpi_device_enable_wake_event(ACPI_HANDLE h) +{ + struct acpi_softc *sc; + ACPI_STATUS status; + ACPI_BUFFER prw_buffer; + ACPI_OBJECT *res; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + if ((sc = devclass_get_softc(acpi_devclass, 0)) == NULL) { + return; + } + + /* + * _PRW object is only required for devices that have the ability + * to wake the system from a system sleeping state. + */ + prw_buffer.Length = ACPI_ALLOCATE_BUFFER; + status = AcpiEvaluateObject(h, "_PRW", NULL, &prw_buffer); + if (ACPI_FAILURE(status)) { + return; + } + + res = (ACPI_OBJECT *)prw_buffer.Pointer; + if (res == NULL) { + return; + } + + if ((res->Type != ACPI_TYPE_PACKAGE) || (res->Package.Count < 2)) { + goto out; + } + + /* + * The element 1 of the _PRW object: + * The lowest power system sleeping state that can be entered + * while still providing wake functionality. + * The sleeping state being entered must be greater or equal to + * the power state declared in element 1 of the _PRW object. + */ + if (res->Package.Elements[1].Type != ACPI_TYPE_INTEGER) { + goto out; + } + + if (sc->acpi_sstate > res->Package.Elements[1].Integer.Value) { + goto out; + } + + /* + * The element 0 of the _PRW object: + */ + switch(res->Package.Elements[0].Type) { + case ACPI_TYPE_INTEGER: + /* + * If the data type of this package element is numeric, then this + * _PRW package element is the bit index in the GPEx_EN, in the + * GPE blocks described in the FADT, of the enable bit that is + * enabled for the wake event. + */ + + status = AcpiEnableEvent(res->Package.Elements[0].Integer.Value, + ACPI_EVENT_GPE, ACPI_EVENT_WAKE_ENABLE); + if (ACPI_FAILURE(status)) + printf("%s: EnableEvent Failed\n", __func__); + break; + + case ACPI_TYPE_PACKAGE: + /* XXX TBD */ + + /* + * If the data type of this package element is a package, then this + * _PRW package element is itself a package containing two + * elements. The first is an object reference to the GPE Block + * device that contains the GPE that will be triggered by the wake + * event. The second element is numeric and it contains the bit + * index in the GPEx_EN, in the GPE Block referenced by the + * first element in the package, of the enable bit that is enabled for + * the wake event. + * For example, if this field is a package then it is of the form: + * Package() {\_SB.PCI0.ISA.GPE, 2} + */ + + break; + + default: + break; + } + +out: + if (prw_buffer.Pointer != NULL) + AcpiOsFree(prw_buffer.Pointer); + return; +} + +/* * Control interface. * * We multiplex ioctls for all participating ACPI devices here. Individual diff --git a/sys/dev/acpica/acpi_button.c b/sys/dev/acpica/acpi_button.c index 1506895..a4bebc2 100644 --- a/sys/dev/acpica/acpi_button.c +++ b/sys/dev/acpica/acpi_button.c @@ -53,6 +53,8 @@ struct acpi_button_softc { static int acpi_button_probe(device_t dev); static int acpi_button_attach(device_t dev); +static int acpi_button_suspend(device_t dev); +static int acpi_button_resume(device_t dev); static void acpi_button_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context); static void acpi_button_notify_pressed_for_sleep(void *arg); static void acpi_button_notify_pressed_for_wakeup(void *arg); @@ -61,6 +63,8 @@ static device_method_t acpi_button_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_button_probe), DEVMETHOD(device_attach, acpi_button_attach), + DEVMETHOD(device_suspend, acpi_button_suspend), + DEVMETHOD(device_resume, acpi_button_resume), {0, 0} }; @@ -114,9 +118,27 @@ acpi_button_attach(device_t dev) device_printf(sc->button_dev, "couldn't install Notify handler - %s\n", AcpiFormatException(status)); return_VALUE(ENXIO); } + acpi_device_enable_wake_capability(sc->button_handle, 1); return_VALUE(0); } +static int +acpi_button_suspend(device_t dev) +{ + struct acpi_button_softc *sc; + + sc = device_get_softc(dev); + acpi_device_enable_wake_event(sc->button_handle); + return (0); +} + +static int +acpi_button_resume(device_t dev) +{ + + return (0); +} + static void acpi_button_notify_pressed_for_sleep(void *arg) { diff --git a/sys/dev/acpica/acpi_lid.c b/sys/dev/acpica/acpi_lid.c index bd186a5..f83b2de 100644 --- a/sys/dev/acpica/acpi_lid.c +++ b/sys/dev/acpica/acpi_lid.c @@ -55,6 +55,8 @@ struct acpi_lid_softc { static int acpi_lid_probe(device_t dev); static int acpi_lid_attach(device_t dev); +static int acpi_lid_suspend(device_t dev); +static int acpi_lid_resume(device_t dev); static void acpi_lid_notify_status_changed(void *arg); static void acpi_lid_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context); @@ -62,6 +64,8 @@ static device_method_t acpi_lid_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_lid_probe), DEVMETHOD(device_attach, acpi_lid_attach), + DEVMETHOD(device_suspend, acpi_lid_suspend), + DEVMETHOD(device_resume, acpi_lid_resume), {0, 0} }; @@ -102,9 +106,26 @@ acpi_lid_attach(device_t dev) * Install notification handler */ AcpiInstallNotifyHandler(sc->lid_handle, ACPI_DEVICE_NOTIFY, acpi_lid_notify_handler, sc); + acpi_device_enable_wake_capability(sc->lid_handle, 1); return_VALUE(0); } +static int +acpi_lid_suspend(device_t dev) +{ + struct acpi_lid_softc *sc; + + sc = device_get_softc(dev); + acpi_device_enable_wake_event(sc->lid_handle); + return (0); +} + +static int +acpi_lid_resume(device_t dev) +{ + return (0); +} + static void acpi_lid_notify_status_changed(void *arg) { diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index 579696d..88c462e 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -334,6 +334,9 @@ extern char *acpi_name(ACPI_HANDLE handle); extern int acpi_avoid(ACPI_HANDLE handle); extern int acpi_disabled(char *subsys); +extern void acpi_device_enable_wake_capability(ACPI_HANDLE h, int enable); +extern void acpi_device_enable_wake_event(ACPI_HANDLE h); + extern int acpi_machdep_init(device_t dev); extern void acpi_install_wakeup_handler(struct acpi_softc *sc); extern int acpi_sleep_machdep(struct acpi_softc *sc, int state); |