aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/dock.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r--drivers/acpi/dock.c148
1 files changed, 119 insertions, 29 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 3c3dee844dfc..90990a4b6526 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -27,6 +27,8 @@
27#include <linux/init.h> 27#include <linux/init.h>
28#include <linux/types.h> 28#include <linux/types.h>
29#include <linux/notifier.h> 29#include <linux/notifier.h>
30#include <linux/platform_device.h>
31#include <linux/jiffies.h>
30#include <acpi/acpi_bus.h> 32#include <acpi/acpi_bus.h>
31#include <acpi/acpi_drivers.h> 33#include <acpi/acpi_drivers.h>
32 34
@@ -38,13 +40,15 @@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
38MODULE_LICENSE("GPL"); 40MODULE_LICENSE("GPL");
39 41
40static struct atomic_notifier_head dock_notifier_list; 42static struct atomic_notifier_head dock_notifier_list;
43static struct platform_device dock_device;
44static char dock_device_name[] = "dock";
41 45
42struct dock_station { 46struct dock_station {
43 acpi_handle handle; 47 acpi_handle handle;
44 unsigned long last_dock_time; 48 unsigned long last_dock_time;
45 u32 flags; 49 u32 flags;
46 spinlock_t dd_lock; 50 spinlock_t dd_lock;
47 spinlock_t hp_lock; 51 struct mutex hp_lock;
48 struct list_head dependent_devices; 52 struct list_head dependent_devices;
49 struct list_head hotplug_devices; 53 struct list_head hotplug_devices;
50}; 54};
@@ -114,9 +118,9 @@ static void
114dock_add_hotplug_device(struct dock_station *ds, 118dock_add_hotplug_device(struct dock_station *ds,
115 struct dock_dependent_device *dd) 119 struct dock_dependent_device *dd)
116{ 120{
117 spin_lock(&ds->hp_lock); 121 mutex_lock(&ds->hp_lock);
118 list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); 122 list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
119 spin_unlock(&ds->hp_lock); 123 mutex_unlock(&ds->hp_lock);
120} 124}
121 125
122/** 126/**
@@ -130,9 +134,9 @@ static void
130dock_del_hotplug_device(struct dock_station *ds, 134dock_del_hotplug_device(struct dock_station *ds,
131 struct dock_dependent_device *dd) 135 struct dock_dependent_device *dd)
132{ 136{
133 spin_lock(&ds->hp_lock); 137 mutex_lock(&ds->hp_lock);
134 list_del(&dd->hotplug_list); 138 list_del(&dd->hotplug_list);
135 spin_unlock(&ds->hp_lock); 139 mutex_unlock(&ds->hp_lock);
136} 140}
137 141
138/** 142/**
@@ -295,7 +299,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
295{ 299{
296 struct dock_dependent_device *dd; 300 struct dock_dependent_device *dd;
297 301
298 spin_lock(&ds->hp_lock); 302 mutex_lock(&ds->hp_lock);
299 303
300 /* 304 /*
301 * First call driver specific hotplug functions 305 * First call driver specific hotplug functions
@@ -317,15 +321,17 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
317 else 321 else
318 dock_create_acpi_device(dd->handle); 322 dock_create_acpi_device(dd->handle);
319 } 323 }
320 spin_unlock(&ds->hp_lock); 324 mutex_unlock(&ds->hp_lock);
321} 325}
322 326
323static void dock_event(struct dock_station *ds, u32 event, int num) 327static void dock_event(struct dock_station *ds, u32 event, int num)
324{ 328{
329 struct device *dev = &dock_device.dev;
325 /* 330 /*
326 * we don't do events until someone tells me that 331 * Indicate that the status of the dock station has
327 * they would like to have them. 332 * changed.
328 */ 333 */
334 kobject_uevent(&dev->kobj, KOBJ_CHANGE);
329} 335}
330 336
331/** 337/**
@@ -440,6 +446,9 @@ static int dock_in_progress(struct dock_station *ds)
440 */ 446 */
441int register_dock_notifier(struct notifier_block *nb) 447int register_dock_notifier(struct notifier_block *nb)
442{ 448{
449 if (!dock_station)
450 return -ENODEV;
451
443 return atomic_notifier_chain_register(&dock_notifier_list, nb); 452 return atomic_notifier_chain_register(&dock_notifier_list, nb);
444} 453}
445 454
@@ -451,6 +460,9 @@ EXPORT_SYMBOL_GPL(register_dock_notifier);
451 */ 460 */
452void unregister_dock_notifier(struct notifier_block *nb) 461void unregister_dock_notifier(struct notifier_block *nb)
453{ 462{
463 if (!dock_station)
464 return;
465
454 atomic_notifier_chain_unregister(&dock_notifier_list, nb); 466 atomic_notifier_chain_unregister(&dock_notifier_list, nb);
455} 467}
456 468
@@ -511,6 +523,37 @@ void unregister_hotplug_dock_device(acpi_handle handle)
511EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); 523EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
512 524
513/** 525/**
526 * handle_eject_request - handle an undock request checking for error conditions
527 *
528 * Check to make sure the dock device is still present, then undock and
529 * hotremove all the devices that may need removing.
530 */
531static int handle_eject_request(struct dock_station *ds, u32 event)
532{
533 if (!dock_present(ds))
534 return -ENODEV;
535
536 if (dock_in_progress(ds))
537 return -EBUSY;
538
539 /*
540 * here we need to generate the undock
541 * event prior to actually doing the undock
542 * so that the device struct still exists.
543 */
544 dock_event(ds, event, UNDOCK_EVENT);
545 hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
546 undock(ds);
547 eject_dock(ds);
548 if (dock_present(ds)) {
549 printk(KERN_ERR PREFIX "Unable to undock!\n");
550 return -EBUSY;
551 }
552
553 return 0;
554}
555
556/**
514 * dock_notify - act upon an acpi dock notification 557 * dock_notify - act upon an acpi dock notification
515 * @handle: the dock station handle 558 * @handle: the dock station handle
516 * @event: the acpi event 559 * @event: the acpi event
@@ -518,9 +561,7 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
518 * 561 *
519 * If we are notified to dock, then check to see if the dock is 562 * If we are notified to dock, then check to see if the dock is
520 * present and then dock. Notify all drivers of the dock event, 563 * present and then dock. Notify all drivers of the dock event,
521 * and then hotplug and devices that may need hotplugging. For undock 564 * and then hotplug and devices that may need hotplugging.
522 * check to make sure the dock device is still present, then undock
523 * and hotremove all the devices that may need removing.
524 */ 565 */
525static void dock_notify(acpi_handle handle, u32 event, void *data) 566static void dock_notify(acpi_handle handle, u32 event, void *data)
526{ 567{
@@ -552,19 +593,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
552 * to the driver who wish to hotplug. 593 * to the driver who wish to hotplug.
553 */ 594 */
554 case ACPI_NOTIFY_EJECT_REQUEST: 595 case ACPI_NOTIFY_EJECT_REQUEST:
555 if (!dock_in_progress(ds) && dock_present(ds)) { 596 handle_eject_request(ds, event);
556 /*
557 * here we need to generate the undock
558 * event prior to actually doing the undock
559 * so that the device struct still exists.
560 */
561 dock_event(ds, event, UNDOCK_EVENT);
562 hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
563 undock(ds);
564 eject_dock(ds);
565 if (dock_present(ds))
566 printk(KERN_ERR PREFIX "Unable to undock!\n");
567 }
568 break; 597 break;
569 default: 598 default:
570 printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); 599 printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -603,6 +632,33 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
603 return AE_OK; 632 return AE_OK;
604} 633}
605 634
635/*
636 * show_docked - read method for "docked" file in sysfs
637 */
638static ssize_t show_docked(struct device *dev,
639 struct device_attribute *attr, char *buf)
640{
641 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
642
643}
644DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
645
646/*
647 * write_undock - write method for "undock" file in sysfs
648 */
649static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
650 const char *buf, size_t count)
651{
652 int ret;
653
654 if (!count)
655 return -EINVAL;
656
657 ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
658 return ret ? ret: count;
659}
660DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
661
606/** 662/**
607 * dock_add - add a new dock station 663 * dock_add - add a new dock station
608 * @handle: the dock station handle 664 * @handle: the dock station handle
@@ -625,9 +681,33 @@ static int dock_add(acpi_handle handle)
625 INIT_LIST_HEAD(&dock_station->dependent_devices); 681 INIT_LIST_HEAD(&dock_station->dependent_devices);
626 INIT_LIST_HEAD(&dock_station->hotplug_devices); 682 INIT_LIST_HEAD(&dock_station->hotplug_devices);
627 spin_lock_init(&dock_station->dd_lock); 683 spin_lock_init(&dock_station->dd_lock);
628 spin_lock_init(&dock_station->hp_lock); 684 mutex_init(&dock_station->hp_lock);
629 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); 685 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
630 686
687 /* initialize platform device stuff */
688 dock_device.name = dock_device_name;
689 ret = platform_device_register(&dock_device);
690 if (ret) {
691 printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
692 kfree(dock_station);
693 return ret;
694 }
695 ret = device_create_file(&dock_device.dev, &dev_attr_docked);
696 if (ret) {
697 printk("Error %d adding sysfs file\n", ret);
698 platform_device_unregister(&dock_device);
699 kfree(dock_station);
700 return ret;
701 }
702 ret = device_create_file(&dock_device.dev, &dev_attr_undock);
703 if (ret) {
704 printk("Error %d adding sysfs file\n", ret);
705 device_remove_file(&dock_device.dev, &dev_attr_docked);
706 platform_device_unregister(&dock_device);
707 kfree(dock_station);
708 return ret;
709 }
710
631 /* Find dependent devices */ 711 /* Find dependent devices */
632 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 712 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
633 ACPI_UINT32_MAX, find_dock_devices, dock_station, 713 ACPI_UINT32_MAX, find_dock_devices, dock_station,
@@ -637,7 +717,8 @@ static int dock_add(acpi_handle handle)
637 dd = alloc_dock_dependent_device(handle); 717 dd = alloc_dock_dependent_device(handle);
638 if (!dd) { 718 if (!dd) {
639 kfree(dock_station); 719 kfree(dock_station);
640 return -ENOMEM; 720 ret = -ENOMEM;
721 goto dock_add_err_unregister;
641 } 722 }
642 add_dock_dependent_device(dock_station, dd); 723 add_dock_dependent_device(dock_station, dd);
643 724
@@ -657,8 +738,12 @@ static int dock_add(acpi_handle handle)
657 return 0; 738 return 0;
658 739
659dock_add_err: 740dock_add_err:
660 kfree(dock_station);
661 kfree(dd); 741 kfree(dd);
742dock_add_err_unregister:
743 device_remove_file(&dock_device.dev, &dev_attr_docked);
744 device_remove_file(&dock_device.dev, &dev_attr_undock);
745 platform_device_unregister(&dock_device);
746 kfree(dock_station);
662 return ret; 747 return ret;
663} 748}
664 749
@@ -685,6 +770,11 @@ static int dock_remove(void)
685 if (ACPI_FAILURE(status)) 770 if (ACPI_FAILURE(status))
686 printk(KERN_ERR "Error removing notify handler\n"); 771 printk(KERN_ERR "Error removing notify handler\n");
687 772
773 /* cleanup sysfs */
774 device_remove_file(&dock_device.dev, &dev_attr_docked);
775 device_remove_file(&dock_device.dev, &dev_attr_undock);
776 platform_device_unregister(&dock_device);
777
688 /* free dock station memory */ 778 /* free dock station memory */
689 kfree(dock_station); 779 kfree(dock_station);
690 return 0; 780 return 0;
@@ -725,7 +815,7 @@ static int __init dock_init(void)
725 ACPI_UINT32_MAX, find_dock, &num, NULL); 815 ACPI_UINT32_MAX, find_dock, &num, NULL);
726 816
727 if (!num) 817 if (!num)
728 return -ENODEV; 818 printk(KERN_INFO "No dock devices found.\n");
729 819
730 return 0; 820 return 0;
731} 821}