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.
This commit is contained in:
iwasaki 2002-07-22 12:52:54 +00:00
parent fcb9022bbd
commit 3961570913
4 changed files with 174 additions and 5 deletions

View File

@ -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.
*

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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);