提交 34bdb1a4 编写于 作者: R Rafael J. Wysocki

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()
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) ...@@ -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 * Get the device's power state from power resources settings and _PSC,
* indirectly (via power resources). * if available.
*/ */
if (device->power.flags.power_resources) {
int error = acpi_power_get_inferred_state(device, &result);
if (error)
return error;
}
if (device->power.flags.explicit_get) { if (device->power.flags.explicit_get) {
acpi_handle handle = device->handle;
unsigned long long psc; unsigned long long psc;
acpi_status status = acpi_evaluate_integer(device->handle, acpi_status status;
"_PSC", NULL, &psc);
status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
result = psc; /*
} * The power resources settings may indicate a power state
/* The test below covers ACPI_STATE_UNKNOWN too. */ * shallower than the actual power state of the device.
if (result <= ACPI_STATE_D2) { *
; /* Do nothing. */ * Moreover, on systems predating ACPI 4.0, if the device
} else if (device->power.flags.power_resources) { * doesn't depend on any power resources and _PSC returns 3,
int error = acpi_power_get_inferred_state(device, &result); * that means "power off". We need to maintain compatibility
if (error) * with those systems.
return error; */
} else if (result == ACPI_STATE_D3_HOT) { if (psc > result && psc < ACPI_STATE_D3_COLD)
result = ACPI_STATE_D3; 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[] = { ...@@ -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; struct acpi_power_resource_entry *entry;
if (list_empty(&ps->resources)) if (list_empty(resources))
return; 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; struct acpi_device *res_dev = &entry->resource->device;
sysfs_remove_link_from_group(&adev->dev.kobj, sysfs_remove_link_from_group(&adev->dev.kobj,
attr_groups[state].name, attr_group->name,
dev_name(&res_dev->dev)); 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; struct acpi_power_resource_entry *entry;
int ret; int ret;
if (list_empty(&ps->resources)) if (list_empty(resources))
return; return;
ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]); ret = sysfs_create_group(&adev->dev.kobj, attr_group);
if (ret) if (ret)
return; return;
list_for_each_entry(entry, &ps->resources, node) { list_for_each_entry(entry, resources, node) {
struct acpi_device *res_dev = &entry->resource->device; struct acpi_device *res_dev = &entry->resource->device;
ret = sysfs_add_link_to_group(&adev->dev.kobj, ret = sysfs_add_link_to_group(&adev->dev.kobj,
attr_groups[state].name, attr_group->name,
&res_dev->dev.kobj, &res_dev->dev.kobj,
dev_name(&res_dev->dev)); dev_name(&res_dev->dev));
if (ret) { if (ret) {
acpi_power_hide_list(adev, state); acpi_power_hide_list(adev, resources, attr_group);
break; 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) void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
{ {
struct acpi_device_power_state *ps; struct acpi_device_power_state *ps;
struct acpi_power_resource_entry *entry; struct acpi_power_resource_entry *entry;
int state; 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) if (!adev->power.flags.power_resources)
return; return;
...@@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add) ...@@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
acpi_power_remove_dependent(resource, adev); acpi_power_remove_dependent(resource, adev);
} }
for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) { for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
if (add) acpi_power_expose_hide(adev,
acpi_power_expose_list(adev, state); &adev->power.states[state].resources,
else &attr_groups[state], add);
acpi_power_hide_list(adev, state);
}
} }
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p) int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册