From 074a57f560da6e305e77d534b64709d1ae532d0f Mon Sep 17 00:00:00 2001 From: Nate Lawson Date: Fri, 9 Apr 2004 06:40:03 +0000 Subject: [PATCH] Add support for packages as the first element of _PRW. This may allow some machines to enable wake events for more devices although I haven't seen a system yet that uses this form. Also, introduce acpi_GetReference() which retrieves an object reference from various types. --- sys/dev/acpica/acpi.c | 69 +++++++++++++++++++---------------- sys/dev/acpica/acpi_package.c | 31 ++++++++++++++++ 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 4b3a45eb1685..83b76a93236b 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1983,9 +1983,11 @@ void acpi_device_enable_wake_event(ACPI_HANDLE h) { struct acpi_softc *sc; + uint32_t gpe_bit, lowest_wake; + ACPI_HANDLE handle; ACPI_STATUS status; ACPI_BUFFER prw_buffer; - ACPI_OBJECT *res; + ACPI_OBJECT *res, *res2; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -1994,67 +1996,72 @@ acpi_device_enable_wake_event(ACPI_HANDLE h) return; /* - * _PRW object is only required for devices that have the ability - * to wake the system from a system sleeping state. + * The _PRW object (7.2.9) is only required for devices that have the + * ability to wake the system from a sleeping state. */ + prw_buffer.Pointer = NULL; 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) + if (!ACPI_PKG_VALID(res, 2)) goto out; /* - * The element 0 of the _PRW object: + * 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 less than (i.e., higher power) or equal to this value. */ - switch(res->Package.Elements[0].Type) { + if (acpi_PkgInt32(res, 1, &lowest_wake) != 0) + goto out; + if (sc->acpi_sstate > lowest_wake) + goto out; + + /* + * 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 = AcpiEnableGpe(NULL, res->Package.Elements[0].Integer.Value, - ACPI_EVENT_WAKE_ENABLE); + gpe_bit = res->Package.Elements[0].Integer.Value; + status = AcpiEnableGpe(NULL, gpe_bit, ACPI_EVENT_WAKE_ENABLE); if (ACPI_FAILURE(status)) - printf("%s: EnableEvent Failed\n", __func__); + printf("wake enable: AcpiEnableGpe failed for %u\n", + gpe_bit); 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 + * 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 + * 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} */ + res2 = &res->Package.Elements[0]; + if (!ACPI_PKG_VALID(res2, 2)) + goto out; + handle = acpi_GetReference(NULL, &res2->Package.Elements[0]); + if (handle == NULL || acpi_PkgInt32(res2, 1, &gpe_bit) != 0) + goto out; + status = AcpiEnableGpe(handle, gpe_bit, ACPI_EVENT_WAKE_ENABLE); + if (ACPI_FAILURE(status)) + printf("wake enable: AcpiEnableGpe (package) failed for %u\n", + gpe_bit); break; default: break; diff --git a/sys/dev/acpica/acpi_package.c b/sys/dev/acpica/acpi_package.c index 001130859983..41f7581e58aa 100644 --- a/sys/dev/acpica/acpi_package.c +++ b/sys/dev/acpica/acpi_package.c @@ -123,3 +123,34 @@ acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *rid, return (0); } + +ACPI_HANDLE +acpi_GetReference(ACPI_HANDLE scope, ACPI_OBJECT *obj) +{ + ACPI_HANDLE h; + + if (obj == NULL) + return (NULL); + + switch (obj->Type) { + case ACPI_TYPE_LOCAL_REFERENCE: + case ACPI_TYPE_ANY: + h = obj->Reference.Handle; + break; + case ACPI_TYPE_STRING: + /* + * The String object usually contains a fully-qualified path, so + * scope can be NULL. + * + * XXX This may not always be the case. + */ + if (ACPI_FAILURE(AcpiGetHandle(scope, obj->String.Pointer, &h))) + h = NULL; + break; + default: + h = NULL; + break; + } + + return (h); +}