diff options
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r-- | drivers/acpi/dock.c | 127 |
1 files changed, 97 insertions, 30 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4546bf873aea..6192c8be66df 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi"); | |||
40 | MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); | 40 | MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); |
41 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
42 | 42 | ||
43 | static int immediate_undock = 1; | ||
44 | module_param(immediate_undock, bool, 0644); | ||
45 | MODULE_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 | |||
43 | static struct atomic_notifier_head dock_notifier_list; | 50 | static struct atomic_notifier_head dock_notifier_list; |
44 | static struct platform_device dock_device; | 51 | static struct platform_device *dock_device; |
45 | static char dock_device_name[] = "dock"; | 52 | static char dock_device_name[] = "dock"; |
46 | 53 | ||
47 | struct dock_station { | 54 | struct dock_station { |
@@ -63,6 +70,7 @@ struct dock_dependent_device { | |||
63 | }; | 70 | }; |
64 | 71 | ||
65 | #define DOCK_DOCKING 0x00000001 | 72 | #define DOCK_DOCKING 0x00000001 |
73 | #define DOCK_UNDOCKING 0x00000002 | ||
66 | #define DOCK_EVENT 3 | 74 | #define DOCK_EVENT 3 |
67 | #define UNDOCK_EVENT 2 | 75 | #define UNDOCK_EVENT 2 |
68 | 76 | ||
@@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
327 | 335 | ||
328 | static void dock_event(struct dock_station *ds, u32 event, int num) | 336 | static void dock_event(struct dock_station *ds, u32 event, int num) |
329 | { | 337 | { |
330 | struct device *dev = &dock_device.dev; | 338 | struct device *dev = &dock_device->dev; |
339 | char event_string[7]; | ||
340 | char *envp[] = { event_string, NULL }; | ||
341 | |||
342 | if (num == UNDOCK_EVENT) | ||
343 | sprintf(event_string, "UNDOCK"); | ||
344 | else | ||
345 | sprintf(event_string, "DOCK"); | ||
346 | |||
331 | /* | 347 | /* |
332 | * Indicate that the status of the dock station has | 348 | * Indicate that the status of the dock station has |
333 | * changed. | 349 | * changed. |
334 | */ | 350 | */ |
335 | kobject_uevent(&dev->kobj, KOBJ_CHANGE); | 351 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); |
336 | } | 352 | } |
337 | 353 | ||
338 | /** | 354 | /** |
@@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock) | |||
380 | union acpi_object arg; | 396 | union acpi_object arg; |
381 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 397 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
382 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 398 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
383 | union acpi_object *obj; | ||
384 | 399 | ||
385 | acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); | 400 | acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); |
386 | obj = name_buffer.pointer; | ||
387 | 401 | ||
388 | printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking"); | 402 | printk(KERN_INFO PREFIX "%s - %s\n", |
403 | (char *)name_buffer.pointer, dock ? "docking" : "undocking"); | ||
389 | 404 | ||
390 | /* _DCK method has one argument */ | 405 | /* _DCK method has one argument */ |
391 | arg_list.count = 1; | 406 | arg_list.count = 1; |
@@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock) | |||
394 | arg.integer.value = dock; | 409 | arg.integer.value = dock; |
395 | status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); | 410 | status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); |
396 | if (ACPI_FAILURE(status)) | 411 | if (ACPI_FAILURE(status)) |
397 | pr_debug("%s: failed to execute _DCK\n", obj->string.pointer); | 412 | printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", |
413 | (char *)name_buffer.pointer); | ||
398 | kfree(buffer.pointer); | 414 | kfree(buffer.pointer); |
399 | kfree(name_buffer.pointer); | 415 | kfree(name_buffer.pointer); |
400 | } | 416 | } |
@@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds) | |||
420 | ds->last_dock_time = jiffies; | 436 | ds->last_dock_time = jiffies; |
421 | } | 437 | } |
422 | 438 | ||
439 | static inline void begin_undock(struct dock_station *ds) | ||
440 | { | ||
441 | ds->flags |= DOCK_UNDOCKING; | ||
442 | } | ||
443 | |||
444 | static inline void complete_undock(struct dock_station *ds) | ||
445 | { | ||
446 | ds->flags &= ~(DOCK_UNDOCKING); | ||
447 | } | ||
448 | |||
423 | /** | 449 | /** |
424 | * dock_in_progress - see if we are in the middle of handling a dock event | 450 | * dock_in_progress - see if we are in the middle of handling a dock event |
425 | * @ds: the dock station | 451 | * @ds: the dock station |
@@ -550,7 +576,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) | |||
550 | printk(KERN_ERR PREFIX "Unable to undock!\n"); | 576 | printk(KERN_ERR PREFIX "Unable to undock!\n"); |
551 | return -EBUSY; | 577 | return -EBUSY; |
552 | } | 578 | } |
553 | 579 | complete_undock(ds); | |
554 | return 0; | 580 | return 0; |
555 | } | 581 | } |
556 | 582 | ||
@@ -594,7 +620,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) | |||
594 | * to the driver who wish to hotplug. | 620 | * to the driver who wish to hotplug. |
595 | */ | 621 | */ |
596 | case ACPI_NOTIFY_EJECT_REQUEST: | 622 | case ACPI_NOTIFY_EJECT_REQUEST: |
597 | handle_eject_request(ds, event); | 623 | begin_undock(ds); |
624 | if (immediate_undock) | ||
625 | handle_eject_request(ds, event); | ||
626 | else | ||
627 | dock_event(ds, event, UNDOCK_EVENT); | ||
598 | break; | 628 | break; |
599 | default: | 629 | default: |
600 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); | 630 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); |
@@ -653,6 +683,17 @@ static ssize_t show_docked(struct device *dev, | |||
653 | DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | 683 | DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); |
654 | 684 | ||
655 | /* | 685 | /* |
686 | * show_flags - read method for flags file in sysfs | ||
687 | */ | ||
688 | static ssize_t show_flags(struct device *dev, | ||
689 | struct device_attribute *attr, char *buf) | ||
690 | { | ||
691 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); | ||
692 | |||
693 | } | ||
694 | DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); | ||
695 | |||
696 | /* | ||
656 | * write_undock - write method for "undock" file in sysfs | 697 | * write_undock - write method for "undock" file in sysfs |
657 | */ | 698 | */ |
658 | static ssize_t write_undock(struct device *dev, struct device_attribute *attr, | 699 | static ssize_t write_undock(struct device *dev, struct device_attribute *attr, |
@@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct device *dev, | |||
675 | struct device_attribute *attr, char *buf) | 716 | struct device_attribute *attr, char *buf) |
676 | { | 717 | { |
677 | unsigned long lbuf; | 718 | unsigned long lbuf; |
678 | acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); | 719 | acpi_status status = acpi_evaluate_integer(dock_station->handle, |
679 | if(ACPI_FAILURE(status)) { | 720 | "_UID", NULL, &lbuf); |
721 | if (ACPI_FAILURE(status)) | ||
680 | return 0; | 722 | return 0; |
681 | } | 723 | |
682 | return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); | 724 | return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); |
683 | } | 725 | } |
684 | DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); | 726 | DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); |
685 | 727 | ||
686 | |||
687 | |||
688 | /** | 728 | /** |
689 | * dock_add - add a new dock station | 729 | * dock_add - add a new dock station |
690 | * @handle: the dock station handle | 730 | * @handle: the dock station handle |
@@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle) | |||
711 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); | 751 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); |
712 | 752 | ||
713 | /* initialize platform device stuff */ | 753 | /* initialize platform device stuff */ |
714 | dock_device.name = dock_device_name; | 754 | dock_device = |
715 | ret = platform_device_register(&dock_device); | 755 | platform_device_register_simple(dock_device_name, 0, NULL, 0); |
756 | if (IS_ERR(dock_device)) { | ||
757 | kfree(dock_station); | ||
758 | dock_station = NULL; | ||
759 | return PTR_ERR(dock_device); | ||
760 | } | ||
761 | |||
762 | /* we want the dock device to send uevents */ | ||
763 | dock_device->dev.uevent_suppress = 0; | ||
764 | |||
765 | ret = device_create_file(&dock_device->dev, &dev_attr_docked); | ||
716 | if (ret) { | 766 | if (ret) { |
717 | printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret); | 767 | printk("Error %d adding sysfs file\n", ret); |
768 | platform_device_unregister(dock_device); | ||
718 | kfree(dock_station); | 769 | kfree(dock_station); |
770 | dock_station = NULL; | ||
719 | return ret; | 771 | return ret; |
720 | } | 772 | } |
721 | ret = device_create_file(&dock_device.dev, &dev_attr_docked); | 773 | ret = device_create_file(&dock_device->dev, &dev_attr_undock); |
722 | if (ret) { | 774 | if (ret) { |
723 | printk("Error %d adding sysfs file\n", ret); | 775 | printk("Error %d adding sysfs file\n", ret); |
724 | platform_device_unregister(&dock_device); | 776 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
777 | platform_device_unregister(dock_device); | ||
725 | kfree(dock_station); | 778 | kfree(dock_station); |
779 | dock_station = NULL; | ||
726 | return ret; | 780 | return ret; |
727 | } | 781 | } |
728 | ret = device_create_file(&dock_device.dev, &dev_attr_undock); | 782 | ret = device_create_file(&dock_device->dev, &dev_attr_uid); |
729 | if (ret) { | 783 | if (ret) { |
730 | printk("Error %d adding sysfs file\n", ret); | 784 | printk("Error %d adding sysfs file\n", ret); |
731 | device_remove_file(&dock_device.dev, &dev_attr_docked); | 785 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
732 | platform_device_unregister(&dock_device); | 786 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
787 | platform_device_unregister(dock_device); | ||
733 | kfree(dock_station); | 788 | kfree(dock_station); |
789 | dock_station = NULL; | ||
734 | return ret; | 790 | return ret; |
735 | } | 791 | } |
736 | ret = device_create_file(&dock_device.dev, &dev_attr_uid); | 792 | ret = device_create_file(&dock_device->dev, &dev_attr_flags); |
737 | if (ret) { | 793 | if (ret) { |
738 | printk("Error %d adding sysfs file\n", ret); | 794 | printk("Error %d adding sysfs file\n", ret); |
739 | platform_device_unregister(&dock_device); | 795 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
796 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
797 | device_remove_file(&dock_device->dev, &dev_attr_uid); | ||
798 | platform_device_unregister(dock_device); | ||
740 | kfree(dock_station); | 799 | kfree(dock_station); |
800 | dock_station = NULL; | ||
741 | return ret; | 801 | return ret; |
742 | } | 802 | } |
743 | 803 | ||
@@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle) | |||
750 | dd = alloc_dock_dependent_device(handle); | 810 | dd = alloc_dock_dependent_device(handle); |
751 | if (!dd) { | 811 | if (!dd) { |
752 | kfree(dock_station); | 812 | kfree(dock_station); |
813 | dock_station = NULL; | ||
753 | ret = -ENOMEM; | 814 | ret = -ENOMEM; |
754 | goto dock_add_err_unregister; | 815 | goto dock_add_err_unregister; |
755 | } | 816 | } |
@@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle) | |||
773 | dock_add_err: | 834 | dock_add_err: |
774 | kfree(dd); | 835 | kfree(dd); |
775 | dock_add_err_unregister: | 836 | dock_add_err_unregister: |
776 | device_remove_file(&dock_device.dev, &dev_attr_docked); | 837 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
777 | device_remove_file(&dock_device.dev, &dev_attr_undock); | 838 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
778 | platform_device_unregister(&dock_device); | 839 | device_remove_file(&dock_device->dev, &dev_attr_uid); |
840 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
841 | platform_device_unregister(dock_device); | ||
779 | kfree(dock_station); | 842 | kfree(dock_station); |
843 | dock_station = NULL; | ||
780 | return ret; | 844 | return ret; |
781 | } | 845 | } |
782 | 846 | ||
@@ -804,12 +868,15 @@ static int dock_remove(void) | |||
804 | printk(KERN_ERR "Error removing notify handler\n"); | 868 | printk(KERN_ERR "Error removing notify handler\n"); |
805 | 869 | ||
806 | /* cleanup sysfs */ | 870 | /* cleanup sysfs */ |
807 | device_remove_file(&dock_device.dev, &dev_attr_docked); | 871 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
808 | device_remove_file(&dock_device.dev, &dev_attr_undock); | 872 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
809 | platform_device_unregister(&dock_device); | 873 | device_remove_file(&dock_device->dev, &dev_attr_uid); |
874 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
875 | platform_device_unregister(dock_device); | ||
810 | 876 | ||
811 | /* free dock station memory */ | 877 | /* free dock station memory */ |
812 | kfree(dock_station); | 878 | kfree(dock_station); |
879 | dock_station = NULL; | ||
813 | return 0; | 880 | return 0; |
814 | } | 881 | } |
815 | 882 | ||