]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.arch/acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch
CommitLineData
2cb7cef9
BS
1From: Shaohua Li <shaohua.li@intel.com>
2Subject: makeing dock driver supports bay and battery hotplug
3Patch-mainline: submitted 2008-08-28
4References: fate#304731,bnc#401740
5
6Making dock driver supports bay and battery hotplug. They are all
7regarded as dock, and unified handled.
8
9Signed-off-by: Shaohua Li <shaohua.li@intel.com>
10Signed-off-by: Holger Macht <hmacht@suse.de>
11---
12
13---
14 drivers/acpi/dock.c | 221 ++++++++++++++++++++++++++++++++++++++++------------
15 1 file changed, 173 insertions(+), 48 deletions(-)
16
17--- a/drivers/acpi/dock.c
18+++ b/drivers/acpi/dock.c
19@@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (d
20 " before undocking");
21
22 static struct atomic_notifier_head dock_notifier_list;
23-static struct platform_device *dock_device;
24 static char dock_device_name[] = "dock";
25
26 static const struct acpi_device_id dock_device_ids[] = {
27@@ -65,7 +64,12 @@ struct dock_station {
28 struct mutex hp_lock;
29 struct list_head dependent_devices;
30 struct list_head hotplug_devices;
31+
32+ struct list_head sibiling;
33+ struct platform_device *dock_device;
34 };
35+static LIST_HEAD(dock_stations);
36+static int dock_station_count;
37
38 struct dock_dependent_device {
39 struct list_head list;
40@@ -77,11 +81,12 @@ struct dock_dependent_device {
41
42 #define DOCK_DOCKING 0x00000001
43 #define DOCK_UNDOCKING 0x00000002
44+#define DOCK_IS_DOCK 0x00000010
45+#define DOCK_IS_ATA 0x00000020
46+#define DOCK_IS_BAT 0x00000040
47 #define DOCK_EVENT 3
48 #define UNDOCK_EVENT 2
49
50-static struct dock_station *dock_station;
51-
52 /*****************************************************************************
53 * Dock Dependent device functions *
54 *****************************************************************************/
55@@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle)
56 return 1;
57 }
58
59+static int is_ejectable(acpi_handle handle)
60+{
61+ acpi_status status;
62+ acpi_handle tmp;
63+
64+ status = acpi_get_handle(handle, "_EJ0", &tmp);
65+ if (ACPI_FAILURE(status))
66+ return 0;
67+ return 1;
68+}
69+
70+static int is_ata(acpi_handle handle)
71+{
72+ acpi_handle tmp;
73+
74+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
75+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
76+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
77+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
78+ return 1;
79+
80+ return 0;
81+}
82+
83+static int is_battery(acpi_handle handle)
84+{
85+ struct acpi_device_info *info;
86+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
87+ int ret = 1;
88+
89+ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer)))
90+ return 0;
91+ info = buffer.pointer;
92+ if (!(info->valid & ACPI_VALID_HID))
93+ ret = 0;
94+ else
95+ ret = !strcmp("PNP0C0A", info->hardware_id.value);
96+
97+ kfree(buffer.pointer);
98+ return ret;
99+}
100+
101+static int is_ejectable_bay(acpi_handle handle)
102+{
103+ acpi_handle phandle;
104+ if (!is_ejectable(handle))
105+ return 0;
106+ if (is_battery(handle) || is_ata(handle))
107+ return 1;
108+ if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
109+ return 1;
110+ return 0;
111+}
112+
113 /**
114 * is_dock_device - see if a device is on a dock station
115 * @handle: acpi handle of the device
116@@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle)
117 */
118 int is_dock_device(acpi_handle handle)
119 {
120- if (!dock_station)
121+ struct dock_station *dock_station;
122+
123+ if (!dock_station_count)
124 return 0;
125
126- if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
127+ if (is_dock(handle))
128 return 1;
129+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
130+ if (find_dock_dependent_device(dock_station, handle))
131+ return 1;
132+ }
133
134 return 0;
135 }
136@@ -341,7 +406,7 @@ static void hotplug_dock_devices(struct
137
138 static void dock_event(struct dock_station *ds, u32 event, int num)
139 {
140- struct device *dev = &dock_device->dev;
141+ struct device *dev = &ds->dock_device->dev;
142 char event_string[13];
143 char *envp[] = { event_string, NULL };
144
145@@ -414,7 +479,7 @@ static void handle_dock(struct dock_stat
146 arg.type = ACPI_TYPE_INTEGER;
147 arg.integer.value = dock;
148 status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
149- if (ACPI_FAILURE(status))
150+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
151 printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
152 (char *)name_buffer.pointer);
153 kfree(buffer.pointer);
154@@ -498,7 +563,7 @@ static int dock_in_progress(struct dock_
155 */
156 int register_dock_notifier(struct notifier_block *nb)
157 {
158- if (!dock_station)
159+ if (!dock_station_count)
160 return -ENODEV;
161
162 return atomic_notifier_chain_register(&dock_notifier_list, nb);
163@@ -512,7 +577,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier
164 */
165 void unregister_dock_notifier(struct notifier_block *nb)
166 {
167- if (!dock_station)
168+ if (!dock_station_count)
169 return;
170
171 atomic_notifier_chain_unregister(&dock_notifier_list, nb);
172@@ -535,20 +600,23 @@ register_hotplug_dock_device(acpi_handle
173 void *context)
174 {
175 struct dock_dependent_device *dd;
176+ struct dock_station *dock_station;
177
178- if (!dock_station)
179+ if (!dock_station_count)
180 return -ENODEV;
181
182 /*
183 * make sure this handle is for a device dependent on the dock,
184 * this would include the dock station itself
185 */
186- dd = find_dock_dependent_device(dock_station, handle);
187- if (dd) {
188- dd->handler = handler;
189- dd->context = context;
190- dock_add_hotplug_device(dock_station, dd);
191- return 0;
192+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
193+ dd = find_dock_dependent_device(dock_station, handle);
194+ if (dd) {
195+ dd->handler = handler;
196+ dd->context = context;
197+ dock_add_hotplug_device(dock_station, dd);
198+ return 0;
199+ }
200 }
201
202 return -EINVAL;
203@@ -563,13 +631,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_
204 void unregister_hotplug_dock_device(acpi_handle handle)
205 {
206 struct dock_dependent_device *dd;
207+ struct dock_station *dock_station;
208
209- if (!dock_station)
210+ if (!dock_station_count)
211 return;
212
213- dd = find_dock_dependent_device(dock_station, handle);
214- if (dd)
215- dock_del_hotplug_device(dock_station, dd);
216+ list_for_each_entry(dock_station, &dock_stations, sibiling) {
217+ dd = find_dock_dependent_device(dock_station, handle);
218+ if (dd)
219+ dock_del_hotplug_device(dock_station, dd);
220+ }
221 }
222
223 EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
224@@ -620,9 +691,28 @@ static void dock_notify(acpi_handle hand
225 {
226 struct dock_station *ds = data;
227 struct acpi_device *tmp;
228+ int surprise_removal = 0;
229
230+ /*
231+ * According to acpi spec 3.0a, if a DEVICE_CHECK notification
232+ * is sent and _DCK is present, it is assumed to mean an undock
233+ * request.
234+ */
235+ if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
236+ event = ACPI_NOTIFY_EJECT_REQUEST;
237+
238+ /*
239+ * dock station: BUS_CHECK - docked or surprise removal
240+ * DEVICE_CHECK - undocked
241+ * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
242+ *
243+ * To simplify event handling, dock dependent device handler always
244+ * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
245+ * ACPI_NOTIFY_EJECT_REQUEST for removal
246+ */
247 switch (event) {
248 case ACPI_NOTIFY_BUS_CHECK:
249+ case ACPI_NOTIFY_DEVICE_CHECK:
250 if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
251 &tmp)) {
252 begin_dock(ds);
253@@ -638,20 +728,17 @@ static void dock_notify(acpi_handle hand
254 complete_dock(ds);
255 dock_event(ds, event, DOCK_EVENT);
256 dock_lock(ds, 1);
257+ break;
258 }
259- break;
260- case ACPI_NOTIFY_DEVICE_CHECK:
261- /*
262- * According to acpi spec 3.0a, if a DEVICE_CHECK notification
263- * is sent and _DCK is present, it is assumed to mean an
264- * undock request. This notify routine will only be called
265- * for objects defining _DCK, so we will fall through to eject
266- * request here. However, we will pass an eject request through
267- * to the driver who wish to hotplug.
268- */
269+ if (dock_present(ds) || dock_in_progress(ds))
270+ break;
271+ /* This is a surprise removal */
272+ surprise_removal = 1;
273+ event = ACPI_NOTIFY_EJECT_REQUEST;
274+ /* Fall back */
275 case ACPI_NOTIFY_EJECT_REQUEST:
276 begin_undock(ds);
277- if (immediate_undock)
278+ if (immediate_undock || surprise_removal)
279 handle_eject_request(ds, event);
280 else
281 dock_event(ds, event, UNDOCK_EVENT);
282@@ -718,6 +805,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show
283 static ssize_t show_flags(struct device *dev,
284 struct device_attribute *attr, char *buf)
285 {
286+ struct dock_station *dock_station = *((struct dock_station **)
287+ dev->platform_data);
288 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
289
290 }
291@@ -730,6 +819,8 @@ static ssize_t write_undock(struct devic
292 const char *buf, size_t count)
293 {
294 int ret;
295+ struct dock_station *dock_station = *((struct dock_station **)
296+ dev->platform_data);
297
298 if (!count)
299 return -EINVAL;
300@@ -747,6 +838,8 @@ static ssize_t show_dock_uid(struct devi
301 struct device_attribute *attr, char *buf)
302 {
303 unsigned long long lbuf;
304+ struct dock_station *dock_station = *((struct dock_station **)
305+ dev->platform_data);
306 acpi_status status = acpi_evaluate_integer(dock_station->handle,
307 "_UID", NULL, &lbuf);
308 if (ACPI_FAILURE(status))
309@@ -768,6 +861,8 @@ static int dock_add(acpi_handle handle)
310 int ret;
311 acpi_status status;
312 struct dock_dependent_device *dd;
313+ struct dock_station *dock_station;
314+ struct platform_device *dock_device;
315
316 /* allocate & initialize the dock_station private data */
317 dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
318@@ -777,22 +872,34 @@ static int dock_add(acpi_handle handle)
319 dock_station->last_dock_time = jiffies - HZ;
320 INIT_LIST_HEAD(&dock_station->dependent_devices);
321 INIT_LIST_HEAD(&dock_station->hotplug_devices);
322+ INIT_LIST_HEAD(&dock_station->sibiling);
323 spin_lock_init(&dock_station->dd_lock);
324 mutex_init(&dock_station->hp_lock);
325 ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
326
327 /* initialize platform device stuff */
328- dock_device =
329- platform_device_register_simple(dock_device_name, 0, NULL, 0);
330+ dock_station->dock_device =
331+ platform_device_register_simple(dock_device_name,
332+ dock_station_count, NULL, 0);
333+ dock_device = dock_station->dock_device;
334 if (IS_ERR(dock_device)) {
335 kfree(dock_station);
336 dock_station = NULL;
337 return PTR_ERR(dock_device);
338 }
339+ platform_device_add_data(dock_device, &dock_station,
340+ sizeof(struct dock_station *));
341
342 /* we want the dock device to send uevents */
343 dock_device->dev.uevent_suppress = 0;
344
345+ if (is_dock(handle))
346+ dock_station->flags |= DOCK_IS_DOCK;
347+ if (is_ata(handle))
348+ dock_station->flags |= DOCK_IS_ATA;
349+ if (is_battery(handle))
350+ dock_station->flags |= DOCK_IS_BAT;
351+
352 ret = device_create_file(&dock_device->dev, &dev_attr_docked);
353 if (ret) {
354 printk("Error %d adding sysfs file\n", ret);
355@@ -858,8 +965,8 @@ static int dock_add(acpi_handle handle)
356 goto dock_add_err;
357 }
358
359- printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
360-
361+ dock_station_count++;
362+ list_add(&dock_station->sibiling, &dock_stations);
363 return 0;
364
365 dock_add_err:
366@@ -878,12 +985,13 @@ dock_add_err_unregister:
367 /**
368 * dock_remove - free up resources related to the dock station
369 */
370-static int dock_remove(void)
371+static int dock_remove(struct dock_station *dock_station)
372 {
373 struct dock_dependent_device *dd, *tmp;
374 acpi_status status;
375+ struct platform_device *dock_device = dock_station->dock_device;
376
377- if (!dock_station)
378+ if (!dock_station_count)
379 return 0;
380
381 /* remove dependent devices */
382@@ -923,41 +1031,58 @@ static int dock_remove(void)
383 static acpi_status
384 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
385 {
386- int *count = context;
387 acpi_status status = AE_OK;
388
389 if (is_dock(handle)) {
390 if (dock_add(handle) >= 0) {
391- (*count)++;
392 status = AE_CTRL_TERMINATE;
393 }
394 }
395 return status;
396 }
397
398-static int __init dock_init(void)
399+static acpi_status
400+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
401 {
402- int num = 0;
403-
404- dock_station = NULL;
405+ /* If bay is in a dock, it's already handled */
406+ if (is_ejectable_bay(handle) && !is_dock_device(handle))
407+ dock_add(handle);
408+ return AE_OK;
409+}
410
411+static int __init dock_init(void)
412+{
413 if (acpi_disabled)
414 return 0;
415
416 /* look for a dock station */
417 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
418- ACPI_UINT32_MAX, find_dock, &num, NULL);
419+ ACPI_UINT32_MAX, find_dock, NULL, NULL);
420
421- if (!num)
422- printk(KERN_INFO "No dock devices found.\n");
423+ /* look for bay */
424+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
425+ ACPI_UINT32_MAX, find_bay, NULL, NULL);
426+ if (!dock_station_count) {
427+ printk(KERN_INFO PREFIX "No dock devices found.\n");
428+ return 0;
429+ }
430
431+ printk(KERN_INFO PREFIX "%s: %d docks/bays found\n",
432+ ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
433 return 0;
434 }
435
436 static void __exit dock_exit(void)
437 {
438- dock_remove();
439+ struct dock_station *dock_station;
440+
441+ list_for_each_entry(dock_station, &dock_stations, sibiling)
442+ dock_remove(dock_station);
443 }
444
445-postcore_initcall(dock_init);
446+/*
447+ * Must be called before drivers of devices in dock, otherwise we can't know
448+ * which devices are in a dock
449+ */
450+subsys_initcall(dock_init);
451 module_exit(dock_exit);