diff options
author | Len Brown <len.brown@intel.com> | 2008-10-22 23:25:26 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-10-22 23:25:26 -0400 |
commit | 47bf31adc541bef0c20de15e800e0011f1ae70c7 (patch) | |
tree | 28903879a8570eaefa57942ec3d475d365f5a465 /drivers | |
parent | 4538fad56ee1c16bce0294b5647d2551f0e03164 (diff) | |
parent | 0a918a9432cc30aede10f904253b66ea6ab485ac (diff) |
Merge branch 'dock' into test
Conflicts:
drivers/acpi/osl.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/Kconfig | 11 | ||||
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/bay.c | 411 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 15 | ||||
-rw-r--r-- | drivers/acpi/dock.c | 382 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 46 | ||||
-rw-r--r-- | drivers/ata/libata-acpi.c | 135 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 6 |
8 files changed, 407 insertions, 600 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 735f5ea17473..3919d6dbe06f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -160,15 +160,8 @@ config ACPI_DOCK | |||
160 | tristate "Dock" | 160 | tristate "Dock" |
161 | depends on EXPERIMENTAL | 161 | depends on EXPERIMENTAL |
162 | help | 162 | help |
163 | This driver adds support for ACPI controlled docking stations | 163 | This driver adds support for ACPI controlled docking stations and removable |
164 | 164 | drive bays such as the IBM ultrabay or the Dell Module Bay. | |
165 | config ACPI_BAY | ||
166 | tristate "Removable Drive Bay (EXPERIMENTAL)" | ||
167 | depends on EXPERIMENTAL | ||
168 | depends on ACPI_DOCK | ||
169 | help | ||
170 | This driver adds support for ACPI controlled removable drive | ||
171 | bays such as the IBM ultrabay or the Dell Module Bay. | ||
172 | 165 | ||
173 | config ACPI_PROCESSOR | 166 | config ACPI_PROCESSOR |
174 | tristate "Processor" | 167 | tristate "Processor" |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 52a4cd4b81d0..ad4bfd558ff3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o | |||
45 | obj-$(CONFIG_ACPI_BUTTON) += button.o | 45 | obj-$(CONFIG_ACPI_BUTTON) += button.o |
46 | obj-$(CONFIG_ACPI_FAN) += fan.o | 46 | obj-$(CONFIG_ACPI_FAN) += fan.o |
47 | obj-$(CONFIG_ACPI_DOCK) += dock.o | 47 | obj-$(CONFIG_ACPI_DOCK) += dock.o |
48 | obj-$(CONFIG_ACPI_BAY) += bay.o | ||
49 | obj-$(CONFIG_ACPI_VIDEO) += video.o | 48 | obj-$(CONFIG_ACPI_VIDEO) += video.o |
50 | obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o | 49 | obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o |
51 | obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o | 50 | obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o |
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c deleted file mode 100644 index 61b6c5beb2d3..000000000000 --- a/drivers/acpi/bay.c +++ /dev/null | |||
@@ -1,411 +0,0 @@ | |||
1 | /* | ||
2 | * bay.c - ACPI removable drive bay driver | ||
3 | * | ||
4 | * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com> | ||
5 | * | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | */ | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/notifier.h> | ||
29 | #include <acpi/acpi_bus.h> | ||
30 | #include <acpi/acpi_drivers.h> | ||
31 | #include <linux/seq_file.h> | ||
32 | #include <asm/uaccess.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | |||
35 | ACPI_MODULE_NAME("bay"); | ||
36 | MODULE_AUTHOR("Kristen Carlson Accardi"); | ||
37 | MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | #define ACPI_BAY_CLASS "bay" | ||
40 | #define ACPI_BAY_COMPONENT 0x10000000 | ||
41 | #define _COMPONENT ACPI_BAY_COMPONENT | ||
42 | #define bay_dprintk(h,s) {\ | ||
43 | char prefix[80] = {'\0'};\ | ||
44 | struct acpi_buffer buffer = {sizeof(prefix), prefix};\ | ||
45 | acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ | ||
46 | printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } | ||
47 | static void bay_notify(acpi_handle handle, u32 event, void *data); | ||
48 | |||
49 | static const struct acpi_device_id bay_device_ids[] = { | ||
50 | {"LNXIOBAY", 0}, | ||
51 | {"", 0}, | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(acpi, bay_device_ids); | ||
54 | |||
55 | struct bay { | ||
56 | acpi_handle handle; | ||
57 | char *name; | ||
58 | struct list_head list; | ||
59 | struct platform_device *pdev; | ||
60 | }; | ||
61 | |||
62 | static LIST_HEAD(drive_bays); | ||
63 | |||
64 | |||
65 | /***************************************************************************** | ||
66 | * Drive Bay functions * | ||
67 | *****************************************************************************/ | ||
68 | /** | ||
69 | * is_ejectable - see if a device is ejectable | ||
70 | * @handle: acpi handle of the device | ||
71 | * | ||
72 | * If an acpi object has a _EJ0 method, then it is ejectable | ||
73 | */ | ||
74 | static int is_ejectable(acpi_handle handle) | ||
75 | { | ||
76 | acpi_status status; | ||
77 | acpi_handle tmp; | ||
78 | |||
79 | status = acpi_get_handle(handle, "_EJ0", &tmp); | ||
80 | if (ACPI_FAILURE(status)) | ||
81 | return 0; | ||
82 | return 1; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * bay_present - see if the bay device is present | ||
87 | * @bay: the drive bay | ||
88 | * | ||
89 | * execute the _STA method. | ||
90 | */ | ||
91 | static int bay_present(struct bay *bay) | ||
92 | { | ||
93 | unsigned long sta; | ||
94 | acpi_status status; | ||
95 | |||
96 | if (bay) { | ||
97 | status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta); | ||
98 | if (ACPI_SUCCESS(status) && sta) | ||
99 | return 1; | ||
100 | } | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * eject_device - respond to an eject request | ||
106 | * @handle - the device to eject | ||
107 | * | ||
108 | * Call this devices _EJ0 method. | ||
109 | */ | ||
110 | static void eject_device(acpi_handle handle) | ||
111 | { | ||
112 | struct acpi_object_list arg_list; | ||
113 | union acpi_object arg; | ||
114 | |||
115 | bay_dprintk(handle, "Ejecting device"); | ||
116 | |||
117 | arg_list.count = 1; | ||
118 | arg_list.pointer = &arg; | ||
119 | arg.type = ACPI_TYPE_INTEGER; | ||
120 | arg.integer.value = 1; | ||
121 | |||
122 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", | ||
123 | &arg_list, NULL))) | ||
124 | pr_debug("Failed to evaluate _EJ0!\n"); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * show_present - read method for "present" file in sysfs | ||
129 | */ | ||
130 | static ssize_t show_present(struct device *dev, | ||
131 | struct device_attribute *attr, char *buf) | ||
132 | { | ||
133 | struct bay *bay = dev_get_drvdata(dev); | ||
134 | return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); | ||
135 | |||
136 | } | ||
137 | static DEVICE_ATTR(present, S_IRUGO, show_present, NULL); | ||
138 | |||
139 | /* | ||
140 | * write_eject - write method for "eject" file in sysfs | ||
141 | */ | ||
142 | static ssize_t write_eject(struct device *dev, struct device_attribute *attr, | ||
143 | const char *buf, size_t count) | ||
144 | { | ||
145 | struct bay *bay = dev_get_drvdata(dev); | ||
146 | |||
147 | if (!count) | ||
148 | return -EINVAL; | ||
149 | |||
150 | eject_device(bay->handle); | ||
151 | return count; | ||
152 | } | ||
153 | static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); | ||
154 | |||
155 | /** | ||
156 | * is_ata - see if a device is an ata device | ||
157 | * @handle: acpi handle of the device | ||
158 | * | ||
159 | * If an acpi object has one of 4 ATA ACPI methods defined, | ||
160 | * then it is an ATA device | ||
161 | */ | ||
162 | static int is_ata(acpi_handle handle) | ||
163 | { | ||
164 | acpi_handle tmp; | ||
165 | |||
166 | if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || | ||
167 | (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || | ||
168 | (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || | ||
169 | (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) | ||
170 | return 1; | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * parent_is_ata(acpi_handle handle) | ||
177 | * | ||
178 | */ | ||
179 | static int parent_is_ata(acpi_handle handle) | ||
180 | { | ||
181 | acpi_handle phandle; | ||
182 | |||
183 | if (acpi_get_parent(handle, &phandle)) | ||
184 | return 0; | ||
185 | |||
186 | return is_ata(phandle); | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * is_ejectable_bay - see if a device is an ejectable drive bay | ||
191 | * @handle: acpi handle of the device | ||
192 | * | ||
193 | * If an acpi object is ejectable and has one of the ACPI ATA | ||
194 | * methods defined, then we can safely call it an ejectable | ||
195 | * drive bay | ||
196 | */ | ||
197 | static int is_ejectable_bay(acpi_handle handle) | ||
198 | { | ||
199 | if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle)) | ||
200 | return 1; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | #if 0 | ||
205 | /** | ||
206 | * eject_removable_drive - try to eject this drive | ||
207 | * @dev : the device structure of the drive | ||
208 | * | ||
209 | * If a device is a removable drive that requires an _EJ0 method | ||
210 | * to be executed in order to safely remove from the system, do | ||
211 | * it. ATM - always returns success | ||
212 | */ | ||
213 | int eject_removable_drive(struct device *dev) | ||
214 | { | ||
215 | acpi_handle handle = DEVICE_ACPI_HANDLE(dev); | ||
216 | |||
217 | if (handle) { | ||
218 | bay_dprintk(handle, "Got device handle"); | ||
219 | if (is_ejectable_bay(handle)) | ||
220 | eject_device(handle); | ||
221 | } else { | ||
222 | printk("No acpi handle for device\n"); | ||
223 | } | ||
224 | |||
225 | /* should I return an error code? */ | ||
226 | return 0; | ||
227 | } | ||
228 | EXPORT_SYMBOL_GPL(eject_removable_drive); | ||
229 | #endif /* 0 */ | ||
230 | |||
231 | static int acpi_bay_add_fs(struct bay *bay) | ||
232 | { | ||
233 | int ret; | ||
234 | struct device *dev = &bay->pdev->dev; | ||
235 | |||
236 | ret = device_create_file(dev, &dev_attr_present); | ||
237 | if (ret) | ||
238 | goto add_fs_err; | ||
239 | ret = device_create_file(dev, &dev_attr_eject); | ||
240 | if (ret) { | ||
241 | device_remove_file(dev, &dev_attr_present); | ||
242 | goto add_fs_err; | ||
243 | } | ||
244 | return 0; | ||
245 | |||
246 | add_fs_err: | ||
247 | bay_dprintk(bay->handle, "Error adding sysfs files\n"); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | static void acpi_bay_remove_fs(struct bay *bay) | ||
252 | { | ||
253 | struct device *dev = &bay->pdev->dev; | ||
254 | |||
255 | /* cleanup sysfs */ | ||
256 | device_remove_file(dev, &dev_attr_present); | ||
257 | device_remove_file(dev, &dev_attr_eject); | ||
258 | } | ||
259 | |||
260 | static int bay_is_dock_device(acpi_handle handle) | ||
261 | { | ||
262 | acpi_handle parent; | ||
263 | |||
264 | acpi_get_parent(handle, &parent); | ||
265 | |||
266 | /* if the device or it's parent is dependent on the | ||
267 | * dock, then we are a dock device | ||
268 | */ | ||
269 | return (is_dock_device(handle) || is_dock_device(parent)); | ||
270 | } | ||
271 | |||
272 | static int bay_add(acpi_handle handle, int id) | ||
273 | { | ||
274 | acpi_status status; | ||
275 | struct bay *new_bay; | ||
276 | struct platform_device *pdev; | ||
277 | struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
278 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer); | ||
279 | |||
280 | bay_dprintk(handle, "Adding notify handler"); | ||
281 | |||
282 | /* | ||
283 | * Initialize bay device structure | ||
284 | */ | ||
285 | new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC); | ||
286 | INIT_LIST_HEAD(&new_bay->list); | ||
287 | new_bay->handle = handle; | ||
288 | new_bay->name = (char *)nbuffer.pointer; | ||
289 | |||
290 | /* initialize platform device stuff */ | ||
291 | pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); | ||
292 | if (IS_ERR(pdev)) { | ||
293 | printk(KERN_ERR PREFIX "Error registering bay device\n"); | ||
294 | goto bay_add_err; | ||
295 | } | ||
296 | new_bay->pdev = pdev; | ||
297 | platform_set_drvdata(pdev, new_bay); | ||
298 | |||
299 | /* | ||
300 | * we want the bay driver to be able to send uevents | ||
301 | */ | ||
302 | pdev->dev.uevent_suppress = 0; | ||
303 | |||
304 | /* register for events on this device */ | ||
305 | status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
306 | bay_notify, new_bay); | ||
307 | if (ACPI_FAILURE(status)) { | ||
308 | printk(KERN_INFO PREFIX "Error installing bay notify handler\n"); | ||
309 | platform_device_unregister(new_bay->pdev); | ||
310 | goto bay_add_err; | ||
311 | } | ||
312 | |||
313 | if (acpi_bay_add_fs(new_bay)) { | ||
314 | acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
315 | bay_notify); | ||
316 | platform_device_unregister(new_bay->pdev); | ||
317 | goto bay_add_err; | ||
318 | } | ||
319 | |||
320 | /* if we are on a dock station, we should register for dock | ||
321 | * notifications. | ||
322 | */ | ||
323 | if (bay_is_dock_device(handle)) { | ||
324 | bay_dprintk(handle, "Is dependent on dock\n"); | ||
325 | register_hotplug_dock_device(handle, bay_notify, new_bay); | ||
326 | } | ||
327 | list_add(&new_bay->list, &drive_bays); | ||
328 | printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name); | ||
329 | return 0; | ||
330 | |||
331 | bay_add_err: | ||
332 | kfree(new_bay->name); | ||
333 | kfree(new_bay); | ||
334 | return -ENODEV; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * bay_notify - act upon an acpi bay notification | ||
339 | * @handle: the bay handle | ||
340 | * @event: the acpi event | ||
341 | * @data: our driver data struct | ||
342 | * | ||
343 | */ | ||
344 | static void bay_notify(acpi_handle handle, u32 event, void *data) | ||
345 | { | ||
346 | struct bay *bay_dev = (struct bay *)data; | ||
347 | struct device *dev = &bay_dev->pdev->dev; | ||
348 | char event_string[12]; | ||
349 | char *envp[] = { event_string, NULL }; | ||
350 | |||
351 | bay_dprintk(handle, "Bay event"); | ||
352 | sprintf(event_string, "BAY_EVENT=%d", event); | ||
353 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | ||
354 | } | ||
355 | |||
356 | static acpi_status | ||
357 | find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
358 | { | ||
359 | int *count = (int *)context; | ||
360 | |||
361 | /* | ||
362 | * there could be more than one ejectable bay. | ||
363 | * so, just return AE_OK always so that every object | ||
364 | * will be checked. | ||
365 | */ | ||
366 | if (is_ejectable_bay(handle)) { | ||
367 | bay_dprintk(handle, "found ejectable bay"); | ||
368 | if (!bay_add(handle, *count)) | ||
369 | (*count)++; | ||
370 | } | ||
371 | return AE_OK; | ||
372 | } | ||
373 | |||
374 | static int __init bay_init(void) | ||
375 | { | ||
376 | int bays = 0; | ||
377 | |||
378 | INIT_LIST_HEAD(&drive_bays); | ||
379 | |||
380 | if (acpi_disabled) | ||
381 | return -ENODEV; | ||
382 | |||
383 | /* look for dockable drive bays */ | ||
384 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
385 | ACPI_UINT32_MAX, find_bay, &bays, NULL); | ||
386 | |||
387 | if (!bays) | ||
388 | return -ENODEV; | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static void __exit bay_exit(void) | ||
394 | { | ||
395 | struct bay *bay, *tmp; | ||
396 | |||
397 | list_for_each_entry_safe(bay, tmp, &drive_bays, list) { | ||
398 | if (is_dock_device(bay->handle)) | ||
399 | unregister_hotplug_dock_device(bay->handle); | ||
400 | acpi_bay_remove_fs(bay); | ||
401 | acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY, | ||
402 | bay_notify); | ||
403 | platform_device_unregister(bay->pdev); | ||
404 | kfree(bay->name); | ||
405 | kfree(bay); | ||
406 | } | ||
407 | } | ||
408 | |||
409 | postcore_initcall(bay_init); | ||
410 | module_exit(bay_exit); | ||
411 | |||
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index e9b116d2b56d..e6311f432edf 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -525,6 +525,19 @@ static int acpi_bus_check_scope(struct acpi_device *device) | |||
525 | return 0; | 525 | return 0; |
526 | } | 526 | } |
527 | 527 | ||
528 | static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); | ||
529 | int register_acpi_bus_notifier(struct notifier_block *nb) | ||
530 | { | ||
531 | return blocking_notifier_chain_register(&acpi_bus_notify_list, nb); | ||
532 | } | ||
533 | EXPORT_SYMBOL_GPL(register_acpi_bus_notifier); | ||
534 | |||
535 | void unregister_acpi_bus_notifier(struct notifier_block *nb) | ||
536 | { | ||
537 | blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb); | ||
538 | } | ||
539 | EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); | ||
540 | |||
528 | /** | 541 | /** |
529 | * acpi_bus_notify | 542 | * acpi_bus_notify |
530 | * --------------- | 543 | * --------------- |
@@ -535,6 +548,8 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) | |||
535 | int result = 0; | 548 | int result = 0; |
536 | struct acpi_device *device = NULL; | 549 | struct acpi_device *device = NULL; |
537 | 550 | ||
551 | blocking_notifier_call_chain(&acpi_bus_notify_list, | ||
552 | type, (void *)handle); | ||
538 | 553 | ||
539 | if (acpi_bus_get_device(handle, &device)) | 554 | if (acpi_bus_get_device(handle, &device)) |
540 | return; | 555 | return; |
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7d2edf143f16..913bb1e89dd6 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,23 +64,29 @@ 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; |
72 | struct list_head hotplug_list; | 76 | struct list_head hotplug_list; |
73 | acpi_handle handle; | 77 | acpi_handle handle; |
74 | acpi_notify_handler handler; | 78 | struct acpi_dock_ops *ops; |
75 | void *context; | 79 | void *context; |
76 | }; | 80 | }; |
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 | } |
@@ -320,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
320 | * First call driver specific hotplug functions | 385 | * First call driver specific hotplug functions |
321 | */ | 386 | */ |
322 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { | 387 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { |
323 | if (dd->handler) | 388 | if (dd->ops && dd->ops->handler) |
324 | dd->handler(dd->handle, event, dd->context); | 389 | dd->ops->handler(dd->handle, event, dd->context); |
325 | } | 390 | } |
326 | 391 | ||
327 | /* | 392 | /* |
@@ -341,9 +406,10 @@ 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 }; |
412 | struct dock_dependent_device *dd; | ||
347 | 413 | ||
348 | if (num == UNDOCK_EVENT) | 414 | if (num == UNDOCK_EVENT) |
349 | sprintf(event_string, "EVENT=undock"); | 415 | sprintf(event_string, "EVENT=undock"); |
@@ -354,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num) | |||
354 | * Indicate that the status of the dock station has | 420 | * Indicate that the status of the dock station has |
355 | * changed. | 421 | * changed. |
356 | */ | 422 | */ |
357 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | 423 | if (num == DOCK_EVENT) |
424 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | ||
425 | |||
426 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) | ||
427 | if (dd->ops && dd->ops->uevent) | ||
428 | dd->ops->uevent(dd->handle, event, dd->context); | ||
429 | if (num != DOCK_EVENT) | ||
430 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | ||
358 | } | 431 | } |
359 | 432 | ||
360 | /** | 433 | /** |
@@ -414,9 +487,10 @@ static void handle_dock(struct dock_station *ds, int dock) | |||
414 | arg.type = ACPI_TYPE_INTEGER; | 487 | arg.type = ACPI_TYPE_INTEGER; |
415 | arg.integer.value = dock; | 488 | arg.integer.value = dock; |
416 | status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); | 489 | status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); |
417 | if (ACPI_FAILURE(status)) | 490 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) |
418 | printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", | 491 | ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute" |
419 | (char *)name_buffer.pointer); | 492 | " _DCK\n", (char *)name_buffer.pointer)); |
493 | |||
420 | kfree(buffer.pointer); | 494 | kfree(buffer.pointer); |
421 | kfree(name_buffer.pointer); | 495 | kfree(name_buffer.pointer); |
422 | } | 496 | } |
@@ -452,6 +526,25 @@ static inline void complete_undock(struct dock_station *ds) | |||
452 | ds->flags &= ~(DOCK_UNDOCKING); | 526 | ds->flags &= ~(DOCK_UNDOCKING); |
453 | } | 527 | } |
454 | 528 | ||
529 | static void dock_lock(struct dock_station *ds, int lock) | ||
530 | { | ||
531 | struct acpi_object_list arg_list; | ||
532 | union acpi_object arg; | ||
533 | acpi_status status; | ||
534 | |||
535 | arg_list.count = 1; | ||
536 | arg_list.pointer = &arg; | ||
537 | arg.type = ACPI_TYPE_INTEGER; | ||
538 | arg.integer.value = !!lock; | ||
539 | status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); | ||
540 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
541 | if (lock) | ||
542 | printk(KERN_WARNING PREFIX "Locking device failed\n"); | ||
543 | else | ||
544 | printk(KERN_WARNING PREFIX "Unlocking device failed\n"); | ||
545 | } | ||
546 | } | ||
547 | |||
455 | /** | 548 | /** |
456 | * dock_in_progress - see if we are in the middle of handling a dock event | 549 | * dock_in_progress - see if we are in the middle of handling a dock event |
457 | * @ds: the dock station | 550 | * @ds: the dock station |
@@ -479,7 +572,7 @@ static int dock_in_progress(struct dock_station *ds) | |||
479 | */ | 572 | */ |
480 | int register_dock_notifier(struct notifier_block *nb) | 573 | int register_dock_notifier(struct notifier_block *nb) |
481 | { | 574 | { |
482 | if (!dock_station) | 575 | if (!dock_station_count) |
483 | return -ENODEV; | 576 | return -ENODEV; |
484 | 577 | ||
485 | return atomic_notifier_chain_register(&dock_notifier_list, nb); | 578 | return atomic_notifier_chain_register(&dock_notifier_list, nb); |
@@ -493,7 +586,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier); | |||
493 | */ | 586 | */ |
494 | void unregister_dock_notifier(struct notifier_block *nb) | 587 | void unregister_dock_notifier(struct notifier_block *nb) |
495 | { | 588 | { |
496 | if (!dock_station) | 589 | if (!dock_station_count) |
497 | return; | 590 | return; |
498 | 591 | ||
499 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); | 592 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); |
@@ -504,7 +597,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); | |||
504 | /** | 597 | /** |
505 | * register_hotplug_dock_device - register a hotplug function | 598 | * register_hotplug_dock_device - register a hotplug function |
506 | * @handle: the handle of the device | 599 | * @handle: the handle of the device |
507 | * @handler: the acpi_notifier_handler to call after docking | 600 | * @ops: handlers to call after docking |
508 | * @context: device specific data | 601 | * @context: device specific data |
509 | * | 602 | * |
510 | * If a driver would like to perform a hotplug operation after a dock | 603 | * If a driver would like to perform a hotplug operation after a dock |
@@ -512,27 +605,36 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); | |||
512 | * the dock driver after _DCK is executed. | 605 | * the dock driver after _DCK is executed. |
513 | */ | 606 | */ |
514 | int | 607 | int |
515 | register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, | 608 | register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, |
516 | void *context) | 609 | void *context) |
517 | { | 610 | { |
518 | struct dock_dependent_device *dd; | 611 | struct dock_dependent_device *dd; |
612 | struct dock_station *dock_station; | ||
613 | int ret = -EINVAL; | ||
519 | 614 | ||
520 | if (!dock_station) | 615 | if (!dock_station_count) |
521 | return -ENODEV; | 616 | return -ENODEV; |
522 | 617 | ||
523 | /* | 618 | /* |
524 | * make sure this handle is for a device dependent on the dock, | 619 | * make sure this handle is for a device dependent on the dock, |
525 | * this would include the dock station itself | 620 | * this would include the dock station itself |
526 | */ | 621 | */ |
527 | dd = find_dock_dependent_device(dock_station, handle); | 622 | list_for_each_entry(dock_station, &dock_stations, sibiling) { |
528 | if (dd) { | 623 | /* |
529 | dd->handler = handler; | 624 | * An ATA bay can be in a dock and itself can be ejected |
530 | dd->context = context; | 625 | * seperately, so there are two 'dock stations' which need the |
531 | dock_add_hotplug_device(dock_station, dd); | 626 | * ops |
532 | return 0; | 627 | */ |
628 | dd = find_dock_dependent_device(dock_station, handle); | ||
629 | if (dd) { | ||
630 | dd->ops = ops; | ||
631 | dd->context = context; | ||
632 | dock_add_hotplug_device(dock_station, dd); | ||
633 | ret = 0; | ||
634 | } | ||
533 | } | 635 | } |
534 | 636 | ||
535 | return -EINVAL; | 637 | return ret; |
536 | } | 638 | } |
537 | 639 | ||
538 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); | 640 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); |
@@ -544,13 +646,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_device); | |||
544 | void unregister_hotplug_dock_device(acpi_handle handle) | 646 | void unregister_hotplug_dock_device(acpi_handle handle) |
545 | { | 647 | { |
546 | struct dock_dependent_device *dd; | 648 | struct dock_dependent_device *dd; |
649 | struct dock_station *dock_station; | ||
547 | 650 | ||
548 | if (!dock_station) | 651 | if (!dock_station_count) |
549 | return; | 652 | return; |
550 | 653 | ||
551 | dd = find_dock_dependent_device(dock_station, handle); | 654 | list_for_each_entry(dock_station, &dock_stations, sibiling) { |
552 | if (dd) | 655 | dd = find_dock_dependent_device(dock_station, handle); |
553 | dock_del_hotplug_device(dock_station, dd); | 656 | if (dd) |
657 | dock_del_hotplug_device(dock_station, dd); | ||
658 | } | ||
554 | } | 659 | } |
555 | 660 | ||
556 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | 661 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); |
@@ -575,13 +680,9 @@ static int handle_eject_request(struct dock_station *ds, u32 event) | |||
575 | */ | 680 | */ |
576 | dock_event(ds, event, UNDOCK_EVENT); | 681 | dock_event(ds, event, UNDOCK_EVENT); |
577 | 682 | ||
578 | if (!dock_present(ds)) { | ||
579 | complete_undock(ds); | ||
580 | return -ENODEV; | ||
581 | } | ||
582 | |||
583 | hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); | 683 | hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); |
584 | undock(ds); | 684 | undock(ds); |
685 | dock_lock(ds, 0); | ||
585 | eject_dock(ds); | 686 | eject_dock(ds); |
586 | if (dock_present(ds)) { | 687 | if (dock_present(ds)) { |
587 | printk(KERN_ERR PREFIX "Unable to undock!\n"); | 688 | printk(KERN_ERR PREFIX "Unable to undock!\n"); |
@@ -604,14 +705,36 @@ static int handle_eject_request(struct dock_station *ds, u32 event) | |||
604 | static void dock_notify(acpi_handle handle, u32 event, void *data) | 705 | static void dock_notify(acpi_handle handle, u32 event, void *data) |
605 | { | 706 | { |
606 | struct dock_station *ds = data; | 707 | struct dock_station *ds = data; |
708 | struct acpi_device *tmp; | ||
709 | int surprise_removal = 0; | ||
710 | |||
711 | /* | ||
712 | * According to acpi spec 3.0a, if a DEVICE_CHECK notification | ||
713 | * is sent and _DCK is present, it is assumed to mean an undock | ||
714 | * request. | ||
715 | */ | ||
716 | if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK) | ||
717 | event = ACPI_NOTIFY_EJECT_REQUEST; | ||
607 | 718 | ||
719 | /* | ||
720 | * dock station: BUS_CHECK - docked or surprise removal | ||
721 | * DEVICE_CHECK - undocked | ||
722 | * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal | ||
723 | * | ||
724 | * To simplify event handling, dock dependent device handler always | ||
725 | * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and | ||
726 | * ACPI_NOTIFY_EJECT_REQUEST for removal | ||
727 | */ | ||
608 | switch (event) { | 728 | switch (event) { |
609 | case ACPI_NOTIFY_BUS_CHECK: | 729 | case ACPI_NOTIFY_BUS_CHECK: |
610 | if (!dock_in_progress(ds) && dock_present(ds)) { | 730 | case ACPI_NOTIFY_DEVICE_CHECK: |
731 | if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, | ||
732 | &tmp)) { | ||
611 | begin_dock(ds); | 733 | begin_dock(ds); |
612 | dock(ds); | 734 | dock(ds); |
613 | if (!dock_present(ds)) { | 735 | if (!dock_present(ds)) { |
614 | printk(KERN_ERR PREFIX "Unable to dock!\n"); | 736 | printk(KERN_ERR PREFIX "Unable to dock!\n"); |
737 | complete_dock(ds); | ||
615 | break; | 738 | break; |
616 | } | 739 | } |
617 | atomic_notifier_call_chain(&dock_notifier_list, | 740 | atomic_notifier_call_chain(&dock_notifier_list, |
@@ -619,20 +742,19 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) | |||
619 | hotplug_dock_devices(ds, event); | 742 | hotplug_dock_devices(ds, event); |
620 | complete_dock(ds); | 743 | complete_dock(ds); |
621 | dock_event(ds, event, DOCK_EVENT); | 744 | dock_event(ds, event, DOCK_EVENT); |
745 | dock_lock(ds, 1); | ||
746 | break; | ||
622 | } | 747 | } |
623 | break; | 748 | if (dock_present(ds) || dock_in_progress(ds)) |
624 | case ACPI_NOTIFY_DEVICE_CHECK: | 749 | break; |
625 | /* | 750 | /* This is a surprise removal */ |
626 | * According to acpi spec 3.0a, if a DEVICE_CHECK notification | 751 | surprise_removal = 1; |
627 | * is sent and _DCK is present, it is assumed to mean an | 752 | event = ACPI_NOTIFY_EJECT_REQUEST; |
628 | * undock request. This notify routine will only be called | 753 | /* Fall back */ |
629 | * for objects defining _DCK, so we will fall through to eject | ||
630 | * request here. However, we will pass an eject request through | ||
631 | * to the driver who wish to hotplug. | ||
632 | */ | ||
633 | case ACPI_NOTIFY_EJECT_REQUEST: | 754 | case ACPI_NOTIFY_EJECT_REQUEST: |
634 | begin_undock(ds); | 755 | begin_undock(ds); |
635 | if (immediate_undock) | 756 | if ((immediate_undock && !(ds->flags & DOCK_IS_ATA)) |
757 | || surprise_removal) | ||
636 | handle_eject_request(ds, event); | 758 | handle_eject_request(ds, event); |
637 | else | 759 | else |
638 | dock_event(ds, event, UNDOCK_EVENT); | 760 | dock_event(ds, event, UNDOCK_EVENT); |
@@ -642,6 +764,51 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) | |||
642 | } | 764 | } |
643 | } | 765 | } |
644 | 766 | ||
767 | struct dock_data { | ||
768 | acpi_handle handle; | ||
769 | unsigned long event; | ||
770 | struct dock_station *ds; | ||
771 | }; | ||
772 | |||
773 | static void acpi_dock_deferred_cb(void *context) | ||
774 | { | ||
775 | struct dock_data *data = (struct dock_data *)context; | ||
776 | |||
777 | dock_notify(data->handle, data->event, data->ds); | ||
778 | kfree(data); | ||
779 | } | ||
780 | |||
781 | static int acpi_dock_notifier_call(struct notifier_block *this, | ||
782 | unsigned long event, void *data) | ||
783 | { | ||
784 | struct dock_station *dock_station; | ||
785 | acpi_handle handle = (acpi_handle)data; | ||
786 | |||
787 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK | ||
788 | && event != ACPI_NOTIFY_EJECT_REQUEST) | ||
789 | return 0; | ||
790 | list_for_each_entry(dock_station, &dock_stations, sibiling) { | ||
791 | if (dock_station->handle == handle) { | ||
792 | struct dock_data *dock_data; | ||
793 | |||
794 | dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); | ||
795 | if (!dock_data) | ||
796 | return 0; | ||
797 | dock_data->handle = handle; | ||
798 | dock_data->event = event; | ||
799 | dock_data->ds = dock_station; | ||
800 | acpi_os_hotplug_execute(acpi_dock_deferred_cb, | ||
801 | dock_data); | ||
802 | return 0 ; | ||
803 | } | ||
804 | } | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static struct notifier_block dock_acpi_notifier = { | ||
809 | .notifier_call = acpi_dock_notifier_call, | ||
810 | }; | ||
811 | |||
645 | /** | 812 | /** |
646 | * find_dock_devices - find devices on the dock station | 813 | * find_dock_devices - find devices on the dock station |
647 | * @handle: the handle of the device we are examining | 814 | * @handle: the handle of the device we are examining |
@@ -688,6 +855,8 @@ fdd_out: | |||
688 | static ssize_t show_docked(struct device *dev, | 855 | static ssize_t show_docked(struct device *dev, |
689 | struct device_attribute *attr, char *buf) | 856 | struct device_attribute *attr, char *buf) |
690 | { | 857 | { |
858 | struct dock_station *dock_station = *((struct dock_station **) | ||
859 | dev->platform_data); | ||
691 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); | 860 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); |
692 | 861 | ||
693 | } | 862 | } |
@@ -699,6 +868,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | |||
699 | static ssize_t show_flags(struct device *dev, | 868 | static ssize_t show_flags(struct device *dev, |
700 | struct device_attribute *attr, char *buf) | 869 | struct device_attribute *attr, char *buf) |
701 | { | 870 | { |
871 | struct dock_station *dock_station = *((struct dock_station **) | ||
872 | dev->platform_data); | ||
702 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); | 873 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); |
703 | 874 | ||
704 | } | 875 | } |
@@ -711,6 +882,8 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, | |||
711 | const char *buf, size_t count) | 882 | const char *buf, size_t count) |
712 | { | 883 | { |
713 | int ret; | 884 | int ret; |
885 | struct dock_station *dock_station = *((struct dock_station **) | ||
886 | dev->platform_data); | ||
714 | 887 | ||
715 | if (!count) | 888 | if (!count) |
716 | return -EINVAL; | 889 | return -EINVAL; |
@@ -728,6 +901,8 @@ static ssize_t show_dock_uid(struct device *dev, | |||
728 | struct device_attribute *attr, char *buf) | 901 | struct device_attribute *attr, char *buf) |
729 | { | 902 | { |
730 | unsigned long lbuf; | 903 | unsigned long lbuf; |
904 | struct dock_station *dock_station = *((struct dock_station **) | ||
905 | dev->platform_data); | ||
731 | acpi_status status = acpi_evaluate_integer(dock_station->handle, | 906 | acpi_status status = acpi_evaluate_integer(dock_station->handle, |
732 | "_UID", NULL, &lbuf); | 907 | "_UID", NULL, &lbuf); |
733 | if (ACPI_FAILURE(status)) | 908 | if (ACPI_FAILURE(status)) |
@@ -737,6 +912,26 @@ static ssize_t show_dock_uid(struct device *dev, | |||
737 | } | 912 | } |
738 | static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); | 913 | static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); |
739 | 914 | ||
915 | static ssize_t show_dock_type(struct device *dev, | ||
916 | struct device_attribute *attr, char *buf) | ||
917 | { | ||
918 | struct dock_station *dock_station = *((struct dock_station **) | ||
919 | dev->platform_data); | ||
920 | char *type; | ||
921 | |||
922 | if (dock_station->flags & DOCK_IS_DOCK) | ||
923 | type = "dock_station"; | ||
924 | else if (dock_station->flags & DOCK_IS_ATA) | ||
925 | type = "ata_bay"; | ||
926 | else if (dock_station->flags & DOCK_IS_BAT) | ||
927 | type = "battery_bay"; | ||
928 | else | ||
929 | type = "unknown"; | ||
930 | |||
931 | return snprintf(buf, PAGE_SIZE, "%s\n", type); | ||
932 | } | ||
933 | static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); | ||
934 | |||
740 | /** | 935 | /** |
741 | * dock_add - add a new dock station | 936 | * dock_add - add a new dock station |
742 | * @handle: the dock station handle | 937 | * @handle: the dock station handle |
@@ -747,8 +942,9 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); | |||
747 | static int dock_add(acpi_handle handle) | 942 | static int dock_add(acpi_handle handle) |
748 | { | 943 | { |
749 | int ret; | 944 | int ret; |
750 | acpi_status status; | ||
751 | struct dock_dependent_device *dd; | 945 | struct dock_dependent_device *dd; |
946 | struct dock_station *dock_station; | ||
947 | struct platform_device *dock_device; | ||
752 | 948 | ||
753 | /* allocate & initialize the dock_station private data */ | 949 | /* allocate & initialize the dock_station private data */ |
754 | dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); | 950 | dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); |
@@ -758,22 +954,34 @@ static int dock_add(acpi_handle handle) | |||
758 | dock_station->last_dock_time = jiffies - HZ; | 954 | dock_station->last_dock_time = jiffies - HZ; |
759 | INIT_LIST_HEAD(&dock_station->dependent_devices); | 955 | INIT_LIST_HEAD(&dock_station->dependent_devices); |
760 | INIT_LIST_HEAD(&dock_station->hotplug_devices); | 956 | INIT_LIST_HEAD(&dock_station->hotplug_devices); |
957 | INIT_LIST_HEAD(&dock_station->sibiling); | ||
761 | spin_lock_init(&dock_station->dd_lock); | 958 | spin_lock_init(&dock_station->dd_lock); |
762 | mutex_init(&dock_station->hp_lock); | 959 | mutex_init(&dock_station->hp_lock); |
763 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); | 960 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); |
764 | 961 | ||
765 | /* initialize platform device stuff */ | 962 | /* initialize platform device stuff */ |
766 | dock_device = | 963 | dock_station->dock_device = |
767 | platform_device_register_simple(dock_device_name, 0, NULL, 0); | 964 | platform_device_register_simple(dock_device_name, |
965 | dock_station_count, NULL, 0); | ||
966 | dock_device = dock_station->dock_device; | ||
768 | if (IS_ERR(dock_device)) { | 967 | if (IS_ERR(dock_device)) { |
769 | kfree(dock_station); | 968 | kfree(dock_station); |
770 | dock_station = NULL; | 969 | dock_station = NULL; |
771 | return PTR_ERR(dock_device); | 970 | return PTR_ERR(dock_device); |
772 | } | 971 | } |
972 | platform_device_add_data(dock_device, &dock_station, | ||
973 | sizeof(struct dock_station *)); | ||
773 | 974 | ||
774 | /* we want the dock device to send uevents */ | 975 | /* we want the dock device to send uevents */ |
775 | dock_device->dev.uevent_suppress = 0; | 976 | dock_device->dev.uevent_suppress = 0; |
776 | 977 | ||
978 | if (is_dock(handle)) | ||
979 | dock_station->flags |= DOCK_IS_DOCK; | ||
980 | if (is_ata(handle)) | ||
981 | dock_station->flags |= DOCK_IS_ATA; | ||
982 | if (is_battery(handle)) | ||
983 | dock_station->flags |= DOCK_IS_BAT; | ||
984 | |||
777 | ret = device_create_file(&dock_device->dev, &dev_attr_docked); | 985 | ret = device_create_file(&dock_device->dev, &dev_attr_docked); |
778 | if (ret) { | 986 | if (ret) { |
779 | printk("Error %d adding sysfs file\n", ret); | 987 | printk("Error %d adding sysfs file\n", ret); |
@@ -812,6 +1020,9 @@ static int dock_add(acpi_handle handle) | |||
812 | dock_station = NULL; | 1020 | dock_station = NULL; |
813 | return ret; | 1021 | return ret; |
814 | } | 1022 | } |
1023 | ret = device_create_file(&dock_device->dev, &dev_attr_type); | ||
1024 | if (ret) | ||
1025 | printk(KERN_ERR"Error %d adding sysfs file\n", ret); | ||
815 | 1026 | ||
816 | /* Find dependent devices */ | 1027 | /* Find dependent devices */ |
817 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 1028 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
@@ -828,24 +1039,12 @@ static int dock_add(acpi_handle handle) | |||
828 | } | 1039 | } |
829 | add_dock_dependent_device(dock_station, dd); | 1040 | add_dock_dependent_device(dock_station, dd); |
830 | 1041 | ||
831 | /* register for dock events */ | 1042 | dock_station_count++; |
832 | status = acpi_install_notify_handler(dock_station->handle, | 1043 | list_add(&dock_station->sibiling, &dock_stations); |
833 | ACPI_SYSTEM_NOTIFY, | ||
834 | dock_notify, dock_station); | ||
835 | |||
836 | if (ACPI_FAILURE(status)) { | ||
837 | printk(KERN_ERR PREFIX "Error installing notify handler\n"); | ||
838 | ret = -ENODEV; | ||
839 | goto dock_add_err; | ||
840 | } | ||
841 | |||
842 | printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION); | ||
843 | |||
844 | return 0; | 1044 | return 0; |
845 | 1045 | ||
846 | dock_add_err: | ||
847 | kfree(dd); | ||
848 | dock_add_err_unregister: | 1046 | dock_add_err_unregister: |
1047 | device_remove_file(&dock_device->dev, &dev_attr_type); | ||
849 | device_remove_file(&dock_device->dev, &dev_attr_docked); | 1048 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
850 | device_remove_file(&dock_device->dev, &dev_attr_undock); | 1049 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
851 | device_remove_file(&dock_device->dev, &dev_attr_uid); | 1050 | device_remove_file(&dock_device->dev, &dev_attr_uid); |
@@ -859,12 +1058,12 @@ dock_add_err_unregister: | |||
859 | /** | 1058 | /** |
860 | * dock_remove - free up resources related to the dock station | 1059 | * dock_remove - free up resources related to the dock station |
861 | */ | 1060 | */ |
862 | static int dock_remove(void) | 1061 | static int dock_remove(struct dock_station *dock_station) |
863 | { | 1062 | { |
864 | struct dock_dependent_device *dd, *tmp; | 1063 | struct dock_dependent_device *dd, *tmp; |
865 | acpi_status status; | 1064 | struct platform_device *dock_device = dock_station->dock_device; |
866 | 1065 | ||
867 | if (!dock_station) | 1066 | if (!dock_station_count) |
868 | return 0; | 1067 | return 0; |
869 | 1068 | ||
870 | /* remove dependent devices */ | 1069 | /* remove dependent devices */ |
@@ -872,14 +1071,8 @@ static int dock_remove(void) | |||
872 | list) | 1071 | list) |
873 | kfree(dd); | 1072 | kfree(dd); |
874 | 1073 | ||
875 | /* remove dock notify handler */ | ||
876 | status = acpi_remove_notify_handler(dock_station->handle, | ||
877 | ACPI_SYSTEM_NOTIFY, | ||
878 | dock_notify); | ||
879 | if (ACPI_FAILURE(status)) | ||
880 | printk(KERN_ERR "Error removing notify handler\n"); | ||
881 | |||
882 | /* cleanup sysfs */ | 1074 | /* cleanup sysfs */ |
1075 | device_remove_file(&dock_device->dev, &dev_attr_type); | ||
883 | device_remove_file(&dock_device->dev, &dev_attr_docked); | 1076 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
884 | device_remove_file(&dock_device->dev, &dev_attr_undock); | 1077 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
885 | device_remove_file(&dock_device->dev, &dev_attr_uid); | 1078 | device_remove_file(&dock_device->dev, &dev_attr_uid); |
@@ -904,41 +1097,60 @@ static int dock_remove(void) | |||
904 | static acpi_status | 1097 | static acpi_status |
905 | find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) | 1098 | find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) |
906 | { | 1099 | { |
907 | int *count = context; | ||
908 | acpi_status status = AE_OK; | 1100 | acpi_status status = AE_OK; |
909 | 1101 | ||
910 | if (is_dock(handle)) { | 1102 | if (is_dock(handle)) { |
911 | if (dock_add(handle) >= 0) { | 1103 | if (dock_add(handle) >= 0) { |
912 | (*count)++; | ||
913 | status = AE_CTRL_TERMINATE; | 1104 | status = AE_CTRL_TERMINATE; |
914 | } | 1105 | } |
915 | } | 1106 | } |
916 | return status; | 1107 | return status; |
917 | } | 1108 | } |
918 | 1109 | ||
919 | static int __init dock_init(void) | 1110 | static acpi_status |
1111 | find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
920 | { | 1112 | { |
921 | int num = 0; | 1113 | /* If bay is a dock, it's already handled */ |
922 | 1114 | if (is_ejectable_bay(handle) && !is_dock(handle)) | |
923 | dock_station = NULL; | 1115 | dock_add(handle); |
1116 | return AE_OK; | ||
1117 | } | ||
924 | 1118 | ||
1119 | static int __init dock_init(void) | ||
1120 | { | ||
925 | if (acpi_disabled) | 1121 | if (acpi_disabled) |
926 | return 0; | 1122 | return 0; |
927 | 1123 | ||
928 | /* look for a dock station */ | 1124 | /* look for a dock station */ |
929 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 1125 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
930 | ACPI_UINT32_MAX, find_dock, &num, NULL); | 1126 | ACPI_UINT32_MAX, find_dock, NULL, NULL); |
931 | 1127 | ||
932 | if (!num) | 1128 | /* look for bay */ |
933 | printk(KERN_INFO "No dock devices found.\n"); | 1129 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
1130 | ACPI_UINT32_MAX, find_bay, NULL, NULL); | ||
1131 | if (!dock_station_count) { | ||
1132 | printk(KERN_INFO PREFIX "No dock devices found.\n"); | ||
1133 | return 0; | ||
1134 | } | ||
934 | 1135 | ||
1136 | register_acpi_bus_notifier(&dock_acpi_notifier); | ||
1137 | printk(KERN_INFO PREFIX "%s: %d docks/bays found\n", | ||
1138 | ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); | ||
935 | return 0; | 1139 | return 0; |
936 | } | 1140 | } |
937 | 1141 | ||
938 | static void __exit dock_exit(void) | 1142 | static void __exit dock_exit(void) |
939 | { | 1143 | { |
940 | dock_remove(); | 1144 | struct dock_station *dock_station; |
1145 | |||
1146 | unregister_acpi_bus_notifier(&dock_acpi_notifier); | ||
1147 | list_for_each_entry(dock_station, &dock_stations, sibiling) | ||
1148 | dock_remove(dock_station); | ||
941 | } | 1149 | } |
942 | 1150 | ||
943 | postcore_initcall(dock_init); | 1151 | /* |
1152 | * Must be called before drivers of devices in dock, otherwise we can't know | ||
1153 | * which devices are in a dock | ||
1154 | */ | ||
1155 | subsys_initcall(dock_init); | ||
944 | module_exit(dock_exit); | 1156 | module_exit(dock_exit); |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 1420a9f69e5d..6234d3e7acd3 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -682,6 +682,22 @@ static void acpi_os_execute_deferred(struct work_struct *work) | |||
682 | return; | 682 | return; |
683 | } | 683 | } |
684 | 684 | ||
685 | static void acpi_os_execute_hp_deferred(struct work_struct *work) | ||
686 | { | ||
687 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); | ||
688 | if (!dpc) { | ||
689 | printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); | ||
690 | return; | ||
691 | } | ||
692 | |||
693 | acpi_os_wait_events_complete(NULL); | ||
694 | |||
695 | dpc->function(dpc->context); | ||
696 | kfree(dpc); | ||
697 | |||
698 | return; | ||
699 | } | ||
700 | |||
685 | /******************************************************************************* | 701 | /******************************************************************************* |
686 | * | 702 | * |
687 | * FUNCTION: acpi_os_execute | 703 | * FUNCTION: acpi_os_execute |
@@ -697,12 +713,13 @@ static void acpi_os_execute_deferred(struct work_struct *work) | |||
697 | * | 713 | * |
698 | ******************************************************************************/ | 714 | ******************************************************************************/ |
699 | 715 | ||
700 | acpi_status acpi_os_execute(acpi_execute_type type, | 716 | static acpi_status __acpi_os_execute(acpi_execute_type type, |
701 | acpi_osd_exec_callback function, void *context) | 717 | acpi_osd_exec_callback function, void *context, int hp) |
702 | { | 718 | { |
703 | acpi_status status = AE_OK; | 719 | acpi_status status = AE_OK; |
704 | struct acpi_os_dpc *dpc; | 720 | struct acpi_os_dpc *dpc; |
705 | struct workqueue_struct *queue; | 721 | struct workqueue_struct *queue; |
722 | int ret; | ||
706 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | 723 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
707 | "Scheduling function [%p(%p)] for deferred execution.\n", | 724 | "Scheduling function [%p(%p)] for deferred execution.\n", |
708 | function, context)); | 725 | function, context)); |
@@ -726,9 +743,17 @@ acpi_status acpi_os_execute(acpi_execute_type type, | |||
726 | dpc->function = function; | 743 | dpc->function = function; |
727 | dpc->context = context; | 744 | dpc->context = context; |
728 | 745 | ||
729 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); | 746 | if (!hp) { |
730 | queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq; | 747 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); |
731 | if (!queue_work(queue, &dpc->work)) { | 748 | queue = (type == OSL_NOTIFY_HANDLER) ? |
749 | kacpi_notify_wq : kacpid_wq; | ||
750 | ret = queue_work(queue, &dpc->work); | ||
751 | } else { | ||
752 | INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred); | ||
753 | ret = schedule_work(&dpc->work); | ||
754 | } | ||
755 | |||
756 | if (!ret) { | ||
732 | printk(KERN_ERR PREFIX | 757 | printk(KERN_ERR PREFIX |
733 | "Call to queue_work() failed.\n"); | 758 | "Call to queue_work() failed.\n"); |
734 | status = AE_ERROR; | 759 | status = AE_ERROR; |
@@ -737,8 +762,19 @@ acpi_status acpi_os_execute(acpi_execute_type type, | |||
737 | return_ACPI_STATUS(status); | 762 | return_ACPI_STATUS(status); |
738 | } | 763 | } |
739 | 764 | ||
765 | acpi_status acpi_os_execute(acpi_execute_type type, | ||
766 | acpi_osd_exec_callback function, void *context) | ||
767 | { | ||
768 | return __acpi_os_execute(type, function, context, 0); | ||
769 | } | ||
740 | EXPORT_SYMBOL(acpi_os_execute); | 770 | EXPORT_SYMBOL(acpi_os_execute); |
741 | 771 | ||
772 | acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, | ||
773 | void *context) | ||
774 | { | ||
775 | return __acpi_os_execute(0, function, context, 1); | ||
776 | } | ||
777 | |||
742 | void acpi_os_wait_events_complete(void *context) | 778 | void acpi_os_wait_events_complete(void *context) |
743 | { | 779 | { |
744 | flush_workqueue(kacpid_wq); | 780 | flush_workqueue(kacpid_wq); |
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 9330b7922f62..c012307d0ba6 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) | |||
120 | ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; | 120 | ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; |
121 | } | 121 | } |
122 | 122 | ||
123 | static void ata_acpi_eject_device(acpi_handle handle) | ||
124 | { | ||
125 | struct acpi_object_list arg_list; | ||
126 | union acpi_object arg; | ||
127 | |||
128 | arg_list.count = 1; | ||
129 | arg_list.pointer = &arg; | ||
130 | arg.type = ACPI_TYPE_INTEGER; | ||
131 | arg.integer.value = 1; | ||
132 | |||
133 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", | ||
134 | &arg_list, NULL))) | ||
135 | printk(KERN_ERR "Failed to evaluate _EJ0!\n"); | ||
136 | } | ||
137 | |||
138 | /* @ap and @dev are the same as ata_acpi_handle_hotplug() */ | 123 | /* @ap and @dev are the same as ata_acpi_handle_hotplug() */ |
139 | static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) | 124 | static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) |
140 | { | 125 | { |
@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) | |||
157 | * @ap: ATA port ACPI event occurred | 142 | * @ap: ATA port ACPI event occurred |
158 | * @dev: ATA device ACPI event occurred (can be NULL) | 143 | * @dev: ATA device ACPI event occurred (can be NULL) |
159 | * @event: ACPI event which occurred | 144 | * @event: ACPI event which occurred |
160 | * @is_dock_event: boolean indicating whether the event was a dock one | ||
161 | * | 145 | * |
162 | * All ACPI bay / device realted events end up in this function. If | 146 | * All ACPI bay / device realted events end up in this function. If |
163 | * the event is port-wide @dev is NULL. If the event is specific to a | 147 | * the event is port-wide @dev is NULL. If the event is specific to a |
@@ -171,117 +155,100 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) | |||
171 | * ACPI notify handler context. May sleep. | 155 | * ACPI notify handler context. May sleep. |
172 | */ | 156 | */ |
173 | static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, | 157 | static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, |
174 | u32 event, int is_dock_event) | 158 | u32 event) |
175 | { | 159 | { |
176 | char event_string[12]; | ||
177 | char *envp[] = { event_string, NULL }; | ||
178 | struct ata_eh_info *ehi = &ap->link.eh_info; | 160 | struct ata_eh_info *ehi = &ap->link.eh_info; |
179 | struct kobject *kobj = NULL; | ||
180 | int wait = 0; | 161 | int wait = 0; |
181 | unsigned long flags; | 162 | unsigned long flags; |
182 | acpi_handle handle, tmphandle; | 163 | acpi_handle handle; |
183 | unsigned long sta; | ||
184 | acpi_status status; | ||
185 | 164 | ||
186 | if (dev) { | 165 | if (dev) |
187 | if (dev->sdev) | ||
188 | kobj = &dev->sdev->sdev_gendev.kobj; | ||
189 | handle = dev->acpi_handle; | 166 | handle = dev->acpi_handle; |
190 | } else { | 167 | else |
191 | kobj = &ap->dev->kobj; | ||
192 | handle = ap->acpi_handle; | 168 | handle = ap->acpi_handle; |
193 | } | ||
194 | |||
195 | status = acpi_get_handle(handle, "_EJ0", &tmphandle); | ||
196 | if (ACPI_FAILURE(status)) | ||
197 | /* This device does not support hotplug */ | ||
198 | return; | ||
199 | |||
200 | if (event == ACPI_NOTIFY_BUS_CHECK || | ||
201 | event == ACPI_NOTIFY_DEVICE_CHECK) | ||
202 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | ||
203 | 169 | ||
204 | spin_lock_irqsave(ap->lock, flags); | 170 | spin_lock_irqsave(ap->lock, flags); |
205 | 171 | /* | |
172 | * When dock driver calls into the routine, it will always use | ||
173 | * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and | ||
174 | * ACPI_NOTIFY_EJECT_REQUEST for remove | ||
175 | */ | ||
206 | switch (event) { | 176 | switch (event) { |
207 | case ACPI_NOTIFY_BUS_CHECK: | 177 | case ACPI_NOTIFY_BUS_CHECK: |
208 | case ACPI_NOTIFY_DEVICE_CHECK: | 178 | case ACPI_NOTIFY_DEVICE_CHECK: |
209 | ata_ehi_push_desc(ehi, "ACPI event"); | 179 | ata_ehi_push_desc(ehi, "ACPI event"); |
210 | 180 | ||
211 | if (ACPI_FAILURE(status)) { | 181 | ata_ehi_hotplugged(ehi); |
212 | ata_port_printk(ap, KERN_ERR, | 182 | ata_port_freeze(ap); |
213 | "acpi: failed to determine bay status (0x%x)\n", | ||
214 | status); | ||
215 | break; | ||
216 | } | ||
217 | |||
218 | if (sta) { | ||
219 | ata_ehi_hotplugged(ehi); | ||
220 | ata_port_freeze(ap); | ||
221 | } else { | ||
222 | /* The device has gone - unplug it */ | ||
223 | ata_acpi_detach_device(ap, dev); | ||
224 | wait = 1; | ||
225 | } | ||
226 | break; | 183 | break; |
227 | case ACPI_NOTIFY_EJECT_REQUEST: | 184 | case ACPI_NOTIFY_EJECT_REQUEST: |
228 | ata_ehi_push_desc(ehi, "ACPI event"); | 185 | ata_ehi_push_desc(ehi, "ACPI event"); |
229 | 186 | ||
230 | if (!is_dock_event) | ||
231 | break; | ||
232 | |||
233 | /* undock event - immediate unplug */ | ||
234 | ata_acpi_detach_device(ap, dev); | 187 | ata_acpi_detach_device(ap, dev); |
235 | wait = 1; | 188 | wait = 1; |
236 | break; | 189 | break; |
237 | } | 190 | } |
238 | 191 | ||
239 | /* make sure kobj doesn't go away while ap->lock is released */ | ||
240 | kobject_get(kobj); | ||
241 | |||
242 | spin_unlock_irqrestore(ap->lock, flags); | 192 | spin_unlock_irqrestore(ap->lock, flags); |
243 | 193 | ||
244 | if (wait) { | 194 | if (wait) |
245 | ata_port_wait_eh(ap); | 195 | ata_port_wait_eh(ap); |
246 | ata_acpi_eject_device(handle); | ||
247 | } | ||
248 | |||
249 | if (kobj && !is_dock_event) { | ||
250 | sprintf(event_string, "BAY_EVENT=%d", event); | ||
251 | kobject_uevent_env(kobj, KOBJ_CHANGE, envp); | ||
252 | } | ||
253 | |||
254 | kobject_put(kobj); | ||
255 | } | 196 | } |
256 | 197 | ||
257 | static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) | 198 | static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) |
258 | { | 199 | { |
259 | struct ata_device *dev = data; | 200 | struct ata_device *dev = data; |
260 | 201 | ||
261 | ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1); | 202 | ata_acpi_handle_hotplug(dev->link->ap, dev, event); |
262 | } | 203 | } |
263 | 204 | ||
264 | static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) | 205 | static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) |
265 | { | 206 | { |
266 | struct ata_port *ap = data; | 207 | struct ata_port *ap = data; |
267 | 208 | ||
268 | ata_acpi_handle_hotplug(ap, NULL, event, 1); | 209 | ata_acpi_handle_hotplug(ap, NULL, event); |
269 | } | 210 | } |
270 | 211 | ||
271 | static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) | 212 | static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, |
213 | u32 event) | ||
272 | { | 214 | { |
273 | struct ata_device *dev = data; | 215 | struct kobject *kobj = NULL; |
216 | char event_string[20]; | ||
217 | char *envp[] = { event_string, NULL }; | ||
218 | |||
219 | if (dev) { | ||
220 | if (dev->sdev) | ||
221 | kobj = &dev->sdev->sdev_gendev.kobj; | ||
222 | } else | ||
223 | kobj = &ap->dev->kobj; | ||
274 | 224 | ||
275 | ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0); | 225 | if (kobj) { |
226 | snprintf(event_string, 20, "BAY_EVENT=%d", event); | ||
227 | kobject_uevent_env(kobj, KOBJ_CHANGE, envp); | ||
228 | } | ||
276 | } | 229 | } |
277 | 230 | ||
278 | static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) | 231 | static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) |
279 | { | 232 | { |
280 | struct ata_port *ap = data; | 233 | ata_acpi_uevent(data, NULL, event); |
234 | } | ||
281 | 235 | ||
282 | ata_acpi_handle_hotplug(ap, NULL, event, 0); | 236 | static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) |
237 | { | ||
238 | struct ata_device *dev = data; | ||
239 | ata_acpi_uevent(dev->link->ap, dev, event); | ||
283 | } | 240 | } |
284 | 241 | ||
242 | static struct acpi_dock_ops ata_acpi_dev_dock_ops = { | ||
243 | .handler = ata_acpi_dev_notify_dock, | ||
244 | .uevent = ata_acpi_dev_uevent, | ||
245 | }; | ||
246 | |||
247 | static struct acpi_dock_ops ata_acpi_ap_dock_ops = { | ||
248 | .handler = ata_acpi_ap_notify_dock, | ||
249 | .uevent = ata_acpi_ap_uevent, | ||
250 | }; | ||
251 | |||
285 | /** | 252 | /** |
286 | * ata_acpi_associate - associate ATA host with ACPI objects | 253 | * ata_acpi_associate - associate ATA host with ACPI objects |
287 | * @host: target ATA host | 254 | * @host: target ATA host |
@@ -315,24 +282,18 @@ void ata_acpi_associate(struct ata_host *host) | |||
315 | ata_acpi_associate_ide_port(ap); | 282 | ata_acpi_associate_ide_port(ap); |
316 | 283 | ||
317 | if (ap->acpi_handle) { | 284 | if (ap->acpi_handle) { |
318 | acpi_install_notify_handler(ap->acpi_handle, | ||
319 | ACPI_SYSTEM_NOTIFY, | ||
320 | ata_acpi_ap_notify, ap); | ||
321 | /* we might be on a docking station */ | 285 | /* we might be on a docking station */ |
322 | register_hotplug_dock_device(ap->acpi_handle, | 286 | register_hotplug_dock_device(ap->acpi_handle, |
323 | ata_acpi_ap_notify_dock, ap); | 287 | &ata_acpi_ap_dock_ops, ap); |
324 | } | 288 | } |
325 | 289 | ||
326 | for (j = 0; j < ata_link_max_devices(&ap->link); j++) { | 290 | for (j = 0; j < ata_link_max_devices(&ap->link); j++) { |
327 | struct ata_device *dev = &ap->link.device[j]; | 291 | struct ata_device *dev = &ap->link.device[j]; |
328 | 292 | ||
329 | if (dev->acpi_handle) { | 293 | if (dev->acpi_handle) { |
330 | acpi_install_notify_handler(dev->acpi_handle, | ||
331 | ACPI_SYSTEM_NOTIFY, | ||
332 | ata_acpi_dev_notify, dev); | ||
333 | /* we might be on a docking station */ | 294 | /* we might be on a docking station */ |
334 | register_hotplug_dock_device(dev->acpi_handle, | 295 | register_hotplug_dock_device(dev->acpi_handle, |
335 | ata_acpi_dev_notify_dock, dev); | 296 | &ata_acpi_dev_dock_ops, dev); |
336 | } | 297 | } |
337 | } | 298 | } |
338 | } | 299 | } |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a3e4705dd8f0..db54c5ef2aa5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, | |||
169 | } | 169 | } |
170 | 170 | ||
171 | 171 | ||
172 | 172 | static struct acpi_dock_ops acpiphp_dock_ops = { | |
173 | .handler = handle_hotplug_event_func, | ||
174 | }; | ||
173 | 175 | ||
174 | /* callback routine to register each ACPI PCI slot object */ | 176 | /* callback routine to register each ACPI PCI slot object */ |
175 | static acpi_status | 177 | static acpi_status |
@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
285 | */ | 287 | */ |
286 | newfunc->flags &= ~FUNC_HAS_EJ0; | 288 | newfunc->flags &= ~FUNC_HAS_EJ0; |
287 | if (register_hotplug_dock_device(handle, | 289 | if (register_hotplug_dock_device(handle, |
288 | handle_hotplug_event_func, newfunc)) | 290 | &acpiphp_dock_ops, newfunc)) |
289 | dbg("failed to register dock device\n"); | 291 | dbg("failed to register dock device\n"); |
290 | 292 | ||
291 | /* we need to be notified when dock events happen | 293 | /* we need to be notified when dock events happen |