diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 183 |
1 files changed, 110 insertions, 73 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 318b1ea7a5bf..408ebde18986 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -60,13 +60,13 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, | |||
60 | } | 60 | } |
61 | 61 | ||
62 | if (acpi_dev->flags.compatible_ids) { | 62 | if (acpi_dev->flags.compatible_ids) { |
63 | struct acpi_compatible_id_list *cid_list; | 63 | struct acpica_device_id_list *cid_list; |
64 | int i; | 64 | int i; |
65 | 65 | ||
66 | cid_list = acpi_dev->pnp.cid_list; | 66 | cid_list = acpi_dev->pnp.cid_list; |
67 | for (i = 0; i < cid_list->count; i++) { | 67 | for (i = 0; i < cid_list->count; i++) { |
68 | count = snprintf(&modalias[len], size, "%s:", | 68 | count = snprintf(&modalias[len], size, "%s:", |
69 | cid_list->id[i].value); | 69 | cid_list->ids[i].string); |
70 | if (count < 0 || count >= size) { | 70 | if (count < 0 || count >= size) { |
71 | printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", | 71 | printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", |
72 | acpi_dev->pnp.device_name, i); | 72 | acpi_dev->pnp.device_name, i); |
@@ -287,14 +287,14 @@ int acpi_match_device_ids(struct acpi_device *device, | |||
287 | } | 287 | } |
288 | 288 | ||
289 | if (device->flags.compatible_ids) { | 289 | if (device->flags.compatible_ids) { |
290 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; | 290 | struct acpica_device_id_list *cid_list = device->pnp.cid_list; |
291 | int i; | 291 | int i; |
292 | 292 | ||
293 | for (id = ids; id->id[0]; id++) { | 293 | for (id = ids; id->id[0]; id++) { |
294 | /* compare multiple _CID entries against driver ids */ | 294 | /* compare multiple _CID entries against driver ids */ |
295 | for (i = 0; i < cid_list->count; i++) { | 295 | for (i = 0; i < cid_list->count; i++) { |
296 | if (!strcmp((char*)id->id, | 296 | if (!strcmp((char*)id->id, |
297 | cid_list->id[i].value)) | 297 | cid_list->ids[i].string)) |
298 | return 0; | 298 | return 0; |
299 | } | 299 | } |
300 | } | 300 | } |
@@ -309,6 +309,10 @@ static void acpi_device_release(struct device *dev) | |||
309 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 309 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
310 | 310 | ||
311 | kfree(acpi_dev->pnp.cid_list); | 311 | kfree(acpi_dev->pnp.cid_list); |
312 | if (acpi_dev->flags.hardware_id) | ||
313 | kfree(acpi_dev->pnp.hardware_id); | ||
314 | if (acpi_dev->flags.unique_id) | ||
315 | kfree(acpi_dev->pnp.unique_id); | ||
312 | kfree(acpi_dev); | 316 | kfree(acpi_dev); |
313 | } | 317 | } |
314 | 318 | ||
@@ -366,7 +370,8 @@ static acpi_status acpi_device_notify_fixed(void *data) | |||
366 | { | 370 | { |
367 | struct acpi_device *device = data; | 371 | struct acpi_device *device = data; |
368 | 372 | ||
369 | acpi_device_notify(device->handle, ACPI_FIXED_HARDWARE_EVENT, device); | 373 | /* Fixed hardware devices have no handles */ |
374 | acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); | ||
370 | return AE_OK; | 375 | return AE_OK; |
371 | } | 376 | } |
372 | 377 | ||
@@ -426,9 +431,6 @@ static int acpi_device_probe(struct device * dev) | |||
426 | if (acpi_drv->ops.notify) { | 431 | if (acpi_drv->ops.notify) { |
427 | ret = acpi_device_install_notify_handler(acpi_dev); | 432 | ret = acpi_device_install_notify_handler(acpi_dev); |
428 | if (ret) { | 433 | if (ret) { |
429 | if (acpi_drv->ops.stop) | ||
430 | acpi_drv->ops.stop(acpi_dev, | ||
431 | acpi_dev->removal_type); | ||
432 | if (acpi_drv->ops.remove) | 434 | if (acpi_drv->ops.remove) |
433 | acpi_drv->ops.remove(acpi_dev, | 435 | acpi_drv->ops.remove(acpi_dev, |
434 | acpi_dev->removal_type); | 436 | acpi_dev->removal_type); |
@@ -452,8 +454,6 @@ static int acpi_device_remove(struct device * dev) | |||
452 | if (acpi_drv) { | 454 | if (acpi_drv) { |
453 | if (acpi_drv->ops.notify) | 455 | if (acpi_drv->ops.notify) |
454 | acpi_device_remove_notify_handler(acpi_dev); | 456 | acpi_device_remove_notify_handler(acpi_dev); |
455 | if (acpi_drv->ops.stop) | ||
456 | acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); | ||
457 | if (acpi_drv->ops.remove) | 457 | if (acpi_drv->ops.remove) |
458 | acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); | 458 | acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); |
459 | } | 459 | } |
@@ -687,7 +687,7 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) | |||
687 | } | 687 | } |
688 | EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); | 688 | EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); |
689 | 689 | ||
690 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) | 690 | void acpi_bus_data_handler(acpi_handle handle, void *context) |
691 | { | 691 | { |
692 | 692 | ||
693 | /* TBD */ | 693 | /* TBD */ |
@@ -1000,33 +1000,89 @@ static int acpi_dock_match(struct acpi_device *device) | |||
1000 | return acpi_get_handle(device->handle, "_DCK", &tmp); | 1000 | return acpi_get_handle(device->handle, "_DCK", &tmp); |
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | static struct acpica_device_id_list* | ||
1004 | acpi_add_cid( | ||
1005 | struct acpi_device_info *info, | ||
1006 | struct acpica_device_id *new_cid) | ||
1007 | { | ||
1008 | struct acpica_device_id_list *cid; | ||
1009 | char *next_id_string; | ||
1010 | acpi_size cid_length; | ||
1011 | acpi_size new_cid_length; | ||
1012 | u32 i; | ||
1013 | |||
1014 | |||
1015 | /* Allocate new CID list with room for the new CID */ | ||
1016 | |||
1017 | if (!new_cid) | ||
1018 | new_cid_length = info->compatible_id_list.list_size; | ||
1019 | else if (info->compatible_id_list.list_size) | ||
1020 | new_cid_length = info->compatible_id_list.list_size + | ||
1021 | new_cid->length + sizeof(struct acpica_device_id); | ||
1022 | else | ||
1023 | new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length; | ||
1024 | |||
1025 | cid = ACPI_ALLOCATE_ZEROED(new_cid_length); | ||
1026 | if (!cid) { | ||
1027 | return NULL; | ||
1028 | } | ||
1029 | |||
1030 | cid->list_size = new_cid_length; | ||
1031 | cid->count = info->compatible_id_list.count; | ||
1032 | if (new_cid) | ||
1033 | cid->count++; | ||
1034 | next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id)); | ||
1035 | |||
1036 | /* Copy all existing CIDs */ | ||
1037 | |||
1038 | for (i = 0; i < info->compatible_id_list.count; i++) { | ||
1039 | cid_length = info->compatible_id_list.ids[i].length; | ||
1040 | cid->ids[i].string = next_id_string; | ||
1041 | cid->ids[i].length = cid_length; | ||
1042 | |||
1043 | ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string, | ||
1044 | cid_length); | ||
1045 | |||
1046 | next_id_string += cid_length; | ||
1047 | } | ||
1048 | |||
1049 | /* Append the new CID */ | ||
1050 | |||
1051 | if (new_cid) { | ||
1052 | cid->ids[i].string = next_id_string; | ||
1053 | cid->ids[i].length = new_cid->length; | ||
1054 | |||
1055 | ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length); | ||
1056 | } | ||
1057 | |||
1058 | return cid; | ||
1059 | } | ||
1060 | |||
1003 | static void acpi_device_set_id(struct acpi_device *device, | 1061 | static void acpi_device_set_id(struct acpi_device *device, |
1004 | struct acpi_device *parent, acpi_handle handle, | 1062 | struct acpi_device *parent, acpi_handle handle, |
1005 | int type) | 1063 | int type) |
1006 | { | 1064 | { |
1007 | struct acpi_device_info *info; | 1065 | struct acpi_device_info *info = NULL; |
1008 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1009 | char *hid = NULL; | 1066 | char *hid = NULL; |
1010 | char *uid = NULL; | 1067 | char *uid = NULL; |
1011 | struct acpi_compatible_id_list *cid_list = NULL; | 1068 | struct acpica_device_id_list *cid_list = NULL; |
1012 | const char *cid_add = NULL; | 1069 | char *cid_add = NULL; |
1013 | acpi_status status; | 1070 | acpi_status status; |
1014 | 1071 | ||
1015 | switch (type) { | 1072 | switch (type) { |
1016 | case ACPI_BUS_TYPE_DEVICE: | 1073 | case ACPI_BUS_TYPE_DEVICE: |
1017 | status = acpi_get_object_info(handle, &buffer); | 1074 | status = acpi_get_object_info(handle, &info); |
1018 | if (ACPI_FAILURE(status)) { | 1075 | if (ACPI_FAILURE(status)) { |
1019 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); | 1076 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); |
1020 | return; | 1077 | return; |
1021 | } | 1078 | } |
1022 | 1079 | ||
1023 | info = buffer.pointer; | ||
1024 | if (info->valid & ACPI_VALID_HID) | 1080 | if (info->valid & ACPI_VALID_HID) |
1025 | hid = info->hardware_id.value; | 1081 | hid = info->hardware_id.string; |
1026 | if (info->valid & ACPI_VALID_UID) | 1082 | if (info->valid & ACPI_VALID_UID) |
1027 | uid = info->unique_id.value; | 1083 | uid = info->unique_id.string; |
1028 | if (info->valid & ACPI_VALID_CID) | 1084 | if (info->valid & ACPI_VALID_CID) |
1029 | cid_list = &info->compatibility_id; | 1085 | cid_list = &info->compatible_id_list; |
1030 | if (info->valid & ACPI_VALID_ADR) { | 1086 | if (info->valid & ACPI_VALID_ADR) { |
1031 | device->pnp.bus_address = info->address; | 1087 | device->pnp.bus_address = info->address; |
1032 | device->flags.bus_address = 1; | 1088 | device->flags.bus_address = 1; |
@@ -1077,55 +1133,46 @@ static void acpi_device_set_id(struct acpi_device *device, | |||
1077 | } | 1133 | } |
1078 | 1134 | ||
1079 | if (hid) { | 1135 | if (hid) { |
1080 | strcpy(device->pnp.hardware_id, hid); | 1136 | device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); |
1081 | device->flags.hardware_id = 1; | 1137 | if (device->pnp.hardware_id) { |
1138 | strcpy(device->pnp.hardware_id, hid); | ||
1139 | device->flags.hardware_id = 1; | ||
1140 | } | ||
1082 | } | 1141 | } |
1142 | if (!device->flags.hardware_id) | ||
1143 | device->pnp.hardware_id = ""; | ||
1144 | |||
1083 | if (uid) { | 1145 | if (uid) { |
1084 | strcpy(device->pnp.unique_id, uid); | 1146 | device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); |
1085 | device->flags.unique_id = 1; | 1147 | if (device->pnp.unique_id) { |
1148 | strcpy(device->pnp.unique_id, uid); | ||
1149 | device->flags.unique_id = 1; | ||
1150 | } | ||
1086 | } | 1151 | } |
1152 | if (!device->flags.unique_id) | ||
1153 | device->pnp.unique_id = ""; | ||
1154 | |||
1087 | if (cid_list || cid_add) { | 1155 | if (cid_list || cid_add) { |
1088 | struct acpi_compatible_id_list *list; | 1156 | struct acpica_device_id_list *list; |
1089 | int size = 0; | 1157 | |
1090 | int count = 0; | 1158 | if (cid_add) { |
1091 | 1159 | struct acpica_device_id cid; | |
1092 | if (cid_list) { | 1160 | cid.length = strlen (cid_add) + 1; |
1093 | size = cid_list->size; | 1161 | cid.string = cid_add; |
1094 | } else if (cid_add) { | 1162 | |
1095 | size = sizeof(struct acpi_compatible_id_list); | 1163 | list = acpi_add_cid(info, &cid); |
1096 | cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); | 1164 | } else { |
1097 | if (!cid_list) { | 1165 | list = acpi_add_cid(info, NULL); |
1098 | printk(KERN_ERR "Memory allocation error\n"); | ||
1099 | kfree(buffer.pointer); | ||
1100 | return; | ||
1101 | } else { | ||
1102 | cid_list->count = 0; | ||
1103 | cid_list->size = size; | ||
1104 | } | ||
1105 | } | 1166 | } |
1106 | if (cid_add) | ||
1107 | size += sizeof(struct acpi_compatible_id); | ||
1108 | list = kmalloc(size, GFP_KERNEL); | ||
1109 | 1167 | ||
1110 | if (list) { | 1168 | if (list) { |
1111 | if (cid_list) { | ||
1112 | memcpy(list, cid_list, cid_list->size); | ||
1113 | count = cid_list->count; | ||
1114 | } | ||
1115 | if (cid_add) { | ||
1116 | strncpy(list->id[count].value, cid_add, | ||
1117 | ACPI_MAX_CID_LENGTH); | ||
1118 | count++; | ||
1119 | device->flags.compatible_ids = 1; | ||
1120 | } | ||
1121 | list->size = size; | ||
1122 | list->count = count; | ||
1123 | device->pnp.cid_list = list; | 1169 | device->pnp.cid_list = list; |
1124 | } else | 1170 | if (cid_add) |
1125 | printk(KERN_ERR PREFIX "Memory allocation error\n"); | 1171 | device->flags.compatible_ids = 1; |
1172 | } | ||
1126 | } | 1173 | } |
1127 | 1174 | ||
1128 | kfree(buffer.pointer); | 1175 | kfree(info); |
1129 | } | 1176 | } |
1130 | 1177 | ||
1131 | static int acpi_device_set_context(struct acpi_device *device, int type) | 1178 | static int acpi_device_set_context(struct acpi_device *device, int type) |
@@ -1265,16 +1312,6 @@ acpi_add_single_object(struct acpi_device **child, | |||
1265 | acpi_device_set_id(device, parent, handle, type); | 1312 | acpi_device_set_id(device, parent, handle, type); |
1266 | 1313 | ||
1267 | /* | 1314 | /* |
1268 | * The ACPI device is attached to acpi handle before getting | ||
1269 | * the power/wakeup/peformance flags. Otherwise OS can't get | ||
1270 | * the corresponding ACPI device by the acpi handle in the course | ||
1271 | * of getting the power/wakeup/performance flags. | ||
1272 | */ | ||
1273 | result = acpi_device_set_context(device, type); | ||
1274 | if (result) | ||
1275 | goto end; | ||
1276 | |||
1277 | /* | ||
1278 | * Power Management | 1315 | * Power Management |
1279 | * ---------------- | 1316 | * ---------------- |
1280 | */ | 1317 | */ |
@@ -1304,6 +1341,8 @@ acpi_add_single_object(struct acpi_device **child, | |||
1304 | goto end; | 1341 | goto end; |
1305 | } | 1342 | } |
1306 | 1343 | ||
1344 | if ((result = acpi_device_set_context(device, type))) | ||
1345 | goto end; | ||
1307 | 1346 | ||
1308 | result = acpi_device_register(device, parent); | 1347 | result = acpi_device_register(device, parent); |
1309 | 1348 | ||
@@ -1318,10 +1357,8 @@ acpi_add_single_object(struct acpi_device **child, | |||
1318 | end: | 1357 | end: |
1319 | if (!result) | 1358 | if (!result) |
1320 | *child = device; | 1359 | *child = device; |
1321 | else { | 1360 | else |
1322 | kfree(device->pnp.cid_list); | 1361 | acpi_device_release(&device->dev); |
1323 | kfree(device); | ||
1324 | } | ||
1325 | 1362 | ||
1326 | return result; | 1363 | return result; |
1327 | } | 1364 | } |