diff options
author | Shaohua Li <shaohua.li@intel.com> | 2008-08-27 22:03:58 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-09-23 23:01:29 -0400 |
commit | db350b084dc2cf816288643861ce07b0562dd723 (patch) | |
tree | 756747843979f6e85dd93d0b305a044a2150242c /drivers/acpi/dock.c | |
parent | 406f692d0803d73acd3984c1e11719d3a913fd5e (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.c | 223 |
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 | ||
50 | static struct atomic_notifier_head dock_notifier_list; | 50 | static struct atomic_notifier_head dock_notifier_list; |
51 | static struct platform_device *dock_device; | ||
52 | static char dock_device_name[] = "dock"; | 51 | static char dock_device_name[] = "dock"; |
53 | 52 | ||
54 | static const struct acpi_device_id dock_device_ids[] = { | 53 | static 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 | }; |
71 | static LIST_HEAD(dock_stations); | ||
72 | static int dock_station_count; | ||
69 | 73 | ||
70 | struct dock_dependent_device { | 74 | struct 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 | ||
83 | static 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 | ||
207 | static 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 | |||
218 | static 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 | |||
231 | static 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 | |||
249 | static 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 | */ |
210 | int is_dock_device(acpi_handle handle) | 269 | int 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 | ||
342 | static void dock_event(struct dock_station *ds, u32 event, int num) | 407 | static 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 | */ |
499 | int register_dock_notifier(struct notifier_block *nb) | 564 | int 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 | */ |
513 | void unregister_dock_notifier(struct notifier_block *nb) | 578 | void 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); | |||
563 | void unregister_hotplug_dock_device(acpi_handle handle) | 631 | void 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 | ||
575 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | 646 | EXPORT_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: | |||
707 | static ssize_t show_docked(struct device *dev, | 794 | static 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); | |||
718 | static ssize_t show_flags(struct device *dev, | 807 | static 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 | ||
865 | dock_add_err: | 974 | dock_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 | */ |
881 | static int dock_remove(void) | 990 | static 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) | |||
923 | static acpi_status | 1033 | static acpi_status |
924 | find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) | 1034 | find_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 | ||
938 | static int __init dock_init(void) | 1046 | static acpi_status |
1047 | find_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 | ||
1055 | static 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 | ||
957 | static void __exit dock_exit(void) | 1077 | static 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 | ||
962 | postcore_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 | */ | ||
1089 | subsys_initcall(dock_init); | ||
963 | module_exit(dock_exit); | 1090 | module_exit(dock_exit); |