From a1fccb476542d7b66020eefb0395d7d577c25664 Mon Sep 17 00:00:00 2001 From: Mitsuru IWASAKI Date: Mon, 22 Jul 2002 12:52:54 +0000 Subject: Add device(power/sleep button and lid) wake function from sleeping state. This is required for some Thinkpad (and maybe VAIO) machines to wake the system up from sleep. Currently partially implemented, more complete implementation will come later. --- sys/dev/acpica/acpi.c | 133 +++++++++++++++++++++++++++++++++++++++++-- sys/dev/acpica/acpi_button.c | 22 +++++++ sys/dev/acpica/acpi_lid.c | 21 +++++++ sys/dev/acpica/acpivar.h | 3 + 4 files changed, 174 insertions(+), 5 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 7d24c2b949a1a..b292bcc6422e0 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) { @@ -1612,6 +1614,127 @@ acpi_disabled(char *subsys) return(0); } +/* + * Device wake capability enable/disable. + */ +void +acpi_device_enable_wake_capability(ACPI_HANDLE h, int enable) +{ + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg; + + /* + * TBD: All Power Resources referenced by elements 2 through N + * of the _PRW object are put into the ON state. + */ + + /* + * 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. * diff --git a/sys/dev/acpica/acpi_button.c b/sys/dev/acpica/acpi_button.c index 150689584c074..a4bebc265acf0 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 bd186a50bd3e8..f83b2de2404fa 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 579696dd8978f..88c462e7b6b12 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); -- cgit v1.3