diff options
author | Len Brown <len.brown@intel.com> | 2006-12-16 00:33:45 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2006-12-16 00:33:45 -0500 |
commit | fb7665544dd60e016494cd5531f5b65ddae22ddc (patch) | |
tree | a28c785088202533100fcea292215e223fb87a89 /drivers/acpi | |
parent | 678f2b7df24c34f90fee264fa3a8069bca9c99ad (diff) | |
parent | 8ea86e0ba7c9d16ae0f35cb0c4165194fa573f7a (diff) |
Pull dock into test branch
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/dock.c | 131 |
1 files changed, 110 insertions, 21 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index bf5b79ed3613..215f5b30a1f1 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -27,6 +27,7 @@ | |||
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> | ||
30 | #include <linux/jiffies.h> | 31 | #include <linux/jiffies.h> |
31 | #include <acpi/acpi_bus.h> | 32 | #include <acpi/acpi_bus.h> |
32 | #include <acpi/acpi_drivers.h> | 33 | #include <acpi/acpi_drivers.h> |
@@ -39,6 +40,8 @@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); | |||
39 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
40 | 41 | ||
41 | static struct atomic_notifier_head dock_notifier_list; | 42 | static struct atomic_notifier_head dock_notifier_list; |
43 | static struct platform_device dock_device; | ||
44 | static char dock_device_name[] = "dock"; | ||
42 | 45 | ||
43 | struct dock_station { | 46 | struct dock_station { |
44 | acpi_handle handle; | 47 | acpi_handle handle; |
@@ -323,10 +326,12 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
323 | 326 | ||
324 | static void dock_event(struct dock_station *ds, u32 event, int num) | 327 | static void dock_event(struct dock_station *ds, u32 event, int num) |
325 | { | 328 | { |
329 | struct device *dev = &dock_device.dev; | ||
326 | /* | 330 | /* |
327 | * we don't do events until someone tells me that | 331 | * Indicate that the status of the dock station has |
328 | * they would like to have them. | 332 | * changed. |
329 | */ | 333 | */ |
334 | kobject_uevent(&dev->kobj, KOBJ_CHANGE); | ||
330 | } | 335 | } |
331 | 336 | ||
332 | /** | 337 | /** |
@@ -441,6 +446,9 @@ static int dock_in_progress(struct dock_station *ds) | |||
441 | */ | 446 | */ |
442 | int register_dock_notifier(struct notifier_block *nb) | 447 | int register_dock_notifier(struct notifier_block *nb) |
443 | { | 448 | { |
449 | if (!dock_station) | ||
450 | return -ENODEV; | ||
451 | |||
444 | return atomic_notifier_chain_register(&dock_notifier_list, nb); | 452 | return atomic_notifier_chain_register(&dock_notifier_list, nb); |
445 | } | 453 | } |
446 | 454 | ||
@@ -452,6 +460,9 @@ EXPORT_SYMBOL_GPL(register_dock_notifier); | |||
452 | */ | 460 | */ |
453 | void unregister_dock_notifier(struct notifier_block *nb) | 461 | void unregister_dock_notifier(struct notifier_block *nb) |
454 | { | 462 | { |
463 | if (!dock_station) | ||
464 | return; | ||
465 | |||
455 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); | 466 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); |
456 | } | 467 | } |
457 | 468 | ||
@@ -512,6 +523,37 @@ void unregister_hotplug_dock_device(acpi_handle handle) | |||
512 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | 523 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); |
513 | 524 | ||
514 | /** | 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 | */ | ||
531 | static 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 | /** | ||
515 | * dock_notify - act upon an acpi dock notification | 557 | * dock_notify - act upon an acpi dock notification |
516 | * @handle: the dock station handle | 558 | * @handle: the dock station handle |
517 | * @event: the acpi event | 559 | * @event: the acpi event |
@@ -519,9 +561,7 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | |||
519 | * | 561 | * |
520 | * 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 |
521 | * present and then dock. Notify all drivers of the dock event, | 563 | * present and then dock. Notify all drivers of the dock event, |
522 | * and then hotplug and devices that may need hotplugging. For undock | 564 | * and then hotplug and devices that may need hotplugging. |
523 | * check to make sure the dock device is still present, then undock | ||
524 | * and hotremove all the devices that may need removing. | ||
525 | */ | 565 | */ |
526 | static void dock_notify(acpi_handle handle, u32 event, void *data) | 566 | static void dock_notify(acpi_handle handle, u32 event, void *data) |
527 | { | 567 | { |
@@ -553,19 +593,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) | |||
553 | * to the driver who wish to hotplug. | 593 | * to the driver who wish to hotplug. |
554 | */ | 594 | */ |
555 | case ACPI_NOTIFY_EJECT_REQUEST: | 595 | case ACPI_NOTIFY_EJECT_REQUEST: |
556 | if (!dock_in_progress(ds) && dock_present(ds)) { | 596 | handle_eject_request(ds, event); |
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; | 597 | break; |
570 | default: | 598 | default: |
571 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); | 599 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); |
@@ -604,6 +632,33 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
604 | return AE_OK; | 632 | return AE_OK; |
605 | } | 633 | } |
606 | 634 | ||
635 | /* | ||
636 | * show_docked - read method for "docked" file in sysfs | ||
637 | */ | ||
638 | static 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 | } | ||
644 | DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | ||
645 | |||
646 | /* | ||
647 | * write_undock - write method for "undock" file in sysfs | ||
648 | */ | ||
649 | static 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 | } | ||
660 | DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); | ||
661 | |||
607 | /** | 662 | /** |
608 | * dock_add - add a new dock station | 663 | * dock_add - add a new dock station |
609 | * @handle: the dock station handle | 664 | * @handle: the dock station handle |
@@ -629,6 +684,30 @@ static int dock_add(acpi_handle handle) | |||
629 | spin_lock_init(&dock_station->hp_lock); | 684 | spin_lock_init(&dock_station->hp_lock); |
630 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); | 685 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); |
631 | 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 | |||
632 | /* Find dependent devices */ | 711 | /* Find dependent devices */ |
633 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 712 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
634 | ACPI_UINT32_MAX, find_dock_devices, dock_station, | 713 | ACPI_UINT32_MAX, find_dock_devices, dock_station, |
@@ -638,7 +717,8 @@ static int dock_add(acpi_handle handle) | |||
638 | dd = alloc_dock_dependent_device(handle); | 717 | dd = alloc_dock_dependent_device(handle); |
639 | if (!dd) { | 718 | if (!dd) { |
640 | kfree(dock_station); | 719 | kfree(dock_station); |
641 | return -ENOMEM; | 720 | ret = -ENOMEM; |
721 | goto dock_add_err_unregister; | ||
642 | } | 722 | } |
643 | add_dock_dependent_device(dock_station, dd); | 723 | add_dock_dependent_device(dock_station, dd); |
644 | 724 | ||
@@ -658,8 +738,12 @@ static int dock_add(acpi_handle handle) | |||
658 | return 0; | 738 | return 0; |
659 | 739 | ||
660 | dock_add_err: | 740 | dock_add_err: |
661 | kfree(dock_station); | ||
662 | kfree(dd); | 741 | kfree(dd); |
742 | dock_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); | ||
663 | return ret; | 747 | return ret; |
664 | } | 748 | } |
665 | 749 | ||
@@ -686,6 +770,11 @@ static int dock_remove(void) | |||
686 | if (ACPI_FAILURE(status)) | 770 | if (ACPI_FAILURE(status)) |
687 | printk(KERN_ERR "Error removing notify handler\n"); | 771 | printk(KERN_ERR "Error removing notify handler\n"); |
688 | 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 | |||
689 | /* free dock station memory */ | 778 | /* free dock station memory */ |
690 | kfree(dock_station); | 779 | kfree(dock_station); |
691 | return 0; | 780 | return 0; |
@@ -726,7 +815,7 @@ static int __init dock_init(void) | |||
726 | ACPI_UINT32_MAX, find_dock, &num, NULL); | 815 | ACPI_UINT32_MAX, find_dock, &num, NULL); |
727 | 816 | ||
728 | if (!num) | 817 | if (!num) |
729 | return -ENODEV; | 818 | printk(KERN_INFO "No dock devices found.\n"); |
730 | 819 | ||
731 | return 0; | 820 | return 0; |
732 | } | 821 | } |