Merge branch 'acpi-pm'
* acpi-pm: ACPI / PM: Expose lists of device wakeup power resources to user space ACPI / PM: Fix potential problem in acpi_device_get_power()
This commit is contained in:
commit
34bdb1a458
@ -0,0 +1,13 @@
|
||||
What: /sys/devices/.../power_resources_wakeup/
|
||||
Date: April 2013
|
||||
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
Description:
|
||||
The /sys/devices/.../power_resources_wakeup/ directory is only
|
||||
present for device objects representing ACPI device nodes that
|
||||
require ACPI power resources for wakeup signaling.
|
||||
|
||||
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 able to signal wakeup. The names of
|
||||
the links are the same as the names of the directories they
|
||||
point to.
|
@ -145,27 +145,36 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the device's power state either directly (via _PSC) or
|
||||
* indirectly (via power resources).
|
||||
* Get the device's power state from power resources settings and _PSC,
|
||||
* if available.
|
||||
*/
|
||||
if (device->power.flags.explicit_get) {
|
||||
unsigned long long psc;
|
||||
acpi_status status = acpi_evaluate_integer(device->handle,
|
||||
"_PSC", NULL, &psc);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
result = psc;
|
||||
}
|
||||
/* The test below covers ACPI_STATE_UNKNOWN too. */
|
||||
if (result <= ACPI_STATE_D2) {
|
||||
; /* Do nothing. */
|
||||
} else if (device->power.flags.power_resources) {
|
||||
if (device->power.flags.power_resources) {
|
||||
int error = acpi_power_get_inferred_state(device, &result);
|
||||
if (error)
|
||||
return error;
|
||||
} else if (result == ACPI_STATE_D3_HOT) {
|
||||
result = ACPI_STATE_D3;
|
||||
}
|
||||
if (device->power.flags.explicit_get) {
|
||||
acpi_handle handle = device->handle;
|
||||
unsigned long long psc;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* The power resources settings may indicate a power state
|
||||
* shallower than the actual power state of the device.
|
||||
*
|
||||
* Moreover, on systems predating ACPI 4.0, if the device
|
||||
* doesn't depend on any power resources and _PSC returns 3,
|
||||
* that means "power off". We need to maintain compatibility
|
||||
* with those systems.
|
||||
*/
|
||||
if (psc > result && psc < ACPI_STATE_D3_COLD)
|
||||
result = psc;
|
||||
else if (result == ACPI_STATE_UNKNOWN)
|
||||
result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -459,57 +459,79 @@ static struct attribute_group attr_groups[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static void acpi_power_hide_list(struct acpi_device *adev, int state)
|
||||
static struct attribute_group wakeup_attr_group = {
|
||||
.name = "power_resources_wakeup",
|
||||
.attrs = attrs,
|
||||
};
|
||||
|
||||
static void acpi_power_hide_list(struct acpi_device *adev,
|
||||
struct list_head *resources,
|
||||
struct attribute_group *attr_group)
|
||||
{
|
||||
struct acpi_device_power_state *ps = &adev->power.states[state];
|
||||
struct acpi_power_resource_entry *entry;
|
||||
|
||||
if (list_empty(&ps->resources))
|
||||
if (list_empty(resources))
|
||||
return;
|
||||
|
||||
list_for_each_entry_reverse(entry, &ps->resources, node) {
|
||||
list_for_each_entry_reverse(entry, resources, node) {
|
||||
struct acpi_device *res_dev = &entry->resource->device;
|
||||
|
||||
sysfs_remove_link_from_group(&adev->dev.kobj,
|
||||
attr_groups[state].name,
|
||||
attr_group->name,
|
||||
dev_name(&res_dev->dev));
|
||||
}
|
||||
sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
|
||||
sysfs_remove_group(&adev->dev.kobj, attr_group);
|
||||
}
|
||||
|
||||
static void acpi_power_expose_list(struct acpi_device *adev, int state)
|
||||
static void acpi_power_expose_list(struct acpi_device *adev,
|
||||
struct list_head *resources,
|
||||
struct attribute_group *attr_group)
|
||||
{
|
||||
struct acpi_device_power_state *ps = &adev->power.states[state];
|
||||
struct acpi_power_resource_entry *entry;
|
||||
int ret;
|
||||
|
||||
if (list_empty(&ps->resources))
|
||||
if (list_empty(resources))
|
||||
return;
|
||||
|
||||
ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
|
||||
ret = sysfs_create_group(&adev->dev.kobj, attr_group);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
list_for_each_entry(entry, &ps->resources, node) {
|
||||
list_for_each_entry(entry, resources, node) {
|
||||
struct acpi_device *res_dev = &entry->resource->device;
|
||||
|
||||
ret = sysfs_add_link_to_group(&adev->dev.kobj,
|
||||
attr_groups[state].name,
|
||||
attr_group->name,
|
||||
&res_dev->dev.kobj,
|
||||
dev_name(&res_dev->dev));
|
||||
if (ret) {
|
||||
acpi_power_hide_list(adev, state);
|
||||
acpi_power_hide_list(adev, resources, attr_group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_power_expose_hide(struct acpi_device *adev,
|
||||
struct list_head *resources,
|
||||
struct attribute_group *attr_group,
|
||||
bool expose)
|
||||
{
|
||||
if (expose)
|
||||
acpi_power_expose_list(adev, resources, attr_group);
|
||||
else
|
||||
acpi_power_hide_list(adev, resources, attr_group);
|
||||
}
|
||||
|
||||
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->wakeup.flags.valid)
|
||||
acpi_power_expose_hide(adev, &adev->wakeup.resources,
|
||||
&wakeup_attr_group, add);
|
||||
|
||||
if (!adev->power.flags.power_resources)
|
||||
return;
|
||||
|
||||
@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
|
||||
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);
|
||||
}
|
||||
for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
|
||||
acpi_power_expose_hide(adev,
|
||||
&adev->power.states[state].resources,
|
||||
&attr_groups[state], add);
|
||||
}
|
||||
|
||||
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
|
||||
|
Loading…
Reference in New Issue
Block a user