1 From: Shaohua Li <shaohua.li@intel.com>
2 Subject: makeing dock driver supports bay and battery hotplug
3 Patch-mainline: submitted 2008-08-28
4 References: fate#304731,bnc#401740
6 Making dock driver supports bay and battery hotplug. They are all
7 regarded as dock, and unified handled.
9 Signed-off-by: Shaohua Li <shaohua.li@intel.com>
10 Signed-off-by: Holger Macht <hmacht@suse.de>
14 drivers/acpi/dock.c | 221 ++++++++++++++++++++++++++++++++++++++++------------
15 1 file changed, 173 insertions(+), 48 deletions(-)
17 --- a/drivers/acpi/dock.c
18 +++ b/drivers/acpi/dock.c
19 @@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (d
22 static struct atomic_notifier_head dock_notifier_list;
23 -static struct platform_device *dock_device;
24 static char dock_device_name[] = "dock";
26 static const struct acpi_device_id dock_device_ids[] = {
27 @@ -65,7 +64,12 @@ struct dock_station {
29 struct list_head dependent_devices;
30 struct list_head hotplug_devices;
32 + struct list_head sibiling;
33 + struct platform_device *dock_device;
35 +static LIST_HEAD(dock_stations);
36 +static int dock_station_count;
38 struct dock_dependent_device {
39 struct list_head list;
40 @@ -77,11 +81,12 @@ struct dock_dependent_device {
42 #define DOCK_DOCKING 0x00000001
43 #define DOCK_UNDOCKING 0x00000002
44 +#define DOCK_IS_DOCK 0x00000010
45 +#define DOCK_IS_ATA 0x00000020
46 +#define DOCK_IS_BAT 0x00000040
48 #define UNDOCK_EVENT 2
50 -static struct dock_station *dock_station;
52 /*****************************************************************************
53 * Dock Dependent device functions *
54 *****************************************************************************/
55 @@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
59 +static int is_ejectable(acpi_handle handle)
64 + status = acpi_get_handle(handle, "_EJ0", &tmp);
65 + if (ACPI_FAILURE(status))
70 +static int is_ata(acpi_handle handle)
74 + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
75 + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
76 + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
77 + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
83 +static int is_battery(acpi_handle handle)
85 + struct acpi_device_info *info;
86 + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
89 + if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
91 + info = buffer.pointer;
92 + if (!(info->valid & ACPI_VALID_HID))
95 + ret = !strcmp("PNP0C0A", info->hardware_id.value);
97 + kfree(buffer.pointer);
101 +static int is_ejectable_bay(acpi_handle handle)
103 + acpi_handle phandle;
104 + if (!is_ejectable(handle))
106 + if (is_battery(handle) || is_ata(handle))
108 + if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
114 * is_dock_device - see if a device is on a dock station
115 * @handle: acpi handle of the device
116 @@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
118 int is_dock_device(acpi_handle handle)
121 + struct dock_station *dock_station;
123 + if (!dock_station_count)
126 - if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
127 + if (is_dock(handle))
129 + list_for_each_entry(dock_station, &dock_stations, sibiling) {
130 + if (find_dock_dependent_device(dock_station, handle))
136 @@ -341,7 +406,7 @@ static void hotplug_dock_devices(struct
138 static void dock_event(struct dock_station *ds, u32 event, int num)
140 - struct device *dev = &dock_device->dev;
141 + struct device *dev = &ds->dock_device->dev;
142 char event_string[13];
143 char *envp[] = { event_string, NULL };
145 @@ -414,7 +479,7 @@ static void handle_dock(struct dock_stat
146 arg.type = ACPI_TYPE_INTEGER;
147 arg.integer.value = dock;
148 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
149 - if (ACPI_FAILURE(status))
150 + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
151 printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
152 (char *)name_buffer.pointer);
153 kfree(buffer.pointer);
154 @@ -498,7 +563,7 @@ static int dock_in_progress(struct dock_
156 int register_dock_notifier(struct notifier_block *nb)
159 + if (!dock_station_count)
162 return atomic_notifier_chain_register(&dock_notifier_list, nb);
163 @@ -512,7 +577,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier
165 void unregister_dock_notifier(struct notifier_block *nb)
168 + if (!dock_station_count)
171 atomic_notifier_chain_unregister(&dock_notifier_list, nb);
172 @@ -535,20 +600,23 @@ register_hotplug_dock_device(acpi_handle
175 struct dock_dependent_device *dd;
176 + struct dock_station *dock_station;
179 + if (!dock_station_count)
183 * make sure this handle is for a device dependent on the dock,
184 * this would include the dock station itself
186 - dd = find_dock_dependent_device(dock_station, handle);
188 - dd->handler = handler;
189 - dd->context = context;
190 - dock_add_hotplug_device(dock_station, dd);
192 + list_for_each_entry(dock_station, &dock_stations, sibiling) {
193 + dd = find_dock_dependent_device(dock_station, handle);
195 + dd->handler = handler;
196 + dd->context = context;
197 + dock_add_hotplug_device(dock_station, dd);
203 @@ -563,13 +631,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_
204 void unregister_hotplug_dock_device(acpi_handle handle)
206 struct dock_dependent_device *dd;
207 + struct dock_station *dock_station;
210 + if (!dock_station_count)
213 - dd = find_dock_dependent_device(dock_station, handle);
215 - dock_del_hotplug_device(dock_station, dd);
216 + list_for_each_entry(dock_station, &dock_stations, sibiling) {
217 + dd = find_dock_dependent_device(dock_station, handle);
219 + dock_del_hotplug_device(dock_station, dd);
223 EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
224 @@ -620,9 +691,28 @@ static void dock_notify(acpi_handle hand
226 struct dock_station *ds = data;
227 struct acpi_device *tmp;
228 + int surprise_removal = 0;
231 + * According to acpi spec 3.0a, if a DEVICE_CHECK notification
232 + * is sent and _DCK is present, it is assumed to mean an undock
235 + if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
236 + event = ACPI_NOTIFY_EJECT_REQUEST;
239 + * dock station: BUS_CHECK - docked or surprise removal
240 + * DEVICE_CHECK - undocked
241 + * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
243 + * To simplify event handling, dock dependent device handler always
244 + * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
245 + * ACPI_NOTIFY_EJECT_REQUEST for removal
248 case ACPI_NOTIFY_BUS_CHECK:
249 + case ACPI_NOTIFY_DEVICE_CHECK:
250 if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
253 @@ -638,20 +728,17 @@ static void dock_notify(acpi_handle hand
255 dock_event(ds, event, DOCK_EVENT);
260 - case ACPI_NOTIFY_DEVICE_CHECK:
262 - * According to acpi spec 3.0a, if a DEVICE_CHECK notification
263 - * is sent and _DCK is present, it is assumed to mean an
264 - * undock request. This notify routine will only be called
265 - * for objects defining _DCK, so we will fall through to eject
266 - * request here. However, we will pass an eject request through
267 - * to the driver who wish to hotplug.
269 + if (dock_present(ds) || dock_in_progress(ds))
271 + /* This is a surprise removal */
272 + surprise_removal = 1;
273 + event = ACPI_NOTIFY_EJECT_REQUEST;
275 case ACPI_NOTIFY_EJECT_REQUEST:
277 - if (immediate_undock)
278 + if (immediate_undock || surprise_removal)
279 handle_eject_request(ds, event);
281 dock_event(ds, event, UNDOCK_EVENT);
282 @@ -718,6 +805,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show
283 static ssize_t show_flags(struct device *dev,
284 struct device_attribute *attr, char *buf)
286 + struct dock_station *dock_station = *((struct dock_station **)
287 + dev->platform_data);
288 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
291 @@ -730,6 +819,8 @@ static ssize_t write_undock(struct devic
292 const char *buf, size_t count)
295 + struct dock_station *dock_station = *((struct dock_station **)
296 + dev->platform_data);
300 @@ -747,6 +838,8 @@ static ssize_t show_dock_uid(struct devi
301 struct device_attribute *attr, char *buf)
303 unsigned long long lbuf;
304 + struct dock_station *dock_station = *((struct dock_station **)
305 + dev->platform_data);
306 acpi_status status = acpi_evaluate_integer(dock_station->handle,
307 "_UID", NULL, &lbuf);
308 if (ACPI_FAILURE(status))
309 @@ -768,6 +861,8 @@ static int dock_add(acpi_handle handle)
312 struct dock_dependent_device *dd;
313 + struct dock_station *dock_station;
314 + struct platform_device *dock_device;
316 /* allocate & initialize the dock_station private data */
317 dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
318 @@ -777,22 +872,34 @@ static int dock_add(acpi_handle handle)
319 dock_station->last_dock_time = jiffies - HZ;
320 INIT_LIST_HEAD(&dock_station->dependent_devices);
321 INIT_LIST_HEAD(&dock_station->hotplug_devices);
322 + INIT_LIST_HEAD(&dock_station->sibiling);
323 spin_lock_init(&dock_station->dd_lock);
324 mutex_init(&dock_station->hp_lock);
325 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
327 /* initialize platform device stuff */
329 - platform_device_register_simple(dock_device_name, 0, NULL, 0);
330 + dock_station->dock_device =
331 + platform_device_register_simple(dock_device_name,
332 + dock_station_count, NULL, 0);
333 + dock_device = dock_station->dock_device;
334 if (IS_ERR(dock_device)) {
337 return PTR_ERR(dock_device);
339 + platform_device_add_data(dock_device, &dock_station,
340 + sizeof(struct dock_station *));
342 /* we want the dock device to send uevents */
343 dock_device->dev.uevent_suppress = 0;
345 + if (is_dock(handle))
346 + dock_station->flags |= DOCK_IS_DOCK;
347 + if (is_ata(handle))
348 + dock_station->flags |= DOCK_IS_ATA;
349 + if (is_battery(handle))
350 + dock_station->flags |= DOCK_IS_BAT;
352 ret = device_create_file(&dock_device->dev, &dev_attr_docked);
354 printk("Error %d adding sysfs file\n", ret);
355 @@ -858,8 +965,8 @@ static int dock_add(acpi_handle handle)
359 - printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
361 + dock_station_count++;
362 + list_add(&dock_station->sibiling, &dock_stations);
366 @@ -878,12 +985,13 @@ dock_add_err_unregister:
368 * dock_remove - free up resources related to the dock station
370 -static int dock_remove(void)
371 +static int dock_remove(struct dock_station *dock_station)
373 struct dock_dependent_device *dd, *tmp;
375 + struct platform_device *dock_device = dock_station->dock_device;
378 + if (!dock_station_count)
381 /* remove dependent devices */
382 @@ -923,41 +1031,58 @@ static int dock_remove(void)
384 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
386 - int *count = context;
387 acpi_status status = AE_OK;
389 if (is_dock(handle)) {
390 if (dock_add(handle) >= 0) {
392 status = AE_CTRL_TERMINATE;
398 -static int __init dock_init(void)
400 +find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
404 - dock_station = NULL;
405 + /* If bay is in a dock, it's already handled */
406 + if (is_ejectable_bay(handle) && !is_dock_device(handle))
411 +static int __init dock_init(void)
416 /* look for a dock station */
417 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
418 - ACPI_UINT32_MAX, find_dock, &num, NULL);
419 + ACPI_UINT32_MAX, find_dock, NULL, NULL);
422 - printk(KERN_INFO "No dock devices found.\n");
424 + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
425 + ACPI_UINT32_MAX, find_bay, NULL, NULL);
426 + if (!dock_station_count) {
427 + printk(KERN_INFO PREFIX "No dock devices found.\n");
431 + printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
432 + ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
436 static void __exit dock_exit(void)
439 + struct dock_station *dock_station;
441 + list_for_each_entry(dock_station, &dock_stations, sibiling)
442 + dock_remove(dock_station);
445 -postcore_initcall(dock_init);
447 + * Must be called before drivers of devices in dock, otherwise we can't know
448 + * which devices are in a dock
450 +subsys_initcall(dock_init);
451 module_exit(dock_exit);