From ff0c41942fd9766a158502d8ed6965c8a7726f53 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Jan 2013 14:11:08 +0100 Subject: ACPI / PM: Change the way power transitions to D3cold are carried out During power transitions into D3cold from any shallower power states we are supposed to transition the device into D3hot and remove power from it afterward, but the current code in acpi_device_set_power() doesn't work this way. At the same time, though, we need to be careful enough to preserve backwards compatibility for systems that don't distinguish between D3hot and D3cold (e.g. designed before ACPI 4). Modify acpi_device_set_power() so that it works in accordance with the expectations in both cases. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/acpi/bus.c') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 1f0d457ecbcf..8e57fc49726e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -270,6 +270,7 @@ int acpi_device_set_power(struct acpi_device *device, int state) int result = 0; acpi_status status = AE_OK; char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; + bool cut_power = false; if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) return -EINVAL; @@ -294,9 +295,13 @@ int acpi_device_set_power(struct acpi_device *device, int state) return -ENODEV; } - /* For D3cold we should execute _PS3, not _PS4. */ - if (state == ACPI_STATE_D3_COLD) + /* For D3cold we should first transition into D3hot. */ + if (state == ACPI_STATE_D3_COLD + && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) { + state = ACPI_STATE_D3_HOT; object_name[3] = '3'; + cut_power = true; + } /* * Transition Power @@ -341,6 +346,9 @@ int acpi_device_set_power(struct acpi_device *device, int state) } } + if (cut_power) + result = acpi_power_transition(device, ACPI_STATE_D3_COLD); + end: if (result) printk(KERN_WARNING PREFIX -- cgit v1.2.3 From ad0c3b0e4863185a9f8874a655a8d2999c915131 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Jan 2013 14:11:08 +0100 Subject: ACPI / PM: More visible function for retrieving device power states The function used for retrieving ACPI device power states, __acpi_bus_get_power(), is now static, because it is only used internally in drivers/acpi/bus.c. However, it will be used outside of that file going forward, so rename it to acpi_device_get_power(), in analogy with acpi_device_set_power(), add a kerneldoc comment to it and add its header to acpi_bus.h. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 15 ++++++++++++--- include/acpi/acpi_bus.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/acpi/bus.c') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 8e57fc49726e..0e1441cc4d7f 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -200,7 +200,16 @@ static const char *state_string(int state) } } -static int __acpi_bus_get_power(struct acpi_device *device, int *state) +/** + * acpi_device_get_power - Get power state of an ACPI device. + * @device: Device to get the power state of. + * @state: Place to store the power state of the device. + * + * This function does not update the device's power.state field, but it may + * update its parent's power.state field (when the parent's power state is + * unknown and the device's power state turns out to be D0). + */ +int acpi_device_get_power(struct acpi_device *device, int *state) { int result = ACPI_STATE_UNKNOWN; @@ -397,7 +406,7 @@ int acpi_bus_init_power(struct acpi_device *device) device->power.state = ACPI_STATE_UNKNOWN; - result = __acpi_bus_get_power(device, &state); + result = acpi_device_get_power(device, &state); if (result) return result; @@ -421,7 +430,7 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) if (result) return result; - result = __acpi_bus_get_power(device, &state); + result = acpi_device_get_power(device, &state); if (result) return result; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a272c3156999..9d7c2ca0f1f7 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -331,6 +331,7 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_set_power(acpi_handle handle, int state); +int acpi_device_get_power(struct acpi_device *device, int *state); int acpi_device_set_power(struct acpi_device *device, int state); int acpi_bus_update_power(acpi_handle handle, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); -- cgit v1.2.3 From 96bfd3cee2a741906b3ef5c1096d2f0a0b8025e0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Jan 2013 14:11:08 +0100 Subject: ACPI / PM: Common string representations of device power states The function returning string representations of ACPI device power states, state_string((), is now static, because it is only used internally in drivers/acpi/bus.c. However, it will be used outside of that file going forward, so rename it to acpi_power_state_string(), add a kerneldoc comment to it and add its header to acpi_bus.h. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 18 ++++++++++++------ include/acpi/acpi_bus.h | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/acpi/bus.c') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 0e1441cc4d7f..6c9b16c16660 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -182,7 +182,11 @@ EXPORT_SYMBOL(acpi_bus_get_private_data); Power Management -------------------------------------------------------------------------- */ -static const char *state_string(int state) +/** + * acpi_power_state_string - String representation of ACPI device power state. + * @state: ACPI device power state to return the string representation of. + */ +const char *acpi_power_state_string(int state) { switch (state) { case ACPI_STATE_D0: @@ -260,7 +264,7 @@ int acpi_device_get_power(struct acpi_device *device, int *state) out: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", - device->pnp.bus_id, state_string(*state))); + device->pnp.bus_id, acpi_power_state_string(*state))); return 0; } @@ -288,13 +292,13 @@ int acpi_device_set_power(struct acpi_device *device, int state) if (state == device->power.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", - state_string(state))); + acpi_power_state_string(state))); return 0; } if (!device->power.states[state].flags.valid) { printk(KERN_WARNING PREFIX "Device does not support %s\n", - state_string(state)); + acpi_power_state_string(state)); return -ENODEV; } if (device->parent && (state < device->parent->power.state)) { @@ -362,12 +366,14 @@ int acpi_device_set_power(struct acpi_device *device, int state) if (result) printk(KERN_WARNING PREFIX "Device [%s] failed to transition to %s\n", - device->pnp.bus_id, state_string(state)); + device->pnp.bus_id, + acpi_power_state_string(state)); else { device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to %s\n", - device->pnp.bus_id, state_string(state))); + device->pnp.bus_id, + acpi_power_state_string(state))); } return result; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 9d7c2ca0f1f7..71eceb99d411 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -331,6 +331,7 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_set_power(acpi_handle handle, int state); +const char *acpi_power_state_string(int state); int acpi_device_get_power(struct acpi_device *device, int *state); int acpi_device_set_power(struct acpi_device *device, int state); int acpi_bus_update_power(acpi_handle handle, int *state_p); -- cgit v1.2.3 From 9ce4e607111764673f7a59d7bc87a16ade5c7bba Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Jan 2013 14:11:08 +0100 Subject: ACPI / PM: Move device power management functions to device_pm.c Move ACPI device power management functions from drivers/acpi/bus.c to drivers/acpi/device_pm.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 293 ----------------------------------------------- drivers/acpi/device_pm.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/internal.h | 1 - include/acpi/acpi_bus.h | 38 ++++++ 4 files changed, 326 insertions(+), 294 deletions(-) (limited to 'drivers/acpi/bus.c') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 6c9b16c16660..01708a165368 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -178,299 +178,6 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) } EXPORT_SYMBOL(acpi_bus_get_private_data); -/* -------------------------------------------------------------------------- - Power Management - -------------------------------------------------------------------------- */ - -/** - * acpi_power_state_string - String representation of ACPI device power state. - * @state: ACPI device power state to return the string representation of. - */ -const char *acpi_power_state_string(int state) -{ - switch (state) { - case ACPI_STATE_D0: - return "D0"; - case ACPI_STATE_D1: - return "D1"; - case ACPI_STATE_D2: - return "D2"; - case ACPI_STATE_D3_HOT: - return "D3hot"; - case ACPI_STATE_D3_COLD: - return "D3"; - default: - return "(unknown)"; - } -} - -/** - * acpi_device_get_power - Get power state of an ACPI device. - * @device: Device to get the power state of. - * @state: Place to store the power state of the device. - * - * This function does not update the device's power.state field, but it may - * update its parent's power.state field (when the parent's power state is - * unknown and the device's power state turns out to be D0). - */ -int acpi_device_get_power(struct acpi_device *device, int *state) -{ - int result = ACPI_STATE_UNKNOWN; - - if (!device || !state) - return -EINVAL; - - if (!device->flags.power_manageable) { - /* TBD: Non-recursive algorithm for walking up hierarchy. */ - *state = device->parent ? - device->parent->power.state : ACPI_STATE_D0; - goto out; - } - - /* - * Get the device's power state either directly (via _PSC) or - * indirectly (via power resources). - */ - if (device->power.flags.explicit_get) { - unsigned long long psc; - acpi_status status = acpi_evaluate_integer(device->handle, - "_PSC", NULL, &psc); - if (ACPI_FAILURE(status)) - return -ENODEV; - - result = psc; - } - /* The test below covers ACPI_STATE_UNKNOWN too. */ - if (result <= ACPI_STATE_D2) { - ; /* Do nothing. */ - } else if (device->power.flags.power_resources) { - int error = acpi_power_get_inferred_state(device, &result); - if (error) - return error; - } else if (result == ACPI_STATE_D3_HOT) { - result = ACPI_STATE_D3; - } - - /* - * If we were unsure about the device parent's power state up to this - * point, the fact that the device is in D0 implies that the parent has - * to be in D0 too. - */ - if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN - && result == ACPI_STATE_D0) - device->parent->power.state = ACPI_STATE_D0; - - *state = result; - - out: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", - device->pnp.bus_id, acpi_power_state_string(*state))); - - return 0; -} - - -/** - * acpi_device_set_power - Set power state of an ACPI device. - * @device: Device to set the power state of. - * @state: New power state to set. - * - * Callers must ensure that the device is power manageable before using this - * function. - */ -int acpi_device_set_power(struct acpi_device *device, int state) -{ - int result = 0; - acpi_status status = AE_OK; - char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; - bool cut_power = false; - - if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) - return -EINVAL; - - /* Make sure this is a valid target state */ - - if (state == device->power.state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", - acpi_power_state_string(state))); - return 0; - } - - if (!device->power.states[state].flags.valid) { - printk(KERN_WARNING PREFIX "Device does not support %s\n", - acpi_power_state_string(state)); - return -ENODEV; - } - if (device->parent && (state < device->parent->power.state)) { - printk(KERN_WARNING PREFIX - "Cannot set device to a higher-powered" - " state than parent\n"); - return -ENODEV; - } - - /* For D3cold we should first transition into D3hot. */ - if (state == ACPI_STATE_D3_COLD - && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) { - state = ACPI_STATE_D3_HOT; - object_name[3] = '3'; - cut_power = true; - } - - /* - * Transition Power - * ---------------- - * On transitions to a high-powered state we first apply power (via - * power resources) then evalute _PSx. Conversly for transitions to - * a lower-powered state. - */ - if (state < device->power.state) { - if (device->power.state >= ACPI_STATE_D3_HOT && - state != ACPI_STATE_D0) { - printk(KERN_WARNING PREFIX - "Cannot transition to non-D0 state from D3\n"); - return -ENODEV; - } - if (device->power.flags.power_resources) { - result = acpi_power_transition(device, state); - if (result) - goto end; - } - if (device->power.states[state].flags.explicit_set) { - status = acpi_evaluate_object(device->handle, - object_name, NULL, NULL); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } - } - } else { - if (device->power.states[state].flags.explicit_set) { - status = acpi_evaluate_object(device->handle, - object_name, NULL, NULL); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } - } - if (device->power.flags.power_resources) { - result = acpi_power_transition(device, state); - if (result) - goto end; - } - } - - if (cut_power) - result = acpi_power_transition(device, ACPI_STATE_D3_COLD); - - end: - if (result) - printk(KERN_WARNING PREFIX - "Device [%s] failed to transition to %s\n", - device->pnp.bus_id, - acpi_power_state_string(state)); - else { - device->power.state = state; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device [%s] transitioned to %s\n", - device->pnp.bus_id, - acpi_power_state_string(state))); - } - - return result; -} -EXPORT_SYMBOL(acpi_device_set_power); - - -int acpi_bus_set_power(acpi_handle handle, int state) -{ - struct acpi_device *device; - int result; - - result = acpi_bus_get_device(handle, &device); - if (result) - return result; - - if (!device->flags.power_manageable) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device [%s] is not power manageable\n", - dev_name(&device->dev))); - return -ENODEV; - } - - return acpi_device_set_power(device, state); -} -EXPORT_SYMBOL(acpi_bus_set_power); - - -int acpi_bus_init_power(struct acpi_device *device) -{ - int state; - int result; - - if (!device) - return -EINVAL; - - device->power.state = ACPI_STATE_UNKNOWN; - - result = acpi_device_get_power(device, &state); - if (result) - return result; - - if (device->power.flags.power_resources) - result = acpi_power_on_resources(device, state); - - if (!result) - device->power.state = state; - - return result; -} - - -int acpi_bus_update_power(acpi_handle handle, int *state_p) -{ - struct acpi_device *device; - int state; - int result; - - result = acpi_bus_get_device(handle, &device); - if (result) - return result; - - result = acpi_device_get_power(device, &state); - if (result) - return result; - - result = acpi_device_set_power(device, state); - if (!result && state_p) - *state_p = state; - - return result; -} -EXPORT_SYMBOL_GPL(acpi_bus_update_power); - - -bool acpi_bus_power_manageable(acpi_handle handle) -{ - struct acpi_device *device; - int result; - - result = acpi_bus_get_device(handle, &device); - return result ? false : device->flags.power_manageable; -} - -EXPORT_SYMBOL(acpi_bus_power_manageable); - -bool acpi_bus_can_wakeup(acpi_handle handle) -{ - struct acpi_device *device; - int result; - - result = acpi_bus_get_device(handle, &device); - return result ? false : device->wakeup.flags.valid; -} - -EXPORT_SYMBOL(acpi_bus_can_wakeup); - static void acpi_print_osc_error(acpi_handle handle, struct acpi_osc_context *context, char *error) { diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 8be4b29e38aa..8bca7465c78d 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -30,6 +30,12 @@ #include #include +#include + +#include "internal.h" + +#define _COMPONENT ACPI_POWER_COMPONENT +ACPI_MODULE_NAME("device_pm"); static DEFINE_MUTEX(acpi_pm_notifier_lock); @@ -93,6 +99,288 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, return status; } +/** + * acpi_power_state_string - String representation of ACPI device power state. + * @state: ACPI device power state to return the string representation of. + */ +const char *acpi_power_state_string(int state) +{ + switch (state) { + case ACPI_STATE_D0: + return "D0"; + case ACPI_STATE_D1: + return "D1"; + case ACPI_STATE_D2: + return "D2"; + case ACPI_STATE_D3_HOT: + return "D3hot"; + case ACPI_STATE_D3_COLD: + return "D3"; + default: + return "(unknown)"; + } +} + +/** + * acpi_device_get_power - Get power state of an ACPI device. + * @device: Device to get the power state of. + * @state: Place to store the power state of the device. + * + * This function does not update the device's power.state field, but it may + * update its parent's power.state field (when the parent's power state is + * unknown and the device's power state turns out to be D0). + */ +int acpi_device_get_power(struct acpi_device *device, int *state) +{ + int result = ACPI_STATE_UNKNOWN; + + if (!device || !state) + return -EINVAL; + + if (!device->flags.power_manageable) { + /* TBD: Non-recursive algorithm for walking up hierarchy. */ + *state = device->parent ? + device->parent->power.state : ACPI_STATE_D0; + goto out; + } + + /* + * Get the device's power state either directly (via _PSC) or + * indirectly (via power resources). + */ + if (device->power.flags.explicit_get) { + unsigned long long psc; + acpi_status status = acpi_evaluate_integer(device->handle, + "_PSC", NULL, &psc); + if (ACPI_FAILURE(status)) + return -ENODEV; + + result = psc; + } + /* The test below covers ACPI_STATE_UNKNOWN too. */ + if (result <= ACPI_STATE_D2) { + ; /* Do nothing. */ + } else if (device->power.flags.power_resources) { + int error = acpi_power_get_inferred_state(device, &result); + if (error) + return error; + } else if (result == ACPI_STATE_D3_HOT) { + result = ACPI_STATE_D3; + } + + /* + * If we were unsure about the device parent's power state up to this + * point, the fact that the device is in D0 implies that the parent has + * to be in D0 too. + */ + if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN + && result == ACPI_STATE_D0) + device->parent->power.state = ACPI_STATE_D0; + + *state = result; + + out: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", + device->pnp.bus_id, acpi_power_state_string(*state))); + + return 0; +} + +/** + * acpi_device_set_power - Set power state of an ACPI device. + * @device: Device to set the power state of. + * @state: New power state to set. + * + * Callers must ensure that the device is power manageable before using this + * function. + */ +int acpi_device_set_power(struct acpi_device *device, int state) +{ + int result = 0; + acpi_status status = AE_OK; + char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; + bool cut_power = false; + + if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) + return -EINVAL; + + /* Make sure this is a valid target state */ + + if (state == device->power.state) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", + acpi_power_state_string(state))); + return 0; + } + + if (!device->power.states[state].flags.valid) { + printk(KERN_WARNING PREFIX "Device does not support %s\n", + acpi_power_state_string(state)); + return -ENODEV; + } + if (device->parent && (state < device->parent->power.state)) { + printk(KERN_WARNING PREFIX + "Cannot set device to a higher-powered" + " state than parent\n"); + return -ENODEV; + } + + /* For D3cold we should first transition into D3hot. */ + if (state == ACPI_STATE_D3_COLD + && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) { + state = ACPI_STATE_D3_HOT; + object_name[3] = '3'; + cut_power = true; + } + + /* + * Transition Power + * ---------------- + * On transitions to a high-powered state we first apply power (via + * power resources) then evalute _PSx. Conversly for transitions to + * a lower-powered state. + */ + if (state < device->power.state) { + if (device->power.state >= ACPI_STATE_D3_HOT && + state != ACPI_STATE_D0) { + printk(KERN_WARNING PREFIX + "Cannot transition to non-D0 state from D3\n"); + return -ENODEV; + } + if (device->power.flags.power_resources) { + result = acpi_power_transition(device, state); + if (result) + goto end; + } + if (device->power.states[state].flags.explicit_set) { + status = acpi_evaluate_object(device->handle, + object_name, NULL, NULL); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto end; + } + } + } else { + if (device->power.states[state].flags.explicit_set) { + status = acpi_evaluate_object(device->handle, + object_name, NULL, NULL); + if (ACPI_FAILURE(status)) { + result = -ENODEV; + goto end; + } + } + if (device->power.flags.power_resources) { + result = acpi_power_transition(device, state); + if (result) + goto end; + } + } + + if (cut_power) + result = acpi_power_transition(device, ACPI_STATE_D3_COLD); + + end: + if (result) + printk(KERN_WARNING PREFIX + "Device [%s] failed to transition to %s\n", + device->pnp.bus_id, + acpi_power_state_string(state)); + else { + device->power.state = state; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device [%s] transitioned to %s\n", + device->pnp.bus_id, + acpi_power_state_string(state))); + } + + return result; +} +EXPORT_SYMBOL(acpi_device_set_power); + +int acpi_bus_set_power(acpi_handle handle, int state) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + if (result) + return result; + + if (!device->flags.power_manageable) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Device [%s] is not power manageable\n", + dev_name(&device->dev))); + return -ENODEV; + } + + return acpi_device_set_power(device, state); +} +EXPORT_SYMBOL(acpi_bus_set_power); + +int acpi_bus_init_power(struct acpi_device *device) +{ + int state; + int result; + + if (!device) + return -EINVAL; + + device->power.state = ACPI_STATE_UNKNOWN; + + result = acpi_device_get_power(device, &state); + if (result) + return result; + + if (device->power.flags.power_resources) + result = acpi_power_on_resources(device, state); + + if (!result) + device->power.state = state; + + return result; +} + +int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + struct acpi_device *device; + int state; + int result; + + result = acpi_bus_get_device(handle, &device); + if (result) + return result; + + result = acpi_device_get_power(device, &state); + if (result) + return result; + + result = acpi_device_set_power(device, state); + if (!result && state_p) + *state_p = state; + + return result; +} +EXPORT_SYMBOL_GPL(acpi_bus_update_power); + +bool acpi_bus_power_manageable(acpi_handle handle) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + return result ? false : device->flags.power_manageable; +} +EXPORT_SYMBOL(acpi_bus_power_manageable); + +bool acpi_bus_can_wakeup(acpi_handle handle) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + return result ? false : device->wakeup.flags.valid; +} +EXPORT_SYMBOL(acpi_bus_can_wakeup); + /** * acpi_device_power_state - Get preferred power state of ACPI device. * @dev: Device whose preferred target power state to return. diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 07f61dbd8136..1f004f35bc67 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -61,7 +61,6 @@ int acpi_device_sleep_wake(struct acpi_device *dev, int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); -int acpi_bus_init_power(struct acpi_device *device); int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 71eceb99d411..fca1b9cb27d9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -330,13 +330,51 @@ void acpi_bus_data_handler(acpi_handle handle, void *context); acpi_status acpi_bus_get_status_handle(acpi_handle handle, unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); + +#ifdef CONFIG_PM int acpi_bus_set_power(acpi_handle handle, int state); const char *acpi_power_state_string(int state); int acpi_device_get_power(struct acpi_device *device, int *state); int acpi_device_set_power(struct acpi_device *device, int state); +int acpi_bus_init_power(struct acpi_device *device); int acpi_bus_update_power(acpi_handle handle, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); bool acpi_bus_can_wakeup(acpi_handle handle); +#else /* !CONFIG_PM */ +static inline int acpi_bus_set_power(acpi_handle handle, int state) +{ + return 0; +} +static inline const char *acpi_power_state_string(int state) +{ + return "D0"; +} +static inline int acpi_device_get_power(struct acpi_device *device, int *state) +{ + return 0; +} +static inline int acpi_device_set_power(struct acpi_device *device, int state) +{ + return 0; +} +static inline int acpi_bus_init_power(struct acpi_device *device) +{ + return 0; +} +static inline int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + return 0; +} +static inline bool acpi_bus_power_manageable(acpi_handle handle) +{ + return false; +} +static inline bool acpi_bus_can_wakeup(acpi_handle handle) +{ + return false; +} +#endif /* !CONFIG_PM */ + #ifdef CONFIG_ACPI_PROC_EVENT int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data); -- cgit v1.2.3