int acpi_device_update_power(struct acpi_device *device, int *state_p) { int state; int result; if (device->power.state == ACPI_STATE_UNKNOWN) { result = acpi_bus_init_power(device); if (!result && state_p) *state_p = device->power.state; return result; } result = acpi_device_get_power(device, &state); if (result) return result; if (state == ACPI_STATE_UNKNOWN) { state = ACPI_STATE_D0; result = acpi_device_set_power(device, state); if (result) return result; } else { if (device->power.flags.power_resources) { /* * We don't need to really switch the state, bu we need * to update the power resources' reference counters. */ result = acpi_power_transition(device, state); if (result) return result; } device->power.state = state; } if (state_p) *state_p = state; return 0; }
int acpi_bus_set_power(acpi_handle handle, int state) { int result = 0; acpi_status status = AE_OK; struct acpi_device *device = NULL; char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; result = acpi_bus_get_device(handle, &device); if (result) return result; if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) return -EINVAL; /* Make sure this is a valid target state */ if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", kobject_name(&device->dev.kobj))); return -ENODEV; } /* * Get device's current power state */ if (!acpi_power_nocheck) { /* * Maybe the incorrect power state is returned on the bogus * bios, which is different with the real power state. * For example: the bios returns D0 state and the real power * state is D3. OS expects to set the device to D0 state. In * such case if OS uses the power state returned by the BIOS, * the device can't be transisted to the correct power state. * So if the acpi_power_nocheck is set, it is unnecessary to * get the power state by calling acpi_bus_get_power. */ acpi_bus_get_power(device->handle, &device->power.state); } if ((state == device->power.state) && !device->flags.force_power_state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); return 0; } if (!device->power.states[state].flags.valid) { printk(KERN_WARNING PREFIX "Device does not support D%d\n", 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; } /* * 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.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; } } end: if (result) printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n", device->pnp.bus_id, state); else { device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n", device->pnp.bus_id, state)); } return result; }
int acpi_bus_set_power ( acpi_handle handle, int state) { int result = 0; acpi_status status = AE_OK; struct acpi_device *device = NULL; char object_name[5] = {'_','P','S','0'+state,'\0'}; ACPI_FUNCTION_TRACE("acpi_bus_set_power"); result = acpi_bus_get_device(handle, &device); if (result) return_VALUE(result); if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) return_VALUE(-EINVAL); /* Make sure this is a valid target state */ if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n")); return_VALUE(-ENODEV); } if (state == device->power.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); return_VALUE(0); } if (!device->power.states[state].flags.valid) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", state)); return_VALUE(-ENODEV); } if (device->parent && (state < device->parent->power.state)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Cannot set device to a higher-powered state than parent\n")); return_VALUE(-ENODEV); } /* * 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.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; } } end: if (result) ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error transitioning device [%s] to D%d\n", device->pnp.bus_id, state)); else ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n", device->pnp.bus_id, state)); return_VALUE(result); }
/** * 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; bool cut_power = false; if (!device || !device->flags.power_manageable || (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 [%s] already in %s\n", device->pnp.bus_id, acpi_power_state_string(state))); return 0; } if (!device->power.states[state].flags.valid) { dev_warn(&device->dev, "Power state %s not supported\n", acpi_power_state_string(state)); return -ENODEV; } if (!device->power.flags.ignore_parent && device->parent && (state < device->parent->power.state)) { dev_warn(&device->dev, "Cannot transition to power state %s for parent in %s\n", acpi_power_state_string(state), acpi_power_state_string(device->parent->power.state)); 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; cut_power = true; } if (state < device->power.state && state != ACPI_STATE_D0 && device->power.state >= ACPI_STATE_D3_HOT) { dev_warn(&device->dev, "Cannot transition to non-D0 state from D3\n"); return -ENODEV; } /* * Transition Power * ---------------- * In accordance with the ACPI specification first apply power (via * power resources) and then evaluate _PSx. */ if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); if (result) goto end; } result = acpi_dev_pm_explicit_set(device, state); if (result) goto end; if (cut_power) { device->power.state = state; state = ACPI_STATE_D3_COLD; result = acpi_power_transition(device, state); } end: if (result) { dev_warn(&device->dev, "Failed to change power state to %s\n", 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; }
static int __acpi_bus_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' }; 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 D%d\n", state)); return 0; } if (!device->power.states[state].flags.valid) { printk(KERN_WARNING PREFIX "Device does not support D%d\n", 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 execute _PS3, not _PS4. */ if (state == ACPI_STATE_D3_COLD) object_name[3] = '3'; /* * 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.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; } } end: if (result) printk(KERN_WARNING PREFIX "Device [%s] failed to transition to D%d\n", device->pnp.bus_id, state); else { device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n", device->pnp.bus_id, state)); } return result; }
/** * 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 target_state = state; int result = 0; if (!device || !device->flags.power_manageable || (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 [%s] already in %s\n", device->pnp.bus_id, acpi_power_state_string(state))); return 0; } if (state == ACPI_STATE_D3_COLD) { /* * For transitions to D3cold we need to execute _PS3 and then * possibly drop references to the power resources in use. */ state = ACPI_STATE_D3_HOT; /* If _PR3 is not available, use D3hot as the target state. */ if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid) target_state = state; } else if (!device->power.states[state].flags.valid) { dev_warn(&device->dev, "Power state %s not supported\n", acpi_power_state_string(state)); return -ENODEV; } if (!device->power.flags.ignore_parent && device->parent && (state < device->parent->power.state)) { dev_warn(&device->dev, "Cannot transition to power state %s for parent in %s\n", acpi_power_state_string(state), acpi_power_state_string(device->parent->power.state)); return -ENODEV; } /* * Transition Power * ---------------- * In accordance with ACPI 6, _PSx is executed before manipulating power * resources, unless the target state is D0, in which case _PS0 is * supposed to be executed after turning the power resources on. */ if (state > ACPI_STATE_D0) { /* * According to ACPI 6, devices cannot go from lower-power * (deeper) states to higher-power (shallower) states. */ if (state < device->power.state) { dev_warn(&device->dev, "Cannot transition from %s to %s\n", acpi_power_state_string(device->power.state), acpi_power_state_string(state)); return -ENODEV; } result = acpi_dev_pm_explicit_set(device, state); if (result) goto end; if (device->power.flags.power_resources) result = acpi_power_transition(device, target_state); } else { if (device->power.flags.power_resources) { result = acpi_power_transition(device, ACPI_STATE_D0); if (result) goto end; } result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); } end: if (result) { dev_warn(&device->dev, "Failed to change power state to %s\n", acpi_power_state_string(state)); } else { device->power.state = target_state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to %s\n", device->pnp.bus_id, acpi_power_state_string(state))); } return result; }
/** * 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; 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; cut_power = true; } if (state < device->power.state && state != ACPI_STATE_D0 && device->power.state >= ACPI_STATE_D3_HOT) { printk(KERN_WARNING PREFIX "Cannot transition to non-D0 state from D3\n"); return -ENODEV; } /* * Transition Power * ---------------- * In accordance with the ACPI specification first apply power (via * power resources) and then evalute _PSx. */ if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); if (result) goto end; } result = acpi_dev_pm_explicit_set(device, state); if (result) goto end; if (cut_power) { device->power.state = state; state = ACPI_STATE_D3_COLD; result = acpi_power_transition(device, state); } 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; }