diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 154 |
1 files changed, 139 insertions, 15 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1fcb8678665c..53502d1bbf26 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -29,6 +29,27 @@ extern struct acpi_device *acpi_root; | |||
29 | 29 | ||
30 | static const char *dummy_hid = "device"; | 30 | static const char *dummy_hid = "device"; |
31 | 31 | ||
32 | /* | ||
33 | * The following ACPI IDs are known to be suitable for representing as | ||
34 | * platform devices. | ||
35 | */ | ||
36 | static const struct acpi_device_id acpi_platform_device_ids[] = { | ||
37 | |||
38 | { "PNP0D40" }, | ||
39 | |||
40 | /* Haswell LPSS devices */ | ||
41 | { "INT33C0", 0 }, | ||
42 | { "INT33C1", 0 }, | ||
43 | { "INT33C2", 0 }, | ||
44 | { "INT33C3", 0 }, | ||
45 | { "INT33C4", 0 }, | ||
46 | { "INT33C5", 0 }, | ||
47 | { "INT33C6", 0 }, | ||
48 | { "INT33C7", 0 }, | ||
49 | |||
50 | { } | ||
51 | }; | ||
52 | |||
32 | static LIST_HEAD(acpi_device_list); | 53 | static LIST_HEAD(acpi_device_list); |
33 | static LIST_HEAD(acpi_bus_id_list); | 54 | static LIST_HEAD(acpi_bus_id_list); |
34 | DEFINE_MUTEX(acpi_device_lock); | 55 | DEFINE_MUTEX(acpi_device_lock); |
@@ -97,6 +118,7 @@ void acpi_bus_hot_remove_device(void *context) | |||
97 | struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context; | 118 | struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context; |
98 | struct acpi_device *device; | 119 | struct acpi_device *device; |
99 | acpi_handle handle = ej_event->handle; | 120 | acpi_handle handle = ej_event->handle; |
121 | acpi_handle temp; | ||
100 | struct acpi_object_list arg_list; | 122 | struct acpi_object_list arg_list; |
101 | union acpi_object arg; | 123 | union acpi_object arg; |
102 | acpi_status status = AE_OK; | 124 | acpi_status status = AE_OK; |
@@ -117,13 +139,16 @@ void acpi_bus_hot_remove_device(void *context) | |||
117 | goto err_out; | 139 | goto err_out; |
118 | } | 140 | } |
119 | 141 | ||
142 | /* device has been freed */ | ||
143 | device = NULL; | ||
144 | |||
120 | /* power off device */ | 145 | /* power off device */ |
121 | status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); | 146 | status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); |
122 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) | 147 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) |
123 | printk(KERN_WARNING PREFIX | 148 | printk(KERN_WARNING PREFIX |
124 | "Power-off device failed\n"); | 149 | "Power-off device failed\n"); |
125 | 150 | ||
126 | if (device->flags.lockable) { | 151 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) { |
127 | arg_list.count = 1; | 152 | arg_list.count = 1; |
128 | arg_list.pointer = &arg; | 153 | arg_list.pointer = &arg; |
129 | arg.type = ACPI_TYPE_INTEGER; | 154 | arg.type = ACPI_TYPE_INTEGER; |
@@ -157,6 +182,7 @@ err_out: | |||
157 | kfree(context); | 182 | kfree(context); |
158 | return; | 183 | return; |
159 | } | 184 | } |
185 | EXPORT_SYMBOL(acpi_bus_hot_remove_device); | ||
160 | 186 | ||
161 | static ssize_t | 187 | static ssize_t |
162 | acpi_eject_store(struct device *d, struct device_attribute *attr, | 188 | acpi_eject_store(struct device *d, struct device_attribute *attr, |
@@ -216,6 +242,25 @@ acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *bu | |||
216 | } | 242 | } |
217 | static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); | 243 | static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); |
218 | 244 | ||
245 | static ssize_t acpi_device_uid_show(struct device *dev, | ||
246 | struct device_attribute *attr, char *buf) | ||
247 | { | ||
248 | struct acpi_device *acpi_dev = to_acpi_device(dev); | ||
249 | |||
250 | return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); | ||
251 | } | ||
252 | static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); | ||
253 | |||
254 | static ssize_t acpi_device_adr_show(struct device *dev, | ||
255 | struct device_attribute *attr, char *buf) | ||
256 | { | ||
257 | struct acpi_device *acpi_dev = to_acpi_device(dev); | ||
258 | |||
259 | return sprintf(buf, "0x%08x\n", | ||
260 | (unsigned int)(acpi_dev->pnp.bus_address)); | ||
261 | } | ||
262 | static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); | ||
263 | |||
219 | static ssize_t | 264 | static ssize_t |
220 | acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { | 265 | acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { |
221 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 266 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
@@ -259,11 +304,21 @@ static ssize_t description_show(struct device *dev, | |||
259 | } | 304 | } |
260 | static DEVICE_ATTR(description, 0444, description_show, NULL); | 305 | static DEVICE_ATTR(description, 0444, description_show, NULL); |
261 | 306 | ||
307 | static ssize_t | ||
308 | acpi_device_sun_show(struct device *dev, struct device_attribute *attr, | ||
309 | char *buf) { | ||
310 | struct acpi_device *acpi_dev = to_acpi_device(dev); | ||
311 | |||
312 | return sprintf(buf, "%lu\n", acpi_dev->pnp.sun); | ||
313 | } | ||
314 | static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); | ||
315 | |||
262 | static int acpi_device_setup_files(struct acpi_device *dev) | 316 | static int acpi_device_setup_files(struct acpi_device *dev) |
263 | { | 317 | { |
264 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | 318 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; |
265 | acpi_status status; | 319 | acpi_status status; |
266 | acpi_handle temp; | 320 | acpi_handle temp; |
321 | unsigned long long sun; | ||
267 | int result = 0; | 322 | int result = 0; |
268 | 323 | ||
269 | /* | 324 | /* |
@@ -300,6 +355,21 @@ static int acpi_device_setup_files(struct acpi_device *dev) | |||
300 | goto end; | 355 | goto end; |
301 | } | 356 | } |
302 | 357 | ||
358 | if (dev->flags.bus_address) | ||
359 | result = device_create_file(&dev->dev, &dev_attr_adr); | ||
360 | if (dev->pnp.unique_id) | ||
361 | result = device_create_file(&dev->dev, &dev_attr_uid); | ||
362 | |||
363 | status = acpi_evaluate_integer(dev->handle, "_SUN", NULL, &sun); | ||
364 | if (ACPI_SUCCESS(status)) { | ||
365 | dev->pnp.sun = (unsigned long)sun; | ||
366 | result = device_create_file(&dev->dev, &dev_attr_sun); | ||
367 | if (result) | ||
368 | goto end; | ||
369 | } else { | ||
370 | dev->pnp.sun = (unsigned long)-1; | ||
371 | } | ||
372 | |||
303 | /* | 373 | /* |
304 | * If device has _EJ0, 'eject' file is created that is used to trigger | 374 | * If device has _EJ0, 'eject' file is created that is used to trigger |
305 | * hot-removal function from userland. | 375 | * hot-removal function from userland. |
@@ -331,6 +401,14 @@ static void acpi_device_remove_files(struct acpi_device *dev) | |||
331 | if (ACPI_SUCCESS(status)) | 401 | if (ACPI_SUCCESS(status)) |
332 | device_remove_file(&dev->dev, &dev_attr_eject); | 402 | device_remove_file(&dev->dev, &dev_attr_eject); |
333 | 403 | ||
404 | status = acpi_get_handle(dev->handle, "_SUN", &temp); | ||
405 | if (ACPI_SUCCESS(status)) | ||
406 | device_remove_file(&dev->dev, &dev_attr_sun); | ||
407 | |||
408 | if (dev->pnp.unique_id) | ||
409 | device_remove_file(&dev->dev, &dev_attr_uid); | ||
410 | if (dev->flags.bus_address) | ||
411 | device_remove_file(&dev->dev, &dev_attr_adr); | ||
334 | device_remove_file(&dev->dev, &dev_attr_modalias); | 412 | device_remove_file(&dev->dev, &dev_attr_modalias); |
335 | device_remove_file(&dev->dev, &dev_attr_hid); | 413 | device_remove_file(&dev->dev, &dev_attr_hid); |
336 | if (dev->handle) | 414 | if (dev->handle) |
@@ -340,8 +418,8 @@ static void acpi_device_remove_files(struct acpi_device *dev) | |||
340 | ACPI Bus operations | 418 | ACPI Bus operations |
341 | -------------------------------------------------------------------------- */ | 419 | -------------------------------------------------------------------------- */ |
342 | 420 | ||
343 | int acpi_match_device_ids(struct acpi_device *device, | 421 | static const struct acpi_device_id *__acpi_match_device( |
344 | const struct acpi_device_id *ids) | 422 | struct acpi_device *device, const struct acpi_device_id *ids) |
345 | { | 423 | { |
346 | const struct acpi_device_id *id; | 424 | const struct acpi_device_id *id; |
347 | struct acpi_hardware_id *hwid; | 425 | struct acpi_hardware_id *hwid; |
@@ -351,14 +429,44 @@ int acpi_match_device_ids(struct acpi_device *device, | |||
351 | * driver for it. | 429 | * driver for it. |
352 | */ | 430 | */ |
353 | if (!device->status.present) | 431 | if (!device->status.present) |
354 | return -ENODEV; | 432 | return NULL; |
355 | 433 | ||
356 | for (id = ids; id->id[0]; id++) | 434 | for (id = ids; id->id[0]; id++) |
357 | list_for_each_entry(hwid, &device->pnp.ids, list) | 435 | list_for_each_entry(hwid, &device->pnp.ids, list) |
358 | if (!strcmp((char *) id->id, hwid->id)) | 436 | if (!strcmp((char *) id->id, hwid->id)) |
359 | return 0; | 437 | return id; |
360 | 438 | ||
361 | return -ENOENT; | 439 | return NULL; |
440 | } | ||
441 | |||
442 | /** | ||
443 | * acpi_match_device - Match a struct device against a given list of ACPI IDs | ||
444 | * @ids: Array of struct acpi_device_id object to match against. | ||
445 | * @dev: The device structure to match. | ||
446 | * | ||
447 | * Check if @dev has a valid ACPI handle and if there is a struct acpi_device | ||
448 | * object for that handle and use that object to match against a given list of | ||
449 | * device IDs. | ||
450 | * | ||
451 | * Return a pointer to the first matching ID on success or %NULL on failure. | ||
452 | */ | ||
453 | const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, | ||
454 | const struct device *dev) | ||
455 | { | ||
456 | struct acpi_device *adev; | ||
457 | |||
458 | if (!ids || !ACPI_HANDLE(dev) | ||
459 | || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev))) | ||
460 | return NULL; | ||
461 | |||
462 | return __acpi_match_device(adev, ids); | ||
463 | } | ||
464 | EXPORT_SYMBOL_GPL(acpi_match_device); | ||
465 | |||
466 | int acpi_match_device_ids(struct acpi_device *device, | ||
467 | const struct acpi_device_id *ids) | ||
468 | { | ||
469 | return __acpi_match_device(device, ids) ? 0 : -ENOENT; | ||
362 | } | 470 | } |
363 | EXPORT_SYMBOL(acpi_match_device_ids); | 471 | EXPORT_SYMBOL(acpi_match_device_ids); |
364 | 472 | ||
@@ -377,6 +485,7 @@ static void acpi_device_release(struct device *dev) | |||
377 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 485 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
378 | 486 | ||
379 | acpi_free_ids(acpi_dev); | 487 | acpi_free_ids(acpi_dev); |
488 | kfree(acpi_dev->pnp.unique_id); | ||
380 | kfree(acpi_dev); | 489 | kfree(acpi_dev); |
381 | } | 490 | } |
382 | 491 | ||
@@ -859,8 +968,8 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, | |||
859 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | 968 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) |
860 | { | 969 | { |
861 | struct acpi_device_id button_device_ids[] = { | 970 | struct acpi_device_id button_device_ids[] = { |
862 | {"PNP0C0D", 0}, | ||
863 | {"PNP0C0C", 0}, | 971 | {"PNP0C0C", 0}, |
972 | {"PNP0C0D", 0}, | ||
864 | {"PNP0C0E", 0}, | 973 | {"PNP0C0E", 0}, |
865 | {"", 0}, | 974 | {"", 0}, |
866 | }; | 975 | }; |
@@ -872,6 +981,11 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | |||
872 | /* Power button, Lid switch always enable wakeup */ | 981 | /* Power button, Lid switch always enable wakeup */ |
873 | if (!acpi_match_device_ids(device, button_device_ids)) { | 982 | if (!acpi_match_device_ids(device, button_device_ids)) { |
874 | device->wakeup.flags.run_wake = 1; | 983 | device->wakeup.flags.run_wake = 1; |
984 | if (!acpi_match_device_ids(device, &button_device_ids[1])) { | ||
985 | /* Do not use Lid/sleep button for S5 wakeup */ | ||
986 | if (device->wakeup.sleep_state == ACPI_STATE_S5) | ||
987 | device->wakeup.sleep_state = ACPI_STATE_S4; | ||
988 | } | ||
875 | device_set_wakeup_capable(&device->dev, true); | 989 | device_set_wakeup_capable(&device->dev, true); |
876 | return; | 990 | return; |
877 | } | 991 | } |
@@ -965,8 +1079,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
965 | * D3hot is only valid if _PR3 present. | 1079 | * D3hot is only valid if _PR3 present. |
966 | */ | 1080 | */ |
967 | if (ps->resources.count || | 1081 | if (ps->resources.count || |
968 | (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) | 1082 | (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) { |
969 | ps->flags.valid = 1; | 1083 | ps->flags.valid = 1; |
1084 | ps->flags.os_accessible = 1; | ||
1085 | } | ||
970 | 1086 | ||
971 | ps->power = -1; /* Unknown - driver assigned */ | 1087 | ps->power = -1; /* Unknown - driver assigned */ |
972 | ps->latency = -1; /* Unknown - driver assigned */ | 1088 | ps->latency = -1; /* Unknown - driver assigned */ |
@@ -982,6 +1098,11 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
982 | if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set) | 1098 | if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set) |
983 | device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1; | 1099 | device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1; |
984 | 1100 | ||
1101 | /* Presence of _PS3 or _PRx means we can put the device into D3 cold */ | ||
1102 | if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set || | ||
1103 | device->power.flags.power_resources) | ||
1104 | device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; | ||
1105 | |||
985 | acpi_bus_init_power(device); | 1106 | acpi_bus_init_power(device); |
986 | 1107 | ||
987 | return 0; | 1108 | return 0; |
@@ -1013,11 +1134,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) | |||
1013 | device->flags.ejectable = 1; | 1134 | device->flags.ejectable = 1; |
1014 | } | 1135 | } |
1015 | 1136 | ||
1016 | /* Presence of _LCK indicates 'lockable' */ | ||
1017 | status = acpi_get_handle(device->handle, "_LCK", &temp); | ||
1018 | if (ACPI_SUCCESS(status)) | ||
1019 | device->flags.lockable = 1; | ||
1020 | |||
1021 | /* Power resources cannot be power manageable. */ | 1137 | /* Power resources cannot be power manageable. */ |
1022 | if (device->device_type == ACPI_BUS_TYPE_POWER) | 1138 | if (device->device_type == ACPI_BUS_TYPE_POWER) |
1023 | return 0; | 1139 | return 0; |
@@ -1185,7 +1301,7 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1185 | { | 1301 | { |
1186 | acpi_status status; | 1302 | acpi_status status; |
1187 | struct acpi_device_info *info; | 1303 | struct acpi_device_info *info; |
1188 | struct acpica_device_id_list *cid_list; | 1304 | struct acpi_pnp_device_id_list *cid_list; |
1189 | int i; | 1305 | int i; |
1190 | 1306 | ||
1191 | switch (device->device_type) { | 1307 | switch (device->device_type) { |
@@ -1212,6 +1328,9 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1212 | device->pnp.bus_address = info->address; | 1328 | device->pnp.bus_address = info->address; |
1213 | device->flags.bus_address = 1; | 1329 | device->flags.bus_address = 1; |
1214 | } | 1330 | } |
1331 | if (info->valid & ACPI_VALID_UID) | ||
1332 | device->pnp.unique_id = kstrdup(info->unique_id.string, | ||
1333 | GFP_KERNEL); | ||
1215 | 1334 | ||
1216 | kfree(info); | 1335 | kfree(info); |
1217 | 1336 | ||
@@ -1483,8 +1602,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, | |||
1483 | */ | 1602 | */ |
1484 | device = NULL; | 1603 | device = NULL; |
1485 | acpi_bus_get_device(handle, &device); | 1604 | acpi_bus_get_device(handle, &device); |
1486 | if (ops->acpi_op_add && !device) | 1605 | if (ops->acpi_op_add && !device) { |
1487 | acpi_add_single_object(&device, handle, type, sta, ops); | 1606 | acpi_add_single_object(&device, handle, type, sta, ops); |
1607 | /* Is the device a known good platform device? */ | ||
1608 | if (device | ||
1609 | && !acpi_match_device_ids(device, acpi_platform_device_ids)) | ||
1610 | acpi_create_platform_device(device); | ||
1611 | } | ||
1488 | 1612 | ||
1489 | if (!device) | 1613 | if (!device) |
1490 | return AE_CTRL_DEPTH; | 1614 | return AE_CTRL_DEPTH; |