diff options
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r-- | drivers/acpi/dock.c | 171 |
1 files changed, 42 insertions, 129 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 5bfd769fc91f..44c6e6c0d545 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -103,8 +103,7 @@ enum dock_callback_type { | |||
103 | * | 103 | * |
104 | * Add the dependent device to the dock's dependent device list. | 104 | * Add the dependent device to the dock's dependent device list. |
105 | */ | 105 | */ |
106 | static int __init | 106 | static int add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) |
107 | add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) | ||
108 | { | 107 | { |
109 | struct dock_dependent_device *dd; | 108 | struct dock_dependent_device *dd; |
110 | 109 | ||
@@ -218,6 +217,17 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, | |||
218 | dock_release_hotplug(dd); | 217 | dock_release_hotplug(dd); |
219 | } | 218 | } |
220 | 219 | ||
220 | static struct dock_station *find_dock_station(acpi_handle handle) | ||
221 | { | ||
222 | struct dock_station *ds; | ||
223 | |||
224 | list_for_each_entry(ds, &dock_stations, sibling) | ||
225 | if (ds->handle == handle) | ||
226 | return ds; | ||
227 | |||
228 | return NULL; | ||
229 | } | ||
230 | |||
221 | /** | 231 | /** |
222 | * find_dock_dependent_device - get a device dependent on this dock | 232 | * find_dock_dependent_device - get a device dependent on this dock |
223 | * @ds: the dock station | 233 | * @ds: the dock station |
@@ -238,33 +248,19 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) | |||
238 | return NULL; | 248 | return NULL; |
239 | } | 249 | } |
240 | 250 | ||
241 | /***************************************************************************** | 251 | void register_dock_dependent_device(struct acpi_device *adev, |
242 | * Dock functions * | 252 | acpi_handle dshandle) |
243 | *****************************************************************************/ | ||
244 | static int __init is_battery(acpi_handle handle) | ||
245 | { | 253 | { |
246 | struct acpi_device_info *info; | 254 | struct dock_station *ds = find_dock_station(dshandle); |
247 | int ret = 1; | 255 | acpi_handle handle = adev->handle; |
248 | 256 | ||
249 | if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) | 257 | if (ds && !find_dock_dependent_device(ds, handle)) |
250 | return 0; | 258 | add_dock_dependent_device(ds, handle); |
251 | if (!(info->valid & ACPI_VALID_HID)) | ||
252 | ret = 0; | ||
253 | else | ||
254 | ret = !strcmp("PNP0C0A", info->hardware_id.string); | ||
255 | |||
256 | kfree(info); | ||
257 | return ret; | ||
258 | } | 259 | } |
259 | 260 | ||
260 | /* Check whether ACPI object is an ejectable battery or disk bay */ | 261 | /***************************************************************************** |
261 | static bool __init is_ejectable_bay(acpi_handle handle) | 262 | * Dock functions * |
262 | { | 263 | *****************************************************************************/ |
263 | if (acpi_has_method(handle, "_EJ0") && is_battery(handle)) | ||
264 | return true; | ||
265 | |||
266 | return acpi_bay_match(handle); | ||
267 | } | ||
268 | 264 | ||
269 | /** | 265 | /** |
270 | * is_dock_device - see if a device is on a dock station | 266 | * is_dock_device - see if a device is on a dock station |
@@ -598,20 +594,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event) | |||
598 | } | 594 | } |
599 | 595 | ||
600 | /** | 596 | /** |
601 | * dock_notify - act upon an acpi dock notification | 597 | * dock_notify - Handle ACPI dock notification. |
602 | * @ds: dock station | 598 | * @adev: Dock station's ACPI device object. |
603 | * @event: the acpi event | 599 | * @event: Event code. |
604 | * | 600 | * |
605 | * If we are notified to dock, then check to see if the dock is | 601 | * If we are notified to dock, then check to see if the dock is |
606 | * present and then dock. Notify all drivers of the dock event, | 602 | * present and then dock. Notify all drivers of the dock event, |
607 | * and then hotplug and devices that may need hotplugging. | 603 | * and then hotplug and devices that may need hotplugging. |
608 | */ | 604 | */ |
609 | static void dock_notify(struct dock_station *ds, u32 event) | 605 | int dock_notify(struct acpi_device *adev, u32 event) |
610 | { | 606 | { |
611 | acpi_handle handle = ds->handle; | 607 | acpi_handle handle = adev->handle; |
612 | struct acpi_device *adev = NULL; | 608 | struct dock_station *ds = find_dock_station(handle); |
613 | int surprise_removal = 0; | 609 | int surprise_removal = 0; |
614 | 610 | ||
611 | if (!ds) | ||
612 | return -ENODEV; | ||
613 | |||
615 | /* | 614 | /* |
616 | * According to acpi spec 3.0a, if a DEVICE_CHECK notification | 615 | * According to acpi spec 3.0a, if a DEVICE_CHECK notification |
617 | * is sent and _DCK is present, it is assumed to mean an undock | 616 | * is sent and _DCK is present, it is assumed to mean an undock |
@@ -632,7 +631,6 @@ static void dock_notify(struct dock_station *ds, u32 event) | |||
632 | switch (event) { | 631 | switch (event) { |
633 | case ACPI_NOTIFY_BUS_CHECK: | 632 | case ACPI_NOTIFY_BUS_CHECK: |
634 | case ACPI_NOTIFY_DEVICE_CHECK: | 633 | case ACPI_NOTIFY_DEVICE_CHECK: |
635 | acpi_bus_get_device(handle, &adev); | ||
636 | if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { | 634 | if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { |
637 | begin_dock(ds); | 635 | begin_dock(ds); |
638 | dock(ds); | 636 | dock(ds); |
@@ -662,49 +660,8 @@ static void dock_notify(struct dock_station *ds, u32 event) | |||
662 | else | 660 | else |
663 | dock_event(ds, event, UNDOCK_EVENT); | 661 | dock_event(ds, event, UNDOCK_EVENT); |
664 | break; | 662 | break; |
665 | default: | ||
666 | acpi_handle_err(handle, "Unknown dock event %d\n", event); | ||
667 | } | 663 | } |
668 | } | 664 | return 0; |
669 | |||
670 | static void acpi_dock_deferred_cb(void *data, u32 event) | ||
671 | { | ||
672 | acpi_scan_lock_acquire(); | ||
673 | dock_notify(data, event); | ||
674 | acpi_scan_lock_release(); | ||
675 | } | ||
676 | |||
677 | static void dock_notify_handler(acpi_handle handle, u32 event, void *data) | ||
678 | { | ||
679 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK | ||
680 | && event != ACPI_NOTIFY_EJECT_REQUEST) | ||
681 | return; | ||
682 | |||
683 | acpi_hotplug_execute(acpi_dock_deferred_cb, data, event); | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * find_dock_devices - find devices on the dock station | ||
688 | * @handle: the handle of the device we are examining | ||
689 | * @lvl: unused | ||
690 | * @context: the dock station private data | ||
691 | * @rv: unused | ||
692 | * | ||
693 | * This function is called by acpi_walk_namespace. It will | ||
694 | * check to see if an object has an _EJD method. If it does, then it | ||
695 | * will see if it is dependent on the dock station. | ||
696 | */ | ||
697 | static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, | ||
698 | void *context, void **rv) | ||
699 | { | ||
700 | struct dock_station *ds = context; | ||
701 | acpi_handle ejd = NULL; | ||
702 | |||
703 | acpi_bus_get_ejd(handle, &ejd); | ||
704 | if (ejd == ds->handle) | ||
705 | add_dock_dependent_device(ds, handle); | ||
706 | |||
707 | return AE_OK; | ||
708 | } | 665 | } |
709 | 666 | ||
710 | /* | 667 | /* |
@@ -803,23 +760,22 @@ static struct attribute_group dock_attribute_group = { | |||
803 | }; | 760 | }; |
804 | 761 | ||
805 | /** | 762 | /** |
806 | * dock_add - add a new dock station | 763 | * acpi_dock_add - Add a new dock station |
807 | * @handle: the dock station handle | 764 | * @adev: Dock station ACPI device object. |
808 | * | 765 | * |
809 | * allocated and initialize a new dock station device. Find all devices | 766 | * allocated and initialize a new dock station device. |
810 | * that are on the dock station, and register for dock event notifications. | ||
811 | */ | 767 | */ |
812 | static int __init dock_add(acpi_handle handle) | 768 | void acpi_dock_add(struct acpi_device *adev) |
813 | { | 769 | { |
814 | struct dock_station *dock_station, ds = { NULL, }; | 770 | struct dock_station *dock_station, ds = { NULL, }; |
771 | acpi_handle handle = adev->handle; | ||
815 | struct platform_device *dd; | 772 | struct platform_device *dd; |
816 | acpi_status status; | ||
817 | int ret; | 773 | int ret; |
818 | 774 | ||
819 | dd = platform_device_register_data(NULL, "dock", dock_station_count, | 775 | dd = platform_device_register_data(NULL, "dock", dock_station_count, |
820 | &ds, sizeof(ds)); | 776 | &ds, sizeof(ds)); |
821 | if (IS_ERR(dd)) | 777 | if (IS_ERR(dd)) |
822 | return PTR_ERR(dd); | 778 | return; |
823 | 779 | ||
824 | dock_station = dd->dev.platform_data; | 780 | dock_station = dd->dev.platform_data; |
825 | 781 | ||
@@ -837,33 +793,24 @@ static int __init dock_add(acpi_handle handle) | |||
837 | dock_station->flags |= DOCK_IS_DOCK; | 793 | dock_station->flags |= DOCK_IS_DOCK; |
838 | if (acpi_ata_match(handle)) | 794 | if (acpi_ata_match(handle)) |
839 | dock_station->flags |= DOCK_IS_ATA; | 795 | dock_station->flags |= DOCK_IS_ATA; |
840 | if (is_battery(handle)) | 796 | if (acpi_device_is_battery(handle)) |
841 | dock_station->flags |= DOCK_IS_BAT; | 797 | dock_station->flags |= DOCK_IS_BAT; |
842 | 798 | ||
843 | ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); | 799 | ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); |
844 | if (ret) | 800 | if (ret) |
845 | goto err_unregister; | 801 | goto err_unregister; |
846 | 802 | ||
847 | /* Find dependent devices */ | ||
848 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
849 | ACPI_UINT32_MAX, find_dock_devices, NULL, | ||
850 | dock_station, NULL); | ||
851 | |||
852 | /* add the dock station as a device dependent on itself */ | 803 | /* add the dock station as a device dependent on itself */ |
853 | ret = add_dock_dependent_device(dock_station, handle); | 804 | ret = add_dock_dependent_device(dock_station, handle); |
854 | if (ret) | 805 | if (ret) |
855 | goto err_rmgroup; | 806 | goto err_rmgroup; |
856 | 807 | ||
857 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
858 | dock_notify_handler, dock_station); | ||
859 | if (ACPI_FAILURE(status)) { | ||
860 | ret = -ENODEV; | ||
861 | goto err_rmgroup; | ||
862 | } | ||
863 | |||
864 | dock_station_count++; | 808 | dock_station_count++; |
865 | list_add(&dock_station->sibling, &dock_stations); | 809 | list_add(&dock_station->sibling, &dock_stations); |
866 | return 0; | 810 | adev->flags.is_dock_station = true; |
811 | dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n", | ||
812 | dock_station_count); | ||
813 | return; | ||
867 | 814 | ||
868 | err_rmgroup: | 815 | err_rmgroup: |
869 | remove_dock_dependent_devices(dock_station); | 816 | remove_dock_dependent_devices(dock_station); |
@@ -871,38 +818,4 @@ err_rmgroup: | |||
871 | err_unregister: | 818 | err_unregister: |
872 | platform_device_unregister(dd); | 819 | platform_device_unregister(dd); |
873 | acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); | 820 | acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); |
874 | return ret; | ||
875 | } | ||
876 | |||
877 | /** | ||
878 | * find_dock_and_bay - look for dock stations and bays | ||
879 | * @handle: acpi handle of a device | ||
880 | * @lvl: unused | ||
881 | * @context: unused | ||
882 | * @rv: unused | ||
883 | * | ||
884 | * This is called by acpi_walk_namespace to look for dock stations and bays. | ||
885 | */ | ||
886 | static acpi_status __init | ||
887 | find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
888 | { | ||
889 | if (acpi_dock_match(handle) || is_ejectable_bay(handle)) | ||
890 | dock_add(handle); | ||
891 | |||
892 | return AE_OK; | ||
893 | } | ||
894 | |||
895 | void __init acpi_dock_init(void) | ||
896 | { | ||
897 | /* look for dock stations and bays */ | ||
898 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
899 | ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); | ||
900 | |||
901 | if (!dock_station_count) { | ||
902 | pr_info(PREFIX "No dock devices found.\n"); | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | pr_info(PREFIX "%s: %d docks/bays found\n", | ||
907 | ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); | ||
908 | } | 821 | } |