aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power_resources_wakeup13
-rw-r--r--drivers/acpi/power.c58
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 @@
1What: /sys/devices/.../power_resources_wakeup/
2Date: April 2013
3Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
4Description:
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
462static void acpi_power_hide_list(struct acpi_device *adev, int state) 462static struct attribute_group wakeup_attr_group = {
463 .name = "power_resources_wakeup",
464 .attrs = attrs,
465};
466
467static 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
480static void acpi_power_expose_list(struct acpi_device *adev, int state) 486static 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
514static 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
507void acpi_power_add_remove_device(struct acpi_device *adev, bool add) 525void 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
534int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) 554int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)