diff options
| -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 */ |
