Merge ../linus
[pandora-kernel.git] / drivers / acpi / dock.c
1 /*
2  *  dock.c - ACPI dock station driver
3  *
4  *  Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
5  *
6  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or (at
11  *  your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful, but
14  *  WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License along
19  *  with this program; if not, write to the Free Software Foundation, Inc.,
20  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21  *
22  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23  */
24
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/types.h>
29 #include <linux/notifier.h>
30 #include <linux/jiffies.h>
31 #include <acpi/acpi_bus.h>
32 #include <acpi/acpi_drivers.h>
33
34 #define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver"
35
36 ACPI_MODULE_NAME("dock")
37 MODULE_AUTHOR("Kristen Carlson Accardi");
38 MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
39 MODULE_LICENSE("GPL");
40
41 static struct atomic_notifier_head dock_notifier_list;
42
43 struct dock_station {
44         acpi_handle handle;
45         unsigned long last_dock_time;
46         u32 flags;
47         spinlock_t dd_lock;
48         spinlock_t hp_lock;
49         struct list_head dependent_devices;
50         struct list_head hotplug_devices;
51 };
52
53 struct dock_dependent_device {
54         struct list_head list;
55         struct list_head hotplug_list;
56         acpi_handle handle;
57         acpi_notify_handler handler;
58         void *context;
59 };
60
61 #define DOCK_DOCKING    0x00000001
62 #define DOCK_EVENT      3
63 #define UNDOCK_EVENT    2
64
65 static struct dock_station *dock_station;
66
67 /*****************************************************************************
68  *                         Dock Dependent device functions                   *
69  *****************************************************************************/
70 /**
71  *  alloc_dock_dependent_device - allocate and init a dependent device
72  *  @handle: the acpi_handle of the dependent device
73  *
74  *  Allocate memory for a dependent device structure for a device referenced
75  *  by the acpi handle
76  */
77 static struct dock_dependent_device *
78 alloc_dock_dependent_device(acpi_handle handle)
79 {
80         struct dock_dependent_device *dd;
81
82         dd = kzalloc(sizeof(*dd), GFP_KERNEL);
83         if (dd) {
84                 dd->handle = handle;
85                 INIT_LIST_HEAD(&dd->list);
86                 INIT_LIST_HEAD(&dd->hotplug_list);
87         }
88         return dd;
89 }
90
91 /**
92  * add_dock_dependent_device - associate a device with the dock station
93  * @ds: The dock station
94  * @dd: The dependent device
95  *
96  * Add the dependent device to the dock's dependent device list.
97  */
98 static void
99 add_dock_dependent_device(struct dock_station *ds,
100                           struct dock_dependent_device *dd)
101 {
102         spin_lock(&ds->dd_lock);
103         list_add_tail(&dd->list, &ds->dependent_devices);
104         spin_unlock(&ds->dd_lock);
105 }
106
107 /**
108  * dock_add_hotplug_device - associate a hotplug handler with the dock station
109  * @ds: The dock station
110  * @dd: The dependent device struct
111  *
112  * Add the dependent device to the dock's hotplug device list
113  */
114 static void
115 dock_add_hotplug_device(struct dock_station *ds,
116                         struct dock_dependent_device *dd)
117 {
118         spin_lock(&ds->hp_lock);
119         list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
120         spin_unlock(&ds->hp_lock);
121 }
122
123 /**
124  * dock_del_hotplug_device - remove a hotplug handler from the dock station
125  * @ds: The dock station
126  * @dd: the dependent device struct
127  *
128  * Delete the dependent device from the dock's hotplug device list
129  */
130 static void
131 dock_del_hotplug_device(struct dock_station *ds,
132                         struct dock_dependent_device *dd)
133 {
134         spin_lock(&ds->hp_lock);
135         list_del(&dd->hotplug_list);
136         spin_unlock(&ds->hp_lock);
137 }
138
139 /**
140  * find_dock_dependent_device - get a device dependent on this dock
141  * @ds: the dock station
142  * @handle: the acpi_handle of the device we want
143  *
144  * iterate over the dependent device list for this dock.  If the
145  * dependent device matches the handle, return.
146  */
147 static struct dock_dependent_device *
148 find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
149 {
150         struct dock_dependent_device *dd;
151
152         spin_lock(&ds->dd_lock);
153         list_for_each_entry(dd, &ds->dependent_devices, list) {
154                 if (handle == dd->handle) {
155                         spin_unlock(&ds->dd_lock);
156                         return dd;
157                 }
158         }
159         spin_unlock(&ds->dd_lock);
160         return NULL;
161 }
162
163 /*****************************************************************************
164  *                         Dock functions                                    *
165  *****************************************************************************/
166 /**
167  * is_dock - see if a device is a dock station
168  * @handle: acpi handle of the device
169  *
170  * If an acpi object has a _DCK method, then it is by definition a dock
171  * station, so return true.
172  */
173 static int is_dock(acpi_handle handle)
174 {
175         acpi_status status;
176         acpi_handle tmp;
177
178         status = acpi_get_handle(handle, "_DCK", &tmp);
179         if (ACPI_FAILURE(status))
180                 return 0;
181         return 1;
182 }
183
184 /**
185  * is_dock_device - see if a device is on a dock station
186  * @handle: acpi handle of the device
187  *
188  * If this device is either the dock station itself,
189  * or is a device dependent on the dock station, then it
190  * is a dock device
191  */
192 int is_dock_device(acpi_handle handle)
193 {
194         if (!dock_station)
195                 return 0;
196
197         if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
198                 return 1;
199
200         return 0;
201 }
202
203 EXPORT_SYMBOL_GPL(is_dock_device);
204
205 /**
206  * dock_present - see if the dock station is present.
207  * @ds: the dock station
208  *
209  * execute the _STA method.  note that present does not
210  * imply that we are docked.
211  */
212 static int dock_present(struct dock_station *ds)
213 {
214         unsigned long sta;
215         acpi_status status;
216
217         if (ds) {
218                 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
219                 if (ACPI_SUCCESS(status) && sta)
220                         return 1;
221         }
222         return 0;
223 }
224
225
226
227 /**
228  * dock_create_acpi_device - add new devices to acpi
229  * @handle - handle of the device to add
230  *
231  *  This function will create a new acpi_device for the given
232  *  handle if one does not exist already.  This should cause
233  *  acpi to scan for drivers for the given devices, and call
234  *  matching driver's add routine.
235  *
236  *  Returns a pointer to the acpi_device corresponding to the handle.
237  */
238 static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
239 {
240         struct acpi_device *device = NULL;
241         struct acpi_device *parent_device;
242         acpi_handle parent;
243         int ret;
244
245         if (acpi_bus_get_device(handle, &device)) {
246                 /*
247                  * no device created for this object,
248                  * so we should create one.
249                  */
250                 acpi_get_parent(handle, &parent);
251                 if (acpi_bus_get_device(parent, &parent_device))
252                         parent_device = NULL;
253
254                 ret = acpi_bus_add(&device, parent_device, handle,
255                         ACPI_BUS_TYPE_DEVICE);
256                 if (ret) {
257                         pr_debug("error adding bus, %x\n",
258                                 -ret);
259                         return NULL;
260                 }
261         }
262         return device;
263 }
264
265 /**
266  * dock_remove_acpi_device - remove the acpi_device struct from acpi
267  * @handle - the handle of the device to remove
268  *
269  *  Tell acpi to remove the acpi_device.  This should cause any loaded
270  *  driver to have it's remove routine called.
271  */
272 static void dock_remove_acpi_device(acpi_handle handle)
273 {
274         struct acpi_device *device;
275         int ret;
276
277         if (!acpi_bus_get_device(handle, &device)) {
278                 ret = acpi_bus_trim(device, 1);
279                 if (ret)
280                         pr_debug("error removing bus, %x\n", -ret);
281         }
282 }
283
284
285 /**
286  * hotplug_dock_devices - insert or remove devices on the dock station
287  * @ds: the dock station
288  * @event: either bus check or eject request
289  *
290  * Some devices on the dock station need to have drivers called
291  * to perform hotplug operations after a dock event has occurred.
292  * Traverse the list of dock devices that have registered a
293  * hotplug handler, and call the handler.
294  */
295 static void hotplug_dock_devices(struct dock_station *ds, u32 event)
296 {
297         struct dock_dependent_device *dd;
298
299         spin_lock(&ds->hp_lock);
300
301         /*
302          * First call driver specific hotplug functions
303          */
304         list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
305                 if (dd->handler)
306                         dd->handler(dd->handle, event, dd->context);
307         }
308
309         /*
310          * Now make sure that an acpi_device is created for each
311          * dependent device, or removed if this is an eject request.
312          * This will cause acpi_drivers to be stopped/started if they
313          * exist
314          */
315         list_for_each_entry(dd, &ds->dependent_devices, list) {
316                 if (event == ACPI_NOTIFY_EJECT_REQUEST)
317                         dock_remove_acpi_device(dd->handle);
318                 else
319                         dock_create_acpi_device(dd->handle);
320         }
321         spin_unlock(&ds->hp_lock);
322 }
323
324 static void dock_event(struct dock_station *ds, u32 event, int num)
325 {
326         /*
327          * we don't do events until someone tells me that
328          * they would like to have them.
329          */
330 }
331
332 /**
333  * eject_dock - respond to a dock eject request
334  * @ds: the dock station
335  *
336  * This is called after _DCK is called, to execute the dock station's
337  * _EJ0 method.
338  */
339 static void eject_dock(struct dock_station *ds)
340 {
341         struct acpi_object_list arg_list;
342         union acpi_object arg;
343         acpi_status status;
344         acpi_handle tmp;
345
346         /* all dock devices should have _EJ0, but check anyway */
347         status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
348         if (ACPI_FAILURE(status)) {
349                 pr_debug("No _EJ0 support for dock device\n");
350                 return;
351         }
352
353         arg_list.count = 1;
354         arg_list.pointer = &arg;
355         arg.type = ACPI_TYPE_INTEGER;
356         arg.integer.value = 1;
357
358         if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
359                                               &arg_list, NULL)))
360                 pr_debug("Failed to evaluate _EJ0!\n");
361 }
362
363 /**
364  * handle_dock - handle a dock event
365  * @ds: the dock station
366  * @dock: to dock, or undock - that is the question
367  *
368  * Execute the _DCK method in response to an acpi event
369  */
370 static void handle_dock(struct dock_station *ds, int dock)
371 {
372         acpi_status status;
373         struct acpi_object_list arg_list;
374         union acpi_object arg;
375         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
376         struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
377         union acpi_object *obj;
378
379         acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
380         obj = name_buffer.pointer;
381
382         printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
383
384         /* _DCK method has one argument */
385         arg_list.count = 1;
386         arg_list.pointer = &arg;
387         arg.type = ACPI_TYPE_INTEGER;
388         arg.integer.value = dock;
389         status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
390         if (ACPI_FAILURE(status))
391                 pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
392         kfree(buffer.pointer);
393         kfree(name_buffer.pointer);
394 }
395
396 static inline void dock(struct dock_station *ds)
397 {
398         handle_dock(ds, 1);
399 }
400
401 static inline void undock(struct dock_station *ds)
402 {
403         handle_dock(ds, 0);
404 }
405
406 static inline void begin_dock(struct dock_station *ds)
407 {
408         ds->flags |= DOCK_DOCKING;
409 }
410
411 static inline void complete_dock(struct dock_station *ds)
412 {
413         ds->flags &= ~(DOCK_DOCKING);
414         ds->last_dock_time = jiffies;
415 }
416
417 /**
418  * dock_in_progress - see if we are in the middle of handling a dock event
419  * @ds: the dock station
420  *
421  * Sometimes while docking, false dock events can be sent to the driver
422  * because good connections aren't made or some other reason.  Ignore these
423  * if we are in the middle of doing something.
424  */
425 static int dock_in_progress(struct dock_station *ds)
426 {
427         if ((ds->flags & DOCK_DOCKING) ||
428             time_before(jiffies, (ds->last_dock_time + HZ)))
429                 return 1;
430         return 0;
431 }
432
433 /**
434  * register_dock_notifier - add yourself to the dock notifier list
435  * @nb: the callers notifier block
436  *
437  * If a driver wishes to be notified about dock events, they can
438  * use this function to put a notifier block on the dock notifier list.
439  * this notifier call chain will be called after a dock event, but
440  * before hotplugging any new devices.
441  */
442 int register_dock_notifier(struct notifier_block *nb)
443 {
444         return atomic_notifier_chain_register(&dock_notifier_list, nb);
445 }
446
447 EXPORT_SYMBOL_GPL(register_dock_notifier);
448
449 /**
450  * unregister_dock_notifier - remove yourself from the dock notifier list
451  * @nb: the callers notifier block
452  */
453 void unregister_dock_notifier(struct notifier_block *nb)
454 {
455         atomic_notifier_chain_unregister(&dock_notifier_list, nb);
456 }
457
458 EXPORT_SYMBOL_GPL(unregister_dock_notifier);
459
460 /**
461  * register_hotplug_dock_device - register a hotplug function
462  * @handle: the handle of the device
463  * @handler: the acpi_notifier_handler to call after docking
464  * @context: device specific data
465  *
466  * If a driver would like to perform a hotplug operation after a dock
467  * event, they can register an acpi_notifiy_handler to be called by
468  * the dock driver after _DCK is executed.
469  */
470 int
471 register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
472                              void *context)
473 {
474         struct dock_dependent_device *dd;
475
476         if (!dock_station)
477                 return -ENODEV;
478
479         /*
480          * make sure this handle is for a device dependent on the dock,
481          * this would include the dock station itself
482          */
483         dd = find_dock_dependent_device(dock_station, handle);
484         if (dd) {
485                 dd->handler = handler;
486                 dd->context = context;
487                 dock_add_hotplug_device(dock_station, dd);
488                 return 0;
489         }
490
491         return -EINVAL;
492 }
493
494 EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
495
496 /**
497  * unregister_hotplug_dock_device - remove yourself from the hotplug list
498  * @handle: the acpi handle of the device
499  */
500 void unregister_hotplug_dock_device(acpi_handle handle)
501 {
502         struct dock_dependent_device *dd;
503
504         if (!dock_station)
505                 return;
506
507         dd = find_dock_dependent_device(dock_station, handle);
508         if (dd)
509                 dock_del_hotplug_device(dock_station, dd);
510 }
511
512 EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
513
514 /**
515  * dock_notify - act upon an acpi dock notification
516  * @handle: the dock station handle
517  * @event: the acpi event
518  * @data: our driver data struct
519  *
520  * If we are notified to dock, then check to see if the dock is
521  * present and then dock.  Notify all drivers of the dock event,
522  * and then hotplug and devices that may need hotplugging.  For undock
523  * check to make sure the dock device is still present, then undock
524  * and hotremove all the devices that may need removing.
525  */
526 static void dock_notify(acpi_handle handle, u32 event, void *data)
527 {
528         struct dock_station *ds = (struct dock_station *)data;
529
530         switch (event) {
531         case ACPI_NOTIFY_BUS_CHECK:
532                 if (!dock_in_progress(ds) && dock_present(ds)) {
533                         begin_dock(ds);
534                         dock(ds);
535                         if (!dock_present(ds)) {
536                                 printk(KERN_ERR PREFIX "Unable to dock!\n");
537                                 break;
538                         }
539                         atomic_notifier_call_chain(&dock_notifier_list,
540                                                    event, NULL);
541                         hotplug_dock_devices(ds, event);
542                         complete_dock(ds);
543                         dock_event(ds, event, DOCK_EVENT);
544                 }
545                 break;
546         case ACPI_NOTIFY_DEVICE_CHECK:
547         /*
548          * According to acpi spec 3.0a, if a DEVICE_CHECK notification
549          * is sent and _DCK is present, it is assumed to mean an
550          * undock request.  This notify routine will only be called
551          * for objects defining _DCK, so we will fall through to eject
552          * request here.  However, we will pass an eject request through
553          * to the driver who wish to hotplug.
554          */
555         case ACPI_NOTIFY_EJECT_REQUEST:
556                 if (!dock_in_progress(ds) && dock_present(ds)) {
557                         /*
558                          * here we need to generate the undock
559                          * event prior to actually doing the undock
560                          * so that the device struct still exists.
561                          */
562                         dock_event(ds, event, UNDOCK_EVENT);
563                         hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
564                         undock(ds);
565                         eject_dock(ds);
566                         if (dock_present(ds))
567                                 printk(KERN_ERR PREFIX "Unable to undock!\n");
568                 }
569                 break;
570         default:
571                 printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
572         }
573 }
574
575 /**
576  * find_dock_devices - find devices on the dock station
577  * @handle: the handle of the device we are examining
578  * @lvl: unused
579  * @context: the dock station private data
580  * @rv: unused
581  *
582  * This function is called by acpi_walk_namespace.  It will
583  * check to see if an object has an _EJD method.  If it does, then it
584  * will see if it is dependent on the dock station.
585  */
586 static acpi_status
587 find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
588 {
589         acpi_status status;
590         acpi_handle tmp;
591         struct dock_station *ds = (struct dock_station *)context;
592         struct dock_dependent_device *dd;
593
594         status = acpi_bus_get_ejd(handle, &tmp);
595         if (ACPI_FAILURE(status))
596                 return AE_OK;
597
598         if (tmp == ds->handle) {
599                 dd = alloc_dock_dependent_device(handle);
600                 if (dd)
601                         add_dock_dependent_device(ds, dd);
602         }
603
604         return AE_OK;
605 }
606
607 /**
608  * dock_add - add a new dock station
609  * @handle: the dock station handle
610  *
611  * allocated and initialize a new dock station device.  Find all devices
612  * that are on the dock station, and register for dock event notifications.
613  */
614 static int dock_add(acpi_handle handle)
615 {
616         int ret;
617         acpi_status status;
618         struct dock_dependent_device *dd;
619
620         /* allocate & initialize the dock_station private data */
621         dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
622         if (!dock_station)
623                 return -ENOMEM;
624         dock_station->handle = handle;
625         dock_station->last_dock_time = jiffies - HZ;
626         INIT_LIST_HEAD(&dock_station->dependent_devices);
627         INIT_LIST_HEAD(&dock_station->hotplug_devices);
628         spin_lock_init(&dock_station->dd_lock);
629         spin_lock_init(&dock_station->hp_lock);
630         ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
631
632         /* Find dependent devices */
633         acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
634                             ACPI_UINT32_MAX, find_dock_devices, dock_station,
635                             NULL);
636
637         /* add the dock station as a device dependent on itself */
638         dd = alloc_dock_dependent_device(handle);
639         if (!dd) {
640                 kfree(dock_station);
641                 return -ENOMEM;
642         }
643         add_dock_dependent_device(dock_station, dd);
644
645         /* register for dock events */
646         status = acpi_install_notify_handler(dock_station->handle,
647                                              ACPI_SYSTEM_NOTIFY,
648                                              dock_notify, dock_station);
649
650         if (ACPI_FAILURE(status)) {
651                 printk(KERN_ERR PREFIX "Error installing notify handler\n");
652                 ret = -ENODEV;
653                 goto dock_add_err;
654         }
655
656         printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME);
657
658         return 0;
659
660 dock_add_err:
661         kfree(dock_station);
662         kfree(dd);
663         return ret;
664 }
665
666 /**
667  * dock_remove - free up resources related to the dock station
668  */
669 static int dock_remove(void)
670 {
671         struct dock_dependent_device *dd, *tmp;
672         acpi_status status;
673
674         if (!dock_station)
675                 return 0;
676
677         /* remove dependent devices */
678         list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,
679                                  list)
680             kfree(dd);
681
682         /* remove dock notify handler */
683         status = acpi_remove_notify_handler(dock_station->handle,
684                                             ACPI_SYSTEM_NOTIFY,
685                                             dock_notify);
686         if (ACPI_FAILURE(status))
687                 printk(KERN_ERR "Error removing notify handler\n");
688
689         /* free dock station memory */
690         kfree(dock_station);
691         return 0;
692 }
693
694 /**
695  * find_dock - look for a dock station
696  * @handle: acpi handle of a device
697  * @lvl: unused
698  * @context: counter of dock stations found
699  * @rv: unused
700  *
701  * This is called by acpi_walk_namespace to look for dock stations.
702  */
703 static acpi_status
704 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
705 {
706         int *count = (int *)context;
707         acpi_status status = AE_OK;
708
709         if (is_dock(handle)) {
710                 if (dock_add(handle) >= 0) {
711                         (*count)++;
712                         status = AE_CTRL_TERMINATE;
713                 }
714         }
715         return status;
716 }
717
718 static int __init dock_init(void)
719 {
720         int num = 0;
721
722         dock_station = NULL;
723
724         /* look for a dock station */
725         acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
726                             ACPI_UINT32_MAX, find_dock, &num, NULL);
727
728         if (!num)
729                 return -ENODEV;
730
731         return 0;
732 }
733
734 static void __exit dock_exit(void)
735 {
736         dock_remove();
737 }
738
739 postcore_initcall(dock_init);
740 module_exit(dock_exit);