1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/slab.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/notifier.h>
31#include <linux/platform_device.h>
32#include <linux/jiffies.h>
33#include <linux/stddef.h>
34#include <linux/acpi.h>
35#include <acpi/acpi_bus.h>
36#include <acpi/acpi_drivers.h>
37
38#include "internal.h"
39
40#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
41
42ACPI_MODULE_NAME("dock");
43MODULE_AUTHOR("Kristen Carlson Accardi");
44MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
45MODULE_LICENSE("GPL");
46
47static bool immediate_undock = 1;
48module_param(immediate_undock, bool, 0644);
49MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
50 "undock immediately when the undock button is pressed, 0 will cause"
51 " the driver to wait for userspace to write the undock sysfs file "
52 " before undocking");
53
54static const struct acpi_device_id dock_device_ids[] = {
55 {"LNXDOCK", 0},
56 {"", 0},
57};
58MODULE_DEVICE_TABLE(acpi, dock_device_ids);
59
60struct dock_station {
61 acpi_handle handle;
62 unsigned long last_dock_time;
63 u32 flags;
64 struct list_head dependent_devices;
65
66 struct list_head sibling;
67 struct platform_device *dock_device;
68};
69static LIST_HEAD(dock_stations);
70static int dock_station_count;
71static DEFINE_MUTEX(hotplug_lock);
72
73struct dock_dependent_device {
74 struct list_head list;
75 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};
81
82#define DOCK_DOCKING 0x00000001
83#define DOCK_UNDOCKING 0x00000002
84#define DOCK_IS_DOCK 0x00000010
85#define DOCK_IS_ATA 0x00000020
86#define DOCK_IS_BAT 0x00000040
87#define DOCK_EVENT 3
88#define UNDOCK_EVENT 2
89
90enum dock_callback_type {
91 DOCK_CALL_HANDLER,
92 DOCK_CALL_FIXUP,
93 DOCK_CALL_UEVENT,
94};
95
96
97
98
99
100
101
102
103
104
105
106static int add_dock_dependent_device(struct dock_station *ds,
107 struct acpi_device *adev)
108{
109 struct dock_dependent_device *dd;
110
111 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
112 if (!dd)
113 return -ENOMEM;
114
115 dd->adev = adev;
116 INIT_LIST_HEAD(&dd->list);
117 list_add_tail(&dd->list, &ds->dependent_devices);
118
119 return 0;
120}
121
122static void remove_dock_dependent_devices(struct dock_station *ds)
123{
124 struct dock_dependent_device *dd, *aux;
125
126 list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
127 list_del(&dd->list);
128 kfree(dd);
129 }
130}
131
132
133
134
135
136
137
138
139
140static 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
146 mutex_lock(&hotplug_lock);
147 if (WARN_ON(dd->hp_context)) {
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
161
162
163
164
165
166
167
168
169static void dock_release_hotplug(struct dock_dependent_device *dd)
170{
171 mutex_lock(&hotplug_lock);
172 if (dd->hp_context && !--dd->hp_refcount) {
173 void (*release)(void *) = dd->hp_release;
174 void *context = dd->hp_context;
175
176 dd->hp_ops = NULL;
177 dd->hp_context = NULL;
178 dd->hp_release = NULL;
179 if (release)
180 release(context);
181 }
182 mutex_unlock(&hotplug_lock);
183}
184
185static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
186 enum dock_callback_type cb_type)
187{
188 struct acpi_device *adev = dd->adev;
189 acpi_notify_handler cb = NULL;
190 bool run = false;
191
192 acpi_lock_hp_context();
193
194 if (!adev->hp)
195 goto no_context;
196
197 if (cb_type == DOCK_CALL_FIXUP) {
198 void (*fixup)(struct acpi_device *);
199
200 fixup = adev->hp->fixup;
201 if (fixup) {
202 acpi_unlock_hp_context();
203 fixup(adev);
204 return;
205 }
206 } else if (cb_type == DOCK_CALL_UEVENT) {
207 void (*uevent)(struct acpi_device *, u32);
208
209 uevent = adev->hp->uevent;
210 if (uevent) {
211 acpi_unlock_hp_context();
212 uevent(adev, event);
213 return;
214 }
215 } else {
216 int (*notify)(struct acpi_device *, u32);
217
218 notify = adev->hp->notify;
219 if (notify) {
220 acpi_unlock_hp_context();
221 notify(adev, event);
222 return;
223 }
224 }
225
226 no_context:
227 acpi_unlock_hp_context();
228
229 mutex_lock(&hotplug_lock);
230
231 if (dd->hp_context) {
232 run = true;
233 dd->hp_refcount++;
234 if (dd->hp_ops) {
235 switch (cb_type) {
236 case DOCK_CALL_FIXUP:
237 cb = dd->hp_ops->fixup;
238 break;
239 case DOCK_CALL_UEVENT:
240 cb = dd->hp_ops->uevent;
241 break;
242 default:
243 cb = dd->hp_ops->handler;
244 }
245 }
246 }
247
248 mutex_unlock(&hotplug_lock);
249
250 if (!run)
251 return;
252
253 if (cb)
254 cb(dd->adev->handle, event, dd->hp_context);
255
256 dock_release_hotplug(dd);
257}
258
259static struct dock_station *find_dock_station(acpi_handle handle)
260{
261 struct dock_station *ds;
262
263 list_for_each_entry(ds, &dock_stations, sibling)
264 if (ds->handle == handle)
265 return ds;
266
267 return NULL;
268}
269
270
271
272
273
274
275
276
277
278static struct dock_dependent_device *
279find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
280{
281 struct dock_dependent_device *dd;
282
283 list_for_each_entry(dd, &ds->dependent_devices, list)
284 if (adev == dd->adev)
285 return dd;
286
287 return NULL;
288}
289
290void register_dock_dependent_device(struct acpi_device *adev,
291 acpi_handle dshandle)
292{
293 struct dock_station *ds = find_dock_station(dshandle);
294
295 if (ds && !find_dock_dependent_device(ds, adev))
296 add_dock_dependent_device(ds, adev);
297}
298
299
300
301
302
303
304
305
306
307
308
309
310
311int is_dock_device(struct acpi_device *adev)
312{
313 struct dock_station *dock_station;
314
315 if (!dock_station_count)
316 return 0;
317
318 if (acpi_dock_match(adev->handle))
319 return 1;
320
321 list_for_each_entry(dock_station, &dock_stations, sibling)
322 if (find_dock_dependent_device(dock_station, adev))
323 return 1;
324
325 return 0;
326}
327EXPORT_SYMBOL_GPL(is_dock_device);
328
329
330
331
332
333
334
335
336static int dock_present(struct dock_station *ds)
337{
338 unsigned long long sta;
339 acpi_status status;
340
341 if (ds) {
342 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
343 if (ACPI_SUCCESS(status) && sta)
344 return 1;
345 }
346 return 0;
347}
348
349
350
351
352
353static void hot_remove_dock_devices(struct dock_station *ds)
354{
355 struct dock_dependent_device *dd;
356
357
358
359
360
361
362 list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
363 dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
364
365 list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
366 acpi_bus_trim(dd->adev);
367}
368
369
370
371
372
373
374
375
376
377
378
379static void hotplug_dock_devices(struct dock_station *ds, u32 event)
380{
381 struct dock_dependent_device *dd;
382
383
384 list_for_each_entry(dd, &ds->dependent_devices, list)
385 dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
386
387
388 list_for_each_entry(dd, &ds->dependent_devices, list)
389 dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
390
391
392
393
394
395
396
397 list_for_each_entry(dd, &ds->dependent_devices, list) {
398 struct acpi_device *adev = dd->adev;
399
400 if (!acpi_device_enumerated(adev)) {
401 int ret = acpi_bus_scan(adev->handle);
402 if (ret)
403 dev_dbg(&adev->dev, "scan error %d\n", -ret);
404 }
405 }
406}
407
408static void dock_event(struct dock_station *ds, u32 event, int num)
409{
410 struct device *dev = &ds->dock_device->dev;
411 char event_string[13];
412 char *envp[] = { event_string, NULL };
413 struct dock_dependent_device *dd;
414
415 if (num == UNDOCK_EVENT)
416 sprintf(event_string, "EVENT=undock");
417 else
418 sprintf(event_string, "EVENT=dock");
419
420
421
422
423
424 if (num == DOCK_EVENT)
425 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
426
427 list_for_each_entry(dd, &ds->dependent_devices, list)
428 dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
429
430 if (num != DOCK_EVENT)
431 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
432}
433
434
435
436
437
438
439
440
441static void handle_dock(struct dock_station *ds, int dock)
442{
443 acpi_status status;
444 struct acpi_object_list arg_list;
445 union acpi_object arg;
446 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
447
448 acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
449
450
451 arg_list.count = 1;
452 arg_list.pointer = &arg;
453 arg.type = ACPI_TYPE_INTEGER;
454 arg.integer.value = dock;
455 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
456 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
457 acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
458 status);
459
460 kfree(buffer.pointer);
461}
462
463static inline void dock(struct dock_station *ds)
464{
465 handle_dock(ds, 1);
466}
467
468static inline void undock(struct dock_station *ds)
469{
470 handle_dock(ds, 0);
471}
472
473static inline void begin_dock(struct dock_station *ds)
474{
475 ds->flags |= DOCK_DOCKING;
476}
477
478static inline void complete_dock(struct dock_station *ds)
479{
480 ds->flags &= ~(DOCK_DOCKING);
481 ds->last_dock_time = jiffies;
482}
483
484static inline void begin_undock(struct dock_station *ds)
485{
486 ds->flags |= DOCK_UNDOCKING;
487}
488
489static inline void complete_undock(struct dock_station *ds)
490{
491 ds->flags &= ~(DOCK_UNDOCKING);
492}
493
494
495
496
497
498
499
500
501
502static int dock_in_progress(struct dock_station *ds)
503{
504 if ((ds->flags & DOCK_DOCKING) ||
505 time_before(jiffies, (ds->last_dock_time + HZ)))
506 return 1;
507 return 0;
508}
509
510
511
512
513
514
515
516
517
518
519
520
521
522int register_hotplug_dock_device(acpi_handle handle,
523 const struct acpi_dock_ops *ops, void *context,
524 void (*init)(void *), void (*release)(void *))
525{
526 struct dock_dependent_device *dd;
527 struct dock_station *dock_station;
528 struct acpi_device *adev;
529 int ret = -EINVAL;
530
531 if (WARN_ON(!context))
532 return -EINVAL;
533
534 if (!dock_station_count)
535 return -ENODEV;
536
537 ret = acpi_bus_get_device(handle, &adev);
538 if (ret)
539 return ret;
540
541
542
543
544
545 list_for_each_entry(dock_station, &dock_stations, sibling) {
546
547
548
549
550
551 dd = find_dock_dependent_device(dock_station, adev);
552 if (dd && !dock_init_hotplug(dd, ops, context, init, release))
553 ret = 0;
554 }
555
556 return ret;
557}
558EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
559
560
561
562
563
564void unregister_hotplug_dock_device(acpi_handle handle)
565{
566 struct dock_dependent_device *dd;
567 struct dock_station *dock_station;
568 struct acpi_device *adev;
569
570 if (!dock_station_count)
571 return;
572
573 if (acpi_bus_get_device(handle, &adev))
574 return;
575
576 list_for_each_entry(dock_station, &dock_stations, sibling) {
577 dd = find_dock_dependent_device(dock_station, adev);
578 if (dd)
579 dock_release_hotplug(dd);
580 }
581}
582EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
583
584
585
586
587
588
589
590static int handle_eject_request(struct dock_station *ds, u32 event)
591{
592 if (dock_in_progress(ds))
593 return -EBUSY;
594
595
596
597
598
599
600
601
602 dock_event(ds, event, UNDOCK_EVENT);
603
604 hot_remove_dock_devices(ds);
605 undock(ds);
606 acpi_evaluate_lck(ds->handle, 0);
607 acpi_evaluate_ej0(ds->handle);
608 if (dock_present(ds)) {
609 acpi_handle_err(ds->handle, "Unable to undock!\n");
610 return -EBUSY;
611 }
612 complete_undock(ds);
613 return 0;
614}
615
616
617
618
619
620
621
622
623
624
625int dock_notify(struct acpi_device *adev, u32 event)
626{
627 acpi_handle handle = adev->handle;
628 struct dock_station *ds = find_dock_station(handle);
629 int surprise_removal = 0;
630
631 if (!ds)
632 return -ENODEV;
633
634
635
636
637
638
639 if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
640 event = ACPI_NOTIFY_EJECT_REQUEST;
641
642
643
644
645
646
647
648
649
650
651 switch (event) {
652 case ACPI_NOTIFY_BUS_CHECK:
653 case ACPI_NOTIFY_DEVICE_CHECK:
654 if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
655 begin_dock(ds);
656 dock(ds);
657 if (!dock_present(ds)) {
658 acpi_handle_err(handle, "Unable to dock!\n");
659 complete_dock(ds);
660 break;
661 }
662 hotplug_dock_devices(ds, event);
663 complete_dock(ds);
664 dock_event(ds, event, DOCK_EVENT);
665 acpi_evaluate_lck(ds->handle, 1);
666 acpi_update_all_gpes();
667 break;
668 }
669 if (dock_present(ds) || dock_in_progress(ds))
670 break;
671
672 surprise_removal = 1;
673 event = ACPI_NOTIFY_EJECT_REQUEST;
674
675 case ACPI_NOTIFY_EJECT_REQUEST:
676 begin_undock(ds);
677 if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
678 || surprise_removal)
679 handle_eject_request(ds, event);
680 else
681 dock_event(ds, event, UNDOCK_EVENT);
682 break;
683 }
684 return 0;
685}
686
687
688
689
690static ssize_t show_docked(struct device *dev,
691 struct device_attribute *attr, char *buf)
692{
693 struct dock_station *dock_station = dev->platform_data;
694 struct acpi_device *adev = NULL;
695
696 acpi_bus_get_device(dock_station->handle, &adev);
697 return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
698}
699static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
700
701
702
703
704static ssize_t show_flags(struct device *dev,
705 struct device_attribute *attr, char *buf)
706{
707 struct dock_station *dock_station = dev->platform_data;
708 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
709
710}
711static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
712
713
714
715
716static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
717 const char *buf, size_t count)
718{
719 int ret;
720 struct dock_station *dock_station = dev->platform_data;
721
722 if (!count)
723 return -EINVAL;
724
725 acpi_scan_lock_acquire();
726 begin_undock(dock_station);
727 ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
728 acpi_scan_lock_release();
729 return ret ? ret: count;
730}
731static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
732
733
734
735
736static ssize_t show_dock_uid(struct device *dev,
737 struct device_attribute *attr, char *buf)
738{
739 unsigned long long lbuf;
740 struct dock_station *dock_station = dev->platform_data;
741 acpi_status status = acpi_evaluate_integer(dock_station->handle,
742 "_UID", NULL, &lbuf);
743 if (ACPI_FAILURE(status))
744 return 0;
745
746 return snprintf(buf, PAGE_SIZE, "%llx\n", lbuf);
747}
748static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
749
750static ssize_t show_dock_type(struct device *dev,
751 struct device_attribute *attr, char *buf)
752{
753 struct dock_station *dock_station = dev->platform_data;
754 char *type;
755
756 if (dock_station->flags & DOCK_IS_DOCK)
757 type = "dock_station";
758 else if (dock_station->flags & DOCK_IS_ATA)
759 type = "ata_bay";
760 else if (dock_station->flags & DOCK_IS_BAT)
761 type = "battery_bay";
762 else
763 type = "unknown";
764
765 return snprintf(buf, PAGE_SIZE, "%s\n", type);
766}
767static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
768
769static struct attribute *dock_attributes[] = {
770 &dev_attr_docked.attr,
771 &dev_attr_flags.attr,
772 &dev_attr_undock.attr,
773 &dev_attr_uid.attr,
774 &dev_attr_type.attr,
775 NULL
776};
777
778static struct attribute_group dock_attribute_group = {
779 .attrs = dock_attributes
780};
781
782
783
784
785
786
787
788void acpi_dock_add(struct acpi_device *adev)
789{
790 struct dock_station *dock_station, ds = { NULL, };
791 acpi_handle handle = adev->handle;
792 struct platform_device *dd;
793 int ret;
794
795 dd = platform_device_register_data(NULL, "dock", dock_station_count,
796 &ds, sizeof(ds));
797 if (IS_ERR(dd))
798 return;
799
800 dock_station = dd->dev.platform_data;
801
802 dock_station->handle = handle;
803 dock_station->dock_device = dd;
804 dock_station->last_dock_time = jiffies - HZ;
805
806 INIT_LIST_HEAD(&dock_station->sibling);
807 INIT_LIST_HEAD(&dock_station->dependent_devices);
808
809
810 dev_set_uevent_suppress(&dd->dev, 0);
811
812 if (acpi_dock_match(handle))
813 dock_station->flags |= DOCK_IS_DOCK;
814 if (acpi_ata_match(handle))
815 dock_station->flags |= DOCK_IS_ATA;
816 if (acpi_device_is_battery(handle))
817 dock_station->flags |= DOCK_IS_BAT;
818
819 ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
820 if (ret)
821 goto err_unregister;
822
823
824 ret = add_dock_dependent_device(dock_station, adev);
825 if (ret)
826 goto err_rmgroup;
827
828 dock_station_count++;
829 list_add(&dock_station->sibling, &dock_stations);
830 adev->flags.is_dock_station = true;
831 dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
832 dock_station_count);
833 return;
834
835err_rmgroup:
836 remove_dock_dependent_devices(dock_station);
837 sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
838err_unregister:
839 platform_device_unregister(dd);
840 acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
841}
842