Merge branch 'acpi-pm'
* acpi-pm: (35 commits) ACPI / PM: Handle missing _PSC in acpi_bus_update_power() ACPI / PM: Do not power manage devices in unknown initial states ACPI / PM: Fix acpi_bus_get_device() check in drivers/acpi/device_pm.c ACPI / PM: Fix /proc/acpi/wakeup for devices w/o bus or parent ACPI / PM: Fix consistency check for power resources during resume ACPI / PM: Expose lists of device power resources to user space sysfs: Functions for adding/removing symlinks to/from attribute groups ACPI / PM: Expose current status of ACPI power resources ACPI / PM: Expose power states of ACPI devices to user space ACPI / scan: Prevent device add uevents from racing with user space ACPI / PM: Fix device power state value after transitions to D3cold ACPI / PM: Use string "D3cold" to represent ACPI_STATE_D3_COLD ACPI / PM: Sanitize checks in acpi_power_on_resources() ACPI / PM: Always evaluate _PSn after setting power resources ACPI / PM: Introduce helper for executing _PSn methods ACPI / PM: Make acpi_bus_init_power() more robust ACPI / PM: Fix build for unusual combination of Kconfig options ACPI / PM: remove leading whitespace from #ifdef ACPI / PM: Consolidate suspend-specific and hibernate-specific code ACPI / PM: Move device power management functions to device_pm.c ...
This commit is contained in:
@@ -174,6 +174,32 @@ err_out:
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
|
||||
|
||||
static ssize_t real_power_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
int state;
|
||||
int ret;
|
||||
|
||||
ret = acpi_device_get_power(adev, &state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%s\n", acpi_power_state_string(state));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
|
||||
|
||||
static ssize_t power_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
|
||||
|
||||
static ssize_t
|
||||
acpi_eject_store(struct device *d, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@@ -365,8 +391,22 @@ static int acpi_device_setup_files(struct acpi_device *dev)
|
||||
* hot-removal function from userland.
|
||||
*/
|
||||
status = acpi_get_handle(dev->handle, "_EJ0", &temp);
|
||||
if (ACPI_SUCCESS(status))
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
result = device_create_file(&dev->dev, &dev_attr_eject);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dev->flags.power_manageable) {
|
||||
result = device_create_file(&dev->dev, &dev_attr_power_state);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (dev->power.flags.power_resources)
|
||||
result = device_create_file(&dev->dev,
|
||||
&dev_attr_real_power_state);
|
||||
}
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
@@ -376,6 +416,13 @@ static void acpi_device_remove_files(struct acpi_device *dev)
|
||||
acpi_status status;
|
||||
acpi_handle temp;
|
||||
|
||||
if (dev->flags.power_manageable) {
|
||||
device_remove_file(&dev->dev, &dev_attr_power_state);
|
||||
if (dev->power.flags.power_resources)
|
||||
device_remove_file(&dev->dev,
|
||||
&dev_attr_real_power_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* If device has _STR, remove 'description' file
|
||||
*/
|
||||
@@ -460,7 +507,7 @@ int acpi_match_device_ids(struct acpi_device *device,
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_match_device_ids);
|
||||
|
||||
static void acpi_free_ids(struct acpi_device *device)
|
||||
void acpi_free_ids(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_hardware_id *id, *tmp;
|
||||
|
||||
@@ -468,6 +515,23 @@ static void acpi_free_ids(struct acpi_device *device)
|
||||
kfree(id->id);
|
||||
kfree(id);
|
||||
}
|
||||
kfree(device->pnp.unique_id);
|
||||
}
|
||||
|
||||
static void acpi_free_power_resources_lists(struct acpi_device *device)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (device->wakeup.flags.valid)
|
||||
acpi_power_resources_list_free(&device->wakeup.resources);
|
||||
|
||||
if (!device->flags.power_manageable)
|
||||
return;
|
||||
|
||||
for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
|
||||
struct acpi_device_power_state *ps = &device->power.states[i];
|
||||
acpi_power_resources_list_free(&ps->resources);
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_device_release(struct device *dev)
|
||||
@@ -475,7 +539,7 @@ static void acpi_device_release(struct device *dev)
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
|
||||
acpi_free_ids(acpi_dev);
|
||||
kfree(acpi_dev->pnp.unique_id);
|
||||
acpi_free_power_resources_lists(acpi_dev);
|
||||
kfree(acpi_dev);
|
||||
}
|
||||
|
||||
@@ -613,12 +677,25 @@ struct bus_type acpi_bus_type = {
|
||||
.uevent = acpi_device_uevent,
|
||||
};
|
||||
|
||||
static int acpi_device_register(struct acpi_device *device)
|
||||
int acpi_device_add(struct acpi_device *device,
|
||||
void (*release)(struct device *))
|
||||
{
|
||||
int result;
|
||||
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
|
||||
int found = 0;
|
||||
|
||||
if (device->handle) {
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_attach_data(device->handle, acpi_bus_data_handler,
|
||||
device);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_err(device->handle,
|
||||
"Unable to attach device data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Linkage
|
||||
* -------
|
||||
@@ -629,11 +706,13 @@ static int acpi_device_register(struct acpi_device *device)
|
||||
INIT_LIST_HEAD(&device->wakeup_list);
|
||||
INIT_LIST_HEAD(&device->physical_node_list);
|
||||
mutex_init(&device->physical_node_lock);
|
||||
INIT_LIST_HEAD(&device->power_dependent);
|
||||
|
||||
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
|
||||
if (!new_bus_id) {
|
||||
printk(KERN_ERR PREFIX "Memory allocation error\n");
|
||||
return -ENOMEM;
|
||||
pr_err(PREFIX "Memory allocation error\n");
|
||||
result = -ENOMEM;
|
||||
goto err_detach;
|
||||
}
|
||||
|
||||
mutex_lock(&acpi_device_lock);
|
||||
@@ -668,11 +747,11 @@ static int acpi_device_register(struct acpi_device *device)
|
||||
if (device->parent)
|
||||
device->dev.parent = &device->parent->dev;
|
||||
device->dev.bus = &acpi_bus_type;
|
||||
device->dev.release = &acpi_device_release;
|
||||
result = device_register(&device->dev);
|
||||
device->dev.release = release;
|
||||
result = device_add(&device->dev);
|
||||
if (result) {
|
||||
dev_err(&device->dev, "Error registering device\n");
|
||||
goto end;
|
||||
goto err;
|
||||
}
|
||||
|
||||
result = acpi_device_setup_files(device);
|
||||
@@ -682,12 +761,16 @@ static int acpi_device_register(struct acpi_device *device)
|
||||
|
||||
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
|
||||
return 0;
|
||||
end:
|
||||
|
||||
err:
|
||||
mutex_lock(&acpi_device_lock);
|
||||
if (device->parent)
|
||||
list_del(&device->node);
|
||||
list_del(&device->wakeup_list);
|
||||
mutex_unlock(&acpi_device_lock);
|
||||
|
||||
err_detach:
|
||||
acpi_detach_data(device->handle, acpi_bus_data_handler);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -702,8 +785,18 @@ static void acpi_device_unregister(struct acpi_device *device)
|
||||
|
||||
acpi_detach_data(device->handle, acpi_bus_data_handler);
|
||||
|
||||
acpi_power_add_remove_device(device, false);
|
||||
acpi_device_remove_files(device);
|
||||
device_unregister(&device->dev);
|
||||
if (device->remove)
|
||||
device->remove(device);
|
||||
|
||||
device_del(&device->dev);
|
||||
/*
|
||||
* Drop the reference counts of all power resources the device depends
|
||||
* on and turn off the ones that have no more references.
|
||||
*/
|
||||
acpi_power_transition(device, ACPI_STATE_D3_COLD);
|
||||
put_device(&device->dev);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
@@ -846,52 +939,43 @@ void acpi_bus_data_handler(acpi_handle handle, void *context)
|
||||
return;
|
||||
}
|
||||
|
||||
static int acpi_bus_get_perf_flags(struct acpi_device *device)
|
||||
{
|
||||
device->performance.state = ACPI_STATE_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
|
||||
struct acpi_device_wakeup *wakeup)
|
||||
static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
|
||||
struct acpi_device_wakeup *wakeup)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *package = NULL;
|
||||
union acpi_object *element = NULL;
|
||||
acpi_status status;
|
||||
int i = 0;
|
||||
int err = -ENODATA;
|
||||
|
||||
if (!wakeup)
|
||||
return AE_BAD_PARAMETER;
|
||||
return -EINVAL;
|
||||
|
||||
INIT_LIST_HEAD(&wakeup->resources);
|
||||
|
||||
/* _PRW */
|
||||
status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
|
||||
return status;
|
||||
return err;
|
||||
}
|
||||
|
||||
package = (union acpi_object *)buffer.pointer;
|
||||
|
||||
if (!package || (package->package.count < 2)) {
|
||||
status = AE_BAD_DATA;
|
||||
if (!package || package->package.count < 2)
|
||||
goto out;
|
||||
}
|
||||
|
||||
element = &(package->package.elements[0]);
|
||||
if (!element) {
|
||||
status = AE_BAD_DATA;
|
||||
if (!element)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (element->type == ACPI_TYPE_PACKAGE) {
|
||||
if ((element->package.count < 2) ||
|
||||
(element->package.elements[0].type !=
|
||||
ACPI_TYPE_LOCAL_REFERENCE)
|
||||
|| (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
|
||||
status = AE_BAD_DATA;
|
||||
|| (element->package.elements[1].type != ACPI_TYPE_INTEGER))
|
||||
goto out;
|
||||
}
|
||||
|
||||
wakeup->gpe_device =
|
||||
element->package.elements[0].reference.handle;
|
||||
wakeup->gpe_number =
|
||||
@@ -900,38 +984,35 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
|
||||
wakeup->gpe_device = NULL;
|
||||
wakeup->gpe_number = element->integer.value;
|
||||
} else {
|
||||
status = AE_BAD_DATA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
element = &(package->package.elements[1]);
|
||||
if (element->type != ACPI_TYPE_INTEGER) {
|
||||
status = AE_BAD_DATA;
|
||||
if (element->type != ACPI_TYPE_INTEGER)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wakeup->sleep_state = element->integer.value;
|
||||
|
||||
if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
|
||||
status = AE_NO_MEMORY;
|
||||
err = acpi_extract_power_resources(package, 2, &wakeup->resources);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
wakeup->resources.count = package->package.count - 2;
|
||||
for (i = 0; i < wakeup->resources.count; i++) {
|
||||
element = &(package->package.elements[i + 2]);
|
||||
if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
status = AE_BAD_DATA;
|
||||
goto out;
|
||||
|
||||
if (!list_empty(&wakeup->resources)) {
|
||||
int sleep_state;
|
||||
|
||||
sleep_state = acpi_power_min_system_level(&wakeup->resources);
|
||||
if (sleep_state < wakeup->sleep_state) {
|
||||
acpi_handle_warn(handle, "Overriding _PRW sleep state "
|
||||
"(S%d) by S%d from power resources\n",
|
||||
(int)wakeup->sleep_state, sleep_state);
|
||||
wakeup->sleep_state = sleep_state;
|
||||
}
|
||||
|
||||
wakeup->resources.handles[i] = element->reference.handle;
|
||||
}
|
||||
|
||||
acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
|
||||
|
||||
out:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
return status;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
|
||||
@@ -971,17 +1052,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
|
||||
{
|
||||
acpi_handle temp;
|
||||
acpi_status status = 0;
|
||||
int psw_error;
|
||||
int err;
|
||||
|
||||
/* Presence of _PRW indicates wake capable */
|
||||
status = acpi_get_handle(device->handle, "_PRW", &temp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
status = acpi_bus_extract_wakeup_device_power_package(device->handle,
|
||||
&device->wakeup);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
|
||||
err = acpi_bus_extract_wakeup_device_power_package(device->handle,
|
||||
&device->wakeup);
|
||||
if (err) {
|
||||
dev_err(&device->dev, "_PRW evaluation error: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -994,20 +1075,73 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
|
||||
* So it is necessary to call _DSW object first. Only when it is not
|
||||
* present will the _PSW object used.
|
||||
*/
|
||||
psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
|
||||
if (psw_error)
|
||||
err = acpi_device_sleep_wake(device, 0, 0, 0);
|
||||
if (err)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"error in _DSW or _PSW evaluation\n"));
|
||||
}
|
||||
|
||||
static void acpi_bus_add_power_resource(acpi_handle handle);
|
||||
|
||||
static int acpi_bus_get_power_flags(struct acpi_device *device)
|
||||
static void acpi_bus_init_power_state(struct acpi_device *device, int state)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
acpi_handle handle = NULL;
|
||||
u32 i = 0;
|
||||
struct acpi_device_power_state *ps = &device->power.states[state];
|
||||
char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
|
||||
INIT_LIST_HEAD(&ps->resources);
|
||||
|
||||
/* Evaluate "_PRx" to get referenced power resources */
|
||||
status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
union acpi_object *package = buffer.pointer;
|
||||
|
||||
if (buffer.length && package
|
||||
&& package->type == ACPI_TYPE_PACKAGE
|
||||
&& package->package.count) {
|
||||
int err = acpi_extract_power_resources(package, 0,
|
||||
&ps->resources);
|
||||
if (!err)
|
||||
device->power.flags.power_resources = 1;
|
||||
}
|
||||
ACPI_FREE(buffer.pointer);
|
||||
}
|
||||
|
||||
/* Evaluate "_PSx" to see if we can do explicit sets */
|
||||
pathname[2] = 'S';
|
||||
status = acpi_get_handle(device->handle, pathname, &handle);
|
||||
if (ACPI_SUCCESS(status))
|
||||
ps->flags.explicit_set = 1;
|
||||
|
||||
/*
|
||||
* State is valid if there are means to put the device into it.
|
||||
* D3hot is only valid if _PR3 present.
|
||||
*/
|
||||
if (!list_empty(&ps->resources)
|
||||
|| (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) {
|
||||
ps->flags.valid = 1;
|
||||
ps->flags.os_accessible = 1;
|
||||
}
|
||||
|
||||
ps->power = -1; /* Unknown - driver assigned */
|
||||
ps->latency = -1; /* Unknown - driver assigned */
|
||||
}
|
||||
|
||||
static void acpi_bus_get_power_flags(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
u32 i;
|
||||
|
||||
/* Presence of _PS0|_PR0 indicates 'power manageable' */
|
||||
status = acpi_get_handle(device->handle, "_PS0", &handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
status = acpi_get_handle(device->handle, "_PR0", &handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
}
|
||||
|
||||
device->flags.power_manageable = 1;
|
||||
|
||||
/*
|
||||
* Power Management Flags
|
||||
@@ -1022,40 +1156,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
|
||||
/*
|
||||
* Enumerate supported power management states
|
||||
*/
|
||||
for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
|
||||
struct acpi_device_power_state *ps = &device->power.states[i];
|
||||
char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
|
||||
for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++)
|
||||
acpi_bus_init_power_state(device, i);
|
||||
|
||||
/* Evaluate "_PRx" to se if power resources are referenced */
|
||||
acpi_evaluate_reference(device->handle, object_name, NULL,
|
||||
&ps->resources);
|
||||
if (ps->resources.count) {
|
||||
int j;
|
||||
|
||||
device->power.flags.power_resources = 1;
|
||||
for (j = 0; j < ps->resources.count; j++)
|
||||
acpi_bus_add_power_resource(ps->resources.handles[j]);
|
||||
}
|
||||
|
||||
/* Evaluate "_PSx" to see if we can do explicit sets */
|
||||
object_name[2] = 'S';
|
||||
status = acpi_get_handle(device->handle, object_name, &handle);
|
||||
if (ACPI_SUCCESS(status))
|
||||
ps->flags.explicit_set = 1;
|
||||
|
||||
/*
|
||||
* State is valid if there are means to put the device into it.
|
||||
* D3hot is only valid if _PR3 present.
|
||||
*/
|
||||
if (ps->resources.count ||
|
||||
(ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) {
|
||||
ps->flags.valid = 1;
|
||||
ps->flags.os_accessible = 1;
|
||||
}
|
||||
|
||||
ps->power = -1; /* Unknown - driver assigned */
|
||||
ps->latency = -1; /* Unknown - driver assigned */
|
||||
}
|
||||
INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
|
||||
|
||||
/* Set defaults for D0 and D3 states (always valid) */
|
||||
device->power.states[ACPI_STATE_D0].flags.valid = 1;
|
||||
@@ -1072,17 +1176,17 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
|
||||
device->power.flags.power_resources)
|
||||
device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
|
||||
|
||||
acpi_bus_init_power(device);
|
||||
|
||||
return 0;
|
||||
if (acpi_bus_init_power(device)) {
|
||||
acpi_free_power_resources_lists(device);
|
||||
device->flags.power_manageable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_bus_get_flags(struct acpi_device *device)
|
||||
static void acpi_bus_get_flags(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
acpi_handle temp = NULL;
|
||||
|
||||
|
||||
/* Presence of _STA indicates 'dynamic_status' */
|
||||
status = acpi_get_handle(device->handle, "_STA", &temp);
|
||||
if (ACPI_SUCCESS(status))
|
||||
@@ -1102,21 +1206,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
|
||||
if (ACPI_SUCCESS(status))
|
||||
device->flags.ejectable = 1;
|
||||
}
|
||||
|
||||
/* Power resources cannot be power manageable. */
|
||||
if (device->device_type == ACPI_BUS_TYPE_POWER)
|
||||
return 0;
|
||||
|
||||
/* Presence of _PS0|_PR0 indicates 'power manageable' */
|
||||
status = acpi_get_handle(device->handle, "_PS0", &temp);
|
||||
if (ACPI_FAILURE(status))
|
||||
status = acpi_get_handle(device->handle, "_PR0", &temp);
|
||||
if (ACPI_SUCCESS(status))
|
||||
device->flags.power_manageable = 1;
|
||||
|
||||
/* TBD: Performance management */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_device_get_busid(struct acpi_device *device)
|
||||
@@ -1341,27 +1430,25 @@ static void acpi_device_set_id(struct acpi_device *device)
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_device_set_context(struct acpi_device *device)
|
||||
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
||||
int type, unsigned long long sta)
|
||||
{
|
||||
acpi_status status;
|
||||
INIT_LIST_HEAD(&device->pnp.ids);
|
||||
device->device_type = type;
|
||||
device->handle = handle;
|
||||
device->parent = acpi_bus_get_parent(handle);
|
||||
STRUCT_TO_INT(device->status) = sta;
|
||||
acpi_device_get_busid(device);
|
||||
acpi_device_set_id(device);
|
||||
acpi_bus_get_flags(device);
|
||||
device_initialize(&device->dev);
|
||||
dev_set_uevent_suppress(&device->dev, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Context
|
||||
* -------
|
||||
* Attach this 'struct acpi_device' to the ACPI object. This makes
|
||||
* resolutions from handle->device very efficient. Fixed hardware
|
||||
* devices have no handles, so we skip them.
|
||||
*/
|
||||
if (!device->handle)
|
||||
return 0;
|
||||
|
||||
status = acpi_attach_data(device->handle,
|
||||
acpi_bus_data_handler, device);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return 0;
|
||||
|
||||
printk(KERN_ERR PREFIX "Error attaching device data\n");
|
||||
return -ENODEV;
|
||||
void acpi_device_add_finalize(struct acpi_device *device)
|
||||
{
|
||||
dev_set_uevent_suppress(&device->dev, false);
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_ADD);
|
||||
}
|
||||
|
||||
static int acpi_add_single_object(struct acpi_device **child,
|
||||
@@ -1378,90 +1465,26 @@ static int acpi_add_single_object(struct acpi_device **child,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&device->pnp.ids);
|
||||
device->device_type = type;
|
||||
device->handle = handle;
|
||||
device->parent = acpi_bus_get_parent(handle);
|
||||
STRUCT_TO_INT(device->status) = sta;
|
||||
|
||||
acpi_device_get_busid(device);
|
||||
|
||||
/*
|
||||
* Flags
|
||||
* -----
|
||||
* Note that we only look for object handles -- cannot evaluate objects
|
||||
* until we know the device is present and properly initialized.
|
||||
*/
|
||||
result = acpi_bus_get_flags(device);
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
/*
|
||||
* Initialize Device
|
||||
* -----------------
|
||||
* TBD: Synch with Core's enumeration/initialization process.
|
||||
*/
|
||||
acpi_device_set_id(device);
|
||||
|
||||
/*
|
||||
* Power Management
|
||||
* ----------------
|
||||
*/
|
||||
if (device->flags.power_manageable) {
|
||||
result = acpi_bus_get_power_flags(device);
|
||||
if (result)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wakeup device management
|
||||
*-----------------------
|
||||
*/
|
||||
acpi_init_device_object(device, handle, type, sta);
|
||||
acpi_bus_get_power_flags(device);
|
||||
acpi_bus_get_wakeup_device_flags(device);
|
||||
|
||||
/*
|
||||
* Performance Management
|
||||
* ----------------------
|
||||
*/
|
||||
if (device->flags.performance_manageable) {
|
||||
result = acpi_bus_get_perf_flags(device);
|
||||
if (result)
|
||||
goto end;
|
||||
device->flags.match_driver = match_driver;
|
||||
result = acpi_device_add(device, acpi_device_release);
|
||||
if (result) {
|
||||
acpi_device_release(&device->dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result = acpi_device_set_context(device)))
|
||||
goto end;
|
||||
|
||||
device->flags.match_driver = match_driver;
|
||||
result = acpi_device_register(device);
|
||||
|
||||
end:
|
||||
if (!result) {
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Adding %s [%s] parent %s\n", dev_name(&device->dev),
|
||||
(char *) buffer.pointer,
|
||||
device->parent ? dev_name(&device->parent->dev) :
|
||||
"(null)"));
|
||||
kfree(buffer.pointer);
|
||||
*child = device;
|
||||
} else
|
||||
acpi_device_release(&device->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
|
||||
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
|
||||
|
||||
static void acpi_bus_add_power_resource(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
|
||||
acpi_bus_get_device(handle, &device);
|
||||
if (!device)
|
||||
acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
|
||||
ACPI_STA_DEFAULT, true);
|
||||
acpi_power_add_remove_device(device, true);
|
||||
acpi_device_add_finalize(device);
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n",
|
||||
dev_name(&device->dev), (char *) buffer.pointer,
|
||||
device->parent ? dev_name(&device->parent->dev) : "(null)"));
|
||||
kfree(buffer.pointer);
|
||||
*child = device;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
|
||||
@@ -1520,20 +1543,26 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
|
||||
if (result)
|
||||
return AE_OK;
|
||||
|
||||
if (type == ACPI_BUS_TYPE_POWER) {
|
||||
acpi_add_power_resource(handle);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
|
||||
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
|
||||
struct acpi_device_wakeup wakeup;
|
||||
acpi_handle temp;
|
||||
|
||||
status = acpi_get_handle(handle, "_PRW", &temp);
|
||||
if (ACPI_SUCCESS(status))
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
acpi_bus_extract_wakeup_device_power_package(handle,
|
||||
&wakeup);
|
||||
acpi_power_resources_list_free(&wakeup.resources);
|
||||
}
|
||||
return AE_CTRL_DEPTH;
|
||||
}
|
||||
|
||||
acpi_add_single_object(&device, handle, type, sta,
|
||||
type == ACPI_BUS_TYPE_POWER);
|
||||
acpi_add_single_object(&device, handle, type, sta, false);
|
||||
if (!device)
|
||||
return AE_CTRL_DEPTH;
|
||||
|
||||
@@ -1687,7 +1716,6 @@ int __init acpi_scan_init(void)
|
||||
printk(KERN_ERR PREFIX "Could not register bus type\n");
|
||||
}
|
||||
|
||||
acpi_power_init();
|
||||
acpi_pci_root_init();
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user