ACPI: dock: unsuppress uevents
[deliverable/linux.git] / drivers / acpi / dock.c
CommitLineData
c8f7a62c
LB
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>
671adbec 30#include <linux/platform_device.h>
914e2637 31#include <linux/jiffies.h>
62a6d7fd 32#include <linux/stddef.h>
c8f7a62c
LB
33#include <acpi/acpi_bus.h>
34#include <acpi/acpi_drivers.h>
35
7cda93e0 36#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
c8f7a62c 37
f52fd66d 38ACPI_MODULE_NAME("dock");
c8f7a62c 39MODULE_AUTHOR("Kristen Carlson Accardi");
7cda93e0 40MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
c8f7a62c
LB
41MODULE_LICENSE("GPL");
42
a0cd35fd
KCA
43static int immediate_undock = 1;
44module_param(immediate_undock, bool, 0644);
45MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
46 "undock immediately when the undock button is pressed, 0 will cause"
47 " the driver to wait for userspace to write the undock sysfs file "
48 " before undocking");
49
c8f7a62c 50static struct atomic_notifier_head dock_notifier_list;
0f6f2804 51static struct platform_device *dock_device;
671adbec 52static char dock_device_name[] = "dock";
c8f7a62c
LB
53
54struct dock_station {
55 acpi_handle handle;
56 unsigned long last_dock_time;
57 u32 flags;
58 spinlock_t dd_lock;
8b0dc866 59 struct mutex hp_lock;
c8f7a62c
LB
60 struct list_head dependent_devices;
61 struct list_head hotplug_devices;
62};
63
64struct dock_dependent_device {
65 struct list_head list;
66 struct list_head hotplug_list;
67 acpi_handle handle;
68 acpi_notify_handler handler;
69 void *context;
70};
71
72#define DOCK_DOCKING 0x00000001
a0cd35fd 73#define DOCK_UNDOCKING 0x00000002
5669021e
KCA
74#define DOCK_EVENT 3
75#define UNDOCK_EVENT 2
c8f7a62c
LB
76
77static struct dock_station *dock_station;
78
79/*****************************************************************************
80 * Dock Dependent device functions *
81 *****************************************************************************/
82/**
83 * alloc_dock_dependent_device - allocate and init a dependent device
84 * @handle: the acpi_handle of the dependent device
85 *
86 * Allocate memory for a dependent device structure for a device referenced
87 * by the acpi handle
88 */
89static struct dock_dependent_device *
90alloc_dock_dependent_device(acpi_handle handle)
91{
92 struct dock_dependent_device *dd;
93
94 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
95 if (dd) {
96 dd->handle = handle;
97 INIT_LIST_HEAD(&dd->list);
98 INIT_LIST_HEAD(&dd->hotplug_list);
99 }
100 return dd;
101}
102
103/**
104 * add_dock_dependent_device - associate a device with the dock station
105 * @ds: The dock station
106 * @dd: The dependent device
107 *
108 * Add the dependent device to the dock's dependent device list.
109 */
110static void
111add_dock_dependent_device(struct dock_station *ds,
112 struct dock_dependent_device *dd)
113{
114 spin_lock(&ds->dd_lock);
115 list_add_tail(&dd->list, &ds->dependent_devices);
116 spin_unlock(&ds->dd_lock);
117}
118
119/**
120 * dock_add_hotplug_device - associate a hotplug handler with the dock station
121 * @ds: The dock station
122 * @dd: The dependent device struct
123 *
124 * Add the dependent device to the dock's hotplug device list
125 */
126static void
127dock_add_hotplug_device(struct dock_station *ds,
128 struct dock_dependent_device *dd)
129{
8b0dc866 130 mutex_lock(&ds->hp_lock);
c8f7a62c 131 list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
8b0dc866 132 mutex_unlock(&ds->hp_lock);
c8f7a62c
LB
133}
134
135/**
136 * dock_del_hotplug_device - remove a hotplug handler from the dock station
137 * @ds: The dock station
138 * @dd: the dependent device struct
139 *
140 * Delete the dependent device from the dock's hotplug device list
141 */
142static void
143dock_del_hotplug_device(struct dock_station *ds,
144 struct dock_dependent_device *dd)
145{
8b0dc866 146 mutex_lock(&ds->hp_lock);
c8f7a62c 147 list_del(&dd->hotplug_list);
8b0dc866 148 mutex_unlock(&ds->hp_lock);
c8f7a62c
LB
149}
150
151/**
152 * find_dock_dependent_device - get a device dependent on this dock
153 * @ds: the dock station
154 * @handle: the acpi_handle of the device we want
155 *
156 * iterate over the dependent device list for this dock. If the
157 * dependent device matches the handle, return.
158 */
159static struct dock_dependent_device *
160find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
161{
162 struct dock_dependent_device *dd;
163
164 spin_lock(&ds->dd_lock);
165 list_for_each_entry(dd, &ds->dependent_devices, list) {
166 if (handle == dd->handle) {
167 spin_unlock(&ds->dd_lock);
168 return dd;
169 }
170 }
171 spin_unlock(&ds->dd_lock);
172 return NULL;
173}
174
175/*****************************************************************************
176 * Dock functions *
177 *****************************************************************************/
178/**
179 * is_dock - see if a device is a dock station
180 * @handle: acpi handle of the device
181 *
182 * If an acpi object has a _DCK method, then it is by definition a dock
183 * station, so return true.
184 */
185static int is_dock(acpi_handle handle)
186{
187 acpi_status status;
188 acpi_handle tmp;
189
190 status = acpi_get_handle(handle, "_DCK", &tmp);
191 if (ACPI_FAILURE(status))
192 return 0;
193 return 1;
194}
195
196/**
197 * is_dock_device - see if a device is on a dock station
198 * @handle: acpi handle of the device
199 *
200 * If this device is either the dock station itself,
201 * or is a device dependent on the dock station, then it
202 * is a dock device
203 */
204int is_dock_device(acpi_handle handle)
205{
206 if (!dock_station)
207 return 0;
208
209 if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
210 return 1;
211
212 return 0;
213}
214
215EXPORT_SYMBOL_GPL(is_dock_device);
216
217/**
218 * dock_present - see if the dock station is present.
219 * @ds: the dock station
220 *
221 * execute the _STA method. note that present does not
222 * imply that we are docked.
223 */
224static int dock_present(struct dock_station *ds)
225{
226 unsigned long sta;
227 acpi_status status;
228
229 if (ds) {
230 status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
231 if (ACPI_SUCCESS(status) && sta)
232 return 1;
233 }
234 return 0;
235}
236
237
238
239/**
240 * dock_create_acpi_device - add new devices to acpi
241 * @handle - handle of the device to add
242 *
243 * This function will create a new acpi_device for the given
244 * handle if one does not exist already. This should cause
245 * acpi to scan for drivers for the given devices, and call
246 * matching driver's add routine.
247 *
248 * Returns a pointer to the acpi_device corresponding to the handle.
249 */
250static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
251{
252 struct acpi_device *device = NULL;
253 struct acpi_device *parent_device;
254 acpi_handle parent;
255 int ret;
256
257 if (acpi_bus_get_device(handle, &device)) {
258 /*
259 * no device created for this object,
260 * so we should create one.
261 */
262 acpi_get_parent(handle, &parent);
263 if (acpi_bus_get_device(parent, &parent_device))
264 parent_device = NULL;
265
266 ret = acpi_bus_add(&device, parent_device, handle,
267 ACPI_BUS_TYPE_DEVICE);
268 if (ret) {
269 pr_debug("error adding bus, %x\n",
270 -ret);
271 return NULL;
272 }
273 }
274 return device;
275}
276
277/**
278 * dock_remove_acpi_device - remove the acpi_device struct from acpi
279 * @handle - the handle of the device to remove
280 *
281 * Tell acpi to remove the acpi_device. This should cause any loaded
282 * driver to have it's remove routine called.
283 */
284static void dock_remove_acpi_device(acpi_handle handle)
285{
286 struct acpi_device *device;
287 int ret;
288
289 if (!acpi_bus_get_device(handle, &device)) {
290 ret = acpi_bus_trim(device, 1);
291 if (ret)
292 pr_debug("error removing bus, %x\n", -ret);
293 }
294}
295
296
297/**
298 * hotplug_dock_devices - insert or remove devices on the dock station
299 * @ds: the dock station
300 * @event: either bus check or eject request
301 *
302 * Some devices on the dock station need to have drivers called
303 * to perform hotplug operations after a dock event has occurred.
304 * Traverse the list of dock devices that have registered a
305 * hotplug handler, and call the handler.
306 */
307static void hotplug_dock_devices(struct dock_station *ds, u32 event)
308{
309 struct dock_dependent_device *dd;
310
8b0dc866 311 mutex_lock(&ds->hp_lock);
c8f7a62c
LB
312
313 /*
314 * First call driver specific hotplug functions
315 */
316 list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
317 if (dd->handler)
318 dd->handler(dd->handle, event, dd->context);
319 }
320
321 /*
322 * Now make sure that an acpi_device is created for each
323 * dependent device, or removed if this is an eject request.
324 * This will cause acpi_drivers to be stopped/started if they
325 * exist
326 */
327 list_for_each_entry(dd, &ds->dependent_devices, list) {
328 if (event == ACPI_NOTIFY_EJECT_REQUEST)
329 dock_remove_acpi_device(dd->handle);
330 else
331 dock_create_acpi_device(dd->handle);
332 }
8b0dc866 333 mutex_unlock(&ds->hp_lock);
c8f7a62c
LB
334}
335
336static void dock_event(struct dock_station *ds, u32 event, int num)
337{
0f6f2804 338 struct device *dev = &dock_device->dev;
5669021e 339 /*
8ea86e0b
KCA
340 * Indicate that the status of the dock station has
341 * changed.
5669021e 342 */
8ea86e0b 343 kobject_uevent(&dev->kobj, KOBJ_CHANGE);
c8f7a62c
LB
344}
345
346/**
347 * eject_dock - respond to a dock eject request
348 * @ds: the dock station
349 *
350 * This is called after _DCK is called, to execute the dock station's
351 * _EJ0 method.
352 */
353static void eject_dock(struct dock_station *ds)
354{
355 struct acpi_object_list arg_list;
356 union acpi_object arg;
357 acpi_status status;
358 acpi_handle tmp;
359
360 /* all dock devices should have _EJ0, but check anyway */
361 status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
362 if (ACPI_FAILURE(status)) {
363 pr_debug("No _EJ0 support for dock device\n");
364 return;
365 }
366
367 arg_list.count = 1;
368 arg_list.pointer = &arg;
369 arg.type = ACPI_TYPE_INTEGER;
370 arg.integer.value = 1;
371
372 if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
373 &arg_list, NULL)))
374 pr_debug("Failed to evaluate _EJ0!\n");
375}
376
377/**
378 * handle_dock - handle a dock event
379 * @ds: the dock station
380 * @dock: to dock, or undock - that is the question
381 *
382 * Execute the _DCK method in response to an acpi event
383 */
384static void handle_dock(struct dock_station *ds, int dock)
385{
386 acpi_status status;
387 struct acpi_object_list arg_list;
388 union acpi_object arg;
389 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
390 struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
391 union acpi_object *obj;
392
393 acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
394 obj = name_buffer.pointer;
395
396 printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
397
398 /* _DCK method has one argument */
399 arg_list.count = 1;
400 arg_list.pointer = &arg;
401 arg.type = ACPI_TYPE_INTEGER;
402 arg.integer.value = dock;
403 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
404 if (ACPI_FAILURE(status))
405 pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
406 kfree(buffer.pointer);
407 kfree(name_buffer.pointer);
408}
409
410static inline void dock(struct dock_station *ds)
411{
412 handle_dock(ds, 1);
413}
414
415static inline void undock(struct dock_station *ds)
416{
417 handle_dock(ds, 0);
418}
419
420static inline void begin_dock(struct dock_station *ds)
421{
422 ds->flags |= DOCK_DOCKING;
423}
424
425static inline void complete_dock(struct dock_station *ds)
426{
427 ds->flags &= ~(DOCK_DOCKING);
428 ds->last_dock_time = jiffies;
429}
430
a0cd35fd
KCA
431static inline void begin_undock(struct dock_station *ds)
432{
433 ds->flags |= DOCK_UNDOCKING;
434}
435
436static inline void complete_undock(struct dock_station *ds)
437{
438 ds->flags &= ~(DOCK_UNDOCKING);
439}
440
c8f7a62c
LB
441/**
442 * dock_in_progress - see if we are in the middle of handling a dock event
443 * @ds: the dock station
444 *
445 * Sometimes while docking, false dock events can be sent to the driver
446 * because good connections aren't made or some other reason. Ignore these
447 * if we are in the middle of doing something.
448 */
449static int dock_in_progress(struct dock_station *ds)
450{
451 if ((ds->flags & DOCK_DOCKING) ||
452 time_before(jiffies, (ds->last_dock_time + HZ)))
453 return 1;
454 return 0;
455}
456
457/**
458 * register_dock_notifier - add yourself to the dock notifier list
459 * @nb: the callers notifier block
460 *
461 * If a driver wishes to be notified about dock events, they can
462 * use this function to put a notifier block on the dock notifier list.
463 * this notifier call chain will be called after a dock event, but
464 * before hotplugging any new devices.
465 */
466int register_dock_notifier(struct notifier_block *nb)
467{
2548c06b
PB
468 if (!dock_station)
469 return -ENODEV;
470
c8f7a62c
LB
471 return atomic_notifier_chain_register(&dock_notifier_list, nb);
472}
473
474EXPORT_SYMBOL_GPL(register_dock_notifier);
475
476/**
477 * unregister_dock_notifier - remove yourself from the dock notifier list
478 * @nb: the callers notifier block
479 */
480void unregister_dock_notifier(struct notifier_block *nb)
481{
2548c06b
PB
482 if (!dock_station)
483 return;
484
c8f7a62c
LB
485 atomic_notifier_chain_unregister(&dock_notifier_list, nb);
486}
487
488EXPORT_SYMBOL_GPL(unregister_dock_notifier);
489
490/**
491 * register_hotplug_dock_device - register a hotplug function
492 * @handle: the handle of the device
493 * @handler: the acpi_notifier_handler to call after docking
494 * @context: device specific data
495 *
496 * If a driver would like to perform a hotplug operation after a dock
497 * event, they can register an acpi_notifiy_handler to be called by
498 * the dock driver after _DCK is executed.
499 */
500int
501register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
502 void *context)
503{
504 struct dock_dependent_device *dd;
505
506 if (!dock_station)
507 return -ENODEV;
508
509 /*
510 * make sure this handle is for a device dependent on the dock,
511 * this would include the dock station itself
512 */
513 dd = find_dock_dependent_device(dock_station, handle);
514 if (dd) {
515 dd->handler = handler;
516 dd->context = context;
517 dock_add_hotplug_device(dock_station, dd);
518 return 0;
519 }
520
521 return -EINVAL;
522}
523
524EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
525
526/**
527 * unregister_hotplug_dock_device - remove yourself from the hotplug list
528 * @handle: the acpi handle of the device
529 */
530void unregister_hotplug_dock_device(acpi_handle handle)
531{
532 struct dock_dependent_device *dd;
533
534 if (!dock_station)
535 return;
536
537 dd = find_dock_dependent_device(dock_station, handle);
538 if (dd)
539 dock_del_hotplug_device(dock_station, dd);
540}
541
542EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
543
c80fdbe8 544/**
545 * handle_eject_request - handle an undock request checking for error conditions
546 *
547 * Check to make sure the dock device is still present, then undock and
548 * hotremove all the devices that may need removing.
549 */
550static int handle_eject_request(struct dock_station *ds, u32 event)
551{
552 if (!dock_present(ds))
553 return -ENODEV;
554
555 if (dock_in_progress(ds))
556 return -EBUSY;
557
558 /*
559 * here we need to generate the undock
560 * event prior to actually doing the undock
561 * so that the device struct still exists.
562 */
563 dock_event(ds, event, UNDOCK_EVENT);
564 hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
565 undock(ds);
566 eject_dock(ds);
567 if (dock_present(ds)) {
568 printk(KERN_ERR PREFIX "Unable to undock!\n");
569 return -EBUSY;
570 }
a0cd35fd 571 complete_undock(ds);
c80fdbe8 572 return 0;
573}
574
c8f7a62c
LB
575/**
576 * dock_notify - act upon an acpi dock notification
577 * @handle: the dock station handle
578 * @event: the acpi event
579 * @data: our driver data struct
580 *
581 * If we are notified to dock, then check to see if the dock is
582 * present and then dock. Notify all drivers of the dock event,
c80fdbe8 583 * and then hotplug and devices that may need hotplugging.
c8f7a62c
LB
584 */
585static void dock_notify(acpi_handle handle, u32 event, void *data)
586{
50dd0969 587 struct dock_station *ds = data;
c8f7a62c
LB
588
589 switch (event) {
590 case ACPI_NOTIFY_BUS_CHECK:
591 if (!dock_in_progress(ds) && dock_present(ds)) {
592 begin_dock(ds);
593 dock(ds);
594 if (!dock_present(ds)) {
595 printk(KERN_ERR PREFIX "Unable to dock!\n");
596 break;
597 }
598 atomic_notifier_call_chain(&dock_notifier_list,
599 event, NULL);
600 hotplug_dock_devices(ds, event);
601 complete_dock(ds);
602 dock_event(ds, event, DOCK_EVENT);
603 }
604 break;
605 case ACPI_NOTIFY_DEVICE_CHECK:
606 /*
607 * According to acpi spec 3.0a, if a DEVICE_CHECK notification
608 * is sent and _DCK is present, it is assumed to mean an
609 * undock request. This notify routine will only be called
610 * for objects defining _DCK, so we will fall through to eject
611 * request here. However, we will pass an eject request through
612 * to the driver who wish to hotplug.
613 */
614 case ACPI_NOTIFY_EJECT_REQUEST:
a0cd35fd
KCA
615 begin_undock(ds);
616 if (immediate_undock)
617 handle_eject_request(ds, event);
618 else
619 dock_event(ds, event, UNDOCK_EVENT);
c8f7a62c
LB
620 break;
621 default:
622 printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
623 }
624}
625
626/**
627 * find_dock_devices - find devices on the dock station
628 * @handle: the handle of the device we are examining
629 * @lvl: unused
630 * @context: the dock station private data
631 * @rv: unused
632 *
633 * This function is called by acpi_walk_namespace. It will
634 * check to see if an object has an _EJD method. If it does, then it
635 * will see if it is dependent on the dock station.
636 */
637static acpi_status
638find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
639{
640 acpi_status status;
fe9a2f77 641 acpi_handle tmp, parent;
50dd0969 642 struct dock_station *ds = context;
c8f7a62c
LB
643 struct dock_dependent_device *dd;
644
645 status = acpi_bus_get_ejd(handle, &tmp);
fe9a2f77
KCA
646 if (ACPI_FAILURE(status)) {
647 /* try the parent device as well */
648 status = acpi_get_parent(handle, &parent);
649 if (ACPI_FAILURE(status))
650 goto fdd_out;
651 /* see if parent is dependent on dock */
652 status = acpi_bus_get_ejd(parent, &tmp);
653 if (ACPI_FAILURE(status))
654 goto fdd_out;
655 }
c8f7a62c
LB
656
657 if (tmp == ds->handle) {
658 dd = alloc_dock_dependent_device(handle);
659 if (dd)
660 add_dock_dependent_device(ds, dd);
661 }
fe9a2f77 662fdd_out:
c8f7a62c
LB
663 return AE_OK;
664}
665
c80fdbe8 666/*
667 * show_docked - read method for "docked" file in sysfs
668 */
669static ssize_t show_docked(struct device *dev,
670 struct device_attribute *attr, char *buf)
671{
672 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
673
674}
675DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
676
a0cd35fd
KCA
677/*
678 * show_flags - read method for flags file in sysfs
679 */
680static ssize_t show_flags(struct device *dev,
681 struct device_attribute *attr, char *buf)
682{
683 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
684
685}
686DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
687
c80fdbe8 688/*
689 * write_undock - write method for "undock" file in sysfs
690 */
691static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
692 const char *buf, size_t count)
693{
694 int ret;
695
696 if (!count)
697 return -EINVAL;
698
699 ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
700 return ret ? ret: count;
701}
702DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
703
ac122bb6
IVE
704/*
705 * show_dock_uid - read method for "uid" file in sysfs
706 */
707static ssize_t show_dock_uid(struct device *dev,
708 struct device_attribute *attr, char *buf)
709{
710 unsigned long lbuf;
38ff4ffc
KCA
711 acpi_status status = acpi_evaluate_integer(dock_station->handle,
712 "_UID", NULL, &lbuf);
713 if (ACPI_FAILURE(status))
ac122bb6 714 return 0;
38ff4ffc 715
ac122bb6
IVE
716 return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
717}
718DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
719
c8f7a62c
LB
720/**
721 * dock_add - add a new dock station
722 * @handle: the dock station handle
723 *
724 * allocated and initialize a new dock station device. Find all devices
725 * that are on the dock station, and register for dock event notifications.
726 */
727static int dock_add(acpi_handle handle)
728{
729 int ret;
730 acpi_status status;
731 struct dock_dependent_device *dd;
732
733 /* allocate & initialize the dock_station private data */
734 dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
735 if (!dock_station)
736 return -ENOMEM;
737 dock_station->handle = handle;
738 dock_station->last_dock_time = jiffies - HZ;
739 INIT_LIST_HEAD(&dock_station->dependent_devices);
740 INIT_LIST_HEAD(&dock_station->hotplug_devices);
741 spin_lock_init(&dock_station->dd_lock);
8b0dc866 742 mutex_init(&dock_station->hp_lock);
07a18684 743 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
c8f7a62c 744
671adbec 745 /* initialize platform device stuff */
0f6f2804
KCA
746 dock_device =
747 platform_device_register_simple(dock_device_name, 0, NULL, 0);
748 if (IS_ERR(dock_device)) {
671adbec 749 kfree(dock_station);
22fe4c21 750 dock_station = NULL;
0f6f2804 751 return PTR_ERR(dock_device);
671adbec 752 }
a0cd35fd 753
9ef2a9a9
KCA
754 /* we want the dock device to send uevents */
755 dock_device->dev.uevent_suppress = 0;
756
0f6f2804 757 ret = device_create_file(&dock_device->dev, &dev_attr_docked);
c80fdbe8 758 if (ret) {
759 printk("Error %d adding sysfs file\n", ret);
0f6f2804 760 platform_device_unregister(dock_device);
c80fdbe8 761 kfree(dock_station);
22fe4c21 762 dock_station = NULL;
c80fdbe8 763 return ret;
764 }
0f6f2804 765 ret = device_create_file(&dock_device->dev, &dev_attr_undock);
c80fdbe8 766 if (ret) {
767 printk("Error %d adding sysfs file\n", ret);
0f6f2804
KCA
768 device_remove_file(&dock_device->dev, &dev_attr_docked);
769 platform_device_unregister(dock_device);
c80fdbe8 770 kfree(dock_station);
22fe4c21 771 dock_station = NULL;
c80fdbe8 772 return ret;
773 }
0f6f2804 774 ret = device_create_file(&dock_device->dev, &dev_attr_uid);
ac122bb6
IVE
775 if (ret) {
776 printk("Error %d adding sysfs file\n", ret);
0f6f2804
KCA
777 device_remove_file(&dock_device->dev, &dev_attr_docked);
778 device_remove_file(&dock_device->dev, &dev_attr_undock);
779 platform_device_unregister(dock_device);
ac122bb6 780 kfree(dock_station);
22fe4c21 781 dock_station = NULL;
ac122bb6
IVE
782 return ret;
783 }
a0cd35fd
KCA
784 ret = device_create_file(&dock_device->dev, &dev_attr_flags);
785 if (ret) {
786 printk("Error %d adding sysfs file\n", ret);
787 device_remove_file(&dock_device->dev, &dev_attr_docked);
788 device_remove_file(&dock_device->dev, &dev_attr_undock);
789 device_remove_file(&dock_device->dev, &dev_attr_uid);
790 platform_device_unregister(dock_device);
791 kfree(dock_station);
792 dock_station = NULL;
793 return ret;
794 }
671adbec 795
c8f7a62c
LB
796 /* Find dependent devices */
797 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
798 ACPI_UINT32_MAX, find_dock_devices, dock_station,
799 NULL);
800
801 /* add the dock station as a device dependent on itself */
802 dd = alloc_dock_dependent_device(handle);
803 if (!dd) {
804 kfree(dock_station);
22fe4c21 805 dock_station = NULL;
671adbec
KCA
806 ret = -ENOMEM;
807 goto dock_add_err_unregister;
c8f7a62c
LB
808 }
809 add_dock_dependent_device(dock_station, dd);
810
811 /* register for dock events */
812 status = acpi_install_notify_handler(dock_station->handle,
813 ACPI_SYSTEM_NOTIFY,
814 dock_notify, dock_station);
815
816 if (ACPI_FAILURE(status)) {
817 printk(KERN_ERR PREFIX "Error installing notify handler\n");
818 ret = -ENODEV;
819 goto dock_add_err;
820 }
821
7cda93e0 822 printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION);
c8f7a62c
LB
823
824 return 0;
825
826dock_add_err:
c8f7a62c 827 kfree(dd);
671adbec 828dock_add_err_unregister:
0f6f2804
KCA
829 device_remove_file(&dock_device->dev, &dev_attr_docked);
830 device_remove_file(&dock_device->dev, &dev_attr_undock);
831 device_remove_file(&dock_device->dev, &dev_attr_uid);
a0cd35fd 832 device_remove_file(&dock_device->dev, &dev_attr_flags);
0f6f2804 833 platform_device_unregister(dock_device);
671adbec 834 kfree(dock_station);
22fe4c21 835 dock_station = NULL;
c8f7a62c
LB
836 return ret;
837}
838
839/**
840 * dock_remove - free up resources related to the dock station
841 */
842static int dock_remove(void)
843{
844 struct dock_dependent_device *dd, *tmp;
845 acpi_status status;
846
847 if (!dock_station)
848 return 0;
849
850 /* remove dependent devices */
851 list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,
852 list)
853 kfree(dd);
854
855 /* remove dock notify handler */
856 status = acpi_remove_notify_handler(dock_station->handle,
857 ACPI_SYSTEM_NOTIFY,
858 dock_notify);
859 if (ACPI_FAILURE(status))
860 printk(KERN_ERR "Error removing notify handler\n");
861
671adbec 862 /* cleanup sysfs */
0f6f2804
KCA
863 device_remove_file(&dock_device->dev, &dev_attr_docked);
864 device_remove_file(&dock_device->dev, &dev_attr_undock);
865 device_remove_file(&dock_device->dev, &dev_attr_uid);
a0cd35fd 866 device_remove_file(&dock_device->dev, &dev_attr_flags);
0f6f2804 867 platform_device_unregister(dock_device);
671adbec 868
c8f7a62c
LB
869 /* free dock station memory */
870 kfree(dock_station);
22fe4c21 871 dock_station = NULL;
c8f7a62c
LB
872 return 0;
873}
874
875/**
876 * find_dock - look for a dock station
877 * @handle: acpi handle of a device
878 * @lvl: unused
879 * @context: counter of dock stations found
880 * @rv: unused
881 *
882 * This is called by acpi_walk_namespace to look for dock stations.
883 */
884static acpi_status
885find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
886{
50dd0969 887 int *count = context;
c8f7a62c
LB
888 acpi_status status = AE_OK;
889
890 if (is_dock(handle)) {
891 if (dock_add(handle) >= 0) {
892 (*count)++;
893 status = AE_CTRL_TERMINATE;
894 }
895 }
896 return status;
897}
898
899static int __init dock_init(void)
900{
901 int num = 0;
902
903 dock_station = NULL;
904
905 /* look for a dock station */
906 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
907 ACPI_UINT32_MAX, find_dock, &num, NULL);
908
909 if (!num)
2548c06b 910 printk(KERN_INFO "No dock devices found.\n");
c8f7a62c
LB
911
912 return 0;
913}
914
915static void __exit dock_exit(void)
916{
917 dock_remove();
918}
919
920postcore_initcall(dock_init);
921module_exit(dock_exit);
This page took 0.134015 seconds and 5 git commands to generate.