summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2002-07-22 12:52:54 +0000
committeriwasaki <iwasaki@FreeBSD.org>2002-07-22 12:52:54 +0000
commit39615709135ccb3ccbc54ac2a0a1540692d913cd (patch)
treeb7be83e0557f6498766c14cd562d2172d12e3f8f
parentfcb9022bbd197d29db9969eb8ddad8754296f8d0 (diff)
downloadFreeBSD-src-39615709135ccb3ccbc54ac2a0a1540692d913cd.zip
FreeBSD-src-39615709135ccb3ccbc54ac2a0a1540692d913cd.tar.gz
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.
-rw-r--r--sys/dev/acpica/acpi.c133
-rw-r--r--sys/dev/acpica/acpi_button.c22
-rw-r--r--sys/dev/acpica/acpi_lid.c21
-rw-r--r--sys/dev/acpica/acpivar.h3
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);
OpenPOWER on IntegriCloud