ACPI: maintain a single list of _HID and _CID IDs

There's no need to treat _HID and _CID differently.  Keeping them in
a single list makes code that uses the IDs a little simpler because it
can just traverse the list rather than checking "do we have a HID?",
"do we have any CIDs?"

Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Reviewed-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
Bjorn Helgaas 2009-09-21 13:35:19 -06:00 committed by Len Brown
parent b1fbfb2ae8
commit 7f47fa6c2f
3 changed files with 60 additions and 132 deletions

View file

@ -45,6 +45,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
{ {
int len; int len;
int count; int count;
struct acpi_hardware_id *id;
if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids)
return -ENODEV; return -ENODEV;
@ -52,33 +53,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
len = snprintf(modalias, size, "acpi:"); len = snprintf(modalias, size, "acpi:");
size -= len; size -= len;
if (acpi_dev->flags.hardware_id) { list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
count = snprintf(&modalias[len], size, "%s:", count = snprintf(&modalias[len], size, "%s:", id->id);
acpi_dev->pnp.hardware_id);
if (count < 0 || count >= size) if (count < 0 || count >= size)
return -EINVAL; return -EINVAL;
len += count; len += count;
size -= 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'; modalias[len] = '\0';
return len; return len;
} }
@ -273,6 +255,7 @@ int acpi_match_device_ids(struct acpi_device *device,
const struct acpi_device_id *ids) const struct acpi_device_id *ids)
{ {
const struct acpi_device_id *id; const struct acpi_device_id *id;
struct acpi_hardware_id *hwid;
/* /*
* If the device is not present, it is unnecessary to load device * If the device is not present, it is unnecessary to load device
@ -281,40 +264,30 @@ int acpi_match_device_ids(struct acpi_device *device,
if (!device->status.present) if (!device->status.present)
return -ENODEV; return -ENODEV;
if (device->flags.hardware_id) { for (id = ids; id->id[0]; id++)
for (id = ids; id->id[0]; id++) { list_for_each_entry(hwid, &device->pnp.ids, list)
if (!strcmp((char*)id->id, device->pnp.hardware_id)) if (!strcmp((char *) id->id, hwid->id))
return 0; 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; return -ENOENT;
} }
EXPORT_SYMBOL(acpi_match_device_ids); 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) static void acpi_device_release(struct device *dev)
{ {
struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_device *acpi_dev = to_acpi_device(dev);
kfree(acpi_dev->pnp.cid_list); acpi_free_ids(acpi_dev);
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); kfree(acpi_dev);
} }
@ -1028,62 +1001,31 @@ static int acpi_dock_match(struct acpi_device *device)
return acpi_get_handle(device->handle, "_DCK", &tmp); return acpi_get_handle(device->handle, "_DCK", &tmp);
} }
static struct acpica_device_id_list* char *acpi_device_hid(struct acpi_device *device)
acpi_add_cid(
struct acpi_device_info *info,
struct acpica_device_id *new_cid)
{ {
struct acpica_device_id_list *cid; struct acpi_hardware_id *hid;
char *next_id_string;
acpi_size cid_length;
acpi_size new_cid_length;
u32 i;
hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
return hid->id;
}
EXPORT_SYMBOL(acpi_device_hid);
/* Allocate new CID list with room for the new CID */ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
{
struct acpi_hardware_id *id;
if (!new_cid) id = kmalloc(sizeof(*id), GFP_KERNEL);
new_cid_length = info->compatible_id_list.list_size; if (!id)
else if (info->compatible_id_list.list_size) return;
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); id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
if (!cid) { if (!id->id) {
return NULL; kfree(id);
return;
} }
cid->list_size = new_cid_length; strcpy(id->id, dev_id);
cid->count = info->compatible_id_list.count; list_add_tail(&id->list, &device->pnp.ids);
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) static void acpi_device_set_id(struct acpi_device *device)
@ -1094,6 +1036,7 @@ static void acpi_device_set_id(struct acpi_device *device)
struct acpica_device_id_list *cid_list = NULL; struct acpica_device_id_list *cid_list = NULL;
char *cid_add = NULL; char *cid_add = NULL;
acpi_status status; acpi_status status;
int i;
switch (device->device_type) { switch (device->device_type) {
case ACPI_BUS_TYPE_DEVICE: case ACPI_BUS_TYPE_DEVICE:
@ -1166,15 +1109,9 @@ static void acpi_device_set_id(struct acpi_device *device)
hid = "device"; hid = "device";
if (hid) { if (hid) {
device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); acpi_add_id(device, hid);
if (device->pnp.hardware_id) { device->flags.hardware_id = 1;
strcpy(device->pnp.hardware_id, hid);
device->flags.hardware_id = 1;
}
} }
if (!device->flags.hardware_id)
device->pnp.hardware_id = "";
if (uid) { if (uid) {
device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1);
if (device->pnp.unique_id) { if (device->pnp.unique_id) {
@ -1185,24 +1122,12 @@ static void acpi_device_set_id(struct acpi_device *device)
if (!device->flags.unique_id) if (!device->flags.unique_id)
device->pnp.unique_id = ""; device->pnp.unique_id = "";
if (cid_list || cid_add) { if (cid_list)
struct acpica_device_id_list *list; for (i = 0; i < cid_list->count; i++)
acpi_add_id(device, cid_list->ids[i].string);
if (cid_add) { if (cid_add) {
struct acpica_device_id cid; acpi_add_id(device, cid_add);
cid.length = strlen (cid_add) + 1; device->flags.compatible_ids = 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); kfree(info);
@ -1269,6 +1194,7 @@ static int acpi_add_single_object(struct acpi_device **child,
return -ENOMEM; return -ENOMEM;
} }
INIT_LIST_HEAD(&device->pnp.ids);
device->device_type = type; device->device_type = type;
device->handle = handle; device->handle = handle;
device->parent = acpi_bus_get_parent(handle); device->parent = acpi_bus_get_parent(handle);

View file

@ -153,6 +153,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
acpi_handle temp = NULL; acpi_handle temp = NULL;
acpi_status status; acpi_status status;
struct pnp_dev *dev; struct pnp_dev *dev;
struct acpi_hardware_id *id;
/* /*
* If a PnPacpi device is not present , the device * If a PnPacpi device is not present , the device
@ -193,15 +194,12 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (dev->capabilities & PNP_CONFIGURABLE) if (dev->capabilities & PNP_CONFIGURABLE)
pnpacpi_parse_resource_option_data(dev); pnpacpi_parse_resource_option_data(dev);
if (device->flags.compatible_ids) { list_for_each_entry(id, &device->pnp.ids, list) {
struct acpica_device_id_list *cid_list = device->pnp.cid_list; if (!strcmp(id->id, acpi_device_hid(device)))
int i; continue;
if (!ispnpidacpi(id->id))
for (i = 0; i < cid_list->count; i++) { continue;
if (!ispnpidacpi(cid_list->ids[i].string)) pnp_add_id(dev, id->id);
continue;
pnp_add_id(dev, cid_list->ids[i].string);
}
} }
/* clear out the damaged flags */ /* clear out the damaged flags */

View file

@ -171,19 +171,23 @@ typedef unsigned long acpi_bus_address;
typedef char acpi_device_name[40]; typedef char acpi_device_name[40];
typedef char acpi_device_class[20]; typedef char acpi_device_class[20];
struct acpi_hardware_id {
struct list_head list;
char *id;
};
struct acpi_device_pnp { struct acpi_device_pnp {
acpi_bus_id bus_id; /* Object name */ acpi_bus_id bus_id; /* Object name */
acpi_bus_address bus_address; /* _ADR */ acpi_bus_address bus_address; /* _ADR */
char *hardware_id; /* _HID */
struct acpica_device_id_list *cid_list; /* _CIDs */
char *unique_id; /* _UID */ char *unique_id; /* _UID */
struct list_head ids; /* _HID and _CIDs */
acpi_device_name device_name; /* Driver-determined */ acpi_device_name device_name; /* Driver-determined */
acpi_device_class device_class; /* " */ acpi_device_class device_class; /* " */
}; };
#define acpi_device_bid(d) ((d)->pnp.bus_id) #define acpi_device_bid(d) ((d)->pnp.bus_id)
#define acpi_device_adr(d) ((d)->pnp.bus_address) #define acpi_device_adr(d) ((d)->pnp.bus_address)
#define acpi_device_hid(d) ((d)->pnp.hardware_id) char *acpi_device_hid(struct acpi_device *device);
#define acpi_device_uid(d) ((d)->pnp.unique_id) #define acpi_device_uid(d) ((d)->pnp.unique_id)
#define acpi_device_name(d) ((d)->pnp.device_name) #define acpi_device_name(d) ((d)->pnp.device_name)
#define acpi_device_class(d) ((d)->pnp.device_class) #define acpi_device_class(d) ((d)->pnp.device_class)