aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r--drivers/acpi/bus.c88
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 3188da3df8da..adceafda9c17 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -182,41 +182,66 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
182 Power Management 182 Power Management
183 -------------------------------------------------------------------------- */ 183 -------------------------------------------------------------------------- */
184 184
185static const char *state_string(int state)
186{
187 switch (state) {
188 case ACPI_STATE_D0:
189 return "D0";
190 case ACPI_STATE_D1:
191 return "D1";
192 case ACPI_STATE_D2:
193 return "D2";
194 case ACPI_STATE_D3_HOT:
195 return "D3hot";
196 case ACPI_STATE_D3_COLD:
197 return "D3";
198 default:
199 return "(unknown)";
200 }
201}
202
185static int __acpi_bus_get_power(struct acpi_device *device, int *state) 203static int __acpi_bus_get_power(struct acpi_device *device, int *state)
186{ 204{
187 int result = 0; 205 int result = ACPI_STATE_UNKNOWN;
188 acpi_status status = 0;
189 unsigned long long psc = 0;
190 206
191 if (!device || !state) 207 if (!device || !state)
192 return -EINVAL; 208 return -EINVAL;
193 209
194 *state = ACPI_STATE_UNKNOWN; 210 if (!device->flags.power_manageable) {
195
196 if (device->flags.power_manageable) {
197 /*
198 * Get the device's power state either directly (via _PSC) or
199 * indirectly (via power resources).
200 */
201 if (device->power.flags.power_resources) {
202 result = acpi_power_get_inferred_state(device, state);
203 if (result)
204 return result;
205 } else if (device->power.flags.explicit_get) {
206 status = acpi_evaluate_integer(device->handle, "_PSC",
207 NULL, &psc);
208 if (ACPI_FAILURE(status))
209 return -ENODEV;
210 *state = (int)psc;
211 }
212 } else {
213 /* TBD: Non-recursive algorithm for walking up hierarchy. */ 211 /* TBD: Non-recursive algorithm for walking up hierarchy. */
214 *state = device->parent ? 212 *state = device->parent ?
215 device->parent->power.state : ACPI_STATE_D0; 213 device->parent->power.state : ACPI_STATE_D0;
214 goto out;
215 }
216
217 /*
218 * Get the device's power state either directly (via _PSC) or
219 * indirectly (via power resources).
220 */
221 if (device->power.flags.explicit_get) {
222 unsigned long long psc;
223 acpi_status status = acpi_evaluate_integer(device->handle,
224 "_PSC", NULL, &psc);
225 if (ACPI_FAILURE(status))
226 return -ENODEV;
227
228 result = psc;
229 }
230 /* The test below covers ACPI_STATE_UNKNOWN too. */
231 if (result <= ACPI_STATE_D2) {
232 ; /* Do nothing. */
233 } else if (device->power.flags.power_resources) {
234 int error = acpi_power_get_inferred_state(device, &result);
235 if (error)
236 return error;
237 } else if (result == ACPI_STATE_D3_HOT) {
238 result = ACPI_STATE_D3;
216 } 239 }
240 *state = result;
217 241
218 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", 242 out:
219 device->pnp.bus_id, *state)); 243 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
244 device->pnp.bus_id, state_string(*state)));
220 245
221 return 0; 246 return 0;
222} 247}
@@ -234,13 +259,14 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
234 /* Make sure this is a valid target state */ 259 /* Make sure this is a valid target state */
235 260
236 if (state == device->power.state) { 261 if (state == device->power.state) {
237 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", 262 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
238 state)); 263 state_string(state)));
239 return 0; 264 return 0;
240 } 265 }
241 266
242 if (!device->power.states[state].flags.valid) { 267 if (!device->power.states[state].flags.valid) {
243 printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); 268 printk(KERN_WARNING PREFIX "Device does not support %s\n",
269 state_string(state));
244 return -ENODEV; 270 return -ENODEV;
245 } 271 }
246 if (device->parent && (state < device->parent->power.state)) { 272 if (device->parent && (state < device->parent->power.state)) {
@@ -294,13 +320,13 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)
294 end: 320 end:
295 if (result) 321 if (result)
296 printk(KERN_WARNING PREFIX 322 printk(KERN_WARNING PREFIX
297 "Device [%s] failed to transition to D%d\n", 323 "Device [%s] failed to transition to %s\n",
298 device->pnp.bus_id, state); 324 device->pnp.bus_id, state_string(state));
299 else { 325 else {
300 device->power.state = state; 326 device->power.state = state;
301 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 327 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
302 "Device [%s] transitioned to D%d\n", 328 "Device [%s] transitioned to %s\n",
303 device->pnp.bus_id, state)); 329 device->pnp.bus_id, state_string(state)));
304 } 330 }
305 331
306 return result; 332 return result;