|
@@ -182,41 +182,66 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
|
|
|
Power Management
|
|
|
-------------------------------------------------------------------------- */
|
|
|
|
|
|
+static const char *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)";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int __acpi_bus_get_power(struct acpi_device *device, int *state)
|
|
|
{
|
|
|
- int result = 0;
|
|
|
- acpi_status status = 0;
|
|
|
- unsigned long long psc = 0;
|
|
|
+ int result = ACPI_STATE_UNKNOWN;
|
|
|
|
|
|
if (!device || !state)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- *state = ACPI_STATE_UNKNOWN;
|
|
|
-
|
|
|
- if (device->flags.power_manageable) {
|
|
|
- /*
|
|
|
- * Get the device's power state either directly (via _PSC) or
|
|
|
- * indirectly (via power resources).
|
|
|
- */
|
|
|
- if (device->power.flags.power_resources) {
|
|
|
- result = acpi_power_get_inferred_state(device, state);
|
|
|
- if (result)
|
|
|
- return result;
|
|
|
- } else if (device->power.flags.explicit_get) {
|
|
|
- status = acpi_evaluate_integer(device->handle, "_PSC",
|
|
|
- NULL, &psc);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- return -ENODEV;
|
|
|
- *state = (int)psc;
|
|
|
- }
|
|
|
- } else {
|
|
|
+ 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;
|
|
|
}
|
|
|
+ *state = result;
|
|
|
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
|
|
|
- device->pnp.bus_id, *state));
|
|
|
+ out:
|
|
|
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
|
|
|
+ device->pnp.bus_id, state_string(*state)));
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -234,13 +259,14 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
|
|
|
/* Make sure this is a valid target state */
|
|
|
|
|
|
if (state == device->power.state) {
|
|
|
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
|
|
|
- state));
|
|
|
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
|
|
|
+ state_string(state)));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
if (!device->power.states[state].flags.valid) {
|
|
|
- printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
|
|
|
+ printk(KERN_WARNING PREFIX "Device does not support %s\n",
|
|
|
+ state_string(state));
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
if (device->parent && (state < device->parent->power.state)) {
|
|
@@ -294,13 +320,13 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
|
|
|
end:
|
|
|
if (result)
|
|
|
printk(KERN_WARNING PREFIX
|
|
|
- "Device [%s] failed to transition to D%d\n",
|
|
|
- device->pnp.bus_id, state);
|
|
|
+ "Device [%s] failed to transition to %s\n",
|
|
|
+ device->pnp.bus_id, state_string(state));
|
|
|
else {
|
|
|
device->power.state = state;
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
|
|
- "Device [%s] transitioned to D%d\n",
|
|
|
- device->pnp.bus_id, state));
|
|
|
+ "Device [%s] transitioned to %s\n",
|
|
|
+ device->pnp.bus_id, state_string(state)));
|
|
|
}
|
|
|
|
|
|
return result;
|