diff options
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r-- | drivers/acpi/power.c | 102 |
1 files changed, 56 insertions, 46 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 67dedeed144c..0003f1009885 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power"); | |||
56 | #define ACPI_POWER_RESOURCE_STATE_ON 0x01 | 56 | #define ACPI_POWER_RESOURCE_STATE_ON 0x01 |
57 | #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF | 57 | #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF |
58 | 58 | ||
59 | int acpi_power_nocheck; | ||
60 | module_param_named(power_nocheck, acpi_power_nocheck, bool, 000); | ||
61 | |||
62 | static int acpi_power_add(struct acpi_device *device); | 59 | static int acpi_power_add(struct acpi_device *device); |
63 | static int acpi_power_remove(struct acpi_device *device, int type); | 60 | static int acpi_power_remove(struct acpi_device *device, int type); |
64 | static int acpi_power_resume(struct acpi_device *device); | 61 | static int acpi_power_resume(struct acpi_device *device); |
@@ -213,11 +210,13 @@ static int acpi_power_on(acpi_handle handle) | |||
213 | resource->name)); | 210 | resource->name)); |
214 | } else { | 211 | } else { |
215 | result = __acpi_power_on(resource); | 212 | result = __acpi_power_on(resource); |
213 | if (result) | ||
214 | resource->ref_count--; | ||
216 | } | 215 | } |
217 | 216 | ||
218 | mutex_unlock(&resource->resource_lock); | 217 | mutex_unlock(&resource->resource_lock); |
219 | 218 | ||
220 | return 0; | 219 | return result; |
221 | } | 220 | } |
222 | 221 | ||
223 | static int acpi_power_off_device(acpi_handle handle) | 222 | static int acpi_power_off_device(acpi_handle handle) |
@@ -264,6 +263,35 @@ static int acpi_power_off_device(acpi_handle handle) | |||
264 | return result; | 263 | return result; |
265 | } | 264 | } |
266 | 265 | ||
266 | static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) | ||
267 | { | ||
268 | int i; | ||
269 | |||
270 | for (i = num_res - 1; i >= 0 ; i--) | ||
271 | acpi_power_off_device(list->handles[i]); | ||
272 | } | ||
273 | |||
274 | static void acpi_power_off_list(struct acpi_handle_list *list) | ||
275 | { | ||
276 | __acpi_power_off_list(list, list->count); | ||
277 | } | ||
278 | |||
279 | static int acpi_power_on_list(struct acpi_handle_list *list) | ||
280 | { | ||
281 | int result = 0; | ||
282 | int i; | ||
283 | |||
284 | for (i = 0; i < list->count; i++) { | ||
285 | result = acpi_power_on(list->handles[i]); | ||
286 | if (result) { | ||
287 | __acpi_power_off_list(list, i); | ||
288 | break; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | return result; | ||
293 | } | ||
294 | |||
267 | /** | 295 | /** |
268 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in | 296 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in |
269 | * ACPI 3.0) _PSW (Power State Wake) | 297 | * ACPI 3.0) _PSW (Power State Wake) |
@@ -421,19 +449,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
421 | Device Power Management | 449 | Device Power Management |
422 | -------------------------------------------------------------------------- */ | 450 | -------------------------------------------------------------------------- */ |
423 | 451 | ||
424 | int acpi_power_get_inferred_state(struct acpi_device *device) | 452 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state) |
425 | { | 453 | { |
426 | int result = 0; | 454 | int result = 0; |
427 | struct acpi_handle_list *list = NULL; | 455 | struct acpi_handle_list *list = NULL; |
428 | int list_state = 0; | 456 | int list_state = 0; |
429 | int i = 0; | 457 | int i = 0; |
430 | 458 | ||
431 | 459 | if (!device || !state) | |
432 | if (!device) | ||
433 | return -EINVAL; | 460 | return -EINVAL; |
434 | 461 | ||
435 | device->power.state = ACPI_STATE_UNKNOWN; | ||
436 | |||
437 | /* | 462 | /* |
438 | * We know a device's inferred power state when all the resources | 463 | * We know a device's inferred power state when all the resources |
439 | * required for a given D-state are 'on'. | 464 | * required for a given D-state are 'on'. |
@@ -448,66 +473,51 @@ int acpi_power_get_inferred_state(struct acpi_device *device) | |||
448 | return result; | 473 | return result; |
449 | 474 | ||
450 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { | 475 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { |
451 | device->power.state = i; | 476 | *state = i; |
452 | return 0; | 477 | return 0; |
453 | } | 478 | } |
454 | } | 479 | } |
455 | 480 | ||
456 | device->power.state = ACPI_STATE_D3; | 481 | *state = ACPI_STATE_D3; |
457 | |||
458 | return 0; | 482 | return 0; |
459 | } | 483 | } |
460 | 484 | ||
461 | int acpi_power_transition(struct acpi_device *device, int state) | 485 | int acpi_power_on_resources(struct acpi_device *device, int state) |
462 | { | 486 | { |
463 | int result = 0; | 487 | if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) |
464 | struct acpi_handle_list *cl = NULL; /* Current Resources */ | 488 | return -EINVAL; |
465 | struct acpi_handle_list *tl = NULL; /* Target Resources */ | ||
466 | int i = 0; | ||
467 | 489 | ||
490 | return acpi_power_on_list(&device->power.states[state].resources); | ||
491 | } | ||
492 | |||
493 | int acpi_power_transition(struct acpi_device *device, int state) | ||
494 | { | ||
495 | int result; | ||
468 | 496 | ||
469 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | 497 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) |
470 | return -EINVAL; | 498 | return -EINVAL; |
471 | 499 | ||
500 | if (device->power.state == state) | ||
501 | return 0; | ||
502 | |||
472 | if ((device->power.state < ACPI_STATE_D0) | 503 | if ((device->power.state < ACPI_STATE_D0) |
473 | || (device->power.state > ACPI_STATE_D3)) | 504 | || (device->power.state > ACPI_STATE_D3)) |
474 | return -ENODEV; | 505 | return -ENODEV; |
475 | 506 | ||
476 | cl = &device->power.states[device->power.state].resources; | ||
477 | tl = &device->power.states[state].resources; | ||
478 | |||
479 | /* TBD: Resources must be ordered. */ | 507 | /* TBD: Resources must be ordered. */ |
480 | 508 | ||
481 | /* | 509 | /* |
482 | * First we reference all power resources required in the target list | 510 | * First we reference all power resources required in the target list |
483 | * (e.g. so the device doesn't lose power while transitioning). | 511 | * (e.g. so the device doesn't lose power while transitioning). Then, |
512 | * we dereference all power resources used in the current list. | ||
484 | */ | 513 | */ |
485 | for (i = 0; i < tl->count; i++) { | 514 | result = acpi_power_on_list(&device->power.states[state].resources); |
486 | result = acpi_power_on(tl->handles[i]); | 515 | if (!result) |
487 | if (result) | 516 | acpi_power_off_list( |
488 | goto end; | 517 | &device->power.states[device->power.state].resources); |
489 | } | ||
490 | |||
491 | if (device->power.state == state) { | ||
492 | goto end; | ||
493 | } | ||
494 | |||
495 | /* | ||
496 | * Then we dereference all power resources used in the current list. | ||
497 | */ | ||
498 | for (i = 0; i < cl->count; i++) { | ||
499 | result = acpi_power_off_device(cl->handles[i]); | ||
500 | if (result) | ||
501 | goto end; | ||
502 | } | ||
503 | 518 | ||
504 | end: | 519 | /* We shouldn't change the state unless the above operations succeed. */ |
505 | if (result) | 520 | device->power.state = result ? ACPI_STATE_UNKNOWN : state; |
506 | device->power.state = ACPI_STATE_UNKNOWN; | ||
507 | else { | ||
508 | /* We shouldn't change the state till all above operations succeed */ | ||
509 | device->power.state = state; | ||
510 | } | ||
511 | 521 | ||
512 | return result; | 522 | return result; |
513 | } | 523 | } |