diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-27 19:53:34 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-27 19:53:34 -0400 |
commit | 929c6dd4195f6b4daf9887da34b3d7fbd0f2e2f5 (patch) | |
tree | 1eb36e31b2e3ca5a747d86689b9fa92dec227272 | |
parent | 60d509fa6a9c4653a86ad830e4c4b30360b23f0e (diff) | |
parent | fd4655c259fa91b3b207345eb7b4d9faa1b6bc8d (diff) |
Merge branch 'acpi-hotplug'
* acpi-hotplug:
ACPI / memhotplug: Remove info->failed bit
ACPI / memhotplug: set info->enabled for memory present at boot time
ACPI: Verify device status after eject
acpi: remove reference to ACPI_HOTPLUG_IO
ACPI: Update _OST handling for notify
ACPI: Update PNPID match handling for notify
ACPI: Update PNPID set/free interfaces
ACPI: Remove acpi_device dependency in acpi_device_set_id()
ACPI / hotplug: Make acpi_hotplug_profile_ktype static
ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
ACPI / container: Use hotplug profile user space interface
ACPI / hotplug: Introduce user space interface for hotplug profiles
ACPI / scan: Introduce acpi_scan_handler_matching()
ACPI / container: Use common hotplug code
ACPI / scan: Introduce common code for ACPI-based device hotplug
ACPI / scan: Introduce acpi_scan_match_handler()
-rw-r--r-- | Documentation/ABI/testing/sysfs-firmware-acpi | 26 | ||||
-rw-r--r-- | drivers/acpi/Kconfig | 5 | ||||
-rw-r--r-- | drivers/acpi/acpi_memhotplug.c | 328 | ||||
-rw-r--r-- | drivers/acpi/container.c | 150 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 13 | ||||
-rw-r--r-- | drivers/acpi/power.c | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 530 | ||||
-rw-r--r-- | drivers/acpi/sysfs.c | 66 | ||||
-rw-r--r-- | drivers/acpi/video_detect.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_opregion.c | 4 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 33 | ||||
-rw-r--r-- | include/linux/acpi.h | 4 |
12 files changed, 597 insertions, 589 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi index dd930c8db41f..ce9bee98b43b 100644 --- a/Documentation/ABI/testing/sysfs-firmware-acpi +++ b/Documentation/ABI/testing/sysfs-firmware-acpi | |||
@@ -18,6 +18,32 @@ Description: | |||
18 | yoffset: The number of pixels between the top of the screen | 18 | yoffset: The number of pixels between the top of the screen |
19 | and the top edge of the image. | 19 | and the top edge of the image. |
20 | 20 | ||
21 | What: /sys/firmware/acpi/hotplug/ | ||
22 | Date: February 2013 | ||
23 | Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
24 | Description: | ||
25 | There are separate hotplug profiles for different classes of | ||
26 | devices supported by ACPI, such as containers, memory modules, | ||
27 | processors, PCI root bridges etc. A hotplug profile for a given | ||
28 | class of devices is a collection of settings defining the way | ||
29 | that class of devices will be handled by the ACPI core hotplug | ||
30 | code. Those profiles are represented in sysfs as subdirectories | ||
31 | of /sys/firmware/acpi/hotplug/. | ||
32 | |||
33 | The following setting is available to user space for each | ||
34 | hotplug profile: | ||
35 | |||
36 | enabled: If set, the ACPI core will handle notifications of | ||
37 | hotplug events associated with the given class of | ||
38 | devices and will allow those devices to be ejected with | ||
39 | the help of the _EJ0 control method. Unsetting it | ||
40 | effectively disables hotplug for the correspoinding | ||
41 | class of devices. | ||
42 | |||
43 | The value of the above attribute is an integer number: 1 (set) | ||
44 | or 0 (unset). Attempts to write any other values to it will | ||
45 | cause -EINVAL to be returned. | ||
46 | |||
21 | What: /sys/firmware/acpi/interrupts/ | 47 | What: /sys/firmware/acpi/interrupts/ |
22 | Date: February 2008 | 48 | Date: February 2008 |
23 | Contact: Len Brown <lenb@kernel.org> | 49 | Contact: Len Brown <lenb@kernel.org> |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4bf68c8d4797..8fcae6df0a42 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -334,7 +334,7 @@ config X86_PM_TIMER | |||
334 | 334 | ||
335 | config ACPI_CONTAINER | 335 | config ACPI_CONTAINER |
336 | bool "Container and Module Devices" | 336 | bool "Container and Module Devices" |
337 | default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO) | 337 | default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU) |
338 | help | 338 | help |
339 | This driver supports ACPI Container and Module devices (IDs | 339 | This driver supports ACPI Container and Module devices (IDs |
340 | ACPI0004, PNP0A05, and PNP0A06). | 340 | ACPI0004, PNP0A05, and PNP0A06). |
@@ -345,9 +345,8 @@ config ACPI_CONTAINER | |||
345 | the module will be called container. | 345 | the module will be called container. |
346 | 346 | ||
347 | config ACPI_HOTPLUG_MEMORY | 347 | config ACPI_HOTPLUG_MEMORY |
348 | tristate "Memory Hotplug" | 348 | bool "Memory Hotplug" |
349 | depends on MEMORY_HOTPLUG | 349 | depends on MEMORY_HOTPLUG |
350 | default n | ||
351 | help | 350 | help |
352 | This driver supports ACPI memory hotplug. The driver | 351 | This driver supports ACPI memory hotplug. The driver |
353 | fields notifications on ACPI memory devices (PNP0C80), | 352 | fields notifications on ACPI memory devices (PNP0C80), |
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index da1f82b445e0..5e6301e94920 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com> | 2 | * Copyright (C) 2004, 2013 Intel Corporation |
3 | * Author: Naveen B S <naveen.b.s@intel.com> | ||
4 | * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
3 | * | 5 | * |
4 | * All rights reserved. | 6 | * All rights reserved. |
5 | * | 7 | * |
@@ -25,14 +27,10 @@ | |||
25 | * ranges. | 27 | * ranges. |
26 | */ | 28 | */ |
27 | 29 | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/types.h> | ||
32 | #include <linux/memory_hotplug.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
35 | #include <acpi/acpi_drivers.h> | 31 | #include <linux/memory_hotplug.h> |
32 | |||
33 | #include "internal.h" | ||
36 | 34 | ||
37 | #define ACPI_MEMORY_DEVICE_CLASS "memory" | 35 | #define ACPI_MEMORY_DEVICE_CLASS "memory" |
38 | #define ACPI_MEMORY_DEVICE_HID "PNP0C80" | 36 | #define ACPI_MEMORY_DEVICE_HID "PNP0C80" |
@@ -44,32 +42,28 @@ | |||
44 | #define PREFIX "ACPI:memory_hp:" | 42 | #define PREFIX "ACPI:memory_hp:" |
45 | 43 | ||
46 | ACPI_MODULE_NAME("acpi_memhotplug"); | 44 | ACPI_MODULE_NAME("acpi_memhotplug"); |
47 | MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); | ||
48 | MODULE_DESCRIPTION("Hotplug Mem Driver"); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | 45 | ||
51 | /* Memory Device States */ | 46 | /* Memory Device States */ |
52 | #define MEMORY_INVALID_STATE 0 | 47 | #define MEMORY_INVALID_STATE 0 |
53 | #define MEMORY_POWER_ON_STATE 1 | 48 | #define MEMORY_POWER_ON_STATE 1 |
54 | #define MEMORY_POWER_OFF_STATE 2 | 49 | #define MEMORY_POWER_OFF_STATE 2 |
55 | 50 | ||
56 | static int acpi_memory_device_add(struct acpi_device *device); | 51 | static int acpi_memory_device_add(struct acpi_device *device, |
57 | static int acpi_memory_device_remove(struct acpi_device *device); | 52 | const struct acpi_device_id *not_used); |
53 | static void acpi_memory_device_remove(struct acpi_device *device); | ||
58 | 54 | ||
59 | static const struct acpi_device_id memory_device_ids[] = { | 55 | static const struct acpi_device_id memory_device_ids[] = { |
60 | {ACPI_MEMORY_DEVICE_HID, 0}, | 56 | {ACPI_MEMORY_DEVICE_HID, 0}, |
61 | {"", 0}, | 57 | {"", 0}, |
62 | }; | 58 | }; |
63 | MODULE_DEVICE_TABLE(acpi, memory_device_ids); | ||
64 | 59 | ||
65 | static struct acpi_driver acpi_memory_device_driver = { | 60 | static struct acpi_scan_handler memory_device_handler = { |
66 | .name = "acpi_memhotplug", | ||
67 | .class = ACPI_MEMORY_DEVICE_CLASS, | ||
68 | .ids = memory_device_ids, | 61 | .ids = memory_device_ids, |
69 | .ops = { | 62 | .attach = acpi_memory_device_add, |
70 | .add = acpi_memory_device_add, | 63 | .detach = acpi_memory_device_remove, |
71 | .remove = acpi_memory_device_remove, | 64 | .hotplug = { |
72 | }, | 65 | .enabled = true, |
66 | }, | ||
73 | }; | 67 | }; |
74 | 68 | ||
75 | struct acpi_memory_info { | 69 | struct acpi_memory_info { |
@@ -79,7 +73,6 @@ struct acpi_memory_info { | |||
79 | unsigned short caching; /* memory cache attribute */ | 73 | unsigned short caching; /* memory cache attribute */ |
80 | unsigned short write_protect; /* memory read/write attribute */ | 74 | unsigned short write_protect; /* memory read/write attribute */ |
81 | unsigned int enabled:1; | 75 | unsigned int enabled:1; |
82 | unsigned int failed:1; | ||
83 | }; | 76 | }; |
84 | 77 | ||
85 | struct acpi_memory_device { | 78 | struct acpi_memory_device { |
@@ -153,48 +146,6 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) | |||
153 | return 0; | 146 | return 0; |
154 | } | 147 | } |
155 | 148 | ||
156 | static int acpi_memory_get_device(acpi_handle handle, | ||
157 | struct acpi_memory_device **mem_device) | ||
158 | { | ||
159 | struct acpi_device *device = NULL; | ||
160 | int result = 0; | ||
161 | |||
162 | acpi_scan_lock_acquire(); | ||
163 | |||
164 | acpi_bus_get_device(handle, &device); | ||
165 | if (device) | ||
166 | goto end; | ||
167 | |||
168 | /* | ||
169 | * Now add the notified device. This creates the acpi_device | ||
170 | * and invokes .add function | ||
171 | */ | ||
172 | result = acpi_bus_scan(handle); | ||
173 | if (result) { | ||
174 | acpi_handle_warn(handle, "ACPI namespace scan failed\n"); | ||
175 | result = -EINVAL; | ||
176 | goto out; | ||
177 | } | ||
178 | result = acpi_bus_get_device(handle, &device); | ||
179 | if (result) { | ||
180 | acpi_handle_warn(handle, "Missing device object\n"); | ||
181 | result = -EINVAL; | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | end: | ||
186 | *mem_device = acpi_driver_data(device); | ||
187 | if (!(*mem_device)) { | ||
188 | dev_err(&device->dev, "driver data not found\n"); | ||
189 | result = -ENODEV; | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | out: | ||
194 | acpi_scan_lock_release(); | ||
195 | return result; | ||
196 | } | ||
197 | |||
198 | static int acpi_memory_check_device(struct acpi_memory_device *mem_device) | 149 | static int acpi_memory_check_device(struct acpi_memory_device *mem_device) |
199 | { | 150 | { |
200 | unsigned long long current_status; | 151 | unsigned long long current_status; |
@@ -249,13 +200,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) | |||
249 | * returns -EEXIST. If add_memory() returns the other error, it | 200 | * returns -EEXIST. If add_memory() returns the other error, it |
250 | * means that this memory block is not used by the kernel. | 201 | * means that this memory block is not used by the kernel. |
251 | */ | 202 | */ |
252 | if (result && result != -EEXIST) { | 203 | if (result && result != -EEXIST) |
253 | info->failed = 1; | ||
254 | continue; | 204 | continue; |
255 | } | ||
256 | 205 | ||
257 | if (!result) | 206 | info->enabled = 1; |
258 | info->enabled = 1; | 207 | |
259 | /* | 208 | /* |
260 | * Add num_enable even if add_memory() returns -EEXIST, so the | 209 | * Add num_enable even if add_memory() returns -EEXIST, so the |
261 | * device is bound to this driver. | 210 | * device is bound to this driver. |
@@ -286,16 +235,8 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) | |||
286 | nid = acpi_get_node(mem_device->device->handle); | 235 | nid = acpi_get_node(mem_device->device->handle); |
287 | 236 | ||
288 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { | 237 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { |
289 | if (info->failed) | ||
290 | /* The kernel does not use this memory block */ | ||
291 | continue; | ||
292 | |||
293 | if (!info->enabled) | 238 | if (!info->enabled) |
294 | /* | 239 | continue; |
295 | * The kernel uses this memory block, but it may be not | ||
296 | * managed by us. | ||
297 | */ | ||
298 | return -EBUSY; | ||
299 | 240 | ||
300 | if (nid < 0) | 241 | if (nid < 0) |
301 | nid = memory_add_physaddr_to_nid(info->start_addr); | 242 | nid = memory_add_physaddr_to_nid(info->start_addr); |
@@ -310,95 +251,21 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) | |||
310 | return result; | 251 | return result; |
311 | } | 252 | } |
312 | 253 | ||
313 | static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) | ||
314 | { | ||
315 | struct acpi_memory_device *mem_device; | ||
316 | struct acpi_device *device; | ||
317 | struct acpi_eject_event *ej_event = NULL; | ||
318 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ | ||
319 | acpi_status status; | ||
320 | |||
321 | switch (event) { | ||
322 | case ACPI_NOTIFY_BUS_CHECK: | ||
323 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
324 | "\nReceived BUS CHECK notification for device\n")); | ||
325 | /* Fall Through */ | ||
326 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
327 | if (event == ACPI_NOTIFY_DEVICE_CHECK) | ||
328 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
329 | "\nReceived DEVICE CHECK notification for device\n")); | ||
330 | if (acpi_memory_get_device(handle, &mem_device)) { | ||
331 | acpi_handle_err(handle, "Cannot find driver data\n"); | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | ost_code = ACPI_OST_SC_SUCCESS; | ||
336 | break; | ||
337 | |||
338 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
339 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
340 | "\nReceived EJECT REQUEST notification for device\n")); | ||
341 | |||
342 | status = AE_ERROR; | ||
343 | acpi_scan_lock_acquire(); | ||
344 | |||
345 | if (acpi_bus_get_device(handle, &device)) { | ||
346 | acpi_handle_err(handle, "Device doesn't exist\n"); | ||
347 | goto unlock; | ||
348 | } | ||
349 | mem_device = acpi_driver_data(device); | ||
350 | if (!mem_device) { | ||
351 | acpi_handle_err(handle, "Driver Data is NULL\n"); | ||
352 | goto unlock; | ||
353 | } | ||
354 | |||
355 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); | ||
356 | if (!ej_event) { | ||
357 | pr_err(PREFIX "No memory, dropping EJECT\n"); | ||
358 | goto unlock; | ||
359 | } | ||
360 | |||
361 | get_device(&device->dev); | ||
362 | ej_event->device = device; | ||
363 | ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; | ||
364 | /* The eject is carried out asynchronously. */ | ||
365 | status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, | ||
366 | ej_event); | ||
367 | if (ACPI_FAILURE(status)) { | ||
368 | put_device(&device->dev); | ||
369 | kfree(ej_event); | ||
370 | } | ||
371 | |||
372 | unlock: | ||
373 | acpi_scan_lock_release(); | ||
374 | if (ACPI_SUCCESS(status)) | ||
375 | return; | ||
376 | default: | ||
377 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
378 | "Unsupported event [0x%x]\n", event)); | ||
379 | |||
380 | /* non-hotplug event; possibly handled by other handler */ | ||
381 | return; | ||
382 | } | ||
383 | |||
384 | /* Inform firmware that the hotplug operation has completed */ | ||
385 | (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL); | ||
386 | } | ||
387 | |||
388 | static void acpi_memory_device_free(struct acpi_memory_device *mem_device) | 254 | static void acpi_memory_device_free(struct acpi_memory_device *mem_device) |
389 | { | 255 | { |
390 | if (!mem_device) | 256 | if (!mem_device) |
391 | return; | 257 | return; |
392 | 258 | ||
393 | acpi_memory_free_device_resources(mem_device); | 259 | acpi_memory_free_device_resources(mem_device); |
260 | mem_device->device->driver_data = NULL; | ||
394 | kfree(mem_device); | 261 | kfree(mem_device); |
395 | } | 262 | } |
396 | 263 | ||
397 | static int acpi_memory_device_add(struct acpi_device *device) | 264 | static int acpi_memory_device_add(struct acpi_device *device, |
265 | const struct acpi_device_id *not_used) | ||
398 | { | 266 | { |
267 | struct acpi_memory_device *mem_device; | ||
399 | int result; | 268 | int result; |
400 | struct acpi_memory_device *mem_device = NULL; | ||
401 | |||
402 | 269 | ||
403 | if (!device) | 270 | if (!device) |
404 | return -EINVAL; | 271 | return -EINVAL; |
@@ -423,147 +290,36 @@ static int acpi_memory_device_add(struct acpi_device *device) | |||
423 | /* Set the device state */ | 290 | /* Set the device state */ |
424 | mem_device->state = MEMORY_POWER_ON_STATE; | 291 | mem_device->state = MEMORY_POWER_ON_STATE; |
425 | 292 | ||
426 | pr_debug("%s\n", acpi_device_name(device)); | 293 | result = acpi_memory_check_device(mem_device); |
294 | if (result) { | ||
295 | acpi_memory_device_free(mem_device); | ||
296 | return 0; | ||
297 | } | ||
427 | 298 | ||
428 | if (!acpi_memory_check_device(mem_device)) { | 299 | result = acpi_memory_enable_device(mem_device); |
429 | /* call add_memory func */ | 300 | if (result) { |
430 | result = acpi_memory_enable_device(mem_device); | 301 | dev_err(&device->dev, "acpi_memory_enable_device() error\n"); |
431 | if (result) { | 302 | acpi_memory_device_free(mem_device); |
432 | dev_err(&device->dev, | 303 | return -ENODEV; |
433 | "Error in acpi_memory_enable_device\n"); | ||
434 | acpi_memory_device_free(mem_device); | ||
435 | } | ||
436 | } | 304 | } |
437 | return result; | 305 | |
306 | dev_dbg(&device->dev, "Memory device configured by ACPI\n"); | ||
307 | return 1; | ||
438 | } | 308 | } |
439 | 309 | ||
440 | static int acpi_memory_device_remove(struct acpi_device *device) | 310 | static void acpi_memory_device_remove(struct acpi_device *device) |
441 | { | 311 | { |
442 | struct acpi_memory_device *mem_device = NULL; | 312 | struct acpi_memory_device *mem_device; |
443 | int result; | ||
444 | 313 | ||
445 | if (!device || !acpi_driver_data(device)) | 314 | if (!device || !acpi_driver_data(device)) |
446 | return -EINVAL; | 315 | return; |
447 | 316 | ||
448 | mem_device = acpi_driver_data(device); | 317 | mem_device = acpi_driver_data(device); |
449 | 318 | acpi_memory_remove_memory(mem_device); | |
450 | result = acpi_memory_remove_memory(mem_device); | ||
451 | if (result) | ||
452 | return result; | ||
453 | |||
454 | acpi_memory_device_free(mem_device); | 319 | acpi_memory_device_free(mem_device); |
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * Helper function to check for memory device | ||
461 | */ | ||
462 | static acpi_status is_memory_device(acpi_handle handle) | ||
463 | { | ||
464 | char *hardware_id; | ||
465 | acpi_status status; | ||
466 | struct acpi_device_info *info; | ||
467 | |||
468 | status = acpi_get_object_info(handle, &info); | ||
469 | if (ACPI_FAILURE(status)) | ||
470 | return status; | ||
471 | |||
472 | if (!(info->valid & ACPI_VALID_HID)) { | ||
473 | kfree(info); | ||
474 | return AE_ERROR; | ||
475 | } | ||
476 | |||
477 | hardware_id = info->hardware_id.string; | ||
478 | if ((hardware_id == NULL) || | ||
479 | (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID))) | ||
480 | status = AE_ERROR; | ||
481 | |||
482 | kfree(info); | ||
483 | return status; | ||
484 | } | ||
485 | |||
486 | static acpi_status | ||
487 | acpi_memory_register_notify_handler(acpi_handle handle, | ||
488 | u32 level, void *ctxt, void **retv) | ||
489 | { | ||
490 | acpi_status status; | ||
491 | |||
492 | |||
493 | status = is_memory_device(handle); | ||
494 | if (ACPI_FAILURE(status)) | ||
495 | return AE_OK; /* continue */ | ||
496 | |||
497 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
498 | acpi_memory_device_notify, NULL); | ||
499 | /* continue */ | ||
500 | return AE_OK; | ||
501 | } | ||
502 | |||
503 | static acpi_status | ||
504 | acpi_memory_deregister_notify_handler(acpi_handle handle, | ||
505 | u32 level, void *ctxt, void **retv) | ||
506 | { | ||
507 | acpi_status status; | ||
508 | |||
509 | |||
510 | status = is_memory_device(handle); | ||
511 | if (ACPI_FAILURE(status)) | ||
512 | return AE_OK; /* continue */ | ||
513 | |||
514 | status = acpi_remove_notify_handler(handle, | ||
515 | ACPI_SYSTEM_NOTIFY, | ||
516 | acpi_memory_device_notify); | ||
517 | |||
518 | return AE_OK; /* continue */ | ||
519 | } | ||
520 | |||
521 | static int __init acpi_memory_device_init(void) | ||
522 | { | ||
523 | int result; | ||
524 | acpi_status status; | ||
525 | |||
526 | |||
527 | result = acpi_bus_register_driver(&acpi_memory_device_driver); | ||
528 | |||
529 | if (result < 0) | ||
530 | return -ENODEV; | ||
531 | |||
532 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
533 | ACPI_UINT32_MAX, | ||
534 | acpi_memory_register_notify_handler, NULL, | ||
535 | NULL, NULL); | ||
536 | |||
537 | if (ACPI_FAILURE(status)) { | ||
538 | ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed")); | ||
539 | acpi_bus_unregister_driver(&acpi_memory_device_driver); | ||
540 | return -ENODEV; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | } | 320 | } |
545 | 321 | ||
546 | static void __exit acpi_memory_device_exit(void) | 322 | void __init acpi_memory_hotplug_init(void) |
547 | { | 323 | { |
548 | acpi_status status; | 324 | acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); |
549 | |||
550 | |||
551 | /* | ||
552 | * Adding this to un-install notification handlers for all the device | ||
553 | * handles. | ||
554 | */ | ||
555 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
556 | ACPI_UINT32_MAX, | ||
557 | acpi_memory_deregister_notify_handler, NULL, | ||
558 | NULL, NULL); | ||
559 | |||
560 | if (ACPI_FAILURE(status)) | ||
561 | ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed")); | ||
562 | |||
563 | acpi_bus_unregister_driver(&acpi_memory_device_driver); | ||
564 | |||
565 | return; | ||
566 | } | 325 | } |
567 | |||
568 | module_init(acpi_memory_device_init); | ||
569 | module_exit(acpi_memory_device_exit); | ||
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 5523ba7d764d..f9f8a08827fa 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c | |||
@@ -1,12 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * acpi_container.c - ACPI Generic Container Driver | 2 | * container.c - ACPI Generic Container Driver |
3 | * ($Revision: ) | ||
4 | * | 3 | * |
5 | * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com) | 4 | * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com) |
6 | * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com) | 5 | * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com) |
7 | * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com) | 6 | * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com) |
8 | * Copyright (C) 2004 Intel Corp. | ||
9 | * Copyright (C) 2004 FUJITSU LIMITED | 7 | * Copyright (C) 2004 FUJITSU LIMITED |
8 | * Copyright (C) 2004, 2013 Intel Corp. | ||
9 | * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
10 | * | 10 | * |
11 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 11 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
12 | * | 12 | * |
@@ -26,14 +26,9 @@ | |||
26 | * | 26 | * |
27 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 27 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
28 | */ | 28 | */ |
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
35 | #include <acpi/acpi_bus.h> | 30 | |
36 | #include <acpi/acpi_drivers.h> | 31 | #include "internal.h" |
37 | 32 | ||
38 | #define PREFIX "ACPI: " | 33 | #define PREFIX "ACPI: " |
39 | 34 | ||
@@ -50,141 +45,20 @@ static const struct acpi_device_id container_device_ids[] = { | |||
50 | static int container_device_attach(struct acpi_device *device, | 45 | static int container_device_attach(struct acpi_device *device, |
51 | const struct acpi_device_id *not_used) | 46 | const struct acpi_device_id *not_used) |
52 | { | 47 | { |
53 | /* | 48 | /* This is necessary for container hotplug to work. */ |
54 | * FIXME: This is necessary, so that acpi_eject_store() doesn't return | ||
55 | * -ENODEV for containers. | ||
56 | */ | ||
57 | return 1; | 49 | return 1; |
58 | } | 50 | } |
59 | 51 | ||
60 | static struct acpi_scan_handler container_device_handler = { | 52 | static struct acpi_scan_handler container_handler = { |
61 | .ids = container_device_ids, | 53 | .ids = container_device_ids, |
62 | .attach = container_device_attach, | 54 | .attach = container_device_attach, |
55 | .hotplug = { | ||
56 | .enabled = true, | ||
57 | .mode = AHM_CONTAINER, | ||
58 | }, | ||
63 | }; | 59 | }; |
64 | 60 | ||
65 | static int is_device_present(acpi_handle handle) | ||
66 | { | ||
67 | acpi_handle temp; | ||
68 | acpi_status status; | ||
69 | unsigned long long sta; | ||
70 | |||
71 | |||
72 | status = acpi_get_handle(handle, "_STA", &temp); | ||
73 | if (ACPI_FAILURE(status)) | ||
74 | return 1; /* _STA not found, assume device present */ | ||
75 | |||
76 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | ||
77 | if (ACPI_FAILURE(status)) | ||
78 | return 0; /* Firmware error */ | ||
79 | |||
80 | return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT); | ||
81 | } | ||
82 | |||
83 | static void container_notify_cb(acpi_handle handle, u32 type, void *context) | ||
84 | { | ||
85 | struct acpi_device *device = NULL; | ||
86 | int result; | ||
87 | int present; | ||
88 | acpi_status status; | ||
89 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ | ||
90 | |||
91 | acpi_scan_lock_acquire(); | ||
92 | |||
93 | switch (type) { | ||
94 | case ACPI_NOTIFY_BUS_CHECK: | ||
95 | /* Fall through */ | ||
96 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
97 | pr_debug("Container driver received %s event\n", | ||
98 | (type == ACPI_NOTIFY_BUS_CHECK) ? | ||
99 | "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"); | ||
100 | |||
101 | present = is_device_present(handle); | ||
102 | status = acpi_bus_get_device(handle, &device); | ||
103 | if (!present) { | ||
104 | if (ACPI_SUCCESS(status)) { | ||
105 | /* device exist and this is a remove request */ | ||
106 | device->flags.eject_pending = 1; | ||
107 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); | ||
108 | goto out; | ||
109 | } | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | if (!ACPI_FAILURE(status) || device) | ||
114 | break; | ||
115 | |||
116 | result = acpi_bus_scan(handle); | ||
117 | if (result) { | ||
118 | acpi_handle_warn(handle, "Failed to add container\n"); | ||
119 | break; | ||
120 | } | ||
121 | result = acpi_bus_get_device(handle, &device); | ||
122 | if (result) { | ||
123 | acpi_handle_warn(handle, "Missing device object\n"); | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); | ||
128 | ost_code = ACPI_OST_SC_SUCCESS; | ||
129 | break; | ||
130 | |||
131 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
132 | if (!acpi_bus_get_device(handle, &device) && device) { | ||
133 | device->flags.eject_pending = 1; | ||
134 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); | ||
135 | goto out; | ||
136 | } | ||
137 | break; | ||
138 | |||
139 | default: | ||
140 | /* non-hotplug event; possibly handled by other handler */ | ||
141 | goto out; | ||
142 | } | ||
143 | |||
144 | /* Inform firmware that the hotplug operation has completed */ | ||
145 | (void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); | ||
146 | |||
147 | out: | ||
148 | acpi_scan_lock_release(); | ||
149 | } | ||
150 | |||
151 | static bool is_container(acpi_handle handle) | ||
152 | { | ||
153 | struct acpi_device_info *info; | ||
154 | bool ret = false; | ||
155 | |||
156 | if (ACPI_FAILURE(acpi_get_object_info(handle, &info))) | ||
157 | return false; | ||
158 | |||
159 | if (info->valid & ACPI_VALID_HID) { | ||
160 | const struct acpi_device_id *id; | ||
161 | |||
162 | for (id = container_device_ids; id->id[0]; id++) { | ||
163 | ret = !strcmp((char *)id->id, info->hardware_id.string); | ||
164 | if (ret) | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | kfree(info); | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static acpi_status acpi_container_register_notify_handler(acpi_handle handle, | ||
173 | u32 lvl, void *ctxt, | ||
174 | void **retv) | ||
175 | { | ||
176 | if (is_container(handle)) | ||
177 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
178 | container_notify_cb, NULL); | ||
179 | |||
180 | return AE_OK; | ||
181 | } | ||
182 | |||
183 | void __init acpi_container_init(void) | 61 | void __init acpi_container_init(void) |
184 | { | 62 | { |
185 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, | 63 | acpi_scan_add_handler_with_hotplug(&container_handler, "container"); |
186 | acpi_container_register_notify_handler, NULL, | ||
187 | NULL, NULL); | ||
188 | |||
189 | acpi_scan_add_handler(&container_device_handler); | ||
190 | } | 64 | } |
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 3c94a732b4b3..7f094adfe05a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -41,6 +41,17 @@ void acpi_container_init(void); | |||
41 | #else | 41 | #else |
42 | static inline void acpi_container_init(void) {} | 42 | static inline void acpi_container_init(void) {} |
43 | #endif | 43 | #endif |
44 | #ifdef CONFIG_ACPI_HOTPLUG_MEMORY | ||
45 | void acpi_memory_hotplug_init(void); | ||
46 | #else | ||
47 | static inline void acpi_memory_hotplug_init(void) {} | ||
48 | #endif | ||
49 | |||
50 | void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, | ||
51 | const char *name); | ||
52 | int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, | ||
53 | const char *hotplug_profile_name); | ||
54 | void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val); | ||
44 | 55 | ||
45 | #ifdef CONFIG_DEBUG_FS | 56 | #ifdef CONFIG_DEBUG_FS |
46 | extern struct dentry *acpi_debugfs_dir; | 57 | extern struct dentry *acpi_debugfs_dir; |
@@ -60,7 +71,7 @@ int acpi_device_add(struct acpi_device *device, | |||
60 | void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, | 71 | void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, |
61 | int type, unsigned long long sta); | 72 | int type, unsigned long long sta); |
62 | void acpi_device_add_finalize(struct acpi_device *device); | 73 | void acpi_device_add_finalize(struct acpi_device *device); |
63 | void acpi_free_ids(struct acpi_device *device); | 74 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); |
64 | 75 | ||
65 | /* -------------------------------------------------------------------------- | 76 | /* -------------------------------------------------------------------------- |
66 | Power Resource | 77 | Power Resource |
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 34f5ef11d427..0481b1b1d2aa 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -824,7 +824,7 @@ static void acpi_release_power_resource(struct device *dev) | |||
824 | list_del(&resource->list_node); | 824 | list_del(&resource->list_node); |
825 | mutex_unlock(&power_resource_list_lock); | 825 | mutex_unlock(&power_resource_list_lock); |
826 | 826 | ||
827 | acpi_free_ids(device); | 827 | acpi_free_pnp_ids(&device->pnp); |
828 | kfree(resource); | 828 | kfree(resource); |
829 | } | 829 | } |
830 | 830 | ||
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5e7e991717d7..8cacc16af6e7 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_scan_handler *handler) | |||
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, | ||
67 | const char *hotplug_profile_name) | ||
68 | { | ||
69 | int error; | ||
70 | |||
71 | error = acpi_scan_add_handler(handler); | ||
72 | if (error) | ||
73 | return error; | ||
74 | |||
75 | acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
66 | /* | 79 | /* |
67 | * Creates hid/cid(s) string needed for modalias and uevent | 80 | * Creates hid/cid(s) string needed for modalias and uevent |
68 | * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: | 81 | * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: |
@@ -107,32 +120,20 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha | |||
107 | } | 120 | } |
108 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | 121 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); |
109 | 122 | ||
110 | /** | 123 | static int acpi_scan_hot_remove(struct acpi_device *device) |
111 | * acpi_bus_hot_remove_device: hot-remove a device and its children | ||
112 | * @context: struct acpi_eject_event pointer (freed in this func) | ||
113 | * | ||
114 | * Hot-remove a device and its children. This function frees up the | ||
115 | * memory space passed by arg context, so that the caller may call | ||
116 | * this function asynchronously through acpi_os_hotplug_execute(). | ||
117 | */ | ||
118 | void acpi_bus_hot_remove_device(void *context) | ||
119 | { | 124 | { |
120 | struct acpi_eject_event *ej_event = context; | ||
121 | struct acpi_device *device = ej_event->device; | ||
122 | acpi_handle handle = device->handle; | 125 | acpi_handle handle = device->handle; |
123 | acpi_handle temp; | 126 | acpi_handle not_used; |
124 | struct acpi_object_list arg_list; | 127 | struct acpi_object_list arg_list; |
125 | union acpi_object arg; | 128 | union acpi_object arg; |
126 | acpi_status status = AE_OK; | 129 | acpi_status status; |
127 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ | 130 | unsigned long long sta; |
128 | |||
129 | mutex_lock(&acpi_scan_lock); | ||
130 | 131 | ||
131 | /* If there is no handle, the device node has been unregistered. */ | 132 | /* If there is no handle, the device node has been unregistered. */ |
132 | if (!device->handle) { | 133 | if (!handle) { |
133 | dev_dbg(&device->dev, "ACPI handle missing\n"); | 134 | dev_dbg(&device->dev, "ACPI handle missing\n"); |
134 | put_device(&device->dev); | 135 | put_device(&device->dev); |
135 | goto out; | 136 | return -EINVAL; |
136 | } | 137 | } |
137 | 138 | ||
138 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 139 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
@@ -143,7 +144,7 @@ void acpi_bus_hot_remove_device(void *context) | |||
143 | put_device(&device->dev); | 144 | put_device(&device->dev); |
144 | device = NULL; | 145 | device = NULL; |
145 | 146 | ||
146 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) { | 147 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", ¬_used))) { |
147 | arg_list.count = 1; | 148 | arg_list.count = 1; |
148 | arg_list.pointer = &arg; | 149 | arg_list.pointer = &arg; |
149 | arg.type = ACPI_TYPE_INTEGER; | 150 | arg.type = ACPI_TYPE_INTEGER; |
@@ -161,18 +162,205 @@ void acpi_bus_hot_remove_device(void *context) | |||
161 | */ | 162 | */ |
162 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); | 163 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); |
163 | if (ACPI_FAILURE(status)) { | 164 | if (ACPI_FAILURE(status)) { |
164 | if (status != AE_NOT_FOUND) | 165 | if (status == AE_NOT_FOUND) { |
165 | acpi_handle_warn(handle, "Eject failed\n"); | 166 | return -ENODEV; |
167 | } else { | ||
168 | acpi_handle_warn(handle, "Eject failed (0x%x)\n", | ||
169 | status); | ||
170 | return -EIO; | ||
171 | } | ||
172 | } | ||
166 | 173 | ||
167 | /* Tell the firmware the hot-remove operation has failed. */ | 174 | /* |
168 | acpi_evaluate_hotplug_ost(handle, ej_event->event, | 175 | * Verify if eject was indeed successful. If not, log an error |
169 | ost_code, NULL); | 176 | * message. No need to call _OST since _EJ0 call was made OK. |
177 | */ | ||
178 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | ||
179 | if (ACPI_FAILURE(status)) { | ||
180 | acpi_handle_warn(handle, | ||
181 | "Status check after eject failed (0x%x)\n", status); | ||
182 | } else if (sta & ACPI_STA_DEVICE_ENABLED) { | ||
183 | acpi_handle_warn(handle, | ||
184 | "Eject incomplete - status 0x%llx\n", sta); | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void acpi_bus_device_eject(void *context) | ||
191 | { | ||
192 | acpi_handle handle = context; | ||
193 | struct acpi_device *device = NULL; | ||
194 | struct acpi_scan_handler *handler; | ||
195 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
196 | |||
197 | mutex_lock(&acpi_scan_lock); | ||
198 | |||
199 | acpi_bus_get_device(handle, &device); | ||
200 | if (!device) | ||
201 | goto err_out; | ||
202 | |||
203 | handler = device->handler; | ||
204 | if (!handler || !handler->hotplug.enabled) { | ||
205 | ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | ||
206 | goto err_out; | ||
207 | } | ||
208 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, | ||
209 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
210 | if (handler->hotplug.mode == AHM_CONTAINER) { | ||
211 | device->flags.eject_pending = true; | ||
212 | kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); | ||
213 | } else { | ||
214 | int error; | ||
215 | |||
216 | get_device(&device->dev); | ||
217 | error = acpi_scan_hot_remove(device); | ||
218 | if (error) | ||
219 | goto err_out; | ||
170 | } | 220 | } |
171 | 221 | ||
172 | out: | 222 | out: |
173 | mutex_unlock(&acpi_scan_lock); | 223 | mutex_unlock(&acpi_scan_lock); |
174 | kfree(context); | ||
175 | return; | 224 | return; |
225 | |||
226 | err_out: | ||
227 | acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code, | ||
228 | NULL); | ||
229 | goto out; | ||
230 | } | ||
231 | |||
232 | static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source) | ||
233 | { | ||
234 | struct acpi_device *device = NULL; | ||
235 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | ||
236 | int error; | ||
237 | |||
238 | mutex_lock(&acpi_scan_lock); | ||
239 | |||
240 | acpi_bus_get_device(handle, &device); | ||
241 | if (device) { | ||
242 | dev_warn(&device->dev, "Attempt to re-insert\n"); | ||
243 | goto out; | ||
244 | } | ||
245 | acpi_evaluate_hotplug_ost(handle, ost_source, | ||
246 | ACPI_OST_SC_INSERT_IN_PROGRESS, NULL); | ||
247 | error = acpi_bus_scan(handle); | ||
248 | if (error) { | ||
249 | acpi_handle_warn(handle, "Namespace scan failure\n"); | ||
250 | goto out; | ||
251 | } | ||
252 | error = acpi_bus_get_device(handle, &device); | ||
253 | if (error) { | ||
254 | acpi_handle_warn(handle, "Missing device node object\n"); | ||
255 | goto out; | ||
256 | } | ||
257 | ost_code = ACPI_OST_SC_SUCCESS; | ||
258 | if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) | ||
259 | kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); | ||
260 | |||
261 | out: | ||
262 | acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL); | ||
263 | mutex_unlock(&acpi_scan_lock); | ||
264 | } | ||
265 | |||
266 | static void acpi_scan_bus_check(void *context) | ||
267 | { | ||
268 | acpi_scan_bus_device_check((acpi_handle)context, | ||
269 | ACPI_NOTIFY_BUS_CHECK); | ||
270 | } | ||
271 | |||
272 | static void acpi_scan_device_check(void *context) | ||
273 | { | ||
274 | acpi_scan_bus_device_check((acpi_handle)context, | ||
275 | ACPI_NOTIFY_DEVICE_CHECK); | ||
276 | } | ||
277 | |||
278 | static void acpi_hotplug_unsupported(acpi_handle handle, u32 type) | ||
279 | { | ||
280 | u32 ost_status; | ||
281 | |||
282 | switch (type) { | ||
283 | case ACPI_NOTIFY_BUS_CHECK: | ||
284 | acpi_handle_debug(handle, | ||
285 | "ACPI_NOTIFY_BUS_CHECK event: unsupported\n"); | ||
286 | ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED; | ||
287 | break; | ||
288 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
289 | acpi_handle_debug(handle, | ||
290 | "ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n"); | ||
291 | ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED; | ||
292 | break; | ||
293 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
294 | acpi_handle_debug(handle, | ||
295 | "ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n"); | ||
296 | ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED; | ||
297 | break; | ||
298 | default: | ||
299 | /* non-hotplug event; possibly handled by other handler */ | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL); | ||
304 | } | ||
305 | |||
306 | static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) | ||
307 | { | ||
308 | acpi_osd_exec_callback callback; | ||
309 | struct acpi_scan_handler *handler = data; | ||
310 | acpi_status status; | ||
311 | |||
312 | if (!handler->hotplug.enabled) | ||
313 | return acpi_hotplug_unsupported(handle, type); | ||
314 | |||
315 | switch (type) { | ||
316 | case ACPI_NOTIFY_BUS_CHECK: | ||
317 | acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); | ||
318 | callback = acpi_scan_bus_check; | ||
319 | break; | ||
320 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
321 | acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); | ||
322 | callback = acpi_scan_device_check; | ||
323 | break; | ||
324 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
325 | acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); | ||
326 | callback = acpi_bus_device_eject; | ||
327 | break; | ||
328 | default: | ||
329 | /* non-hotplug event; possibly handled by other handler */ | ||
330 | return; | ||
331 | } | ||
332 | status = acpi_os_hotplug_execute(callback, handle); | ||
333 | if (ACPI_FAILURE(status)) | ||
334 | acpi_evaluate_hotplug_ost(handle, type, | ||
335 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, | ||
336 | NULL); | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * acpi_bus_hot_remove_device: hot-remove a device and its children | ||
341 | * @context: struct acpi_eject_event pointer (freed in this func) | ||
342 | * | ||
343 | * Hot-remove a device and its children. This function frees up the | ||
344 | * memory space passed by arg context, so that the caller may call | ||
345 | * this function asynchronously through acpi_os_hotplug_execute(). | ||
346 | */ | ||
347 | void acpi_bus_hot_remove_device(void *context) | ||
348 | { | ||
349 | struct acpi_eject_event *ej_event = context; | ||
350 | struct acpi_device *device = ej_event->device; | ||
351 | acpi_handle handle = device->handle; | ||
352 | int error; | ||
353 | |||
354 | mutex_lock(&acpi_scan_lock); | ||
355 | |||
356 | error = acpi_scan_hot_remove(device); | ||
357 | if (error && handle) | ||
358 | acpi_evaluate_hotplug_ost(handle, ej_event->event, | ||
359 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, | ||
360 | NULL); | ||
361 | |||
362 | mutex_unlock(&acpi_scan_lock); | ||
363 | kfree(context); | ||
176 | } | 364 | } |
177 | EXPORT_SYMBOL(acpi_bus_hot_remove_device); | 365 | EXPORT_SYMBOL(acpi_bus_hot_remove_device); |
178 | 366 | ||
@@ -206,51 +394,61 @@ static ssize_t | |||
206 | acpi_eject_store(struct device *d, struct device_attribute *attr, | 394 | acpi_eject_store(struct device *d, struct device_attribute *attr, |
207 | const char *buf, size_t count) | 395 | const char *buf, size_t count) |
208 | { | 396 | { |
209 | int ret = count; | ||
210 | acpi_status status; | ||
211 | acpi_object_type type = 0; | ||
212 | struct acpi_device *acpi_device = to_acpi_device(d); | 397 | struct acpi_device *acpi_device = to_acpi_device(d); |
213 | struct acpi_eject_event *ej_event; | 398 | struct acpi_eject_event *ej_event; |
399 | acpi_object_type not_used; | ||
400 | acpi_status status; | ||
401 | u32 ost_source; | ||
402 | int ret; | ||
214 | 403 | ||
215 | if ((!count) || (buf[0] != '1')) { | 404 | if (!count || buf[0] != '1') |
216 | return -EINVAL; | 405 | return -EINVAL; |
217 | } | ||
218 | if (!acpi_device->driver && !acpi_device->handler) { | ||
219 | ret = -ENODEV; | ||
220 | goto err; | ||
221 | } | ||
222 | status = acpi_get_type(acpi_device->handle, &type); | ||
223 | if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { | ||
224 | ret = -ENODEV; | ||
225 | goto err; | ||
226 | } | ||
227 | 406 | ||
228 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); | 407 | if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) |
229 | if (!ej_event) { | 408 | && !acpi_device->driver) |
230 | ret = -ENOMEM; | 409 | return -ENODEV; |
231 | goto err; | 410 | |
232 | } | 411 | status = acpi_get_type(acpi_device->handle, ¬_used); |
412 | if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) | ||
413 | return -ENODEV; | ||
414 | |||
415 | mutex_lock(&acpi_scan_lock); | ||
233 | 416 | ||
234 | get_device(&acpi_device->dev); | ||
235 | ej_event->device = acpi_device; | ||
236 | if (acpi_device->flags.eject_pending) { | 417 | if (acpi_device->flags.eject_pending) { |
237 | /* event originated from ACPI eject notification */ | 418 | /* ACPI eject notification event. */ |
238 | ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; | 419 | ost_source = ACPI_NOTIFY_EJECT_REQUEST; |
239 | acpi_device->flags.eject_pending = 0; | 420 | acpi_device->flags.eject_pending = 0; |
240 | } else { | 421 | } else { |
241 | /* event originated from user */ | 422 | /* Eject initiated by user space. */ |
242 | ej_event->event = ACPI_OST_EC_OSPM_EJECT; | 423 | ost_source = ACPI_OST_EC_OSPM_EJECT; |
243 | (void) acpi_evaluate_hotplug_ost(acpi_device->handle, | ||
244 | ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
245 | } | 424 | } |
246 | 425 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); | |
426 | if (!ej_event) { | ||
427 | ret = -ENOMEM; | ||
428 | goto err_out; | ||
429 | } | ||
430 | acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source, | ||
431 | ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
432 | ej_event->device = acpi_device; | ||
433 | ej_event->event = ost_source; | ||
434 | get_device(&acpi_device->dev); | ||
247 | status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); | 435 | status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event); |
248 | if (ACPI_FAILURE(status)) { | 436 | if (ACPI_FAILURE(status)) { |
249 | put_device(&acpi_device->dev); | 437 | put_device(&acpi_device->dev); |
250 | kfree(ej_event); | 438 | kfree(ej_event); |
439 | ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; | ||
440 | goto err_out; | ||
251 | } | 441 | } |
252 | err: | 442 | ret = count; |
443 | |||
444 | out: | ||
445 | mutex_unlock(&acpi_scan_lock); | ||
253 | return ret; | 446 | return ret; |
447 | |||
448 | err_out: | ||
449 | acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source, | ||
450 | ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); | ||
451 | goto out; | ||
254 | } | 452 | } |
255 | 453 | ||
256 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); | 454 | static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); |
@@ -376,7 +574,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) | |||
376 | goto end; | 574 | goto end; |
377 | } | 575 | } |
378 | 576 | ||
379 | if (dev->flags.bus_address) | 577 | if (dev->pnp.type.bus_address) |
380 | result = device_create_file(&dev->dev, &dev_attr_adr); | 578 | result = device_create_file(&dev->dev, &dev_attr_adr); |
381 | if (dev->pnp.unique_id) | 579 | if (dev->pnp.unique_id) |
382 | result = device_create_file(&dev->dev, &dev_attr_uid); | 580 | result = device_create_file(&dev->dev, &dev_attr_uid); |
@@ -449,7 +647,7 @@ static void acpi_device_remove_files(struct acpi_device *dev) | |||
449 | 647 | ||
450 | if (dev->pnp.unique_id) | 648 | if (dev->pnp.unique_id) |
451 | device_remove_file(&dev->dev, &dev_attr_uid); | 649 | device_remove_file(&dev->dev, &dev_attr_uid); |
452 | if (dev->flags.bus_address) | 650 | if (dev->pnp.type.bus_address) |
453 | device_remove_file(&dev->dev, &dev_attr_adr); | 651 | device_remove_file(&dev->dev, &dev_attr_adr); |
454 | device_remove_file(&dev->dev, &dev_attr_modalias); | 652 | device_remove_file(&dev->dev, &dev_attr_modalias); |
455 | device_remove_file(&dev->dev, &dev_attr_hid); | 653 | device_remove_file(&dev->dev, &dev_attr_hid); |
@@ -512,17 +710,6 @@ int acpi_match_device_ids(struct acpi_device *device, | |||
512 | } | 710 | } |
513 | EXPORT_SYMBOL(acpi_match_device_ids); | 711 | EXPORT_SYMBOL(acpi_match_device_ids); |
514 | 712 | ||
515 | void acpi_free_ids(struct acpi_device *device) | ||
516 | { | ||
517 | struct acpi_hardware_id *id, *tmp; | ||
518 | |||
519 | list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) { | ||
520 | kfree(id->id); | ||
521 | kfree(id); | ||
522 | } | ||
523 | kfree(device->pnp.unique_id); | ||
524 | } | ||
525 | |||
526 | static void acpi_free_power_resources_lists(struct acpi_device *device) | 713 | static void acpi_free_power_resources_lists(struct acpi_device *device) |
527 | { | 714 | { |
528 | int i; | 715 | int i; |
@@ -543,7 +730,7 @@ static void acpi_device_release(struct device *dev) | |||
543 | { | 730 | { |
544 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 731 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
545 | 732 | ||
546 | acpi_free_ids(acpi_dev); | 733 | acpi_free_pnp_ids(&acpi_dev->pnp); |
547 | acpi_free_power_resources_lists(acpi_dev); | 734 | acpi_free_power_resources_lists(acpi_dev); |
548 | kfree(acpi_dev); | 735 | kfree(acpi_dev); |
549 | } | 736 | } |
@@ -1256,19 +1443,17 @@ static void acpi_device_get_busid(struct acpi_device *device) | |||
1256 | } | 1443 | } |
1257 | 1444 | ||
1258 | /* | 1445 | /* |
1259 | * acpi_bay_match - see if a device is an ejectable driver bay | 1446 | * acpi_bay_match - see if an acpi object is an ejectable driver bay |
1260 | * | 1447 | * |
1261 | * If an acpi object is ejectable and has one of the ACPI ATA methods defined, | 1448 | * If an acpi object is ejectable and has one of the ACPI ATA methods defined, |
1262 | * then we can safely call it an ejectable drive bay | 1449 | * then we can safely call it an ejectable drive bay |
1263 | */ | 1450 | */ |
1264 | static int acpi_bay_match(struct acpi_device *device){ | 1451 | static int acpi_bay_match(acpi_handle handle) |
1452 | { | ||
1265 | acpi_status status; | 1453 | acpi_status status; |
1266 | acpi_handle handle; | ||
1267 | acpi_handle tmp; | 1454 | acpi_handle tmp; |
1268 | acpi_handle phandle; | 1455 | acpi_handle phandle; |
1269 | 1456 | ||
1270 | handle = device->handle; | ||
1271 | |||
1272 | status = acpi_get_handle(handle, "_EJ0", &tmp); | 1457 | status = acpi_get_handle(handle, "_EJ0", &tmp); |
1273 | if (ACPI_FAILURE(status)) | 1458 | if (ACPI_FAILURE(status)) |
1274 | return -ENODEV; | 1459 | return -ENODEV; |
@@ -1292,12 +1477,12 @@ static int acpi_bay_match(struct acpi_device *device){ | |||
1292 | } | 1477 | } |
1293 | 1478 | ||
1294 | /* | 1479 | /* |
1295 | * acpi_dock_match - see if a device has a _DCK method | 1480 | * acpi_dock_match - see if an acpi object has a _DCK method |
1296 | */ | 1481 | */ |
1297 | static int acpi_dock_match(struct acpi_device *device) | 1482 | static int acpi_dock_match(acpi_handle handle) |
1298 | { | 1483 | { |
1299 | acpi_handle tmp; | 1484 | acpi_handle tmp; |
1300 | return acpi_get_handle(device->handle, "_DCK", &tmp); | 1485 | return acpi_get_handle(handle, "_DCK", &tmp); |
1301 | } | 1486 | } |
1302 | 1487 | ||
1303 | const char *acpi_device_hid(struct acpi_device *device) | 1488 | const char *acpi_device_hid(struct acpi_device *device) |
@@ -1312,7 +1497,7 @@ const char *acpi_device_hid(struct acpi_device *device) | |||
1312 | } | 1497 | } |
1313 | EXPORT_SYMBOL(acpi_device_hid); | 1498 | EXPORT_SYMBOL(acpi_device_hid); |
1314 | 1499 | ||
1315 | static void acpi_add_id(struct acpi_device *device, const char *dev_id) | 1500 | static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id) |
1316 | { | 1501 | { |
1317 | struct acpi_hardware_id *id; | 1502 | struct acpi_hardware_id *id; |
1318 | 1503 | ||
@@ -1326,7 +1511,8 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) | |||
1326 | return; | 1511 | return; |
1327 | } | 1512 | } |
1328 | 1513 | ||
1329 | list_add_tail(&id->list, &device->pnp.ids); | 1514 | list_add_tail(&id->list, &pnp->ids); |
1515 | pnp->type.hardware_id = 1; | ||
1330 | } | 1516 | } |
1331 | 1517 | ||
1332 | /* | 1518 | /* |
@@ -1334,7 +1520,7 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) | |||
1334 | * lacks the SMBUS01 HID and the methods do not have the necessary "_" | 1520 | * lacks the SMBUS01 HID and the methods do not have the necessary "_" |
1335 | * prefix. Work around this. | 1521 | * prefix. Work around this. |
1336 | */ | 1522 | */ |
1337 | static int acpi_ibm_smbus_match(struct acpi_device *device) | 1523 | static int acpi_ibm_smbus_match(acpi_handle handle) |
1338 | { | 1524 | { |
1339 | acpi_handle h_dummy; | 1525 | acpi_handle h_dummy; |
1340 | struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; | 1526 | struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; |
@@ -1344,7 +1530,7 @@ static int acpi_ibm_smbus_match(struct acpi_device *device) | |||
1344 | return -ENODEV; | 1530 | return -ENODEV; |
1345 | 1531 | ||
1346 | /* Look for SMBS object */ | 1532 | /* Look for SMBS object */ |
1347 | result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path); | 1533 | result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path); |
1348 | if (result) | 1534 | if (result) |
1349 | return result; | 1535 | return result; |
1350 | 1536 | ||
@@ -1355,48 +1541,50 @@ static int acpi_ibm_smbus_match(struct acpi_device *device) | |||
1355 | 1541 | ||
1356 | /* Does it have the necessary (but misnamed) methods? */ | 1542 | /* Does it have the necessary (but misnamed) methods? */ |
1357 | result = -ENODEV; | 1543 | result = -ENODEV; |
1358 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) && | 1544 | if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) && |
1359 | ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) && | 1545 | ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) && |
1360 | ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy))) | 1546 | ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy))) |
1361 | result = 0; | 1547 | result = 0; |
1362 | out: | 1548 | out: |
1363 | kfree(path.pointer); | 1549 | kfree(path.pointer); |
1364 | return result; | 1550 | return result; |
1365 | } | 1551 | } |
1366 | 1552 | ||
1367 | static void acpi_device_set_id(struct acpi_device *device) | 1553 | static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, |
1554 | int device_type) | ||
1368 | { | 1555 | { |
1369 | acpi_status status; | 1556 | acpi_status status; |
1370 | struct acpi_device_info *info; | 1557 | struct acpi_device_info *info; |
1371 | struct acpi_pnp_device_id_list *cid_list; | 1558 | struct acpi_pnp_device_id_list *cid_list; |
1372 | int i; | 1559 | int i; |
1373 | 1560 | ||
1374 | switch (device->device_type) { | 1561 | switch (device_type) { |
1375 | case ACPI_BUS_TYPE_DEVICE: | 1562 | case ACPI_BUS_TYPE_DEVICE: |
1376 | if (ACPI_IS_ROOT_DEVICE(device)) { | 1563 | if (handle == ACPI_ROOT_OBJECT) { |
1377 | acpi_add_id(device, ACPI_SYSTEM_HID); | 1564 | acpi_add_id(pnp, ACPI_SYSTEM_HID); |
1378 | break; | 1565 | break; |
1379 | } | 1566 | } |
1380 | 1567 | ||
1381 | status = acpi_get_object_info(device->handle, &info); | 1568 | status = acpi_get_object_info(handle, &info); |
1382 | if (ACPI_FAILURE(status)) { | 1569 | if (ACPI_FAILURE(status)) { |
1383 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); | 1570 | pr_err(PREFIX "%s: Error reading device info\n", |
1571 | __func__); | ||
1384 | return; | 1572 | return; |
1385 | } | 1573 | } |
1386 | 1574 | ||
1387 | if (info->valid & ACPI_VALID_HID) | 1575 | if (info->valid & ACPI_VALID_HID) |
1388 | acpi_add_id(device, info->hardware_id.string); | 1576 | acpi_add_id(pnp, info->hardware_id.string); |
1389 | if (info->valid & ACPI_VALID_CID) { | 1577 | if (info->valid & ACPI_VALID_CID) { |
1390 | cid_list = &info->compatible_id_list; | 1578 | cid_list = &info->compatible_id_list; |
1391 | for (i = 0; i < cid_list->count; i++) | 1579 | for (i = 0; i < cid_list->count; i++) |
1392 | acpi_add_id(device, cid_list->ids[i].string); | 1580 | acpi_add_id(pnp, cid_list->ids[i].string); |
1393 | } | 1581 | } |
1394 | if (info->valid & ACPI_VALID_ADR) { | 1582 | if (info->valid & ACPI_VALID_ADR) { |
1395 | device->pnp.bus_address = info->address; | 1583 | pnp->bus_address = info->address; |
1396 | device->flags.bus_address = 1; | 1584 | pnp->type.bus_address = 1; |
1397 | } | 1585 | } |
1398 | if (info->valid & ACPI_VALID_UID) | 1586 | if (info->valid & ACPI_VALID_UID) |
1399 | device->pnp.unique_id = kstrdup(info->unique_id.string, | 1587 | pnp->unique_id = kstrdup(info->unique_id.string, |
1400 | GFP_KERNEL); | 1588 | GFP_KERNEL); |
1401 | 1589 | ||
1402 | kfree(info); | 1590 | kfree(info); |
@@ -1405,40 +1593,50 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1405 | * Some devices don't reliably have _HIDs & _CIDs, so add | 1593 | * Some devices don't reliably have _HIDs & _CIDs, so add |
1406 | * synthetic HIDs to make sure drivers can find them. | 1594 | * synthetic HIDs to make sure drivers can find them. |
1407 | */ | 1595 | */ |
1408 | if (acpi_is_video_device(device)) | 1596 | if (acpi_is_video_device(handle)) |
1409 | acpi_add_id(device, ACPI_VIDEO_HID); | 1597 | acpi_add_id(pnp, ACPI_VIDEO_HID); |
1410 | else if (ACPI_SUCCESS(acpi_bay_match(device))) | 1598 | else if (ACPI_SUCCESS(acpi_bay_match(handle))) |
1411 | acpi_add_id(device, ACPI_BAY_HID); | 1599 | acpi_add_id(pnp, ACPI_BAY_HID); |
1412 | else if (ACPI_SUCCESS(acpi_dock_match(device))) | 1600 | else if (ACPI_SUCCESS(acpi_dock_match(handle))) |
1413 | acpi_add_id(device, ACPI_DOCK_HID); | 1601 | acpi_add_id(pnp, ACPI_DOCK_HID); |
1414 | else if (!acpi_ibm_smbus_match(device)) | 1602 | else if (!acpi_ibm_smbus_match(handle)) |
1415 | acpi_add_id(device, ACPI_SMBUS_IBM_HID); | 1603 | acpi_add_id(pnp, ACPI_SMBUS_IBM_HID); |
1416 | else if (list_empty(&device->pnp.ids) && | 1604 | else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) { |
1417 | ACPI_IS_ROOT_DEVICE(device->parent)) { | 1605 | acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ |
1418 | acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ | 1606 | strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME); |
1419 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); | 1607 | strcpy(pnp->device_class, ACPI_BUS_CLASS); |
1420 | strcpy(device->pnp.device_class, ACPI_BUS_CLASS); | ||
1421 | } | 1608 | } |
1422 | 1609 | ||
1423 | break; | 1610 | break; |
1424 | case ACPI_BUS_TYPE_POWER: | 1611 | case ACPI_BUS_TYPE_POWER: |
1425 | acpi_add_id(device, ACPI_POWER_HID); | 1612 | acpi_add_id(pnp, ACPI_POWER_HID); |
1426 | break; | 1613 | break; |
1427 | case ACPI_BUS_TYPE_PROCESSOR: | 1614 | case ACPI_BUS_TYPE_PROCESSOR: |
1428 | acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID); | 1615 | acpi_add_id(pnp, ACPI_PROCESSOR_OBJECT_HID); |
1429 | break; | 1616 | break; |
1430 | case ACPI_BUS_TYPE_THERMAL: | 1617 | case ACPI_BUS_TYPE_THERMAL: |
1431 | acpi_add_id(device, ACPI_THERMAL_HID); | 1618 | acpi_add_id(pnp, ACPI_THERMAL_HID); |
1432 | break; | 1619 | break; |
1433 | case ACPI_BUS_TYPE_POWER_BUTTON: | 1620 | case ACPI_BUS_TYPE_POWER_BUTTON: |
1434 | acpi_add_id(device, ACPI_BUTTON_HID_POWERF); | 1621 | acpi_add_id(pnp, ACPI_BUTTON_HID_POWERF); |
1435 | break; | 1622 | break; |
1436 | case ACPI_BUS_TYPE_SLEEP_BUTTON: | 1623 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
1437 | acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); | 1624 | acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF); |
1438 | break; | 1625 | break; |
1439 | } | 1626 | } |
1440 | } | 1627 | } |
1441 | 1628 | ||
1629 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp) | ||
1630 | { | ||
1631 | struct acpi_hardware_id *id, *tmp; | ||
1632 | |||
1633 | list_for_each_entry_safe(id, tmp, &pnp->ids, list) { | ||
1634 | kfree(id->id); | ||
1635 | kfree(id); | ||
1636 | } | ||
1637 | kfree(pnp->unique_id); | ||
1638 | } | ||
1639 | |||
1442 | void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, | 1640 | void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, |
1443 | int type, unsigned long long sta) | 1641 | int type, unsigned long long sta) |
1444 | { | 1642 | { |
@@ -1448,7 +1646,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, | |||
1448 | device->parent = acpi_bus_get_parent(handle); | 1646 | device->parent = acpi_bus_get_parent(handle); |
1449 | STRUCT_TO_INT(device->status) = sta; | 1647 | STRUCT_TO_INT(device->status) = sta; |
1450 | acpi_device_get_busid(device); | 1648 | acpi_device_get_busid(device); |
1451 | acpi_device_set_id(device); | 1649 | acpi_set_pnp_ids(handle, &device->pnp, type); |
1452 | acpi_bus_get_flags(device); | 1650 | acpi_bus_get_flags(device); |
1453 | device->flags.match_driver = false; | 1651 | device->flags.match_driver = false; |
1454 | device_initialize(&device->dev); | 1652 | device_initialize(&device->dev); |
@@ -1536,6 +1734,75 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, | |||
1536 | return 0; | 1734 | return 0; |
1537 | } | 1735 | } |
1538 | 1736 | ||
1737 | static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, | ||
1738 | char *idstr, | ||
1739 | const struct acpi_device_id **matchid) | ||
1740 | { | ||
1741 | const struct acpi_device_id *devid; | ||
1742 | |||
1743 | for (devid = handler->ids; devid->id[0]; devid++) | ||
1744 | if (!strcmp((char *)devid->id, idstr)) { | ||
1745 | if (matchid) | ||
1746 | *matchid = devid; | ||
1747 | |||
1748 | return true; | ||
1749 | } | ||
1750 | |||
1751 | return false; | ||
1752 | } | ||
1753 | |||
1754 | static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr, | ||
1755 | const struct acpi_device_id **matchid) | ||
1756 | { | ||
1757 | struct acpi_scan_handler *handler; | ||
1758 | |||
1759 | list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) | ||
1760 | if (acpi_scan_handler_matching(handler, idstr, matchid)) | ||
1761 | return handler; | ||
1762 | |||
1763 | return NULL; | ||
1764 | } | ||
1765 | |||
1766 | void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val) | ||
1767 | { | ||
1768 | if (!!hotplug->enabled == !!val) | ||
1769 | return; | ||
1770 | |||
1771 | mutex_lock(&acpi_scan_lock); | ||
1772 | |||
1773 | hotplug->enabled = val; | ||
1774 | |||
1775 | mutex_unlock(&acpi_scan_lock); | ||
1776 | } | ||
1777 | |||
1778 | static void acpi_scan_init_hotplug(acpi_handle handle, int type) | ||
1779 | { | ||
1780 | struct acpi_device_pnp pnp = {}; | ||
1781 | struct acpi_hardware_id *hwid; | ||
1782 | struct acpi_scan_handler *handler; | ||
1783 | |||
1784 | INIT_LIST_HEAD(&pnp.ids); | ||
1785 | acpi_set_pnp_ids(handle, &pnp, type); | ||
1786 | |||
1787 | if (!pnp.type.hardware_id) | ||
1788 | return; | ||
1789 | |||
1790 | /* | ||
1791 | * This relies on the fact that acpi_install_notify_handler() will not | ||
1792 | * install the same notify handler routine twice for the same handle. | ||
1793 | */ | ||
1794 | list_for_each_entry(hwid, &pnp.ids, list) { | ||
1795 | handler = acpi_scan_match_handler(hwid->id, NULL); | ||
1796 | if (handler) { | ||
1797 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
1798 | acpi_hotplug_notify_cb, handler); | ||
1799 | break; | ||
1800 | } | ||
1801 | } | ||
1802 | |||
1803 | acpi_free_pnp_ids(&pnp); | ||
1804 | } | ||
1805 | |||
1539 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | 1806 | static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, |
1540 | void *not_used, void **return_value) | 1807 | void *not_used, void **return_value) |
1541 | { | 1808 | { |
@@ -1558,6 +1825,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | |||
1558 | return AE_OK; | 1825 | return AE_OK; |
1559 | } | 1826 | } |
1560 | 1827 | ||
1828 | acpi_scan_init_hotplug(handle, type); | ||
1829 | |||
1561 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && | 1830 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
1562 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { | 1831 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { |
1563 | struct acpi_device_wakeup wakeup; | 1832 | struct acpi_device_wakeup wakeup; |
@@ -1583,42 +1852,26 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | |||
1583 | return AE_OK; | 1852 | return AE_OK; |
1584 | } | 1853 | } |
1585 | 1854 | ||
1586 | static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id) | 1855 | static int acpi_scan_attach_handler(struct acpi_device *device) |
1587 | { | 1856 | { |
1588 | struct acpi_scan_handler *handler; | 1857 | struct acpi_hardware_id *hwid; |
1858 | int ret = 0; | ||
1589 | 1859 | ||
1590 | list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) { | 1860 | list_for_each_entry(hwid, &device->pnp.ids, list) { |
1591 | const struct acpi_device_id *devid; | 1861 | const struct acpi_device_id *devid; |
1862 | struct acpi_scan_handler *handler; | ||
1592 | 1863 | ||
1593 | for (devid = handler->ids; devid->id[0]; devid++) { | 1864 | handler = acpi_scan_match_handler(hwid->id, &devid); |
1594 | int ret; | 1865 | if (handler) { |
1595 | |||
1596 | if (strcmp((char *)devid->id, id)) | ||
1597 | continue; | ||
1598 | |||
1599 | ret = handler->attach(device, devid); | 1866 | ret = handler->attach(device, devid); |
1600 | if (ret > 0) { | 1867 | if (ret > 0) { |
1601 | device->handler = handler; | 1868 | device->handler = handler; |
1602 | return ret; | 1869 | break; |
1603 | } else if (ret < 0) { | 1870 | } else if (ret < 0) { |
1604 | return ret; | 1871 | break; |
1605 | } | 1872 | } |
1606 | } | 1873 | } |
1607 | } | 1874 | } |
1608 | return 0; | ||
1609 | } | ||
1610 | |||
1611 | static int acpi_scan_attach_handler(struct acpi_device *device) | ||
1612 | { | ||
1613 | struct acpi_hardware_id *hwid; | ||
1614 | int ret = 0; | ||
1615 | |||
1616 | list_for_each_entry(hwid, &device->pnp.ids, list) { | ||
1617 | ret = acpi_scan_do_attach_handler(device, hwid->id); | ||
1618 | if (ret) | ||
1619 | break; | ||
1620 | |||
1621 | } | ||
1622 | return ret; | 1875 | return ret; |
1623 | } | 1876 | } |
1624 | 1877 | ||
@@ -1791,6 +2044,7 @@ int __init acpi_scan_init(void) | |||
1791 | acpi_csrt_init(); | 2044 | acpi_csrt_init(); |
1792 | acpi_container_init(); | 2045 | acpi_container_init(); |
1793 | acpi_pci_slot_init(); | 2046 | acpi_pci_slot_init(); |
2047 | acpi_memory_hotplug_init(); | ||
1794 | 2048 | ||
1795 | mutex_lock(&acpi_scan_lock); | 2049 | mutex_lock(&acpi_scan_lock); |
1796 | /* | 2050 | /* |
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 41c0504470db..fcae5fa2e1b3 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include <linux/moduleparam.h> | 7 | #include <linux/moduleparam.h> |
8 | #include <acpi/acpi_drivers.h> | 8 | #include <acpi/acpi_drivers.h> |
9 | 9 | ||
10 | #include "internal.h" | ||
11 | |||
10 | #define _COMPONENT ACPI_SYSTEM_COMPONENT | 12 | #define _COMPONENT ACPI_SYSTEM_COMPONENT |
11 | ACPI_MODULE_NAME("sysfs"); | 13 | ACPI_MODULE_NAME("sysfs"); |
12 | 14 | ||
@@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); | |||
249 | static LIST_HEAD(acpi_table_attr_list); | 251 | static LIST_HEAD(acpi_table_attr_list); |
250 | static struct kobject *tables_kobj; | 252 | static struct kobject *tables_kobj; |
251 | static struct kobject *dynamic_tables_kobj; | 253 | static struct kobject *dynamic_tables_kobj; |
254 | static struct kobject *hotplug_kobj; | ||
252 | 255 | ||
253 | struct acpi_table_attr { | 256 | struct acpi_table_attr { |
254 | struct bin_attribute attr; | 257 | struct bin_attribute attr; |
@@ -716,6 +719,67 @@ acpi_show_profile(struct device *dev, struct device_attribute *attr, | |||
716 | static const struct device_attribute pm_profile_attr = | 719 | static const struct device_attribute pm_profile_attr = |
717 | __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); | 720 | __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); |
718 | 721 | ||
722 | static ssize_t hotplug_enabled_show(struct kobject *kobj, | ||
723 | struct kobj_attribute *attr, char *buf) | ||
724 | { | ||
725 | struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); | ||
726 | |||
727 | return sprintf(buf, "%d\n", hotplug->enabled); | ||
728 | } | ||
729 | |||
730 | static ssize_t hotplug_enabled_store(struct kobject *kobj, | ||
731 | struct kobj_attribute *attr, | ||
732 | const char *buf, size_t size) | ||
733 | { | ||
734 | struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj); | ||
735 | unsigned int val; | ||
736 | |||
737 | if (kstrtouint(buf, 10, &val) || val > 1) | ||
738 | return -EINVAL; | ||
739 | |||
740 | acpi_scan_hotplug_enabled(hotplug, val); | ||
741 | return size; | ||
742 | } | ||
743 | |||
744 | static struct kobj_attribute hotplug_enabled_attr = | ||
745 | __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show, | ||
746 | hotplug_enabled_store); | ||
747 | |||
748 | static struct attribute *hotplug_profile_attrs[] = { | ||
749 | &hotplug_enabled_attr.attr, | ||
750 | NULL | ||
751 | }; | ||
752 | |||
753 | static struct kobj_type acpi_hotplug_profile_ktype = { | ||
754 | .sysfs_ops = &kobj_sysfs_ops, | ||
755 | .default_attrs = hotplug_profile_attrs, | ||
756 | }; | ||
757 | |||
758 | void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, | ||
759 | const char *name) | ||
760 | { | ||
761 | int error; | ||
762 | |||
763 | if (!hotplug_kobj) | ||
764 | goto err_out; | ||
765 | |||
766 | kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype); | ||
767 | error = kobject_set_name(&hotplug->kobj, "%s", name); | ||
768 | if (error) | ||
769 | goto err_out; | ||
770 | |||
771 | hotplug->kobj.parent = hotplug_kobj; | ||
772 | error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL); | ||
773 | if (error) | ||
774 | goto err_out; | ||
775 | |||
776 | kobject_uevent(&hotplug->kobj, KOBJ_ADD); | ||
777 | return; | ||
778 | |||
779 | err_out: | ||
780 | pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name); | ||
781 | } | ||
782 | |||
719 | int __init acpi_sysfs_init(void) | 783 | int __init acpi_sysfs_init(void) |
720 | { | 784 | { |
721 | int result; | 785 | int result; |
@@ -723,6 +787,8 @@ int __init acpi_sysfs_init(void) | |||
723 | result = acpi_tables_sysfs_init(); | 787 | result = acpi_tables_sysfs_init(); |
724 | if (result) | 788 | if (result) |
725 | return result; | 789 | return result; |
790 | |||
791 | hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj); | ||
726 | result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); | 792 | result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); |
727 | return result; | 793 | return result; |
728 | } | 794 | } |
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 4ac2593234e7..66f67626f02e 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c | |||
@@ -67,40 +67,37 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, | |||
67 | return 0; | 67 | return 0; |
68 | } | 68 | } |
69 | 69 | ||
70 | /* Returns true if the device is a video device which can be handled by | 70 | /* Returns true if the ACPI object is a video device which can be |
71 | * video.ko. | 71 | * handled by video.ko. |
72 | * The device will get a Linux specific CID added in scan.c to | 72 | * The device will get a Linux specific CID added in scan.c to |
73 | * identify the device as an ACPI graphics device | 73 | * identify the device as an ACPI graphics device |
74 | * Be aware that the graphics device may not be physically present | 74 | * Be aware that the graphics device may not be physically present |
75 | * Use acpi_video_get_capabilities() to detect general ACPI video | 75 | * Use acpi_video_get_capabilities() to detect general ACPI video |
76 | * capabilities of present cards | 76 | * capabilities of present cards |
77 | */ | 77 | */ |
78 | long acpi_is_video_device(struct acpi_device *device) | 78 | long acpi_is_video_device(acpi_handle handle) |
79 | { | 79 | { |
80 | acpi_handle h_dummy; | 80 | acpi_handle h_dummy; |
81 | long video_caps = 0; | 81 | long video_caps = 0; |
82 | 82 | ||
83 | if (!device) | ||
84 | return 0; | ||
85 | |||
86 | /* Is this device able to support video switching ? */ | 83 | /* Is this device able to support video switching ? */ |
87 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) || | 84 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) || |
88 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) | 85 | ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy))) |
89 | video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; | 86 | video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; |
90 | 87 | ||
91 | /* Is this device able to retrieve a video ROM ? */ | 88 | /* Is this device able to retrieve a video ROM ? */ |
92 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) | 89 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy))) |
93 | video_caps |= ACPI_VIDEO_ROM_AVAILABLE; | 90 | video_caps |= ACPI_VIDEO_ROM_AVAILABLE; |
94 | 91 | ||
95 | /* Is this device able to configure which video head to be POSTed ? */ | 92 | /* Is this device able to configure which video head to be POSTed ? */ |
96 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && | 93 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) && |
97 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && | 94 | ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) && |
98 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) | 95 | ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy))) |
99 | video_caps |= ACPI_VIDEO_DEVICE_POSTING; | 96 | video_caps |= ACPI_VIDEO_DEVICE_POSTING; |
100 | 97 | ||
101 | /* Only check for backlight functionality if one of the above hit. */ | 98 | /* Only check for backlight functionality if one of the above hit. */ |
102 | if (video_caps) | 99 | if (video_caps) |
103 | acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle, | 100 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, |
104 | ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL, | 101 | ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL, |
105 | &video_caps, NULL); | 102 | &video_caps, NULL); |
106 | 103 | ||
@@ -127,7 +124,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
127 | if (!dev) | 124 | if (!dev) |
128 | return AE_OK; | 125 | return AE_OK; |
129 | pci_dev_put(dev); | 126 | pci_dev_put(dev); |
130 | *cap |= acpi_is_video_device(acpi_dev); | 127 | *cap |= acpi_is_video_device(handle); |
131 | } | 128 | } |
132 | return AE_OK; | 129 | return AE_OK; |
133 | } | 130 | } |
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 4d338740f2cb..a8117e614009 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c | |||
@@ -350,11 +350,11 @@ static void intel_didl_outputs(struct drm_device *dev) | |||
350 | if (!handle || acpi_bus_get_device(handle, &acpi_dev)) | 350 | if (!handle || acpi_bus_get_device(handle, &acpi_dev)) |
351 | return; | 351 | return; |
352 | 352 | ||
353 | if (acpi_is_video_device(acpi_dev)) | 353 | if (acpi_is_video_device(handle)) |
354 | acpi_video_bus = acpi_dev; | 354 | acpi_video_bus = acpi_dev; |
355 | else { | 355 | else { |
356 | list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { | 356 | list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { |
357 | if (acpi_is_video_device(acpi_cdev)) { | 357 | if (acpi_is_video_device(acpi_cdev->handle)) { |
358 | acpi_video_bus = acpi_cdev; | 358 | acpi_video_bus = acpi_cdev; |
359 | break; | 359 | break; |
360 | } | 360 | } |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 22ba56e834e2..98db31d9f9b4 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -88,11 +88,30 @@ struct acpi_device; | |||
88 | * ----------------- | 88 | * ----------------- |
89 | */ | 89 | */ |
90 | 90 | ||
91 | enum acpi_hotplug_mode { | ||
92 | AHM_GENERIC = 0, | ||
93 | AHM_CONTAINER, | ||
94 | AHM_COUNT | ||
95 | }; | ||
96 | |||
97 | struct acpi_hotplug_profile { | ||
98 | struct kobject kobj; | ||
99 | bool enabled:1; | ||
100 | enum acpi_hotplug_mode mode; | ||
101 | }; | ||
102 | |||
103 | static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile( | ||
104 | struct kobject *kobj) | ||
105 | { | ||
106 | return container_of(kobj, struct acpi_hotplug_profile, kobj); | ||
107 | } | ||
108 | |||
91 | struct acpi_scan_handler { | 109 | struct acpi_scan_handler { |
92 | const struct acpi_device_id *ids; | 110 | const struct acpi_device_id *ids; |
93 | struct list_head list_node; | 111 | struct list_head list_node; |
94 | int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id); | 112 | int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id); |
95 | void (*detach)(struct acpi_device *dev); | 113 | void (*detach)(struct acpi_device *dev); |
114 | struct acpi_hotplug_profile hotplug; | ||
96 | }; | 115 | }; |
97 | 116 | ||
98 | /* | 117 | /* |
@@ -142,7 +161,6 @@ struct acpi_device_status { | |||
142 | 161 | ||
143 | struct acpi_device_flags { | 162 | struct acpi_device_flags { |
144 | u32 dynamic_status:1; | 163 | u32 dynamic_status:1; |
145 | u32 bus_address:1; | ||
146 | u32 removable:1; | 164 | u32 removable:1; |
147 | u32 ejectable:1; | 165 | u32 ejectable:1; |
148 | u32 suprise_removal_ok:1; | 166 | u32 suprise_removal_ok:1; |
@@ -150,7 +168,7 @@ struct acpi_device_flags { | |||
150 | u32 performance_manageable:1; | 168 | u32 performance_manageable:1; |
151 | u32 eject_pending:1; | 169 | u32 eject_pending:1; |
152 | u32 match_driver:1; | 170 | u32 match_driver:1; |
153 | u32 reserved:23; | 171 | u32 reserved:24; |
154 | }; | 172 | }; |
155 | 173 | ||
156 | /* File System */ | 174 | /* File System */ |
@@ -173,10 +191,17 @@ struct acpi_hardware_id { | |||
173 | char *id; | 191 | char *id; |
174 | }; | 192 | }; |
175 | 193 | ||
194 | struct acpi_pnp_type { | ||
195 | u32 hardware_id:1; | ||
196 | u32 bus_address:1; | ||
197 | u32 reserved:30; | ||
198 | }; | ||
199 | |||
176 | struct acpi_device_pnp { | 200 | struct acpi_device_pnp { |
177 | acpi_bus_id bus_id; /* Object name */ | 201 | acpi_bus_id bus_id; /* Object name */ |
202 | struct acpi_pnp_type type; /* ID type */ | ||
178 | acpi_bus_address bus_address; /* _ADR */ | 203 | acpi_bus_address bus_address; /* _ADR */ |
179 | char *unique_id; /* _UID */ | 204 | char *unique_id; /* _UID */ |
180 | struct list_head ids; /* _HID and _CIDs */ | 205 | struct list_head ids; /* _HID and _CIDs */ |
181 | acpi_device_name device_name; /* Driver-determined */ | 206 | acpi_device_name device_name; /* Driver-determined */ |
182 | acpi_device_class device_class; /* " */ | 207 | acpi_device_class device_class; /* " */ |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index bcbdd7484e58..edaf311473e5 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -204,7 +204,7 @@ extern bool wmi_has_guid(const char *guid); | |||
204 | #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) | 204 | #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) |
205 | 205 | ||
206 | extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle); | 206 | extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle); |
207 | extern long acpi_is_video_device(struct acpi_device *device); | 207 | extern long acpi_is_video_device(acpi_handle handle); |
208 | extern void acpi_video_dmi_promote_vendor(void); | 208 | extern void acpi_video_dmi_promote_vendor(void); |
209 | extern void acpi_video_dmi_demote_vendor(void); | 209 | extern void acpi_video_dmi_demote_vendor(void); |
210 | extern int acpi_video_backlight_support(void); | 210 | extern int acpi_video_backlight_support(void); |
@@ -217,7 +217,7 @@ static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle) | |||
217 | return 0; | 217 | return 0; |
218 | } | 218 | } |
219 | 219 | ||
220 | static inline long acpi_is_video_device(struct acpi_device *device) | 220 | static inline long acpi_is_video_device(acpi_handle handle) |
221 | { | 221 | { |
222 | return 0; | 222 | return 0; |
223 | } | 223 | } |