Module Name: src Committed By: jruoho Date: Wed May 12 15:59:52 UTC 2010
Modified Files: src/sys/dev/acpi: acpi_power.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.11 -r1.12 src/sys/dev/acpi/acpi_power.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/acpi/acpi_power.c diff -u src/sys/dev/acpi/acpi_power.c:1.11 src/sys/dev/acpi/acpi_power.c:1.12 --- src/sys/dev/acpi/acpi_power.c:1.11 Tue Apr 27 05:34:14 2010 +++ src/sys/dev/acpi/acpi_power.c Wed May 12 15:59:52 2010 @@ -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 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 @@ 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 @@ 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 @@ return rv; } -#endif static ACPI_STATUS acpi_power_get_indirect(struct acpi_devnode *ad) @@ -410,27 +410,25 @@ } /* - * 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 @@ 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 @@ 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;