diff options
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r-- | drivers/acpi/dock.c | 463 |
1 files changed, 113 insertions, 350 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c431c88faaff..f0fc6260266b 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -1,7 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * dock.c - ACPI dock station driver | 2 | * dock.c - ACPI dock station driver |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com> | 4 | * Copyright (C) 2006, 2014, Intel Corp. |
5 | * Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com> | ||
6 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
5 | * | 7 | * |
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7 | * | 9 | * |
@@ -35,8 +37,6 @@ | |||
35 | 37 | ||
36 | #include "internal.h" | 38 | #include "internal.h" |
37 | 39 | ||
38 | #define PREFIX "ACPI: " | ||
39 | |||
40 | #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" | 40 | #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" |
41 | 41 | ||
42 | ACPI_MODULE_NAME("dock"); | 42 | ACPI_MODULE_NAME("dock"); |
@@ -68,15 +68,10 @@ struct dock_station { | |||
68 | }; | 68 | }; |
69 | static LIST_HEAD(dock_stations); | 69 | static LIST_HEAD(dock_stations); |
70 | static int dock_station_count; | 70 | static int dock_station_count; |
71 | static DEFINE_MUTEX(hotplug_lock); | ||
72 | 71 | ||
73 | struct dock_dependent_device { | 72 | struct dock_dependent_device { |
74 | struct list_head list; | 73 | struct list_head list; |
75 | acpi_handle handle; | 74 | struct acpi_device *adev; |
76 | const struct acpi_dock_ops *hp_ops; | ||
77 | void *hp_context; | ||
78 | unsigned int hp_refcount; | ||
79 | void (*hp_release)(void *); | ||
80 | }; | 75 | }; |
81 | 76 | ||
82 | #define DOCK_DOCKING 0x00000001 | 77 | #define DOCK_DOCKING 0x00000001 |
@@ -98,13 +93,13 @@ enum dock_callback_type { | |||
98 | *****************************************************************************/ | 93 | *****************************************************************************/ |
99 | /** | 94 | /** |
100 | * add_dock_dependent_device - associate a device with the dock station | 95 | * add_dock_dependent_device - associate a device with the dock station |
101 | * @ds: The dock station | 96 | * @ds: Dock station. |
102 | * @handle: handle of the dependent device | 97 | * @adev: Dependent ACPI device object. |
103 | * | 98 | * |
104 | * Add the dependent device to the dock's dependent device list. | 99 | * Add the dependent device to the dock's dependent device list. |
105 | */ | 100 | */ |
106 | static int __init | 101 | static int add_dock_dependent_device(struct dock_station *ds, |
107 | add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) | 102 | struct acpi_device *adev) |
108 | { | 103 | { |
109 | struct dock_dependent_device *dd; | 104 | struct dock_dependent_device *dd; |
110 | 105 | ||
@@ -112,180 +107,120 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) | |||
112 | if (!dd) | 107 | if (!dd) |
113 | return -ENOMEM; | 108 | return -ENOMEM; |
114 | 109 | ||
115 | dd->handle = handle; | 110 | dd->adev = adev; |
116 | INIT_LIST_HEAD(&dd->list); | 111 | INIT_LIST_HEAD(&dd->list); |
117 | list_add_tail(&dd->list, &ds->dependent_devices); | 112 | list_add_tail(&dd->list, &ds->dependent_devices); |
118 | 113 | ||
119 | return 0; | 114 | return 0; |
120 | } | 115 | } |
121 | 116 | ||
122 | static void remove_dock_dependent_devices(struct dock_station *ds) | 117 | static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, |
118 | enum dock_callback_type cb_type) | ||
123 | { | 119 | { |
124 | struct dock_dependent_device *dd, *aux; | 120 | struct acpi_device *adev = dd->adev; |
125 | 121 | ||
126 | list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) { | 122 | acpi_lock_hp_context(); |
127 | list_del(&dd->list); | ||
128 | kfree(dd); | ||
129 | } | ||
130 | } | ||
131 | 123 | ||
132 | /** | 124 | if (!adev->hp) |
133 | * dock_init_hotplug - Initialize a hotplug device on a docking station. | 125 | goto out; |
134 | * @dd: Dock-dependent device. | ||
135 | * @ops: Dock operations to attach to the dependent device. | ||
136 | * @context: Data to pass to the @ops callbacks and @release. | ||
137 | * @init: Optional initialization routine to run after setting up context. | ||
138 | * @release: Optional release routine to run on removal. | ||
139 | */ | ||
140 | static int dock_init_hotplug(struct dock_dependent_device *dd, | ||
141 | const struct acpi_dock_ops *ops, void *context, | ||
142 | void (*init)(void *), void (*release)(void *)) | ||
143 | { | ||
144 | int ret = 0; | ||
145 | 126 | ||
146 | mutex_lock(&hotplug_lock); | 127 | if (cb_type == DOCK_CALL_FIXUP) { |
147 | if (WARN_ON(dd->hp_context)) { | 128 | void (*fixup)(struct acpi_device *); |
148 | ret = -EEXIST; | ||
149 | } else { | ||
150 | dd->hp_refcount = 1; | ||
151 | dd->hp_ops = ops; | ||
152 | dd->hp_context = context; | ||
153 | dd->hp_release = release; | ||
154 | if (init) | ||
155 | init(context); | ||
156 | } | ||
157 | mutex_unlock(&hotplug_lock); | ||
158 | return ret; | ||
159 | } | ||
160 | 129 | ||
161 | /** | 130 | fixup = adev->hp->fixup; |
162 | * dock_release_hotplug - Decrement hotplug reference counter of dock device. | 131 | if (fixup) { |
163 | * @dd: Dock-dependent device. | 132 | acpi_unlock_hp_context(); |
164 | * | 133 | fixup(adev); |
165 | * Decrement the reference counter of @dd and if 0, detach its hotplug | 134 | return; |
166 | * operations from it, reset its context pointer and run the optional release | 135 | } |
167 | * routine if present. | 136 | } else if (cb_type == DOCK_CALL_UEVENT) { |
168 | */ | 137 | void (*uevent)(struct acpi_device *, u32); |
169 | static void dock_release_hotplug(struct dock_dependent_device *dd) | 138 | |
170 | { | 139 | uevent = adev->hp->uevent; |
171 | mutex_lock(&hotplug_lock); | 140 | if (uevent) { |
172 | if (dd->hp_context && !--dd->hp_refcount) { | 141 | acpi_unlock_hp_context(); |
173 | void (*release)(void *) = dd->hp_release; | 142 | uevent(adev, event); |
174 | void *context = dd->hp_context; | 143 | return; |
175 | 144 | } | |
176 | dd->hp_ops = NULL; | 145 | } else { |
177 | dd->hp_context = NULL; | 146 | int (*notify)(struct acpi_device *, u32); |
178 | dd->hp_release = NULL; | ||
179 | if (release) | ||
180 | release(context); | ||
181 | } | ||
182 | mutex_unlock(&hotplug_lock); | ||
183 | } | ||
184 | 147 | ||
185 | static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, | 148 | notify = adev->hp->notify; |
186 | enum dock_callback_type cb_type) | 149 | if (notify) { |
187 | { | 150 | acpi_unlock_hp_context(); |
188 | acpi_notify_handler cb = NULL; | 151 | notify(adev, event); |
189 | bool run = false; | 152 | return; |
190 | |||
191 | mutex_lock(&hotplug_lock); | ||
192 | |||
193 | if (dd->hp_context) { | ||
194 | run = true; | ||
195 | dd->hp_refcount++; | ||
196 | if (dd->hp_ops) { | ||
197 | switch (cb_type) { | ||
198 | case DOCK_CALL_FIXUP: | ||
199 | cb = dd->hp_ops->fixup; | ||
200 | break; | ||
201 | case DOCK_CALL_UEVENT: | ||
202 | cb = dd->hp_ops->uevent; | ||
203 | break; | ||
204 | default: | ||
205 | cb = dd->hp_ops->handler; | ||
206 | } | ||
207 | } | 153 | } |
208 | } | 154 | } |
209 | 155 | ||
210 | mutex_unlock(&hotplug_lock); | 156 | out: |
157 | acpi_unlock_hp_context(); | ||
158 | } | ||
211 | 159 | ||
212 | if (!run) | 160 | static struct dock_station *find_dock_station(acpi_handle handle) |
213 | return; | 161 | { |
162 | struct dock_station *ds; | ||
214 | 163 | ||
215 | if (cb) | 164 | list_for_each_entry(ds, &dock_stations, sibling) |
216 | cb(dd->handle, event, dd->hp_context); | 165 | if (ds->handle == handle) |
166 | return ds; | ||
217 | 167 | ||
218 | dock_release_hotplug(dd); | 168 | return NULL; |
219 | } | 169 | } |
220 | 170 | ||
221 | /** | 171 | /** |
222 | * find_dock_dependent_device - get a device dependent on this dock | 172 | * find_dock_dependent_device - get a device dependent on this dock |
223 | * @ds: the dock station | 173 | * @ds: the dock station |
224 | * @handle: the acpi_handle of the device we want | 174 | * @adev: ACPI device object to find. |
225 | * | 175 | * |
226 | * iterate over the dependent device list for this dock. If the | 176 | * iterate over the dependent device list for this dock. If the |
227 | * dependent device matches the handle, return. | 177 | * dependent device matches the handle, return. |
228 | */ | 178 | */ |
229 | static struct dock_dependent_device * | 179 | static struct dock_dependent_device * |
230 | find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) | 180 | find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev) |
231 | { | 181 | { |
232 | struct dock_dependent_device *dd; | 182 | struct dock_dependent_device *dd; |
233 | 183 | ||
234 | list_for_each_entry(dd, &ds->dependent_devices, list) | 184 | list_for_each_entry(dd, &ds->dependent_devices, list) |
235 | if (handle == dd->handle) | 185 | if (adev == dd->adev) |
236 | return dd; | 186 | return dd; |
237 | 187 | ||
238 | return NULL; | 188 | return NULL; |
239 | } | 189 | } |
240 | 190 | ||
241 | /***************************************************************************** | 191 | void register_dock_dependent_device(struct acpi_device *adev, |
242 | * Dock functions * | 192 | acpi_handle dshandle) |
243 | *****************************************************************************/ | ||
244 | static int __init is_battery(acpi_handle handle) | ||
245 | { | 193 | { |
246 | struct acpi_device_info *info; | 194 | struct dock_station *ds = find_dock_station(dshandle); |
247 | int ret = 1; | ||
248 | 195 | ||
249 | if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) | 196 | if (ds && !find_dock_dependent_device(ds, adev)) |
250 | return 0; | 197 | add_dock_dependent_device(ds, adev); |
251 | if (!(info->valid & ACPI_VALID_HID)) | ||
252 | ret = 0; | ||
253 | else | ||
254 | ret = !strcmp("PNP0C0A", info->hardware_id.string); | ||
255 | |||
256 | kfree(info); | ||
257 | return ret; | ||
258 | } | 198 | } |
259 | 199 | ||
260 | /* Check whether ACPI object is an ejectable battery or disk bay */ | 200 | /***************************************************************************** |
261 | static bool __init is_ejectable_bay(acpi_handle handle) | 201 | * Dock functions * |
262 | { | 202 | *****************************************************************************/ |
263 | if (acpi_has_method(handle, "_EJ0") && is_battery(handle)) | ||
264 | return true; | ||
265 | |||
266 | return acpi_bay_match(handle); | ||
267 | } | ||
268 | 203 | ||
269 | /** | 204 | /** |
270 | * is_dock_device - see if a device is on a dock station | 205 | * is_dock_device - see if a device is on a dock station |
271 | * @handle: acpi handle of the device | 206 | * @adev: ACPI device object to check. |
272 | * | 207 | * |
273 | * If this device is either the dock station itself, | 208 | * If this device is either the dock station itself, |
274 | * or is a device dependent on the dock station, then it | 209 | * or is a device dependent on the dock station, then it |
275 | * is a dock device | 210 | * is a dock device |
276 | */ | 211 | */ |
277 | int is_dock_device(acpi_handle handle) | 212 | int is_dock_device(struct acpi_device *adev) |
278 | { | 213 | { |
279 | struct dock_station *dock_station; | 214 | struct dock_station *dock_station; |
280 | 215 | ||
281 | if (!dock_station_count) | 216 | if (!dock_station_count) |
282 | return 0; | 217 | return 0; |
283 | 218 | ||
284 | if (acpi_dock_match(handle)) | 219 | if (acpi_dock_match(adev->handle)) |
285 | return 1; | 220 | return 1; |
286 | 221 | ||
287 | list_for_each_entry(dock_station, &dock_stations, sibling) | 222 | list_for_each_entry(dock_station, &dock_stations, sibling) |
288 | if (find_dock_dependent_device(dock_station, handle)) | 223 | if (find_dock_dependent_device(dock_station, adev)) |
289 | return 1; | 224 | return 1; |
290 | 225 | ||
291 | return 0; | 226 | return 0; |
@@ -313,43 +248,6 @@ static int dock_present(struct dock_station *ds) | |||
313 | } | 248 | } |
314 | 249 | ||
315 | /** | 250 | /** |
316 | * dock_create_acpi_device - add new devices to acpi | ||
317 | * @handle - handle of the device to add | ||
318 | * | ||
319 | * This function will create a new acpi_device for the given | ||
320 | * handle if one does not exist already. This should cause | ||
321 | * acpi to scan for drivers for the given devices, and call | ||
322 | * matching driver's add routine. | ||
323 | */ | ||
324 | static void dock_create_acpi_device(acpi_handle handle) | ||
325 | { | ||
326 | struct acpi_device *device = NULL; | ||
327 | int ret; | ||
328 | |||
329 | acpi_bus_get_device(handle, &device); | ||
330 | if (!acpi_device_enumerated(device)) { | ||
331 | ret = acpi_bus_scan(handle); | ||
332 | if (ret) | ||
333 | pr_debug("error adding bus, %x\n", -ret); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * dock_remove_acpi_device - remove the acpi_device struct from acpi | ||
339 | * @handle - the handle of the device to remove | ||
340 | * | ||
341 | * Tell acpi to remove the acpi_device. This should cause any loaded | ||
342 | * driver to have it's remove routine called. | ||
343 | */ | ||
344 | static void dock_remove_acpi_device(acpi_handle handle) | ||
345 | { | ||
346 | struct acpi_device *device; | ||
347 | |||
348 | if (!acpi_bus_get_device(handle, &device)) | ||
349 | acpi_bus_trim(device); | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * hot_remove_dock_devices - Remove dock station devices. | 251 | * hot_remove_dock_devices - Remove dock station devices. |
354 | * @ds: Dock station. | 252 | * @ds: Dock station. |
355 | */ | 253 | */ |
@@ -366,7 +264,7 @@ static void hot_remove_dock_devices(struct dock_station *ds) | |||
366 | dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false); | 264 | dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false); |
367 | 265 | ||
368 | list_for_each_entry_reverse(dd, &ds->dependent_devices, list) | 266 | list_for_each_entry_reverse(dd, &ds->dependent_devices, list) |
369 | dock_remove_acpi_device(dd->handle); | 267 | acpi_bus_trim(dd->adev); |
370 | } | 268 | } |
371 | 269 | ||
372 | /** | 270 | /** |
@@ -392,12 +290,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
392 | dock_hotplug_event(dd, event, DOCK_CALL_HANDLER); | 290 | dock_hotplug_event(dd, event, DOCK_CALL_HANDLER); |
393 | 291 | ||
394 | /* | 292 | /* |
395 | * Now make sure that an acpi_device is created for each dependent | 293 | * Check if all devices have been enumerated already. If not, run |
396 | * device. That will cause scan handlers to be attached to device | 294 | * acpi_bus_scan() for them and that will cause scan handlers to be |
397 | * objects or acpi_drivers to be stopped/started if they are present. | 295 | * attached to device objects or acpi_drivers to be stopped/started if |
296 | * they are present. | ||
398 | */ | 297 | */ |
399 | list_for_each_entry(dd, &ds->dependent_devices, list) | 298 | list_for_each_entry(dd, &ds->dependent_devices, list) { |
400 | dock_create_acpi_device(dd->handle); | 299 | struct acpi_device *adev = dd->adev; |
300 | |||
301 | if (!acpi_device_enumerated(adev)) { | ||
302 | int ret = acpi_bus_scan(adev->handle); | ||
303 | if (ret) | ||
304 | dev_dbg(&adev->dev, "scan error %d\n", -ret); | ||
305 | } | ||
306 | } | ||
401 | } | 307 | } |
402 | 308 | ||
403 | static void dock_event(struct dock_station *ds, u32 event, int num) | 309 | static void dock_event(struct dock_station *ds, u32 event, int num) |
@@ -501,71 +407,6 @@ static int dock_in_progress(struct dock_station *ds) | |||
501 | } | 407 | } |
502 | 408 | ||
503 | /** | 409 | /** |
504 | * register_hotplug_dock_device - register a hotplug function | ||
505 | * @handle: the handle of the device | ||
506 | * @ops: handlers to call after docking | ||
507 | * @context: device specific data | ||
508 | * @init: Optional initialization routine to run after registration | ||
509 | * @release: Optional release routine to run on unregistration | ||
510 | * | ||
511 | * If a driver would like to perform a hotplug operation after a dock | ||
512 | * event, they can register an acpi_notifiy_handler to be called by | ||
513 | * the dock driver after _DCK is executed. | ||
514 | */ | ||
515 | int register_hotplug_dock_device(acpi_handle handle, | ||
516 | const struct acpi_dock_ops *ops, void *context, | ||
517 | void (*init)(void *), void (*release)(void *)) | ||
518 | { | ||
519 | struct dock_dependent_device *dd; | ||
520 | struct dock_station *dock_station; | ||
521 | int ret = -EINVAL; | ||
522 | |||
523 | if (WARN_ON(!context)) | ||
524 | return -EINVAL; | ||
525 | |||
526 | if (!dock_station_count) | ||
527 | return -ENODEV; | ||
528 | |||
529 | /* | ||
530 | * make sure this handle is for a device dependent on the dock, | ||
531 | * this would include the dock station itself | ||
532 | */ | ||
533 | list_for_each_entry(dock_station, &dock_stations, sibling) { | ||
534 | /* | ||
535 | * An ATA bay can be in a dock and itself can be ejected | ||
536 | * separately, so there are two 'dock stations' which need the | ||
537 | * ops | ||
538 | */ | ||
539 | dd = find_dock_dependent_device(dock_station, handle); | ||
540 | if (dd && !dock_init_hotplug(dd, ops, context, init, release)) | ||
541 | ret = 0; | ||
542 | } | ||
543 | |||
544 | return ret; | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); | ||
547 | |||
548 | /** | ||
549 | * unregister_hotplug_dock_device - remove yourself from the hotplug list | ||
550 | * @handle: the acpi handle of the device | ||
551 | */ | ||
552 | void unregister_hotplug_dock_device(acpi_handle handle) | ||
553 | { | ||
554 | struct dock_dependent_device *dd; | ||
555 | struct dock_station *dock_station; | ||
556 | |||
557 | if (!dock_station_count) | ||
558 | return; | ||
559 | |||
560 | list_for_each_entry(dock_station, &dock_stations, sibling) { | ||
561 | dd = find_dock_dependent_device(dock_station, handle); | ||
562 | if (dd) | ||
563 | dock_release_hotplug(dd); | ||
564 | } | ||
565 | } | ||
566 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | ||
567 | |||
568 | /** | ||
569 | * handle_eject_request - handle an undock request checking for error conditions | 410 | * handle_eject_request - handle an undock request checking for error conditions |
570 | * | 411 | * |
571 | * Check to make sure the dock device is still present, then undock and | 412 | * Check to make sure the dock device is still present, then undock and |
@@ -598,20 +439,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event) | |||
598 | } | 439 | } |
599 | 440 | ||
600 | /** | 441 | /** |
601 | * dock_notify - act upon an acpi dock notification | 442 | * dock_notify - Handle ACPI dock notification. |
602 | * @ds: dock station | 443 | * @adev: Dock station's ACPI device object. |
603 | * @event: the acpi event | 444 | * @event: Event code. |
604 | * | 445 | * |
605 | * If we are notified to dock, then check to see if the dock is | 446 | * If we are notified to dock, then check to see if the dock is |
606 | * present and then dock. Notify all drivers of the dock event, | 447 | * present and then dock. Notify all drivers of the dock event, |
607 | * and then hotplug and devices that may need hotplugging. | 448 | * and then hotplug and devices that may need hotplugging. |
608 | */ | 449 | */ |
609 | static void dock_notify(struct dock_station *ds, u32 event) | 450 | int dock_notify(struct acpi_device *adev, u32 event) |
610 | { | 451 | { |
611 | acpi_handle handle = ds->handle; | 452 | acpi_handle handle = adev->handle; |
612 | struct acpi_device *ad; | 453 | struct dock_station *ds = find_dock_station(handle); |
613 | int surprise_removal = 0; | 454 | int surprise_removal = 0; |
614 | 455 | ||
456 | if (!ds) | ||
457 | return -ENODEV; | ||
458 | |||
615 | /* | 459 | /* |
616 | * According to acpi spec 3.0a, if a DEVICE_CHECK notification | 460 | * According to acpi spec 3.0a, if a DEVICE_CHECK notification |
617 | * is sent and _DCK is present, it is assumed to mean an undock | 461 | * is sent and _DCK is present, it is assumed to mean an undock |
@@ -632,7 +476,7 @@ static void dock_notify(struct dock_station *ds, u32 event) | |||
632 | switch (event) { | 476 | switch (event) { |
633 | case ACPI_NOTIFY_BUS_CHECK: | 477 | case ACPI_NOTIFY_BUS_CHECK: |
634 | case ACPI_NOTIFY_DEVICE_CHECK: | 478 | case ACPI_NOTIFY_DEVICE_CHECK: |
635 | if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) { | 479 | if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { |
636 | begin_dock(ds); | 480 | begin_dock(ds); |
637 | dock(ds); | 481 | dock(ds); |
638 | if (!dock_present(ds)) { | 482 | if (!dock_present(ds)) { |
@@ -661,49 +505,8 @@ static void dock_notify(struct dock_station *ds, u32 event) | |||
661 | else | 505 | else |
662 | dock_event(ds, event, UNDOCK_EVENT); | 506 | dock_event(ds, event, UNDOCK_EVENT); |
663 | break; | 507 | break; |
664 | default: | ||
665 | acpi_handle_err(handle, "Unknown dock event %d\n", event); | ||
666 | } | 508 | } |
667 | } | 509 | return 0; |
668 | |||
669 | static void acpi_dock_deferred_cb(void *data, u32 event) | ||
670 | { | ||
671 | acpi_scan_lock_acquire(); | ||
672 | dock_notify(data, event); | ||
673 | acpi_scan_lock_release(); | ||
674 | } | ||
675 | |||
676 | static void dock_notify_handler(acpi_handle handle, u32 event, void *data) | ||
677 | { | ||
678 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK | ||
679 | && event != ACPI_NOTIFY_EJECT_REQUEST) | ||
680 | return; | ||
681 | |||
682 | acpi_hotplug_execute(acpi_dock_deferred_cb, data, event); | ||
683 | } | ||
684 | |||
685 | /** | ||
686 | * find_dock_devices - find devices on the dock station | ||
687 | * @handle: the handle of the device we are examining | ||
688 | * @lvl: unused | ||
689 | * @context: the dock station private data | ||
690 | * @rv: unused | ||
691 | * | ||
692 | * This function is called by acpi_walk_namespace. It will | ||
693 | * check to see if an object has an _EJD method. If it does, then it | ||
694 | * will see if it is dependent on the dock station. | ||
695 | */ | ||
696 | static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, | ||
697 | void *context, void **rv) | ||
698 | { | ||
699 | struct dock_station *ds = context; | ||
700 | acpi_handle ejd = NULL; | ||
701 | |||
702 | acpi_bus_get_ejd(handle, &ejd); | ||
703 | if (ejd == ds->handle) | ||
704 | add_dock_dependent_device(ds, handle); | ||
705 | |||
706 | return AE_OK; | ||
707 | } | 510 | } |
708 | 511 | ||
709 | /* | 512 | /* |
@@ -712,13 +515,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, | |||
712 | static ssize_t show_docked(struct device *dev, | 515 | static ssize_t show_docked(struct device *dev, |
713 | struct device_attribute *attr, char *buf) | 516 | struct device_attribute *attr, char *buf) |
714 | { | 517 | { |
715 | struct acpi_device *tmp; | ||
716 | |||
717 | struct dock_station *dock_station = dev->platform_data; | 518 | struct dock_station *dock_station = dev->platform_data; |
519 | struct acpi_device *adev = NULL; | ||
718 | 520 | ||
719 | if (!acpi_bus_get_device(dock_station->handle, &tmp)) | 521 | acpi_bus_get_device(dock_station->handle, &adev); |
720 | return snprintf(buf, PAGE_SIZE, "1\n"); | 522 | return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev)); |
721 | return snprintf(buf, PAGE_SIZE, "0\n"); | ||
722 | } | 523 | } |
723 | static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | 524 | static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); |
724 | 525 | ||
@@ -804,23 +605,28 @@ static struct attribute_group dock_attribute_group = { | |||
804 | }; | 605 | }; |
805 | 606 | ||
806 | /** | 607 | /** |
807 | * dock_add - add a new dock station | 608 | * acpi_dock_add - Add a new dock station |
808 | * @handle: the dock station handle | 609 | * @adev: Dock station ACPI device object. |
809 | * | 610 | * |
810 | * allocated and initialize a new dock station device. Find all devices | 611 | * allocated and initialize a new dock station device. |
811 | * that are on the dock station, and register for dock event notifications. | ||
812 | */ | 612 | */ |
813 | static int __init dock_add(acpi_handle handle) | 613 | void acpi_dock_add(struct acpi_device *adev) |
814 | { | 614 | { |
815 | struct dock_station *dock_station, ds = { NULL, }; | 615 | struct dock_station *dock_station, ds = { NULL, }; |
616 | struct platform_device_info pdevinfo; | ||
617 | acpi_handle handle = adev->handle; | ||
816 | struct platform_device *dd; | 618 | struct platform_device *dd; |
817 | acpi_status status; | ||
818 | int ret; | 619 | int ret; |
819 | 620 | ||
820 | dd = platform_device_register_data(NULL, "dock", dock_station_count, | 621 | memset(&pdevinfo, 0, sizeof(pdevinfo)); |
821 | &ds, sizeof(ds)); | 622 | pdevinfo.name = "dock"; |
623 | pdevinfo.id = dock_station_count; | ||
624 | pdevinfo.acpi_node.companion = adev; | ||
625 | pdevinfo.data = &ds; | ||
626 | pdevinfo.size_data = sizeof(ds); | ||
627 | dd = platform_device_register_full(&pdevinfo); | ||
822 | if (IS_ERR(dd)) | 628 | if (IS_ERR(dd)) |
823 | return PTR_ERR(dd); | 629 | return; |
824 | 630 | ||
825 | dock_station = dd->dev.platform_data; | 631 | dock_station = dd->dev.platform_data; |
826 | 632 | ||
@@ -838,72 +644,29 @@ static int __init dock_add(acpi_handle handle) | |||
838 | dock_station->flags |= DOCK_IS_DOCK; | 644 | dock_station->flags |= DOCK_IS_DOCK; |
839 | if (acpi_ata_match(handle)) | 645 | if (acpi_ata_match(handle)) |
840 | dock_station->flags |= DOCK_IS_ATA; | 646 | dock_station->flags |= DOCK_IS_ATA; |
841 | if (is_battery(handle)) | 647 | if (acpi_device_is_battery(adev)) |
842 | dock_station->flags |= DOCK_IS_BAT; | 648 | dock_station->flags |= DOCK_IS_BAT; |
843 | 649 | ||
844 | ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); | 650 | ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); |
845 | if (ret) | 651 | if (ret) |
846 | goto err_unregister; | 652 | goto err_unregister; |
847 | 653 | ||
848 | /* Find dependent devices */ | ||
849 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
850 | ACPI_UINT32_MAX, find_dock_devices, NULL, | ||
851 | dock_station, NULL); | ||
852 | |||
853 | /* add the dock station as a device dependent on itself */ | 654 | /* add the dock station as a device dependent on itself */ |
854 | ret = add_dock_dependent_device(dock_station, handle); | 655 | ret = add_dock_dependent_device(dock_station, adev); |
855 | if (ret) | 656 | if (ret) |
856 | goto err_rmgroup; | 657 | goto err_rmgroup; |
857 | 658 | ||
858 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
859 | dock_notify_handler, dock_station); | ||
860 | if (ACPI_FAILURE(status)) { | ||
861 | ret = -ENODEV; | ||
862 | goto err_rmgroup; | ||
863 | } | ||
864 | |||
865 | dock_station_count++; | 659 | dock_station_count++; |
866 | list_add(&dock_station->sibling, &dock_stations); | 660 | list_add(&dock_station->sibling, &dock_stations); |
867 | return 0; | 661 | adev->flags.is_dock_station = true; |
662 | dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n", | ||
663 | dock_station_count); | ||
664 | return; | ||
868 | 665 | ||
869 | err_rmgroup: | 666 | err_rmgroup: |
870 | remove_dock_dependent_devices(dock_station); | ||
871 | sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); | 667 | sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); |
668 | |||
872 | err_unregister: | 669 | err_unregister: |
873 | platform_device_unregister(dd); | 670 | platform_device_unregister(dd); |
874 | acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); | 671 | acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); |
875 | return ret; | ||
876 | } | ||
877 | |||
878 | /** | ||
879 | * find_dock_and_bay - look for dock stations and bays | ||
880 | * @handle: acpi handle of a device | ||
881 | * @lvl: unused | ||
882 | * @context: unused | ||
883 | * @rv: unused | ||
884 | * | ||
885 | * This is called by acpi_walk_namespace to look for dock stations and bays. | ||
886 | */ | ||
887 | static acpi_status __init | ||
888 | find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
889 | { | ||
890 | if (acpi_dock_match(handle) || is_ejectable_bay(handle)) | ||
891 | dock_add(handle); | ||
892 | |||
893 | return AE_OK; | ||
894 | } | ||
895 | |||
896 | void __init acpi_dock_init(void) | ||
897 | { | ||
898 | /* look for dock stations and bays */ | ||
899 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
900 | ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); | ||
901 | |||
902 | if (!dock_station_count) { | ||
903 | pr_info(PREFIX "No dock devices found.\n"); | ||
904 | return; | ||
905 | } | ||
906 | |||
907 | pr_info(PREFIX "%s: %d docks/bays found\n", | ||
908 | ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); | ||
909 | } | 672 | } |