[The previous version wouldn't work correctly.] --- From: Shaohua Li <shaohua.li@xxxxxxxxx>, Rafael J. Wysocki <rjw@xxxxxxx> Based on the David Brownell's patch at http://marc.info/?l=linux-acpi&m=117873972806360&w=2 Add a helper routine returning the lowest power (highest number) ACPI device power state that given device can be in while the system is in the sleep state indicated by acpi_target_sleep_state . Signed-off-by: Rafael J. Wysocki <rjw@xxxxxxx> --- drivers/acpi/sleep/main.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 + 2 files changed, 53 insertions(+) Index: linux-2.6.22-rc6/drivers/acpi/sleep/main.c =================================================================== --- linux-2.6.22-rc6.orig/drivers/acpi/sleep/main.c +++ linux-2.6.22-rc6/drivers/acpi/sleep/main.c @@ -262,6 +262,57 @@ static struct hibernation_ops acpi_hiber }; #endif /* CONFIG_SOFTWARE_SUSPEND */ +/** + * acpi_pm_device_sleep_state - return the lowest power (highest number) + * ACPI device power state given device can be + * in while the system is in the sleep state + * indicated by %acpi_target_sleep_state + * @handle: Represents the device the state is evaluated for + */ + +int acpi_pm_device_sleep_state(acpi_handle handle) +{ + char acpi_method[] = "_SxD"; + unsigned long d_min, d_max; + struct acpi_device *dev; + + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) + printk(KERN_ERR "ACPI handle has no context!\n"); + return -ENODEV; + } + acpi_method[2] = '0' + acpi_target_sleep_state; + /* + * If the sleep state is S0, we will return D3, but if the device has + * _S0W, we will use the value from _S0W + */ + d_min = ACPI_STATE_D3; + d_max = ACPI_STATE_D3; + /* + * If present, _SxD methods give the minimum D-state we may use + * for each S-state ... with lowest latency state switching. + * + * We rely on acpi_evaluate_integer() not clobbering the integer + * provided -- that's our fault recovery, we ignore retval. + */ + if (acpi_target_sleep_state > ACPI_STATE_S0) + acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); + + /* + * If _PRW says we can wake from the upcoming system state, the _SxD + * value can wake ... and we'll assume a wakeup-aware driver. If _SxW + * methods exist (ACPI 3.x), they give the lowest power D-state that + * can also wake the system. _S0W can be valid. + */ + if (acpi_target_sleep_state == ACPI_STATE_S0 || + (dev->wakeup.state.enabled && + dev->wakeup.sleep_state <= acpi_target_sleep_state)) { + d_max = d_min; + acpi_method[3] = 'W'; + acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); + } + return d_max; +} + /* * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. Index: linux-2.6.22-rc6/include/acpi/acpi_bus.h =================================================================== --- linux-2.6.22-rc6.orig/include/acpi/acpi_bus.h +++ linux-2.6.22-rc6/include/acpi/acpi_bus.h @@ -364,6 +364,8 @@ acpi_handle acpi_get_child(acpi_handle, acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) +int acpi_pm_device_sleep_state(acpi_handle handle); + #endif /* CONFIG_ACPI */ #endif /*__ACPI_BUS_H__*/ - To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html