diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 166 |
1 files changed, 46 insertions, 120 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 53b96e7a64ab..2e8889f62666 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -45,6 +45,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, | |||
45 | { | 45 | { |
46 | int len; | 46 | int len; |
47 | int count; | 47 | int count; |
48 | struct acpi_hardware_id *id; | ||
48 | 49 | ||
49 | if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) | 50 | if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) |
50 | return -ENODEV; | 51 | return -ENODEV; |
@@ -52,33 +53,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, | |||
52 | len = snprintf(modalias, size, "acpi:"); | 53 | len = snprintf(modalias, size, "acpi:"); |
53 | size -= len; | 54 | size -= len; |
54 | 55 | ||
55 | if (acpi_dev->flags.hardware_id) { | 56 | list_for_each_entry(id, &acpi_dev->pnp.ids, list) { |
56 | count = snprintf(&modalias[len], size, "%s:", | 57 | count = snprintf(&modalias[len], size, "%s:", id->id); |
57 | acpi_dev->pnp.hardware_id); | ||
58 | if (count < 0 || count >= size) | 58 | if (count < 0 || count >= size) |
59 | return -EINVAL; | 59 | return -EINVAL; |
60 | len += count; | 60 | len += count; |
61 | size -= count; | 61 | size -= count; |
62 | } | 62 | } |
63 | 63 | ||
64 | if (acpi_dev->flags.compatible_ids) { | ||
65 | struct acpica_device_id_list *cid_list; | ||
66 | int i; | ||
67 | |||
68 | cid_list = acpi_dev->pnp.cid_list; | ||
69 | for (i = 0; i < cid_list->count; i++) { | ||
70 | count = snprintf(&modalias[len], size, "%s:", | ||
71 | cid_list->ids[i].string); | ||
72 | if (count < 0 || count >= size) { | ||
73 | printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", | ||
74 | acpi_dev->pnp.device_name, i); | ||
75 | break; | ||
76 | } | ||
77 | len += count; | ||
78 | size -= count; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | modalias[len] = '\0'; | 64 | modalias[len] = '\0'; |
83 | return len; | 65 | return len; |
84 | } | 66 | } |
@@ -273,6 +255,7 @@ int acpi_match_device_ids(struct acpi_device *device, | |||
273 | const struct acpi_device_id *ids) | 255 | const struct acpi_device_id *ids) |
274 | { | 256 | { |
275 | const struct acpi_device_id *id; | 257 | const struct acpi_device_id *id; |
258 | struct acpi_hardware_id *hwid; | ||
276 | 259 | ||
277 | /* | 260 | /* |
278 | * If the device is not present, it is unnecessary to load device | 261 | * 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, | |||
281 | if (!device->status.present) | 264 | if (!device->status.present) |
282 | return -ENODEV; | 265 | return -ENODEV; |
283 | 266 | ||
284 | if (device->flags.hardware_id) { | 267 | for (id = ids; id->id[0]; id++) |
285 | for (id = ids; id->id[0]; id++) { | 268 | list_for_each_entry(hwid, &device->pnp.ids, list) |
286 | if (!strcmp((char*)id->id, device->pnp.hardware_id)) | 269 | if (!strcmp((char *) id->id, hwid->id)) |
287 | return 0; | 270 | return 0; |
288 | } | ||
289 | } | ||
290 | |||
291 | if (device->flags.compatible_ids) { | ||
292 | struct acpica_device_id_list *cid_list = device->pnp.cid_list; | ||
293 | int i; | ||
294 | |||
295 | for (id = ids; id->id[0]; id++) { | ||
296 | /* compare multiple _CID entries against driver ids */ | ||
297 | for (i = 0; i < cid_list->count; i++) { | ||
298 | if (!strcmp((char*)id->id, | ||
299 | cid_list->ids[i].string)) | ||
300 | return 0; | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | 271 | ||
305 | return -ENOENT; | 272 | return -ENOENT; |
306 | } | 273 | } |
307 | EXPORT_SYMBOL(acpi_match_device_ids); | 274 | EXPORT_SYMBOL(acpi_match_device_ids); |
308 | 275 | ||
276 | static void acpi_free_ids(struct acpi_device *device) | ||
277 | { | ||
278 | struct acpi_hardware_id *id, *tmp; | ||
279 | |||
280 | list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) { | ||
281 | kfree(id->id); | ||
282 | kfree(id); | ||
283 | } | ||
284 | } | ||
285 | |||
309 | static void acpi_device_release(struct device *dev) | 286 | static void acpi_device_release(struct device *dev) |
310 | { | 287 | { |
311 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 288 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
312 | 289 | ||
313 | kfree(acpi_dev->pnp.cid_list); | 290 | acpi_free_ids(acpi_dev); |
314 | if (acpi_dev->flags.hardware_id) | ||
315 | kfree(acpi_dev->pnp.hardware_id); | ||
316 | if (acpi_dev->flags.unique_id) | ||
317 | kfree(acpi_dev->pnp.unique_id); | ||
318 | kfree(acpi_dev); | 291 | kfree(acpi_dev); |
319 | } | 292 | } |
320 | 293 | ||
@@ -1028,62 +1001,31 @@ static int acpi_dock_match(struct acpi_device *device) | |||
1028 | return acpi_get_handle(device->handle, "_DCK", &tmp); | 1001 | return acpi_get_handle(device->handle, "_DCK", &tmp); |
1029 | } | 1002 | } |
1030 | 1003 | ||
1031 | static struct acpica_device_id_list* | 1004 | char *acpi_device_hid(struct acpi_device *device) |
1032 | acpi_add_cid( | ||
1033 | struct acpi_device_info *info, | ||
1034 | struct acpica_device_id *new_cid) | ||
1035 | { | 1005 | { |
1036 | struct acpica_device_id_list *cid; | 1006 | struct acpi_hardware_id *hid; |
1037 | char *next_id_string; | ||
1038 | acpi_size cid_length; | ||
1039 | acpi_size new_cid_length; | ||
1040 | u32 i; | ||
1041 | |||
1042 | |||
1043 | /* Allocate new CID list with room for the new CID */ | ||
1044 | |||
1045 | if (!new_cid) | ||
1046 | new_cid_length = info->compatible_id_list.list_size; | ||
1047 | else if (info->compatible_id_list.list_size) | ||
1048 | new_cid_length = info->compatible_id_list.list_size + | ||
1049 | new_cid->length + sizeof(struct acpica_device_id); | ||
1050 | else | ||
1051 | new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length; | ||
1052 | |||
1053 | cid = ACPI_ALLOCATE_ZEROED(new_cid_length); | ||
1054 | if (!cid) { | ||
1055 | return NULL; | ||
1056 | } | ||
1057 | |||
1058 | cid->list_size = new_cid_length; | ||
1059 | cid->count = info->compatible_id_list.count; | ||
1060 | if (new_cid) | ||
1061 | cid->count++; | ||
1062 | next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id)); | ||
1063 | |||
1064 | /* Copy all existing CIDs */ | ||
1065 | 1007 | ||
1066 | for (i = 0; i < info->compatible_id_list.count; i++) { | 1008 | hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); |
1067 | cid_length = info->compatible_id_list.ids[i].length; | 1009 | return hid->id; |
1068 | cid->ids[i].string = next_id_string; | 1010 | } |
1069 | cid->ids[i].length = cid_length; | 1011 | EXPORT_SYMBOL(acpi_device_hid); |
1070 | |||
1071 | ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string, | ||
1072 | cid_length); | ||
1073 | |||
1074 | next_id_string += cid_length; | ||
1075 | } | ||
1076 | 1012 | ||
1077 | /* Append the new CID */ | 1013 | static void acpi_add_id(struct acpi_device *device, const char *dev_id) |
1014 | { | ||
1015 | struct acpi_hardware_id *id; | ||
1078 | 1016 | ||
1079 | if (new_cid) { | 1017 | id = kmalloc(sizeof(*id), GFP_KERNEL); |
1080 | cid->ids[i].string = next_id_string; | 1018 | if (!id) |
1081 | cid->ids[i].length = new_cid->length; | 1019 | return; |
1082 | 1020 | ||
1083 | ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length); | 1021 | id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); |
1022 | if (!id->id) { | ||
1023 | kfree(id); | ||
1024 | return; | ||
1084 | } | 1025 | } |
1085 | 1026 | ||
1086 | return cid; | 1027 | strcpy(id->id, dev_id); |
1028 | list_add_tail(&id->list, &device->pnp.ids); | ||
1087 | } | 1029 | } |
1088 | 1030 | ||
1089 | static void acpi_device_set_id(struct acpi_device *device) | 1031 | static void acpi_device_set_id(struct acpi_device *device) |
@@ -1094,6 +1036,7 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1094 | struct acpica_device_id_list *cid_list = NULL; | 1036 | struct acpica_device_id_list *cid_list = NULL; |
1095 | char *cid_add = NULL; | 1037 | char *cid_add = NULL; |
1096 | acpi_status status; | 1038 | acpi_status status; |
1039 | int i; | ||
1097 | 1040 | ||
1098 | switch (device->device_type) { | 1041 | switch (device->device_type) { |
1099 | case ACPI_BUS_TYPE_DEVICE: | 1042 | case ACPI_BUS_TYPE_DEVICE: |
@@ -1166,15 +1109,9 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1166 | hid = "device"; | 1109 | hid = "device"; |
1167 | 1110 | ||
1168 | if (hid) { | 1111 | if (hid) { |
1169 | device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); | 1112 | acpi_add_id(device, hid); |
1170 | if (device->pnp.hardware_id) { | 1113 | device->flags.hardware_id = 1; |
1171 | strcpy(device->pnp.hardware_id, hid); | ||
1172 | device->flags.hardware_id = 1; | ||
1173 | } | ||
1174 | } | 1114 | } |
1175 | if (!device->flags.hardware_id) | ||
1176 | device->pnp.hardware_id = ""; | ||
1177 | |||
1178 | if (uid) { | 1115 | if (uid) { |
1179 | device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); | 1116 | device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); |
1180 | if (device->pnp.unique_id) { | 1117 | if (device->pnp.unique_id) { |
@@ -1185,24 +1122,12 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1185 | if (!device->flags.unique_id) | 1122 | if (!device->flags.unique_id) |
1186 | device->pnp.unique_id = ""; | 1123 | device->pnp.unique_id = ""; |
1187 | 1124 | ||
1188 | if (cid_list || cid_add) { | 1125 | if (cid_list) |
1189 | struct acpica_device_id_list *list; | 1126 | for (i = 0; i < cid_list->count; i++) |
1190 | 1127 | acpi_add_id(device, cid_list->ids[i].string); | |
1191 | if (cid_add) { | 1128 | if (cid_add) { |
1192 | struct acpica_device_id cid; | 1129 | acpi_add_id(device, cid_add); |
1193 | cid.length = strlen (cid_add) + 1; | 1130 | device->flags.compatible_ids = 1; |
1194 | cid.string = cid_add; | ||
1195 | |||
1196 | list = acpi_add_cid(info, &cid); | ||
1197 | } else { | ||
1198 | list = acpi_add_cid(info, NULL); | ||
1199 | } | ||
1200 | |||
1201 | if (list) { | ||
1202 | device->pnp.cid_list = list; | ||
1203 | if (cid_add) | ||
1204 | device->flags.compatible_ids = 1; | ||
1205 | } | ||
1206 | } | 1131 | } |
1207 | 1132 | ||
1208 | kfree(info); | 1133 | kfree(info); |
@@ -1269,6 +1194,7 @@ static int acpi_add_single_object(struct acpi_device **child, | |||
1269 | return -ENOMEM; | 1194 | return -ENOMEM; |
1270 | } | 1195 | } |
1271 | 1196 | ||
1197 | INIT_LIST_HEAD(&device->pnp.ids); | ||
1272 | device->device_type = type; | 1198 | device->device_type = type; |
1273 | device->handle = handle; | 1199 | device->handle = handle; |
1274 | device->parent = acpi_bus_get_parent(handle); | 1200 | device->parent = acpi_bus_get_parent(handle); |