diff options
| author | jruoho <jruoho@NetBSD.org> | 2010-05-12 15:59:52 +0000 |
|---|---|---|
| committer | jruoho <jruoho@NetBSD.org> | 2010-05-12 15:59:52 +0000 |
| commit | a24d11861624bdfdfdde9ef214b99fec3cd0d045 (patch) | |
| tree | a31c9f408eec0ae381d9cfc278a95a2386574e81 /sys/dev | |
| parent | f4b66b25068041fab52dfa13a436ee4bd2d74362 (diff) | |
Initial pass for issues observed by dyoung@ on HP Pavilion N3270. In this
laptop there is a PNP0C0B ("ACPI fan") with the following properties:
_PSC : Power state for D3 (alone).
_PR0 : Power resources for D0.
_PSx : Power state switch for D0 and D3.
Thus, it is impossible to get or set the D3 power state via power resources
alone; there is only a single PowerResource() and it is for D0.
To tackle this:
1. Evaluate the direct _PSC control method if and only if there is no
given _PRx. The order is important; it is known that some other
systems implement the _PSC method (like _STA) incorrectly.
2. If no _PRx is available (and thus no _ON or _OFF), do not error out.
Instead, if we have AE_NOT_FOUND, continue to evaluate the power state
switch method, _PSx, which (on this laptop) should alone suffice for
the D0 -> D3 transition.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/acpi/acpi_power.c | 47 |
1 files changed, 25 insertions, 22 deletions
diff --git a/sys/dev/acpi/acpi_power.c b/sys/dev/acpi/acpi_power.c index 34ca6e62633..a3e2c06b7af 100644 --- a/sys/dev/acpi/acpi_power.c +++ b/sys/dev/acpi/acpi_power.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_power.c,v 1.11 2010/04/27 05:34:14 jruoho Exp $ */ +/* $NetBSD: acpi_power.c,v 1.12 2010/05/12 15:59:52 jruoho Exp $ */ /*- * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. @@ -56,7 +56,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_power.c,v 1.11 2010/04/27 05:34:14 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_power.c,v 1.12 2010/05/12 15:59:52 jruoho Exp $"); #include <sys/param.h> #include <sys/kmem.h> @@ -104,10 +104,7 @@ static const struct sysctlnode *anode = NULL; static struct acpi_power_res *acpi_power_res_init(ACPI_HANDLE); static struct acpi_power_res *acpi_power_res_get(ACPI_HANDLE); -#if 0 static ACPI_STATUS acpi_power_get_direct(struct acpi_devnode *); -#endif - static ACPI_STATUS acpi_power_get_indirect(struct acpi_devnode *); static ACPI_STATUS acpi_power_switch(struct acpi_devnode *, int, bool); @@ -267,9 +264,18 @@ acpi_power_get(struct acpi_devnode *ad, int *state) goto fail; } + /* + * Because the _PSC control method, like _STA, + * is known to be implemented incorrectly in + * many systems, we first try to retrieve the + * power state indirectly via power resources. + */ rv = acpi_power_get_indirect(ad); if (ACPI_FAILURE(rv)) + rv = acpi_power_get_direct(ad); + + if (ACPI_FAILURE(rv)) goto fail; KASSERT(ad->ad_state != ACPI_STATE_ERROR); @@ -296,11 +302,6 @@ fail: return false; } -#if 0 -/* - * Unfortunately, comparable to _STA, there are systems - * where the convenient _PSC is implemented incorrectly. - */ static ACPI_STATUS acpi_power_get_direct(struct acpi_devnode *ad) { @@ -315,7 +316,6 @@ acpi_power_get_direct(struct acpi_devnode *ad) return rv; } -#endif static ACPI_STATUS acpi_power_get_indirect(struct acpi_devnode *ad) @@ -410,27 +410,25 @@ acpi_power_set(struct acpi_devnode *ad, int state) } /* - * We first sweep through the resources required - * for the target state, turning things on and - * building references. After this we dereference - * the resources required for the current state, + * We first sweep through the resources required for the target + * state, turning things on and building references. After this + * we dereference the resources required for the current state, * turning the resources off as we go. */ rv = acpi_power_switch(ad, state, true); - if (ACPI_FAILURE(rv)) + if (ACPI_FAILURE(rv) && rv != AE_CTRL_CONTINUE) goto fail; rv = acpi_power_switch(ad, ad->ad_state, false); - if (ACPI_FAILURE(rv)) + if (ACPI_FAILURE(rv) && rv != AE_CTRL_CONTINUE) goto fail; - ad->ad_state = state; - /* - * Last but not least, invoke the power - * state switch method, if available. + * Last but not least, invoke the power state switch method, + * if available. Because some systems use only _PSx for the + * power state transitions, we do this even if there is no _PRx. */ (void)snprintf(path, sizeof(path), "_PS%d", state); (void)AcpiEvaluateObject(ad->ad_handle, path, NULL, NULL); @@ -438,6 +436,8 @@ acpi_power_set(struct acpi_devnode *ad, int state) aprint_debug_dev(ad->ad_root, "%s turned from " "D%d to D%d\n", ad->ad_name, old, state); + ad->ad_state = state; + return true; fail: @@ -472,13 +472,16 @@ acpi_power_switch(struct acpi_devnode *ad, int state, bool on) pkg = acpi_power_pkg_get(ad->ad_handle, state); if (pkg == NULL) - return AE_NOT_EXIST; + return AE_CTRL_CONTINUE; if (on != false) rv = acpi_foreach_package_object(pkg, acpi_power_res_on, ad); else rv = acpi_foreach_package_object(pkg, acpi_power_res_off, ad); + if (rv == AE_CTRL_CONTINUE) + rv = AE_ERROR; + ACPI_FREE(pkg); return rv; |
