diff options
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r-- | drivers/acpi/power.c | 90 |
1 files changed, 50 insertions, 40 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 4c9c2fb5d98f..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); |
@@ -266,6 +263,35 @@ static int acpi_power_off_device(acpi_handle handle) | |||
266 | return result; | 263 | return result; |
267 | } | 264 | } |
268 | 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 | |||
269 | /** | 295 | /** |
270 | * 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 |
271 | * ACPI 3.0) _PSW (Power State Wake) | 297 | * ACPI 3.0) _PSW (Power State Wake) |
@@ -423,19 +449,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
423 | Device Power Management | 449 | Device Power Management |
424 | -------------------------------------------------------------------------- */ | 450 | -------------------------------------------------------------------------- */ |
425 | 451 | ||
426 | int acpi_power_get_inferred_state(struct acpi_device *device) | 452 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state) |
427 | { | 453 | { |
428 | int result = 0; | 454 | int result = 0; |
429 | struct acpi_handle_list *list = NULL; | 455 | struct acpi_handle_list *list = NULL; |
430 | int list_state = 0; | 456 | int list_state = 0; |
431 | int i = 0; | 457 | int i = 0; |
432 | 458 | ||
433 | 459 | if (!device || !state) | |
434 | if (!device) | ||
435 | return -EINVAL; | 460 | return -EINVAL; |
436 | 461 | ||
437 | device->power.state = ACPI_STATE_UNKNOWN; | ||
438 | |||
439 | /* | 462 | /* |
440 | * 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 |
441 | * required for a given D-state are 'on'. | 464 | * required for a given D-state are 'on'. |
@@ -450,22 +473,26 @@ int acpi_power_get_inferred_state(struct acpi_device *device) | |||
450 | return result; | 473 | return result; |
451 | 474 | ||
452 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { | 475 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { |
453 | device->power.state = i; | 476 | *state = i; |
454 | return 0; | 477 | return 0; |
455 | } | 478 | } |
456 | } | 479 | } |
457 | 480 | ||
458 | device->power.state = ACPI_STATE_D3; | 481 | *state = ACPI_STATE_D3; |
459 | |||
460 | return 0; | 482 | return 0; |
461 | } | 483 | } |
462 | 484 | ||
485 | int acpi_power_on_resources(struct acpi_device *device, int state) | ||
486 | { | ||
487 | if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) | ||
488 | return -EINVAL; | ||
489 | |||
490 | return acpi_power_on_list(&device->power.states[state].resources); | ||
491 | } | ||
492 | |||
463 | int acpi_power_transition(struct acpi_device *device, int state) | 493 | int acpi_power_transition(struct acpi_device *device, int state) |
464 | { | 494 | { |
465 | int result = 0; | 495 | int result; |
466 | struct acpi_handle_list *cl = NULL; /* Current Resources */ | ||
467 | struct acpi_handle_list *tl = NULL; /* Target Resources */ | ||
468 | int i = 0; | ||
469 | 496 | ||
470 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | 497 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) |
471 | return -EINVAL; | 498 | return -EINVAL; |
@@ -477,37 +504,20 @@ int acpi_power_transition(struct acpi_device *device, int state) | |||
477 | || (device->power.state > ACPI_STATE_D3)) | 504 | || (device->power.state > ACPI_STATE_D3)) |
478 | return -ENODEV; | 505 | return -ENODEV; |
479 | 506 | ||
480 | cl = &device->power.states[device->power.state].resources; | ||
481 | tl = &device->power.states[state].resources; | ||
482 | |||
483 | /* TBD: Resources must be ordered. */ | 507 | /* TBD: Resources must be ordered. */ |
484 | 508 | ||
485 | /* | 509 | /* |
486 | * First we reference all power resources required in the target list | 510 | * First we reference all power resources required in the target list |
487 | * (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. | ||
488 | */ | 513 | */ |
489 | for (i = 0; i < tl->count; i++) { | 514 | result = acpi_power_on_list(&device->power.states[state].resources); |
490 | result = acpi_power_on(tl->handles[i]); | 515 | if (!result) |
491 | if (result) | 516 | acpi_power_off_list( |
492 | goto end; | 517 | &device->power.states[device->power.state].resources); |
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 | } |