}
if (acpi_dev->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list;
+ struct acpica_device_id_list *cid_list;
int i;
cid_list = acpi_dev->pnp.cid_list;
for (i = 0; i < cid_list->count; i++) {
count = snprintf(&modalias[len], size, "%s:",
- cid_list->id[i].value);
+ cid_list->ids[i].string);
if (count < 0 || count >= size) {
printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
acpi_dev->pnp.device_name, i);
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
-static int acpi_bus_hot_remove_device(void *context)
+static void acpi_bus_hot_remove_device(void *context)
{
struct acpi_device *device;
acpi_handle handle = context;
acpi_status status = AE_OK;
if (acpi_bus_get_device(handle, &device))
- return 0;
+ return;
if (!device)
- return 0;
+ return;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Hot-removing device %s...\n", dev_name(&device->dev)));
if (acpi_bus_trim(device, 1)) {
printk(KERN_ERR PREFIX
"Removing device failed\n");
- return -1;
+ return;
}
/* power off device */
*/
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
if (ACPI_FAILURE(status))
- return -ENODEV;
+ printk(KERN_WARNING PREFIX
+ "Eject device failed\n");
- return 0;
+ return;
}
static ssize_t
acpi_status status;
acpi_object_type type = 0;
struct acpi_device *acpi_device = to_acpi_device(d);
- struct task_struct *task;
if ((!count) || (buf[0] != '1')) {
return -EINVAL;
goto err;
}
- /* remove the device in another thread to fix the deadlock issue */
- task = kthread_run(acpi_bus_hot_remove_device,
- acpi_device->handle, "acpi_hot_remove_device");
- if (IS_ERR(task))
- ret = PTR_ERR(task);
+ acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle);
err:
return ret;
}
}
if (device->flags.compatible_ids) {
- struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+ struct acpica_device_id_list *cid_list = device->pnp.cid_list;
int i;
for (id = ids; id->id[0]; id++) {
/* compare multiple _CID entries against driver ids */
for (i = 0; i < cid_list->count; i++) {
if (!strcmp((char*)id->id,
- cid_list->id[i].value))
+ cid_list->ids[i].string))
return 0;
}
}
struct acpi_device *acpi_dev = to_acpi_device(dev);
kfree(acpi_dev->pnp.cid_list);
+ if (acpi_dev->flags.hardware_id)
+ kfree(acpi_dev->pnp.hardware_id);
+ if (acpi_dev->flags.unique_id)
+ kfree(acpi_dev->pnp.unique_id);
kfree(acpi_dev);
}
{
struct acpi_device *device = data;
- acpi_device_notify(device->handle, ACPI_FIXED_HARDWARE_EVENT, device);
+ /* Fixed hardware devices have no handles */
+ acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
return AE_OK;
}
static int acpi_device_install_notify_handler(struct acpi_device *device)
{
acpi_status status;
- char *hid;
- hid = acpi_device_hid(device);
- if (!strcmp(hid, ACPI_BUTTON_HID_POWERF))
+ if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
status =
acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
acpi_device_notify_fixed,
device);
- else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEPF))
+ else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
status =
acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
acpi_device_notify_fixed,
static void acpi_device_remove_notify_handler(struct acpi_device *device)
{
- if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF))
+ if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
acpi_device_notify_fixed);
- else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF))
+ else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
acpi_device_notify_fixed);
else
if (acpi_drv->ops.notify) {
ret = acpi_device_install_notify_handler(acpi_dev);
if (ret) {
- if (acpi_drv->ops.stop)
- acpi_drv->ops.stop(acpi_dev,
- acpi_dev->removal_type);
if (acpi_drv->ops.remove)
acpi_drv->ops.remove(acpi_dev,
acpi_dev->removal_type);
if (acpi_drv) {
if (acpi_drv->ops.notify)
acpi_device_remove_notify_handler(acpi_dev);
- if (acpi_drv->ops.stop)
- acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
if (acpi_drv->ops.remove)
acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
}
.uevent = acpi_device_uevent,
};
-static int acpi_device_register(struct acpi_device *device,
- struct acpi_device *parent)
+static int acpi_device_register(struct acpi_device *device)
{
int result;
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
int found = 0;
+
/*
* Linkage
* -------
mutex_unlock(&acpi_device_lock);
if (device->parent)
- device->dev.parent = &parent->dev;
+ device->dev.parent = &device->parent->dev;
device->dev.bus = &acpi_bus_type;
device->dev.release = &acpi_device_release;
result = device_register(&device->dev);
}
EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+void acpi_bus_data_handler(acpi_handle handle, void *context)
{
/* TBD */
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ device->wakeup.prepare_count = 0;
/* Call _PSW/_DSW object to disable its ability to wake the sleeping
* system for the ACPI device with the _PRW object.
* The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
return 0;
}
-static void acpi_device_get_busid(struct acpi_device *device,
- acpi_handle handle, int type)
+static void acpi_device_get_busid(struct acpi_device *device)
{
char bus_id[5] = { '?', 0 };
struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
* The device's Bus ID is simply the object name.
* TBD: Shouldn't this value be unique (within the ACPI namespace)?
*/
- switch (type) {
+ switch (device->device_type) {
case ACPI_BUS_TYPE_SYSTEM:
strcpy(device->pnp.bus_id, "ACPI");
break;
strcpy(device->pnp.bus_id, "SLPF");
break;
default:
- acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+ acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
/* Clean up trailing underscores (if any) */
for (i = 3; i > 1; i--) {
if (bus_id[i] == '_')
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
-static void acpi_device_set_id(struct acpi_device *device,
- struct acpi_device *parent, acpi_handle handle,
- int type)
+static struct acpica_device_id_list*
+acpi_add_cid(
+ struct acpi_device_info *info,
+ struct acpica_device_id *new_cid)
{
- struct acpi_device_info *info;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpica_device_id_list *cid;
+ char *next_id_string;
+ acpi_size cid_length;
+ acpi_size new_cid_length;
+ u32 i;
+
+
+ /* Allocate new CID list with room for the new CID */
+
+ if (!new_cid)
+ new_cid_length = info->compatible_id_list.list_size;
+ else if (info->compatible_id_list.list_size)
+ new_cid_length = info->compatible_id_list.list_size +
+ new_cid->length + sizeof(struct acpica_device_id);
+ else
+ new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length;
+
+ cid = ACPI_ALLOCATE_ZEROED(new_cid_length);
+ if (!cid) {
+ return NULL;
+ }
+
+ cid->list_size = new_cid_length;
+ cid->count = info->compatible_id_list.count;
+ if (new_cid)
+ cid->count++;
+ next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id));
+
+ /* Copy all existing CIDs */
+
+ for (i = 0; i < info->compatible_id_list.count; i++) {
+ cid_length = info->compatible_id_list.ids[i].length;
+ cid->ids[i].string = next_id_string;
+ cid->ids[i].length = cid_length;
+
+ ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string,
+ cid_length);
+
+ next_id_string += cid_length;
+ }
+
+ /* Append the new CID */
+
+ if (new_cid) {
+ cid->ids[i].string = next_id_string;
+ cid->ids[i].length = new_cid->length;
+
+ ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length);
+ }
+
+ return cid;
+}
+
+static void acpi_device_set_id(struct acpi_device *device)
+{
+ struct acpi_device_info *info = NULL;
char *hid = NULL;
char *uid = NULL;
- struct acpi_compatible_id_list *cid_list = NULL;
- const char *cid_add = NULL;
+ struct acpica_device_id_list *cid_list = NULL;
+ char *cid_add = NULL;
acpi_status status;
- switch (type) {
+ switch (device->device_type) {
case ACPI_BUS_TYPE_DEVICE:
- status = acpi_get_object_info(handle, &buffer);
+ status = acpi_get_object_info(device->handle, &info);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
return;
}
- info = buffer.pointer;
if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.value;
+ hid = info->hardware_id.string;
if (info->valid & ACPI_VALID_UID)
- uid = info->unique_id.value;
+ uid = info->unique_id.string;
if (info->valid & ACPI_VALID_CID)
- cid_list = &info->compatibility_id;
+ cid_list = &info->compatible_id_list;
if (info->valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
* ----
* Fix for the system root bus device -- the only root-level device.
*/
- if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
+ if (((acpi_handle)device->parent == ACPI_ROOT_OBJECT) &&
+ (device->device_type == ACPI_BUS_TYPE_DEVICE)) {
hid = ACPI_BUS_HID;
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
}
if (hid) {
- strcpy(device->pnp.hardware_id, hid);
- device->flags.hardware_id = 1;
+ device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1);
+ if (device->pnp.hardware_id) {
+ strcpy(device->pnp.hardware_id, hid);
+ device->flags.hardware_id = 1;
+ }
}
+ if (!device->flags.hardware_id)
+ device->pnp.hardware_id = "";
+
if (uid) {
- strcpy(device->pnp.unique_id, uid);
- device->flags.unique_id = 1;
+ device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1);
+ if (device->pnp.unique_id) {
+ strcpy(device->pnp.unique_id, uid);
+ device->flags.unique_id = 1;
+ }
}
+ if (!device->flags.unique_id)
+ device->pnp.unique_id = "";
+
if (cid_list || cid_add) {
- struct acpi_compatible_id_list *list;
- int size = 0;
- int count = 0;
-
- if (cid_list) {
- size = cid_list->size;
- } else if (cid_add) {
- size = sizeof(struct acpi_compatible_id_list);
- cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
- if (!cid_list) {
- printk(KERN_ERR "Memory allocation error\n");
- kfree(buffer.pointer);
- return;
- } else {
- cid_list->count = 0;
- cid_list->size = size;
- }
+ struct acpica_device_id_list *list;
+
+ if (cid_add) {
+ struct acpica_device_id cid;
+ cid.length = strlen (cid_add) + 1;
+ cid.string = cid_add;
+
+ list = acpi_add_cid(info, &cid);
+ } else {
+ list = acpi_add_cid(info, NULL);
}
- if (cid_add)
- size += sizeof(struct acpi_compatible_id);
- list = kmalloc(size, GFP_KERNEL);
if (list) {
- if (cid_list) {
- memcpy(list, cid_list, cid_list->size);
- count = cid_list->count;
- }
- if (cid_add) {
- strncpy(list->id[count].value, cid_add,
- ACPI_MAX_CID_LENGTH);
- count++;
- device->flags.compatible_ids = 1;
- }
- list->size = size;
- list->count = count;
device->pnp.cid_list = list;
- } else
- printk(KERN_ERR PREFIX "Memory allocation error\n");
+ if (cid_add)
+ device->flags.compatible_ids = 1;
+ }
}
- kfree(buffer.pointer);
+ kfree(info);
}
-static int acpi_device_set_context(struct acpi_device *device, int type)
+static int acpi_device_set_context(struct acpi_device *device)
{
- acpi_status status = AE_OK;
- int result = 0;
+ acpi_status status;
+
/*
* Context
* -------
* Attach this 'struct acpi_device' to the ACPI object. This makes
- * resolutions from handle->device very efficient. Note that we need
- * to be careful with fixed-feature devices as they all attach to the
- * root object.
+ * resolutions from handle->device very efficient. Fixed hardware
+ * devices have no handles, so we skip them.
*/
- if (type != ACPI_BUS_TYPE_POWER_BUTTON &&
- type != ACPI_BUS_TYPE_SLEEP_BUTTON) {
- status = acpi_attach_data(device->handle,
- acpi_bus_data_handler, device);
+ if (!device->handle)
+ return 0;
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error attaching device data\n");
- result = -ENODEV;
- }
- }
- return result;
+ 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;
}
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
{
- int result = 0;
- struct acpi_device *device = NULL;
-
-
- if (!child)
- return -EINVAL;
+ int result;
+ struct acpi_device *device;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
return -ENOMEM;
}
+ device->device_type = type;
device->handle = handle;
device->parent = parent;
device->bus_ops = *ops; /* workround for not call .start */
-
- acpi_device_get_busid(device, handle, type);
+ acpi_device_get_busid(device);
/*
* Flags
* Hardware ID, Unique ID, & Bus Address
* -------------------------------------
*/
- acpi_device_set_id(device, parent, handle, type);
-
- /*
- * The ACPI device is attached to acpi handle before getting
- * the power/wakeup/peformance flags. Otherwise OS can't get
- * the corresponding ACPI device by the acpi handle in the course
- * of getting the power/wakeup/performance flags.
- */
- result = acpi_device_set_context(device, type);
- if (result)
- goto end;
+ acpi_device_set_id(device);
/*
* Power Management
goto end;
}
+ if ((result = acpi_device_set_context(device)))
+ goto end;
- result = acpi_device_register(device, parent);
+ result = acpi_device_register(device);
/*
* Bind _ADR-Based Devices when hot add
}
end:
- if (!result)
+ 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 {
- kfree(device->pnp.cid_list);
- kfree(device);
- }
+ } else
+ acpi_device_release(&device->dev);
return result;
}
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
-static int acpi_bus_scan_fixed(struct acpi_device *root)
+static int acpi_bus_scan_fixed(void)
{
int result = 0;
struct acpi_device *device = NULL;
struct acpi_bus_ops ops;
- if (!root)
- return -ENODEV;
-
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
ops.acpi_op_start = 1;
/*
* Enumerate devices in the ACPI namespace.
*/
- result = acpi_bus_scan_fixed(acpi_root);
+ result = acpi_bus_scan_fixed();
if (!result)
result = acpi_bus_scan(acpi_root, &ops);