aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r--drivers/acpi/power.c90
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
59int acpi_power_nocheck;
60module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
61
62static int acpi_power_add(struct acpi_device *device); 59static int acpi_power_add(struct acpi_device *device);
63static int acpi_power_remove(struct acpi_device *device, int type); 60static int acpi_power_remove(struct acpi_device *device, int type);
64static int acpi_power_resume(struct acpi_device *device); 61static 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
266static 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
274static void acpi_power_off_list(struct acpi_handle_list *list)
275{
276 __acpi_power_off_list(list, list->count);
277}
278
279static 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
426int acpi_power_get_inferred_state(struct acpi_device *device) 452int 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
485int 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
463int acpi_power_transition(struct acpi_device *device, int state) 493int 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}