diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D0 | 13 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D1 | 14 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D2 | 14 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D3hot | 14 | ||||
-rw-r--r-- | drivers/acpi/power.c | 104 |
5 files changed, 146 insertions, 13 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D0 b/Documentation/ABI/testing/sysfs-devices-power_resources_D0 new file mode 100644 index 00000000000..73b77a6be19 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D0 @@ -0,0 +1,13 @@ +What: /sys/devices/.../power_resources_D0/ +Date: January 2013 +Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> +Description: + The /sys/devices/.../power_resources_D0/ directory is only + present for device objects representing ACPI device nodes that + use ACPI power resources for power management. + + If present, it contains symbolic links to device directories + representing ACPI power resources that need to be turned on for + the given device node to be in ACPI power state D0. The names + of the links are the same as the names of the directories they + point to. diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D1 b/Documentation/ABI/testing/sysfs-devices-power_resources_D1 new file mode 100644 index 00000000000..30c20703fb8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D1 @@ -0,0 +1,14 @@ +What: /sys/devices/.../power_resources_D1/ +Date: January 2013 +Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> +Description: + The /sys/devices/.../power_resources_D1/ directory is only + present for device objects representing ACPI device nodes that + use ACPI power resources for power management and support ACPI + power state D1. + + If present, it contains symbolic links to device directories + representing ACPI power resources that need to be turned on for + the given device node to be in ACPI power state D1. The names + of the links are the same as the names of the directories they + point to. diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D2 b/Documentation/ABI/testing/sysfs-devices-power_resources_D2 new file mode 100644 index 00000000000..fd9d84b421e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D2 @@ -0,0 +1,14 @@ +What: /sys/devices/.../power_resources_D2/ +Date: January 2013 +Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> +Description: + The /sys/devices/.../power_resources_D2/ directory is only + present for device objects representing ACPI device nodes that + use ACPI power resources for power management and support ACPI + power state D2. + + If present, it contains symbolic links to device directories + representing ACPI power resources that need to be turned on for + the given device node to be in ACPI power state D2. The names + of the links are the same as the names of the directories they + point to. diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot b/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot new file mode 100644 index 00000000000..3df32c20add --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot @@ -0,0 +1,14 @@ +What: /sys/devices/.../power_resources_D3hot/ +Date: January 2013 +Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> +Description: + The /sys/devices/.../power_resources_D3hot/ directory is only + present for device objects representing ACPI device nodes that + use ACPI power resources for power management and support ACPI + power state D3hot. + + If present, it contains symbolic links to device directories + representing ACPI power resources that need to be turned on for + the given device node to be in ACPI power state D3hot. The + names of the links are the same as the names of the directories + they point to. diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 946720a4db5..9466f56b938 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -41,6 +41,7 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/sysfs.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> #include "sleep.h" @@ -417,24 +418,101 @@ static void acpi_power_remove_dependent(struct acpi_power_resource *resource, } } -void acpi_power_add_remove_device(struct acpi_device *adev, bool add) +static struct attribute *attrs[] = { + NULL, +}; + +static struct attribute_group attr_groups[] = { + [ACPI_STATE_D0] = { + .name = "power_resources_D0", + .attrs = attrs, + }, + [ACPI_STATE_D1] = { + .name = "power_resources_D1", + .attrs = attrs, + }, + [ACPI_STATE_D2] = { + .name = "power_resources_D2", + .attrs = attrs, + }, + [ACPI_STATE_D3_HOT] = { + .name = "power_resources_D3hot", + .attrs = attrs, + }, +}; + +static void acpi_power_hide_list(struct acpi_device *adev, int state) +{ + struct acpi_device_power_state *ps = &adev->power.states[state]; + struct acpi_power_resource_entry *entry; + + if (list_empty(&ps->resources)) + return; + + list_for_each_entry_reverse(entry, &ps->resources, node) { + struct acpi_device *res_dev = &entry->resource->device; + + sysfs_remove_link_from_group(&adev->dev.kobj, + attr_groups[state].name, + dev_name(&res_dev->dev)); + } + sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]); +} + +static void acpi_power_expose_list(struct acpi_device *adev, int state) { - if (adev->power.flags.power_resources) { - struct acpi_device_power_state *ps; - struct acpi_power_resource_entry *entry; - - ps = &adev->power.states[ACPI_STATE_D0]; - list_for_each_entry(entry, &ps->resources, node) { - struct acpi_power_resource *resource = entry->resource; - - if (add) - acpi_power_add_dependent(resource, adev); - else - acpi_power_remove_dependent(resource, adev); + struct acpi_device_power_state *ps = &adev->power.states[state]; + struct acpi_power_resource_entry *entry; + int ret; + + if (list_empty(&ps->resources)) + return; + + ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]); + if (ret) + return; + + list_for_each_entry(entry, &ps->resources, node) { + struct acpi_device *res_dev = &entry->resource->device; + + ret = sysfs_add_link_to_group(&adev->dev.kobj, + attr_groups[state].name, + &res_dev->dev.kobj, + dev_name(&res_dev->dev)); + if (ret) { + acpi_power_hide_list(adev, state); + break; } } } +void acpi_power_add_remove_device(struct acpi_device *adev, bool add) +{ + struct acpi_device_power_state *ps; + struct acpi_power_resource_entry *entry; + int state; + + if (!adev->power.flags.power_resources) + return; + + ps = &adev->power.states[ACPI_STATE_D0]; + list_for_each_entry(entry, &ps->resources, node) { + struct acpi_power_resource *resource = entry->resource; + + if (add) + acpi_power_add_dependent(resource, adev); + else + acpi_power_remove_dependent(resource, adev); + } + + for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) { + if (add) + acpi_power_expose_list(adev, state); + else + acpi_power_hide_list(adev, state); + } +} + int acpi_power_min_system_level(struct list_head *list) { struct acpi_power_resource_entry *entry; |