diff options
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r-- | drivers/acpi/dock.c | 95 |
1 files changed, 79 insertions, 16 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 2c2f28db9fb2..e4c1a4ff4e31 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -515,6 +515,37 @@ void unregister_hotplug_dock_device(acpi_handle handle) | |||
515 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | 515 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); |
516 | 516 | ||
517 | /** | 517 | /** |
518 | * handle_eject_request - handle an undock request checking for error conditions | ||
519 | * | ||
520 | * Check to make sure the dock device is still present, then undock and | ||
521 | * hotremove all the devices that may need removing. | ||
522 | */ | ||
523 | static int handle_eject_request(struct dock_station *ds, u32 event) | ||
524 | { | ||
525 | if (!dock_present(ds)) | ||
526 | return -ENODEV; | ||
527 | |||
528 | if (dock_in_progress(ds)) | ||
529 | return -EBUSY; | ||
530 | |||
531 | /* | ||
532 | * here we need to generate the undock | ||
533 | * event prior to actually doing the undock | ||
534 | * so that the device struct still exists. | ||
535 | */ | ||
536 | dock_event(ds, event, UNDOCK_EVENT); | ||
537 | hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); | ||
538 | undock(ds); | ||
539 | eject_dock(ds); | ||
540 | if (dock_present(ds)) { | ||
541 | printk(KERN_ERR PREFIX "Unable to undock!\n"); | ||
542 | return -EBUSY; | ||
543 | } | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | /** | ||
518 | * dock_notify - act upon an acpi dock notification | 549 | * dock_notify - act upon an acpi dock notification |
519 | * @handle: the dock station handle | 550 | * @handle: the dock station handle |
520 | * @event: the acpi event | 551 | * @event: the acpi event |
@@ -522,9 +553,7 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | |||
522 | * | 553 | * |
523 | * If we are notified to dock, then check to see if the dock is | 554 | * If we are notified to dock, then check to see if the dock is |
524 | * present and then dock. Notify all drivers of the dock event, | 555 | * present and then dock. Notify all drivers of the dock event, |
525 | * and then hotplug and devices that may need hotplugging. For undock | 556 | * and then hotplug and devices that may need hotplugging. |
526 | * check to make sure the dock device is still present, then undock | ||
527 | * and hotremove all the devices that may need removing. | ||
528 | */ | 557 | */ |
529 | static void dock_notify(acpi_handle handle, u32 event, void *data) | 558 | static void dock_notify(acpi_handle handle, u32 event, void *data) |
530 | { | 559 | { |
@@ -556,19 +585,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) | |||
556 | * to the driver who wish to hotplug. | 585 | * to the driver who wish to hotplug. |
557 | */ | 586 | */ |
558 | case ACPI_NOTIFY_EJECT_REQUEST: | 587 | case ACPI_NOTIFY_EJECT_REQUEST: |
559 | if (!dock_in_progress(ds) && dock_present(ds)) { | 588 | handle_eject_request(ds, event); |
560 | /* | ||
561 | * here we need to generate the undock | ||
562 | * event prior to actually doing the undock | ||
563 | * so that the device struct still exists. | ||
564 | */ | ||
565 | dock_event(ds, event, UNDOCK_EVENT); | ||
566 | hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); | ||
567 | undock(ds); | ||
568 | eject_dock(ds); | ||
569 | if (dock_present(ds)) | ||
570 | printk(KERN_ERR PREFIX "Unable to undock!\n"); | ||
571 | } | ||
572 | break; | 589 | break; |
573 | default: | 590 | default: |
574 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); | 591 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); |
@@ -607,6 +624,33 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
607 | return AE_OK; | 624 | return AE_OK; |
608 | } | 625 | } |
609 | 626 | ||
627 | /* | ||
628 | * show_docked - read method for "docked" file in sysfs | ||
629 | */ | ||
630 | static ssize_t show_docked(struct device *dev, | ||
631 | struct device_attribute *attr, char *buf) | ||
632 | { | ||
633 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); | ||
634 | |||
635 | } | ||
636 | DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | ||
637 | |||
638 | /* | ||
639 | * write_undock - write method for "undock" file in sysfs | ||
640 | */ | ||
641 | static ssize_t write_undock(struct device *dev, struct device_attribute *attr, | ||
642 | const char *buf, size_t count) | ||
643 | { | ||
644 | int ret; | ||
645 | |||
646 | if (!count) | ||
647 | return -EINVAL; | ||
648 | |||
649 | ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); | ||
650 | return ret ? ret: count; | ||
651 | } | ||
652 | DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); | ||
653 | |||
610 | /** | 654 | /** |
611 | * dock_add - add a new dock station | 655 | * dock_add - add a new dock station |
612 | * @handle: the dock station handle | 656 | * @handle: the dock station handle |
@@ -640,6 +684,21 @@ static int dock_add(acpi_handle handle) | |||
640 | kfree(dock_station); | 684 | kfree(dock_station); |
641 | return ret; | 685 | return ret; |
642 | } | 686 | } |
687 | ret = device_create_file(&dock_device.dev, &dev_attr_docked); | ||
688 | if (ret) { | ||
689 | printk("Error %d adding sysfs file\n", ret); | ||
690 | platform_device_unregister(&dock_device); | ||
691 | kfree(dock_station); | ||
692 | return ret; | ||
693 | } | ||
694 | ret = device_create_file(&dock_device.dev, &dev_attr_undock); | ||
695 | if (ret) { | ||
696 | printk("Error %d adding sysfs file\n", ret); | ||
697 | device_remove_file(&dock_device.dev, &dev_attr_docked); | ||
698 | platform_device_unregister(&dock_device); | ||
699 | kfree(dock_station); | ||
700 | return ret; | ||
701 | } | ||
643 | 702 | ||
644 | /* Find dependent devices */ | 703 | /* Find dependent devices */ |
645 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 704 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
@@ -673,6 +732,8 @@ static int dock_add(acpi_handle handle) | |||
673 | dock_add_err: | 732 | dock_add_err: |
674 | kfree(dd); | 733 | kfree(dd); |
675 | dock_add_err_unregister: | 734 | dock_add_err_unregister: |
735 | device_remove_file(&dock_device.dev, &dev_attr_docked); | ||
736 | device_remove_file(&dock_device.dev, &dev_attr_undock); | ||
676 | platform_device_unregister(&dock_device); | 737 | platform_device_unregister(&dock_device); |
677 | kfree(dock_station); | 738 | kfree(dock_station); |
678 | return ret; | 739 | return ret; |
@@ -702,6 +763,8 @@ static int dock_remove(void) | |||
702 | printk(KERN_ERR "Error removing notify handler\n"); | 763 | printk(KERN_ERR "Error removing notify handler\n"); |
703 | 764 | ||
704 | /* cleanup sysfs */ | 765 | /* cleanup sysfs */ |
766 | device_remove_file(&dock_device.dev, &dev_attr_docked); | ||
767 | device_remove_file(&dock_device.dev, &dev_attr_undock); | ||
705 | platform_device_unregister(&dock_device); | 768 | platform_device_unregister(&dock_device); |
706 | 769 | ||
707 | /* free dock station memory */ | 770 | /* free dock station memory */ |