summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/dock.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-15 19:51:01 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-15 19:51:01 -0500
commit1e2380cd144f6a9619f72f80ad9a93268f63b8dc (patch)
tree03f661af52c942b0d1c7523c1bd05af59b610671 /drivers/acpi/dock.c
parentd6a40224a30687f6e0471c4476e3a1a9adc28a96 (diff)
ACPI / dock: Dispatch dock notifications from the global notify handler
The ACPI dock station code carries out an extra namespace scan before the main one in order to find and register all of the dock device objects. Then, it registers a notify handler for each of them for handling dock events. However, dock device objects need not be scanned for upfront. They very well can be enumerated and registered during the first phase of the main namespace scan, before attaching scan handlers and ACPI drivers to ACPI device objects. Then, the dependent devices can be added to the in the second phase. That makes it possible to drop the extra namespace scan, so do it. Moreover, it is not necessary to register notify handlers for all of the dock stations' namespace nodes, becuase notifications may be dispatched from the global notify handler for them. Do that and drop two functions used for dock notify handling, acpi_dock_deferred_cb() and dock_notify_handler(), that aren't necessary any more. Finally, some dock station objects have _HID objects matching the ACPI container scan handler which causes it to claim those objects and try to handle their hotplug, but that is not a good idea, because those objects have their own special hotplug handling anyway. For this reason, the hotplug_notify flag should not be set for ACPI device objects representing dock stations and the container scan handler should be made ignore those objects, so make that happen. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r--drivers/acpi/dock.c171
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 */
106static int __init 106static int add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
107add_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
220static 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/***************************************************************************** 251void register_dock_dependent_device(struct acpi_device *adev,
242 * Dock functions * 252 acpi_handle dshandle)
243 *****************************************************************************/
244static 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/*****************************************************************************
261static 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 */
609static void dock_notify(struct dock_station *ds, u32 event) 605int 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
670static 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
677static 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 */
697static 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 */
812static int __init dock_add(acpi_handle handle) 768void 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
868err_rmgroup: 815err_rmgroup:
869 remove_dock_dependent_devices(dock_station); 816 remove_dock_dependent_devices(dock_station);
@@ -871,38 +818,4 @@ err_rmgroup:
871err_unregister: 818err_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 */
886static acpi_status __init
887find_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
895void __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}