diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_wakeup | 13 | ||||
-rw-r--r-- | drivers/acpi/power.c | 58 |
2 files changed, 52 insertions, 19 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup b/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup new file mode 100644 index 000000000000..e0588feeb6e1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup | |||
@@ -0,0 +1,13 @@ | |||
1 | What: /sys/devices/.../power_resources_wakeup/ | ||
2 | Date: April 2013 | ||
3 | Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
4 | Description: | ||
5 | The /sys/devices/.../power_resources_wakeup/ directory is only | ||
6 | present for device objects representing ACPI device nodes that | ||
7 | require ACPI power resources for wakeup signaling. | ||
8 | |||
9 | If present, it contains symbolic links to device directories | ||
10 | representing ACPI power resources that need to be turned on for | ||
11 | the given device node to be able to signal wakeup. The names of | ||
12 | the links are the same as the names of the directories they | ||
13 | point to. | ||
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 34f5ef11d427..0e3f57674fd1 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -459,57 +459,79 @@ static struct attribute_group attr_groups[] = { | |||
459 | }, | 459 | }, |
460 | }; | 460 | }; |
461 | 461 | ||
462 | static void acpi_power_hide_list(struct acpi_device *adev, int state) | 462 | static struct attribute_group wakeup_attr_group = { |
463 | .name = "power_resources_wakeup", | ||
464 | .attrs = attrs, | ||
465 | }; | ||
466 | |||
467 | static void acpi_power_hide_list(struct acpi_device *adev, | ||
468 | struct list_head *resources, | ||
469 | struct attribute_group *attr_group) | ||
463 | { | 470 | { |
464 | struct acpi_device_power_state *ps = &adev->power.states[state]; | ||
465 | struct acpi_power_resource_entry *entry; | 471 | struct acpi_power_resource_entry *entry; |
466 | 472 | ||
467 | if (list_empty(&ps->resources)) | 473 | if (list_empty(resources)) |
468 | return; | 474 | return; |
469 | 475 | ||
470 | list_for_each_entry_reverse(entry, &ps->resources, node) { | 476 | list_for_each_entry_reverse(entry, resources, node) { |
471 | struct acpi_device *res_dev = &entry->resource->device; | 477 | struct acpi_device *res_dev = &entry->resource->device; |
472 | 478 | ||
473 | sysfs_remove_link_from_group(&adev->dev.kobj, | 479 | sysfs_remove_link_from_group(&adev->dev.kobj, |
474 | attr_groups[state].name, | 480 | attr_group->name, |
475 | dev_name(&res_dev->dev)); | 481 | dev_name(&res_dev->dev)); |
476 | } | 482 | } |
477 | sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]); | 483 | sysfs_remove_group(&adev->dev.kobj, attr_group); |
478 | } | 484 | } |
479 | 485 | ||
480 | static void acpi_power_expose_list(struct acpi_device *adev, int state) | 486 | static void acpi_power_expose_list(struct acpi_device *adev, |
487 | struct list_head *resources, | ||
488 | struct attribute_group *attr_group) | ||
481 | { | 489 | { |
482 | struct acpi_device_power_state *ps = &adev->power.states[state]; | ||
483 | struct acpi_power_resource_entry *entry; | 490 | struct acpi_power_resource_entry *entry; |
484 | int ret; | 491 | int ret; |
485 | 492 | ||
486 | if (list_empty(&ps->resources)) | 493 | if (list_empty(resources)) |
487 | return; | 494 | return; |
488 | 495 | ||
489 | ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]); | 496 | ret = sysfs_create_group(&adev->dev.kobj, attr_group); |
490 | if (ret) | 497 | if (ret) |
491 | return; | 498 | return; |
492 | 499 | ||
493 | list_for_each_entry(entry, &ps->resources, node) { | 500 | list_for_each_entry(entry, resources, node) { |
494 | struct acpi_device *res_dev = &entry->resource->device; | 501 | struct acpi_device *res_dev = &entry->resource->device; |
495 | 502 | ||
496 | ret = sysfs_add_link_to_group(&adev->dev.kobj, | 503 | ret = sysfs_add_link_to_group(&adev->dev.kobj, |
497 | attr_groups[state].name, | 504 | attr_group->name, |
498 | &res_dev->dev.kobj, | 505 | &res_dev->dev.kobj, |
499 | dev_name(&res_dev->dev)); | 506 | dev_name(&res_dev->dev)); |
500 | if (ret) { | 507 | if (ret) { |
501 | acpi_power_hide_list(adev, state); | 508 | acpi_power_hide_list(adev, resources, attr_group); |
502 | break; | 509 | break; |
503 | } | 510 | } |
504 | } | 511 | } |
505 | } | 512 | } |
506 | 513 | ||
514 | static void acpi_power_expose_hide(struct acpi_device *adev, | ||
515 | struct list_head *resources, | ||
516 | struct attribute_group *attr_group, | ||
517 | bool expose) | ||
518 | { | ||
519 | if (expose) | ||
520 | acpi_power_expose_list(adev, resources, attr_group); | ||
521 | else | ||
522 | acpi_power_hide_list(adev, resources, attr_group); | ||
523 | } | ||
524 | |||
507 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add) | 525 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add) |
508 | { | 526 | { |
509 | struct acpi_device_power_state *ps; | 527 | struct acpi_device_power_state *ps; |
510 | struct acpi_power_resource_entry *entry; | 528 | struct acpi_power_resource_entry *entry; |
511 | int state; | 529 | int state; |
512 | 530 | ||
531 | if (adev->wakeup.flags.valid) | ||
532 | acpi_power_expose_hide(adev, &adev->wakeup.resources, | ||
533 | &wakeup_attr_group, add); | ||
534 | |||
513 | if (!adev->power.flags.power_resources) | 535 | if (!adev->power.flags.power_resources) |
514 | return; | 536 | return; |
515 | 537 | ||
@@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add) | |||
523 | acpi_power_remove_dependent(resource, adev); | 545 | acpi_power_remove_dependent(resource, adev); |
524 | } | 546 | } |
525 | 547 | ||
526 | for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) { | 548 | for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) |
527 | if (add) | 549 | acpi_power_expose_hide(adev, |
528 | acpi_power_expose_list(adev, state); | 550 | &adev->power.states[state].resources, |
529 | else | 551 | &attr_groups[state], add); |
530 | acpi_power_hide_list(adev, state); | ||
531 | } | ||
532 | } | 552 | } |
533 | 553 | ||
534 | int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) | 554 | int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) |