]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.arch/acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch
Updated xen patches taken from suse.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.arch / acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch
1 From: Shaohua Li <shaohua.li@intel.com>
2 Subject: makeing dock driver supports bay and battery hotplug
3 Patch-mainline: submitted 2008-08-28
4 References: fate#304731,bnc#401740
5
6 Making dock driver supports bay and battery hotplug. They are all
7 regarded as dock, and unified handled.
8
9 Signed-off-by: Shaohua Li <shaohua.li@intel.com>
10 Signed-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);