aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/dock.c
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2008-08-27 22:03:58 -0400
committerLen Brown <len.brown@intel.com>2008-09-23 23:01:29 -0400
commitdb350b084dc2cf816288643861ce07b0562dd723 (patch)
tree756747843979f6e85dd93d0b305a044a2150242c /drivers/acpi/dock.c
parent406f692d0803d73acd3984c1e11719d3a913fd5e (diff)
dock: add bay and battery hotplug support
Make the dock driver support bay and battery hotplug. They are all regarded as dock, so handling can be unified. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r--drivers/acpi/dock.c223
1 files changed, 175 insertions, 48 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 7bdf93b74690..799a0fdbb62d 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
48 " before undocking"); 48 " before undocking");
49 49
50static struct atomic_notifier_head dock_notifier_list; 50static struct atomic_notifier_head dock_notifier_list;
51static struct platform_device *dock_device;
52static char dock_device_name[] = "dock"; 51static char dock_device_name[] = "dock";
53 52
54static const struct acpi_device_id dock_device_ids[] = { 53static const struct acpi_device_id dock_device_ids[] = {
@@ -65,7 +64,12 @@ struct dock_station {
65 struct mutex hp_lock; 64 struct mutex hp_lock;
66 struct list_head dependent_devices; 65 struct list_head dependent_devices;
67 struct list_head hotplug_devices; 66 struct list_head hotplug_devices;
67
68 struct list_head sibiling;
69 struct platform_device *dock_device;
68}; 70};
71static LIST_HEAD(dock_stations);
72static int dock_station_count;
69 73
70struct dock_dependent_device { 74struct dock_dependent_device {
71 struct list_head list; 75 struct list_head list;
@@ -77,11 +81,12 @@ struct dock_dependent_device {
77 81
78#define DOCK_DOCKING 0x00000001 82#define DOCK_DOCKING 0x00000001
79#define DOCK_UNDOCKING 0x00000002 83#define DOCK_UNDOCKING 0x00000002
84#define DOCK_IS_DOCK 0x00000010
85#define DOCK_IS_ATA 0x00000020
86#define DOCK_IS_BAT 0x00000040
80#define DOCK_EVENT 3 87#define DOCK_EVENT 3
81#define UNDOCK_EVENT 2 88#define UNDOCK_EVENT 2
82 89
83static struct dock_station *dock_station;
84
85/***************************************************************************** 90/*****************************************************************************
86 * Dock Dependent device functions * 91 * Dock Dependent device functions *
87 *****************************************************************************/ 92 *****************************************************************************/
@@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
199 return 1; 204 return 1;
200} 205}
201 206
207static int is_ejectable(acpi_handle handle)
208{
209 acpi_status status;
210 acpi_handle tmp;
211
212 status = acpi_get_handle(handle, "_EJ0", &tmp);
213 if (ACPI_FAILURE(status))
214 return 0;
215 return 1;
216}
217
218static int is_ata(acpi_handle handle)
219{
220 acpi_handle tmp;
221
222 if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
223 (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
224 (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
225 (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
226 return 1;
227
228 return 0;
229}
230
231static int is_battery(acpi_handle handle)
232{
233 struct acpi_device_info *info;
234 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
235 int ret = 1;
236
237 if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
238 return 0;
239 info = buffer.pointer;
240 if (!(info->valid & ACPI_VALID_HID))
241 ret = 0;
242 else
243 ret = !strcmp("PNP0C0A", info->hardware_id.value);
244
245 kfree(buffer.pointer);
246 return ret;
247}
248
249static int is_ejectable_bay(acpi_handle handle)
250{
251 acpi_handle phandle;
252 if (!is_ejectable(handle))
253 return 0;
254 if (is_battery(handle) || is_ata(handle))
255 return 1;
256 if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
257 return 1;
258 return 0;
259}
260
202/** 261/**
203 * is_dock_device - see if a device is on a dock station 262 * is_dock_device - see if a device is on a dock station
204 * @handle: acpi handle of the device 263 * @handle: acpi handle of the device
@@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
209 */ 268 */
210int is_dock_device(acpi_handle handle) 269int is_dock_device(acpi_handle handle)
211{ 270{
212 if (!dock_station) 271 struct dock_station *dock_station;
272
273 if (!dock_station_count)
213 return 0; 274 return 0;
214 275
215 if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) 276 if (is_dock(handle))
216 return 1; 277 return 1;
278 list_for_each_entry(dock_station, &dock_stations, sibiling) {
279 if (find_dock_dependent_device(dock_station, handle))
280 return 1;
281 }
217 282
218 return 0; 283 return 0;
219} 284}
@@ -341,7 +406,7 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
341 406
342static void dock_event(struct dock_station *ds, u32 event, int num) 407static void dock_event(struct dock_station *ds, u32 event, int num)
343{ 408{
344 struct device *dev = &dock_device->dev; 409 struct device *dev = &ds->dock_device->dev;
345 char event_string[13]; 410 char event_string[13];
346 char *envp[] = { event_string, NULL }; 411 char *envp[] = { event_string, NULL };
347 412
@@ -414,7 +479,7 @@ static void handle_dock(struct dock_station *ds, int dock)
414 arg.type = ACPI_TYPE_INTEGER; 479 arg.type = ACPI_TYPE_INTEGER;
415 arg.integer.value = dock; 480 arg.integer.value = dock;
416 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); 481 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
417 if (ACPI_FAILURE(status)) 482 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
418 printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", 483 printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
419 (char *)name_buffer.pointer); 484 (char *)name_buffer.pointer);
420 kfree(buffer.pointer); 485 kfree(buffer.pointer);
@@ -498,7 +563,7 @@ static int dock_in_progress(struct dock_station *ds)
498 */ 563 */
499int register_dock_notifier(struct notifier_block *nb) 564int register_dock_notifier(struct notifier_block *nb)
500{ 565{
501 if (!dock_station) 566 if (!dock_station_count)
502 return -ENODEV; 567 return -ENODEV;
503 568
504 return atomic_notifier_chain_register(&dock_notifier_list, nb); 569 return atomic_notifier_chain_register(&dock_notifier_list, nb);
@@ -512,7 +577,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier);
512 */ 577 */
513void unregister_dock_notifier(struct notifier_block *nb) 578void unregister_dock_notifier(struct notifier_block *nb)
514{ 579{
515 if (!dock_station) 580 if (!dock_station_count)
516 return; 581 return;
517 582
518 atomic_notifier_chain_unregister(&dock_notifier_list, nb); 583 atomic_notifier_chain_unregister(&dock_notifier_list, nb);
@@ -535,20 +600,23 @@ register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
535 void *context) 600 void *context)
536{ 601{
537 struct dock_dependent_device *dd; 602 struct dock_dependent_device *dd;
603 struct dock_station *dock_station;
538 604
539 if (!dock_station) 605 if (!dock_station_count)
540 return -ENODEV; 606 return -ENODEV;
541 607
542 /* 608 /*
543 * make sure this handle is for a device dependent on the dock, 609 * make sure this handle is for a device dependent on the dock,
544 * this would include the dock station itself 610 * this would include the dock station itself
545 */ 611 */
546 dd = find_dock_dependent_device(dock_station, handle); 612 list_for_each_entry(dock_station, &dock_stations, sibiling) {
547 if (dd) { 613 dd = find_dock_dependent_device(dock_station, handle);
548 dd->handler = handler; 614 if (dd) {
549 dd->context = context; 615 dd->handler = handler;
550 dock_add_hotplug_device(dock_station, dd); 616 dd->context = context;
551 return 0; 617 dock_add_hotplug_device(dock_station, dd);
618 return 0;
619 }
552 } 620 }
553 621
554 return -EINVAL; 622 return -EINVAL;
@@ -563,13 +631,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
563void unregister_hotplug_dock_device(acpi_handle handle) 631void unregister_hotplug_dock_device(acpi_handle handle)
564{ 632{
565 struct dock_dependent_device *dd; 633 struct dock_dependent_device *dd;
634 struct dock_station *dock_station;
566 635
567 if (!dock_station) 636 if (!dock_station_count)
568 return; 637 return;
569 638
570 dd = find_dock_dependent_device(dock_station, handle); 639 list_for_each_entry(dock_station, &dock_stations, sibiling) {
571 if (dd) 640 dd = find_dock_dependent_device(dock_station, handle);
572 dock_del_hotplug_device(dock_station, dd); 641 if (dd)
642 dock_del_hotplug_device(dock_station, dd);
643 }
573} 644}
574 645
575EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); 646EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
@@ -620,9 +691,28 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
620{ 691{
621 struct dock_station *ds = data; 692 struct dock_station *ds = data;
622 struct acpi_device *tmp; 693 struct acpi_device *tmp;
694 int surprise_removal = 0;
623 695
696 /*
697 * According to acpi spec 3.0a, if a DEVICE_CHECK notification
698 * is sent and _DCK is present, it is assumed to mean an undock
699 * request.
700 */
701 if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
702 event = ACPI_NOTIFY_EJECT_REQUEST;
703
704 /*
705 * dock station: BUS_CHECK - docked or surprise removal
706 * DEVICE_CHECK - undocked
707 * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
708 *
709 * To simplify event handling, dock dependent device handler always
710 * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
711 * ACPI_NOTIFY_EJECT_REQUEST for removal
712 */
624 switch (event) { 713 switch (event) {
625 case ACPI_NOTIFY_BUS_CHECK: 714 case ACPI_NOTIFY_BUS_CHECK:
715 case ACPI_NOTIFY_DEVICE_CHECK:
626 if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, 716 if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
627 &tmp)) { 717 &tmp)) {
628 begin_dock(ds); 718 begin_dock(ds);
@@ -638,20 +728,17 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
638 complete_dock(ds); 728 complete_dock(ds);
639 dock_event(ds, event, DOCK_EVENT); 729 dock_event(ds, event, DOCK_EVENT);
640 dock_lock(ds, 1); 730 dock_lock(ds, 1);
731 break;
641 } 732 }
642 break; 733 if (dock_present(ds) || dock_in_progress(ds))
643 case ACPI_NOTIFY_DEVICE_CHECK: 734 break;
644 /* 735 /* This is a surprise removal */
645 * According to acpi spec 3.0a, if a DEVICE_CHECK notification 736 surprise_removal = 1;
646 * is sent and _DCK is present, it is assumed to mean an 737 event = ACPI_NOTIFY_EJECT_REQUEST;
647 * undock request. This notify routine will only be called 738 /* Fall back */
648 * for objects defining _DCK, so we will fall through to eject
649 * request here. However, we will pass an eject request through
650 * to the driver who wish to hotplug.
651 */
652 case ACPI_NOTIFY_EJECT_REQUEST: 739 case ACPI_NOTIFY_EJECT_REQUEST:
653 begin_undock(ds); 740 begin_undock(ds);
654 if (immediate_undock) 741 if (immediate_undock || surprise_removal)
655 handle_eject_request(ds, event); 742 handle_eject_request(ds, event);
656 else 743 else
657 dock_event(ds, event, UNDOCK_EVENT); 744 dock_event(ds, event, UNDOCK_EVENT);
@@ -707,6 +794,8 @@ fdd_out:
707static ssize_t show_docked(struct device *dev, 794static ssize_t show_docked(struct device *dev,
708 struct device_attribute *attr, char *buf) 795 struct device_attribute *attr, char *buf)
709{ 796{
797 struct dock_station *dock_station = *((struct dock_station **)
798 dev->platform_data);
710 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); 799 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
711 800
712} 801}
@@ -718,6 +807,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
718static ssize_t show_flags(struct device *dev, 807static ssize_t show_flags(struct device *dev,
719 struct device_attribute *attr, char *buf) 808 struct device_attribute *attr, char *buf)
720{ 809{
810 struct dock_station *dock_station = *((struct dock_station **)
811 dev->platform_data);
721 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); 812 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
722 813
723} 814}
@@ -730,6 +821,8 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
730 const char *buf, size_t count) 821 const char *buf, size_t count)
731{ 822{
732 int ret; 823 int ret;
824 struct dock_station *dock_station = *((struct dock_station **)
825 dev->platform_data);
733 826
734 if (!count) 827 if (!count)
735 return -EINVAL; 828 return -EINVAL;
@@ -747,6 +840,8 @@ static ssize_t show_dock_uid(struct device *dev,
747 struct device_attribute *attr, char *buf) 840 struct device_attribute *attr, char *buf)
748{ 841{
749 unsigned long lbuf; 842 unsigned long lbuf;
843 struct dock_station *dock_station = *((struct dock_station **)
844 dev->platform_data);
750 acpi_status status = acpi_evaluate_integer(dock_station->handle, 845 acpi_status status = acpi_evaluate_integer(dock_station->handle,
751 "_UID", NULL, &lbuf); 846 "_UID", NULL, &lbuf);
752 if (ACPI_FAILURE(status)) 847 if (ACPI_FAILURE(status))
@@ -768,6 +863,8 @@ static int dock_add(acpi_handle handle)
768 int ret; 863 int ret;
769 acpi_status status; 864 acpi_status status;
770 struct dock_dependent_device *dd; 865 struct dock_dependent_device *dd;
866 struct dock_station *dock_station;
867 struct platform_device *dock_device;
771 868
772 /* allocate & initialize the dock_station private data */ 869 /* allocate & initialize the dock_station private data */
773 dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); 870 dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
@@ -777,22 +874,34 @@ static int dock_add(acpi_handle handle)
777 dock_station->last_dock_time = jiffies - HZ; 874 dock_station->last_dock_time = jiffies - HZ;
778 INIT_LIST_HEAD(&dock_station->dependent_devices); 875 INIT_LIST_HEAD(&dock_station->dependent_devices);
779 INIT_LIST_HEAD(&dock_station->hotplug_devices); 876 INIT_LIST_HEAD(&dock_station->hotplug_devices);
877 INIT_LIST_HEAD(&dock_station->sibiling);
780 spin_lock_init(&dock_station->dd_lock); 878 spin_lock_init(&dock_station->dd_lock);
781 mutex_init(&dock_station->hp_lock); 879 mutex_init(&dock_station->hp_lock);
782 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); 880 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
783 881
784 /* initialize platform device stuff */ 882 /* initialize platform device stuff */
785 dock_device = 883 dock_station->dock_device =
786 platform_device_register_simple(dock_device_name, 0, NULL, 0); 884 platform_device_register_simple(dock_device_name,
885 dock_station_count, NULL, 0);
886 dock_device = dock_station->dock_device;
787 if (IS_ERR(dock_device)) { 887 if (IS_ERR(dock_device)) {
788 kfree(dock_station); 888 kfree(dock_station);
789 dock_station = NULL; 889 dock_station = NULL;
790 return PTR_ERR(dock_device); 890 return PTR_ERR(dock_device);
791 } 891 }
892 platform_device_add_data(dock_device, &dock_station,
893 sizeof(struct dock_station *));
792 894
793 /* we want the dock device to send uevents */ 895 /* we want the dock device to send uevents */
794 dock_device->dev.uevent_suppress = 0; 896 dock_device->dev.uevent_suppress = 0;
795 897
898 if (is_dock(handle))
899 dock_station->flags |= DOCK_IS_DOCK;
900 if (is_ata(handle))
901 dock_station->flags |= DOCK_IS_ATA;
902 if (is_battery(handle))
903 dock_station->flags |= DOCK_IS_BAT;
904
796 ret = device_create_file(&dock_device->dev, &dev_attr_docked); 905 ret = device_create_file(&dock_device->dev, &dev_attr_docked);
797 if (ret) { 906 if (ret) {
798 printk("Error %d adding sysfs file\n", ret); 907 printk("Error %d adding sysfs file\n", ret);
@@ -858,8 +967,8 @@ static int dock_add(acpi_handle handle)
858 goto dock_add_err; 967 goto dock_add_err;
859 } 968 }
860 969
861 printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION); 970 dock_station_count++;
862 971 list_add(&dock_station->sibiling, &dock_stations);
863 return 0; 972 return 0;
864 973
865dock_add_err: 974dock_add_err:
@@ -878,12 +987,13 @@ dock_add_err_unregister:
878/** 987/**
879 * dock_remove - free up resources related to the dock station 988 * dock_remove - free up resources related to the dock station
880 */ 989 */
881static int dock_remove(void) 990static int dock_remove(struct dock_station *dock_station)
882{ 991{
883 struct dock_dependent_device *dd, *tmp; 992 struct dock_dependent_device *dd, *tmp;
884 acpi_status status; 993 acpi_status status;
994 struct platform_device *dock_device = dock_station->dock_device;
885 995
886 if (!dock_station) 996 if (!dock_station_count)
887 return 0; 997 return 0;
888 998
889 /* remove dependent devices */ 999 /* remove dependent devices */
@@ -923,41 +1033,58 @@ static int dock_remove(void)
923static acpi_status 1033static acpi_status
924find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) 1034find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
925{ 1035{
926 int *count = context;
927 acpi_status status = AE_OK; 1036 acpi_status status = AE_OK;
928 1037
929 if (is_dock(handle)) { 1038 if (is_dock(handle)) {
930 if (dock_add(handle) >= 0) { 1039 if (dock_add(handle) >= 0) {
931 (*count)++;
932 status = AE_CTRL_TERMINATE; 1040 status = AE_CTRL_TERMINATE;
933 } 1041 }
934 } 1042 }
935 return status; 1043 return status;
936} 1044}
937 1045
938static int __init dock_init(void) 1046static acpi_status
1047find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
939{ 1048{
940 int num = 0; 1049 /* If bay is in a dock, it's already handled */
941 1050 if (is_ejectable_bay(handle) && !is_dock_device(handle))
942 dock_station = NULL; 1051 dock_add(handle);
1052 return AE_OK;
1053}
943 1054
1055static int __init dock_init(void)
1056{
944 if (acpi_disabled) 1057 if (acpi_disabled)
945 return 0; 1058 return 0;
946 1059
947 /* look for a dock station */ 1060 /* look for a dock station */
948 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 1061 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
949 ACPI_UINT32_MAX, find_dock, &num, NULL); 1062 ACPI_UINT32_MAX, find_dock, NULL, NULL);
950 1063
951 if (!num) 1064 /* look for bay */
952 printk(KERN_INFO "No dock devices found.\n"); 1065 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1066 ACPI_UINT32_MAX, find_bay, NULL, NULL);
1067 if (!dock_station_count) {
1068 printk(KERN_INFO PREFIX "No dock devices found.\n");
1069 return 0;
1070 }
953 1071
1072 printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
1073 ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
954 return 0; 1074 return 0;
955} 1075}
956 1076
957static void __exit dock_exit(void) 1077static void __exit dock_exit(void)
958{ 1078{
959 dock_remove(); 1079 struct dock_station *dock_station;
1080
1081 list_for_each_entry(dock_station, &dock_stations, sibiling)
1082 dock_remove(dock_station);
960} 1083}
961 1084
962postcore_initcall(dock_init); 1085/*
1086 * Must be called before drivers of devices in dock, otherwise we can't know
1087 * which devices are in a dock
1088 */
1089subsys_initcall(dock_init);
963module_exit(dock_exit); 1090module_exit(dock_exit);