aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r--drivers/acpi/scan.c154
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
30static const char *dummy_hid = "device"; 30static 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 */
36static 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
32static LIST_HEAD(acpi_device_list); 53static LIST_HEAD(acpi_device_list);
33static LIST_HEAD(acpi_bus_id_list); 54static LIST_HEAD(acpi_bus_id_list);
34DEFINE_MUTEX(acpi_device_lock); 55DEFINE_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}
185EXPORT_SYMBOL(acpi_bus_hot_remove_device);
160 186
161static ssize_t 187static ssize_t
162acpi_eject_store(struct device *d, struct device_attribute *attr, 188acpi_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}
217static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); 243static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
218 244
245static 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}
252static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
253
254static 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}
262static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
263
219static ssize_t 264static ssize_t
220acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { 265acpi_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}
260static DEVICE_ATTR(description, 0444, description_show, NULL); 305static DEVICE_ATTR(description, 0444, description_show, NULL);
261 306
307static ssize_t
308acpi_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}
314static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
315
262static int acpi_device_setup_files(struct acpi_device *dev) 316static 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
343int acpi_match_device_ids(struct acpi_device *device, 421static 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 */
453const 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}
464EXPORT_SYMBOL_GPL(acpi_match_device);
465
466int 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}
363EXPORT_SYMBOL(acpi_match_device_ids); 471EXPORT_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,
859static void acpi_bus_set_run_wake_flags(struct acpi_device *device) 968static 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;