Merge master.kernel.org:/home/rmk/linux-2.6-serial
[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 <acpi/acpi_bus.h>
31 #include <acpi/acpi_drivers.h>
32
33 #define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver"
34
35 ACPI_MODULE_NAME("dock")
36 MODULE_AUTHOR("Kristen Carlson Accardi");
37 MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
38 MODULE_LICENSE("GPL");
39
40 static struct atomic_notifier_head dock_notifier_list;
41
42 struct dock_station {
43         acpi_handle handle;
44         unsigned long last_dock_time;
45         u32 flags;
46         spinlock_t dd_lock;
47         spinlock_t hp_lock;
48         struct list_head dependent_devices;
49         struct list_head hotplug_devices;
50 };
51
52 struct dock_dependent_device {
53         struct list_head list;
54         struct list_head hotplug_list;
55         acpi_handle handle;
56         acpi_notify_handler handler;
57         void *context;
58 };
59
60 #define DOCK_DOCKING    0x00000001
61 #define DOCK_EVENT      KOBJ_DOCK
62 #define UNDOCK_EVENT    KOBJ_UNDOCK
63
64 static struct dock_station *dock_station;
65
66 /*****************************************************************************
67  *                         Dock Dependent device functions                   *
68  *****************************************************************************/
69 /**
70  *  alloc_dock_dependent_device - allocate and init a dependent device
71  *  @handle: the acpi_handle of the dependent device
72  *
73  *  Allocate memory for a dependent device structure for a device referenced
74  *  by the acpi handle
75  */
76 static struct dock_dependent_device *
77 alloc_dock_dependent_device(acpi_handle handle)
78 {
79         struct dock_dependent_device *dd;
80
81         dd = kzalloc(sizeof(*dd), GFP_KERNEL);
82         if (dd) {
83                 dd->handle = handle;
84                 INIT_LIST_HEAD(&dd->list);
85                 INIT_LIST_HEAD(&dd->hotplug_list);
86         }
87         return dd;
88 }
89
90 /**
91  * add_dock_dependent_device - associate a device with the dock station
92  * @ds: The dock station
93  * @dd: The dependent device
94  *
95  * Add the dependent device to the dock's dependent device list.
96  */
97 static void
98 add_dock_dependent_device(struct dock_station *ds,
99                           struct dock_dependent_device *dd)
100 {
101         spin_lock(&ds->dd_lock);
102         list_add_tail(&dd->list, &ds->dependent_devices);
103         spin_unlock(&ds->dd_lock);
104 }
105
106 /**
107  * dock_add_hotplug_device - associate a hotplug handler with the dock station
108  * @ds: The dock station
109  * @dd: The dependent device struct
110  *
111  * Add the dependent device to the dock's hotplug device list
112  */
113 static void
114 dock_add_hotplug_device(struct dock_station *ds,
115                         struct dock_dependent_device *dd)
116 {
117         spin_lock(&ds->hp_lock);
118         list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
119         spin_unlock(&ds->hp_lock);
120 }
121
122 /**
123  * dock_del_hotplug_device - remove a hotplug handler from the dock station
124  * @ds: The dock station
125  * @dd: the dependent device struct
126  *
127  * Delete the dependent device from the dock's hotplug device list
128  */
129 static void
130 dock_del_hotplug_device(struct dock_station *ds,
131                         struct dock_dependent_device *dd)
132 {
133         spin_lock(&ds->hp_lock);
134         list_del(&dd->hotplug_list);
135         spin_unlock(&ds->hp_lock);
136 }
137
138 /**
139  * find_dock_dependent_device - get a device dependent on this dock
140  * @ds: the dock station
141  * @handle: the acpi_handle of the device we want
142  *
143  * iterate over the dependent device list for this dock.  If the
144  * dependent device matches the handle, return.
145  */
146 static struct dock_dependent_device *
147 find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
148 {
149         struct dock_dependent_device *dd;
150
151         spin_lock(&ds->dd_lock);
152         list_for_each_entry(dd, &ds->dependent_devices, list) {
153                 if (handle == dd->handle) {
154                         spin_unlock(&ds->dd_lock);
155                         return dd;
156                 }
157         }
158         spin_unlock(&ds->dd_lock);
159         return NULL;
160 }
161
162 /*****************************************************************************
163  *                         Dock functions                                    *
164  *****************************************************************************/
165 /**
166  * is_dock - see if a device is a dock station
167  * @handle: acpi handle of the device
168  *
169  * If an acpi object has a _DCK method, then it is by definition a dock
170  * station, so return true.
171  */
172 static int is_dock(acpi_handle handle)
173 {
174         acpi_status status;
175         acpi_handle tmp;
176
177         status = acpi_get_handle(handle, "_DCK", &tmp);
178         if (ACPI_FAILURE(status))
179                 return 0;
180         return 1;
181 }
182
183 /**
184  * is_dock_device - see if a device is on a dock station
185  * @handle: acpi handle of the device
186  *
187  * If this device is either the dock station itself,
188  * or is a device dependent on the dock station, then it
189  * is a dock device
190  */
191 int is_dock_device(acpi_handle handle)
192 {
193         if (!dock_station)
194                 return 0;
195
196         if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
197                 return 1;
198
199         return 0;
200 }
201
202 EXPORT_SYMBOL_GPL(is_dock_device);
203
204 /**
205  * dock_present - see if the dock station is present.
206  * @ds: the dock station
207  *
208  * execute the _STA method.  note that present does not
209  * imply that we are docked.
210  */
211 static int dock_present(struct dock_station *ds)
212 {
213         unsigned long sta;
214         acpi_status status;
215
216         if (ds) {
217                 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
218                 if (ACPI_SUCCESS(status) && sta)
219                         return 1;
220         }
221         return 0;
222 }
223
224
225
226 /**
227  * dock_create_acpi_device - add new devices to acpi
228  * @handle - handle of the device to add
229  *
230  *  This function will create a new acpi_device for the given
231  *  handle if one does not exist already.  This should cause
232  *  acpi to scan for drivers for the given devices, and call
233  *  matching driver's add routine.
234  *
235  *  Returns a pointer to the acpi_device corresponding to the handle.
236  */
237 static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
238 {
239         struct acpi_device *device = NULL;
240         struct acpi_device *parent_device;
241         acpi_handle parent;
242         int ret;
243
244         if (acpi_bus_get_device(handle, &device)) {
245                 /*
246                  * no device created for this object,
247                  * so we should create one.
248                  */
249                 acpi_get_parent(handle, &parent);
250                 if (acpi_bus_get_device(parent, &parent_device))
251                         parent_device = NULL;
252
253                 ret = acpi_bus_add(&device, parent_device, handle,
254                         ACPI_BUS_TYPE_DEVICE);
255                 if (ret) {
256                         pr_debug("error adding bus, %x\n",
257                                 -ret);
258                         return NULL;
259                 }
260         }
261         return device;
262 }
263
264 /**
265  * dock_remove_acpi_device - remove the acpi_device struct from acpi
266  * @handle - the handle of the device to remove
267  *
268  *  Tell acpi to remove the acpi_device.  This should cause any loaded
269  *  driver to have it's remove routine called.
270  */
271 static void dock_remove_acpi_device(acpi_handle handle)
272 {
273         struct acpi_device *device;
274         int ret;
275
276         if (!acpi_bus_get_device(handle, &device)) {
277                 ret = acpi_bus_trim(device, 1);
278                 if (ret)
279                         pr_debug("error removing bus, %x\n", -ret);
280         }
281 }
282
283
284 /**
285  * hotplug_dock_devices - insert or remove devices on the dock station
286  * @ds: the dock station
287  * @event: either bus check or eject request
288  *
289  * Some devices on the dock station need to have drivers called
290  * to perform hotplug operations after a dock event has occurred.
291  * Traverse the list of dock devices that have registered a
292  * hotplug handler, and call the handler.
293  */
294 static void hotplug_dock_devices(struct dock_station *ds, u32 event)
295 {
296         struct dock_dependent_device *dd;
297
298         spin_lock(&ds->hp_lock);
299
300         /*
301          * First call driver specific hotplug functions
302          */
303         list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
304                 if (dd->handler)
305                         dd->handler(dd->handle, event, dd->context);
306         }
307
308         /*
309          * Now make sure that an acpi_device is created for each
310          * dependent device, or removed if this is an eject request.
311          * This will cause acpi_drivers to be stopped/started if they
312          * exist
313          */
314         list_for_each_entry(dd, &ds->dependent_devices, list) {
315                 if (event == ACPI_NOTIFY_EJECT_REQUEST)
316                         dock_remove_acpi_device(dd->handle);
317                 else
318                         dock_create_acpi_device(dd->handle);
319         }
320         spin_unlock(&ds->hp_lock);
321 }
322
323 static void dock_event(struct dock_station *ds, u32 event, int num)
324 {
325         struct acpi_device *device;
326
327         device = dock_create_acpi_device(ds->handle);
328         if (device)
329                 kobject_uevent(&device->kobj, num);
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);