{
int len;
int count;
-
- if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids)
- return -ENODEV;
+ struct acpi_hardware_id *id;
len = snprintf(modalias, size, "acpi:");
size -= len;
- if (acpi_dev->flags.hardware_id) {
- count = snprintf(&modalias[len], size, "%s:",
- acpi_dev->pnp.hardware_id);
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0 || count >= size)
return -EINVAL;
len += count;
size -= count;
}
- if (acpi_dev->flags.compatible_ids) {
- 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->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);
- break;
- }
- len += count;
- size -= count;
- }
- }
-
modalias[len] = '\0';
return len;
}
acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct acpi_device *acpi_dev = to_acpi_device(dev);
- return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+ return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
}
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
goto end;
}
- if (dev->flags.hardware_id) {
- result = device_create_file(&dev->dev, &dev_attr_hid);
- if (result)
- goto end;
- }
+ result = device_create_file(&dev->dev, &dev_attr_hid);
+ if (result)
+ goto end;
- if (dev->flags.hardware_id || dev->flags.compatible_ids) {
- result = device_create_file(&dev->dev, &dev_attr_modalias);
- if (result)
- goto end;
- }
+ result = device_create_file(&dev->dev, &dev_attr_modalias);
+ if (result)
+ goto end;
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
if (ACPI_SUCCESS(status))
device_remove_file(&dev->dev, &dev_attr_eject);
- if (dev->flags.hardware_id || dev->flags.compatible_ids)
- device_remove_file(&dev->dev, &dev_attr_modalias);
-
- if (dev->flags.hardware_id)
- device_remove_file(&dev->dev, &dev_attr_hid);
+ device_remove_file(&dev->dev, &dev_attr_modalias);
+ device_remove_file(&dev->dev, &dev_attr_hid);
if (dev->handle)
device_remove_file(&dev->dev, &dev_attr_path);
}
const struct acpi_device_id *ids)
{
const struct acpi_device_id *id;
+ struct acpi_hardware_id *hwid;
/*
* If the device is not present, it is unnecessary to load device
if (!device->status.present)
return -ENODEV;
- if (device->flags.hardware_id) {
- for (id = ids; id->id[0]; id++) {
- if (!strcmp((char*)id->id, device->pnp.hardware_id))
+ for (id = ids; id->id[0]; id++)
+ list_for_each_entry(hwid, &device->pnp.ids, list)
+ if (!strcmp((char *) id->id, hwid->id))
return 0;
- }
- }
-
- if (device->flags.compatible_ids) {
- 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->ids[i].string))
- return 0;
- }
- }
- }
return -ENOENT;
}
EXPORT_SYMBOL(acpi_match_device_ids);
+static void acpi_free_ids(struct acpi_device *device)
+{
+ struct acpi_hardware_id *id, *tmp;
+
+ list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
+ kfree(id->id);
+ kfree(id);
+ }
+}
+
static void acpi_device_release(struct device *dev)
{
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);
+ acpi_free_ids(acpi_dev);
kfree(acpi_dev);
}
* If failed, create one and link it into acpi_bus_id_list
*/
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
- if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
- acpi_device_bus_id->instance_no ++;
+ if (!strcmp(acpi_device_bus_id->bus_id,
+ acpi_device_hid(device))) {
+ acpi_device_bus_id->instance_no++;
found = 1;
kfree(new_bus_id);
break;
}
if (!found) {
acpi_device_bus_id = new_bus_id;
- strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+ strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
acpi_device_bus_id->instance_no = 0;
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
}
if (ACPI_SUCCESS(status))
device->flags.dynamic_status = 1;
- /* Presence of _CID indicates 'compatible_ids' */
- status = acpi_get_handle(device->handle, "_CID", &temp);
- if (ACPI_SUCCESS(status))
- device->flags.compatible_ids = 1;
-
/* Presence of _RMV indicates 'removable' */
status = acpi_get_handle(device->handle, "_RMV", &temp);
if (ACPI_SUCCESS(status))
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
-static struct acpica_device_id_list*
-acpi_add_cid(
- struct acpi_device_info *info,
- struct acpica_device_id *new_cid)
+char *acpi_device_hid(struct acpi_device *device)
{
- 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 */
+ struct acpi_hardware_id *hid;
- 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;
- }
+ hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
+ return hid->id;
+}
+EXPORT_SYMBOL(acpi_device_hid);
- /* Append the new CID */
+static void acpi_add_id(struct acpi_device *device, const char *dev_id)
+{
+ struct acpi_hardware_id *id;
- if (new_cid) {
- cid->ids[i].string = next_id_string;
- cid->ids[i].length = new_cid->length;
+ id = kmalloc(sizeof(*id), GFP_KERNEL);
+ if (!id)
+ return;
- ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length);
+ id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
+ if (!id->id) {
+ kfree(id);
+ return;
}
- return cid;
+ strcpy(id->id, dev_id);
+ list_add_tail(&id->list, &device->pnp.ids);
}
static void acpi_device_set_id(struct acpi_device *device)
{
- struct acpi_device_info *info = NULL;
- char *hid = NULL;
- char *uid = NULL;
- struct acpica_device_id_list *cid_list = NULL;
- char *cid_add = NULL;
acpi_status status;
+ struct acpi_device_info *info;
+ struct acpica_device_id_list *cid_list;
+ int i;
switch (device->device_type) {
case ACPI_BUS_TYPE_DEVICE:
if (ACPI_IS_ROOT_DEVICE(device)) {
- hid = ACPI_SYSTEM_HID;
+ acpi_add_id(device, ACPI_SYSTEM_HID);
break;
} else if (ACPI_IS_ROOT_DEVICE(device->parent)) {
/* \_SB_, the only root-level namespace device */
- hid = ACPI_BUS_HID;
+ acpi_add_id(device, ACPI_BUS_HID);
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
break;
}
if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.string;
- if (info->valid & ACPI_VALID_UID)
- uid = info->unique_id.string;
- if (info->valid & ACPI_VALID_CID)
+ acpi_add_id(device, info->hardware_id.string);
+ if (info->valid & ACPI_VALID_CID) {
cid_list = &info->compatible_id_list;
+ for (i = 0; i < cid_list->count; i++)
+ acpi_add_id(device, cid_list->ids[i].string);
+ }
if (info->valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
}
- /* If we have a video/bay/dock device, add our selfdefined
- HID to the CID list. Like that the video/bay/dock drivers
- will get autoloaded and the device might still match
- against another driver.
- */
+ kfree(info);
+
+ /*
+ * Some devices don't reliably have _HIDs & _CIDs, so add
+ * synthetic HIDs to make sure drivers can find them.
+ */
if (acpi_is_video_device(device))
- cid_add = ACPI_VIDEO_HID;
+ acpi_add_id(device, ACPI_VIDEO_HID);
else if (ACPI_SUCCESS(acpi_bay_match(device)))
- cid_add = ACPI_BAY_HID;
+ acpi_add_id(device, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(device)))
- cid_add = ACPI_DOCK_HID;
+ acpi_add_id(device, ACPI_DOCK_HID);
break;
case ACPI_BUS_TYPE_POWER:
- hid = ACPI_POWER_HID;
+ acpi_add_id(device, ACPI_POWER_HID);
break;
case ACPI_BUS_TYPE_PROCESSOR:
- hid = ACPI_PROCESSOR_OBJECT_HID;
+ acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
break;
case ACPI_BUS_TYPE_THERMAL:
- hid = ACPI_THERMAL_HID;
+ acpi_add_id(device, ACPI_THERMAL_HID);
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
- hid = ACPI_BUTTON_HID_POWERF;
+ acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
- hid = ACPI_BUTTON_HID_SLEEPF;
+ acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
break;
}
- if (hid) {
- 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) {
- 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 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 (list) {
- device->pnp.cid_list = list;
- if (cid_add)
- device->flags.compatible_ids = 1;
- }
- }
-
- kfree(info);
+ /*
+ * We build acpi_devices for some objects that don't have _HID or _CID,
+ * e.g., PCI bridges and slots. Drivers can't bind to these objects,
+ * but we do use them indirectly by traversing the acpi_device tree.
+ * This generic ID isn't useful for driver binding, but it provides
+ * the useful property that "every acpi_device has an ID."
+ */
+ if (list_empty(&device->pnp.ids))
+ acpi_add_id(device, "device");
}
static int acpi_device_set_context(struct acpi_device *device)
return -ENOMEM;
}
+ INIT_LIST_HEAD(&device->pnp.ids);
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
* -----------------
* TBD: Synch with Core's enumeration/initialization process.
*/
-
- /*
- * Hardware ID, Unique ID, & Bus Address
- * -------------------------------------
- */
acpi_device_set_id(device);
/*
struct acpi_device **child)
{
acpi_status status;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
void *device = NULL;
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n",
- (char *) buffer.pointer);
-
status = acpi_bus_check_add(handle, 0, ops, &device);
if (ACPI_SUCCESS(status))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,