diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/Kconfig | 12 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/x86/classmate-laptop.c | 609 | ||||
-rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c | 30 | ||||
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 150 | ||||
-rw-r--r-- | drivers/platform/x86/tc1100-wmi.c | 115 |
6 files changed, 792 insertions, 125 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index fc5bf9d2a3f3..ec4faffe6b05 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -464,4 +464,16 @@ config TOSHIBA_BT_RFKILL | |||
464 | 464 | ||
465 | If you have a modern Toshiba laptop with a Bluetooth and an | 465 | If you have a modern Toshiba laptop with a Bluetooth and an |
466 | RFKill switch (such as the Portege R500), say Y. | 466 | RFKill switch (such as the Portege R500), say Y. |
467 | |||
468 | config ACPI_CMPC | ||
469 | tristate "CMPC Laptop Extras" | ||
470 | depends on X86 && ACPI | ||
471 | select INPUT | ||
472 | select BACKLIGHT_CLASS_DEVICE | ||
473 | default n | ||
474 | help | ||
475 | Support for Intel Classmate PC ACPI devices, including some | ||
476 | keys as input device, backlight device, tablet and accelerometer | ||
477 | devices. | ||
478 | |||
467 | endif # X86_PLATFORM_DEVICES | 479 | endif # X86_PLATFORM_DEVICES |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index b7474b6a8bf1..9cd9fa0a27e6 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o | 5 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o |
6 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o | 6 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o |
7 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o | 7 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o |
8 | obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o | ||
8 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o | 9 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o |
9 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o | 10 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o |
10 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o | 11 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o |
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c new file mode 100644 index 000000000000..ed90082cdf1d --- /dev/null +++ b/drivers/platform/x86/classmate-laptop.c | |||
@@ -0,0 +1,609 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | */ | ||
18 | |||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/workqueue.h> | ||
23 | #include <acpi/acpi_drivers.h> | ||
24 | #include <linux/backlight.h> | ||
25 | #include <linux/input.h> | ||
26 | |||
27 | MODULE_LICENSE("GPL"); | ||
28 | |||
29 | |||
30 | struct cmpc_accel { | ||
31 | int sensitivity; | ||
32 | }; | ||
33 | |||
34 | #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 | ||
35 | |||
36 | |||
37 | /* | ||
38 | * Generic input device code. | ||
39 | */ | ||
40 | |||
41 | typedef void (*input_device_init)(struct input_dev *dev); | ||
42 | |||
43 | static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name, | ||
44 | input_device_init idev_init) | ||
45 | { | ||
46 | struct input_dev *inputdev; | ||
47 | int error; | ||
48 | |||
49 | inputdev = input_allocate_device(); | ||
50 | if (!inputdev) | ||
51 | return -ENOMEM; | ||
52 | inputdev->name = name; | ||
53 | inputdev->dev.parent = &acpi->dev; | ||
54 | idev_init(inputdev); | ||
55 | error = input_register_device(inputdev); | ||
56 | if (error) { | ||
57 | input_free_device(inputdev); | ||
58 | return error; | ||
59 | } | ||
60 | dev_set_drvdata(&acpi->dev, inputdev); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi) | ||
65 | { | ||
66 | struct input_dev *inputdev = dev_get_drvdata(&acpi->dev); | ||
67 | input_unregister_device(inputdev); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Accelerometer code. | ||
73 | */ | ||
74 | static acpi_status cmpc_start_accel(acpi_handle handle) | ||
75 | { | ||
76 | union acpi_object param[2]; | ||
77 | struct acpi_object_list input; | ||
78 | acpi_status status; | ||
79 | |||
80 | param[0].type = ACPI_TYPE_INTEGER; | ||
81 | param[0].integer.value = 0x3; | ||
82 | param[1].type = ACPI_TYPE_INTEGER; | ||
83 | input.count = 2; | ||
84 | input.pointer = param; | ||
85 | status = acpi_evaluate_object(handle, "ACMD", &input, NULL); | ||
86 | return status; | ||
87 | } | ||
88 | |||
89 | static acpi_status cmpc_stop_accel(acpi_handle handle) | ||
90 | { | ||
91 | union acpi_object param[2]; | ||
92 | struct acpi_object_list input; | ||
93 | acpi_status status; | ||
94 | |||
95 | param[0].type = ACPI_TYPE_INTEGER; | ||
96 | param[0].integer.value = 0x4; | ||
97 | param[1].type = ACPI_TYPE_INTEGER; | ||
98 | input.count = 2; | ||
99 | input.pointer = param; | ||
100 | status = acpi_evaluate_object(handle, "ACMD", &input, NULL); | ||
101 | return status; | ||
102 | } | ||
103 | |||
104 | static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val) | ||
105 | { | ||
106 | union acpi_object param[2]; | ||
107 | struct acpi_object_list input; | ||
108 | |||
109 | param[0].type = ACPI_TYPE_INTEGER; | ||
110 | param[0].integer.value = 0x02; | ||
111 | param[1].type = ACPI_TYPE_INTEGER; | ||
112 | param[1].integer.value = val; | ||
113 | input.count = 2; | ||
114 | input.pointer = param; | ||
115 | return acpi_evaluate_object(handle, "ACMD", &input, NULL); | ||
116 | } | ||
117 | |||
118 | static acpi_status cmpc_get_accel(acpi_handle handle, | ||
119 | unsigned char *x, | ||
120 | unsigned char *y, | ||
121 | unsigned char *z) | ||
122 | { | ||
123 | union acpi_object param[2]; | ||
124 | struct acpi_object_list input; | ||
125 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 }; | ||
126 | unsigned char *locs; | ||
127 | acpi_status status; | ||
128 | |||
129 | param[0].type = ACPI_TYPE_INTEGER; | ||
130 | param[0].integer.value = 0x01; | ||
131 | param[1].type = ACPI_TYPE_INTEGER; | ||
132 | input.count = 2; | ||
133 | input.pointer = param; | ||
134 | status = acpi_evaluate_object(handle, "ACMD", &input, &output); | ||
135 | if (ACPI_SUCCESS(status)) { | ||
136 | union acpi_object *obj; | ||
137 | obj = output.pointer; | ||
138 | locs = obj->buffer.pointer; | ||
139 | *x = locs[0]; | ||
140 | *y = locs[1]; | ||
141 | *z = locs[2]; | ||
142 | kfree(output.pointer); | ||
143 | } | ||
144 | return status; | ||
145 | } | ||
146 | |||
147 | static void cmpc_accel_handler(struct acpi_device *dev, u32 event) | ||
148 | { | ||
149 | if (event == 0x81) { | ||
150 | unsigned char x, y, z; | ||
151 | acpi_status status; | ||
152 | |||
153 | status = cmpc_get_accel(dev->handle, &x, &y, &z); | ||
154 | if (ACPI_SUCCESS(status)) { | ||
155 | struct input_dev *inputdev = dev_get_drvdata(&dev->dev); | ||
156 | |||
157 | input_report_abs(inputdev, ABS_X, x); | ||
158 | input_report_abs(inputdev, ABS_Y, y); | ||
159 | input_report_abs(inputdev, ABS_Z, z); | ||
160 | input_sync(inputdev); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static ssize_t cmpc_accel_sensitivity_show(struct device *dev, | ||
166 | struct device_attribute *attr, | ||
167 | char *buf) | ||
168 | { | ||
169 | struct acpi_device *acpi; | ||
170 | struct input_dev *inputdev; | ||
171 | struct cmpc_accel *accel; | ||
172 | |||
173 | acpi = to_acpi_device(dev); | ||
174 | inputdev = dev_get_drvdata(&acpi->dev); | ||
175 | accel = dev_get_drvdata(&inputdev->dev); | ||
176 | |||
177 | return sprintf(buf, "%d\n", accel->sensitivity); | ||
178 | } | ||
179 | |||
180 | static ssize_t cmpc_accel_sensitivity_store(struct device *dev, | ||
181 | struct device_attribute *attr, | ||
182 | const char *buf, size_t count) | ||
183 | { | ||
184 | struct acpi_device *acpi; | ||
185 | struct input_dev *inputdev; | ||
186 | struct cmpc_accel *accel; | ||
187 | unsigned long sensitivity; | ||
188 | int r; | ||
189 | |||
190 | acpi = to_acpi_device(dev); | ||
191 | inputdev = dev_get_drvdata(&acpi->dev); | ||
192 | accel = dev_get_drvdata(&inputdev->dev); | ||
193 | |||
194 | r = strict_strtoul(buf, 0, &sensitivity); | ||
195 | if (r) | ||
196 | return r; | ||
197 | |||
198 | accel->sensitivity = sensitivity; | ||
199 | cmpc_accel_set_sensitivity(acpi->handle, sensitivity); | ||
200 | |||
201 | return strnlen(buf, count); | ||
202 | } | ||
203 | |||
204 | struct device_attribute cmpc_accel_sensitivity_attr = { | ||
205 | .attr = { .name = "sensitivity", .mode = 0660 }, | ||
206 | .show = cmpc_accel_sensitivity_show, | ||
207 | .store = cmpc_accel_sensitivity_store | ||
208 | }; | ||
209 | |||
210 | static int cmpc_accel_open(struct input_dev *input) | ||
211 | { | ||
212 | struct acpi_device *acpi; | ||
213 | |||
214 | acpi = to_acpi_device(input->dev.parent); | ||
215 | if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle))) | ||
216 | return 0; | ||
217 | return -EIO; | ||
218 | } | ||
219 | |||
220 | static void cmpc_accel_close(struct input_dev *input) | ||
221 | { | ||
222 | struct acpi_device *acpi; | ||
223 | |||
224 | acpi = to_acpi_device(input->dev.parent); | ||
225 | cmpc_stop_accel(acpi->handle); | ||
226 | } | ||
227 | |||
228 | static void cmpc_accel_idev_init(struct input_dev *inputdev) | ||
229 | { | ||
230 | set_bit(EV_ABS, inputdev->evbit); | ||
231 | input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0); | ||
232 | input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0); | ||
233 | input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0); | ||
234 | inputdev->open = cmpc_accel_open; | ||
235 | inputdev->close = cmpc_accel_close; | ||
236 | } | ||
237 | |||
238 | static int cmpc_accel_add(struct acpi_device *acpi) | ||
239 | { | ||
240 | int error; | ||
241 | struct input_dev *inputdev; | ||
242 | struct cmpc_accel *accel; | ||
243 | |||
244 | accel = kmalloc(sizeof(*accel), GFP_KERNEL); | ||
245 | if (!accel) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT; | ||
249 | cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity); | ||
250 | |||
251 | error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr); | ||
252 | if (error) | ||
253 | goto failed_file; | ||
254 | |||
255 | error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel", | ||
256 | cmpc_accel_idev_init); | ||
257 | if (error) | ||
258 | goto failed_input; | ||
259 | |||
260 | inputdev = dev_get_drvdata(&acpi->dev); | ||
261 | dev_set_drvdata(&inputdev->dev, accel); | ||
262 | |||
263 | return 0; | ||
264 | |||
265 | failed_input: | ||
266 | device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr); | ||
267 | failed_file: | ||
268 | kfree(accel); | ||
269 | return error; | ||
270 | } | ||
271 | |||
272 | static int cmpc_accel_remove(struct acpi_device *acpi, int type) | ||
273 | { | ||
274 | struct input_dev *inputdev; | ||
275 | struct cmpc_accel *accel; | ||
276 | |||
277 | inputdev = dev_get_drvdata(&acpi->dev); | ||
278 | accel = dev_get_drvdata(&inputdev->dev); | ||
279 | |||
280 | device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr); | ||
281 | return cmpc_remove_acpi_notify_device(acpi); | ||
282 | } | ||
283 | |||
284 | static const struct acpi_device_id cmpc_accel_device_ids[] = { | ||
285 | {"ACCE0000", 0}, | ||
286 | {"", 0} | ||
287 | }; | ||
288 | MODULE_DEVICE_TABLE(acpi, cmpc_accel_device_ids); | ||
289 | |||
290 | static struct acpi_driver cmpc_accel_acpi_driver = { | ||
291 | .owner = THIS_MODULE, | ||
292 | .name = "cmpc_accel", | ||
293 | .class = "cmpc_accel", | ||
294 | .ids = cmpc_accel_device_ids, | ||
295 | .ops = { | ||
296 | .add = cmpc_accel_add, | ||
297 | .remove = cmpc_accel_remove, | ||
298 | .notify = cmpc_accel_handler, | ||
299 | } | ||
300 | }; | ||
301 | |||
302 | |||
303 | /* | ||
304 | * Tablet mode code. | ||
305 | */ | ||
306 | static acpi_status cmpc_get_tablet(acpi_handle handle, | ||
307 | unsigned long long *value) | ||
308 | { | ||
309 | union acpi_object param; | ||
310 | struct acpi_object_list input; | ||
311 | unsigned long long output; | ||
312 | acpi_status status; | ||
313 | |||
314 | param.type = ACPI_TYPE_INTEGER; | ||
315 | param.integer.value = 0x01; | ||
316 | input.count = 1; | ||
317 | input.pointer = ¶m; | ||
318 | status = acpi_evaluate_integer(handle, "TCMD", &input, &output); | ||
319 | if (ACPI_SUCCESS(status)) | ||
320 | *value = output; | ||
321 | return status; | ||
322 | } | ||
323 | |||
324 | static void cmpc_tablet_handler(struct acpi_device *dev, u32 event) | ||
325 | { | ||
326 | unsigned long long val = 0; | ||
327 | struct input_dev *inputdev = dev_get_drvdata(&dev->dev); | ||
328 | |||
329 | if (event == 0x81) { | ||
330 | if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) | ||
331 | input_report_switch(inputdev, SW_TABLET_MODE, !val); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | static void cmpc_tablet_idev_init(struct input_dev *inputdev) | ||
336 | { | ||
337 | unsigned long long val = 0; | ||
338 | struct acpi_device *acpi; | ||
339 | |||
340 | set_bit(EV_SW, inputdev->evbit); | ||
341 | set_bit(SW_TABLET_MODE, inputdev->swbit); | ||
342 | |||
343 | acpi = to_acpi_device(inputdev->dev.parent); | ||
344 | if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) | ||
345 | input_report_switch(inputdev, SW_TABLET_MODE, !val); | ||
346 | } | ||
347 | |||
348 | static int cmpc_tablet_add(struct acpi_device *acpi) | ||
349 | { | ||
350 | return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet", | ||
351 | cmpc_tablet_idev_init); | ||
352 | } | ||
353 | |||
354 | static int cmpc_tablet_remove(struct acpi_device *acpi, int type) | ||
355 | { | ||
356 | return cmpc_remove_acpi_notify_device(acpi); | ||
357 | } | ||
358 | |||
359 | static int cmpc_tablet_resume(struct acpi_device *acpi) | ||
360 | { | ||
361 | struct input_dev *inputdev = dev_get_drvdata(&acpi->dev); | ||
362 | unsigned long long val = 0; | ||
363 | if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) | ||
364 | input_report_switch(inputdev, SW_TABLET_MODE, !val); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static const struct acpi_device_id cmpc_tablet_device_ids[] = { | ||
369 | {"TBLT0000", 0}, | ||
370 | {"", 0} | ||
371 | }; | ||
372 | MODULE_DEVICE_TABLE(acpi, cmpc_tablet_device_ids); | ||
373 | |||
374 | static struct acpi_driver cmpc_tablet_acpi_driver = { | ||
375 | .owner = THIS_MODULE, | ||
376 | .name = "cmpc_tablet", | ||
377 | .class = "cmpc_tablet", | ||
378 | .ids = cmpc_tablet_device_ids, | ||
379 | .ops = { | ||
380 | .add = cmpc_tablet_add, | ||
381 | .remove = cmpc_tablet_remove, | ||
382 | .resume = cmpc_tablet_resume, | ||
383 | .notify = cmpc_tablet_handler, | ||
384 | } | ||
385 | }; | ||
386 | |||
387 | |||
388 | /* | ||
389 | * Backlight code. | ||
390 | */ | ||
391 | |||
392 | static acpi_status cmpc_get_brightness(acpi_handle handle, | ||
393 | unsigned long long *value) | ||
394 | { | ||
395 | union acpi_object param; | ||
396 | struct acpi_object_list input; | ||
397 | unsigned long long output; | ||
398 | acpi_status status; | ||
399 | |||
400 | param.type = ACPI_TYPE_INTEGER; | ||
401 | param.integer.value = 0xC0; | ||
402 | input.count = 1; | ||
403 | input.pointer = ¶m; | ||
404 | status = acpi_evaluate_integer(handle, "GRDI", &input, &output); | ||
405 | if (ACPI_SUCCESS(status)) | ||
406 | *value = output; | ||
407 | return status; | ||
408 | } | ||
409 | |||
410 | static acpi_status cmpc_set_brightness(acpi_handle handle, | ||
411 | unsigned long long value) | ||
412 | { | ||
413 | union acpi_object param[2]; | ||
414 | struct acpi_object_list input; | ||
415 | acpi_status status; | ||
416 | unsigned long long output; | ||
417 | |||
418 | param[0].type = ACPI_TYPE_INTEGER; | ||
419 | param[0].integer.value = 0xC0; | ||
420 | param[1].type = ACPI_TYPE_INTEGER; | ||
421 | param[1].integer.value = value; | ||
422 | input.count = 2; | ||
423 | input.pointer = param; | ||
424 | status = acpi_evaluate_integer(handle, "GWRI", &input, &output); | ||
425 | return status; | ||
426 | } | ||
427 | |||
428 | static int cmpc_bl_get_brightness(struct backlight_device *bd) | ||
429 | { | ||
430 | acpi_status status; | ||
431 | acpi_handle handle; | ||
432 | unsigned long long brightness; | ||
433 | |||
434 | handle = bl_get_data(bd); | ||
435 | status = cmpc_get_brightness(handle, &brightness); | ||
436 | if (ACPI_SUCCESS(status)) | ||
437 | return brightness; | ||
438 | else | ||
439 | return -1; | ||
440 | } | ||
441 | |||
442 | static int cmpc_bl_update_status(struct backlight_device *bd) | ||
443 | { | ||
444 | acpi_status status; | ||
445 | acpi_handle handle; | ||
446 | |||
447 | handle = bl_get_data(bd); | ||
448 | status = cmpc_set_brightness(handle, bd->props.brightness); | ||
449 | if (ACPI_SUCCESS(status)) | ||
450 | return 0; | ||
451 | else | ||
452 | return -1; | ||
453 | } | ||
454 | |||
455 | static struct backlight_ops cmpc_bl_ops = { | ||
456 | .get_brightness = cmpc_bl_get_brightness, | ||
457 | .update_status = cmpc_bl_update_status | ||
458 | }; | ||
459 | |||
460 | static int cmpc_bl_add(struct acpi_device *acpi) | ||
461 | { | ||
462 | struct backlight_device *bd; | ||
463 | |||
464 | bd = backlight_device_register("cmpc_bl", &acpi->dev, | ||
465 | acpi->handle, &cmpc_bl_ops); | ||
466 | bd->props.max_brightness = 7; | ||
467 | dev_set_drvdata(&acpi->dev, bd); | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int cmpc_bl_remove(struct acpi_device *acpi, int type) | ||
472 | { | ||
473 | struct backlight_device *bd; | ||
474 | |||
475 | bd = dev_get_drvdata(&acpi->dev); | ||
476 | backlight_device_unregister(bd); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static const struct acpi_device_id cmpc_device_ids[] = { | ||
481 | {"IPML200", 0}, | ||
482 | {"", 0} | ||
483 | }; | ||
484 | MODULE_DEVICE_TABLE(acpi, cmpc_device_ids); | ||
485 | |||
486 | static struct acpi_driver cmpc_bl_acpi_driver = { | ||
487 | .owner = THIS_MODULE, | ||
488 | .name = "cmpc", | ||
489 | .class = "cmpc", | ||
490 | .ids = cmpc_device_ids, | ||
491 | .ops = { | ||
492 | .add = cmpc_bl_add, | ||
493 | .remove = cmpc_bl_remove | ||
494 | } | ||
495 | }; | ||
496 | |||
497 | |||
498 | /* | ||
499 | * Extra keys code. | ||
500 | */ | ||
501 | static int cmpc_keys_codes[] = { | ||
502 | KEY_UNKNOWN, | ||
503 | KEY_WLAN, | ||
504 | KEY_SWITCHVIDEOMODE, | ||
505 | KEY_BRIGHTNESSDOWN, | ||
506 | KEY_BRIGHTNESSUP, | ||
507 | KEY_VENDOR, | ||
508 | KEY_MAX | ||
509 | }; | ||
510 | |||
511 | static void cmpc_keys_handler(struct acpi_device *dev, u32 event) | ||
512 | { | ||
513 | struct input_dev *inputdev; | ||
514 | int code = KEY_MAX; | ||
515 | |||
516 | if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes)) | ||
517 | code = cmpc_keys_codes[event & 0x0F]; | ||
518 | inputdev = dev_get_drvdata(&dev->dev);; | ||
519 | input_report_key(inputdev, code, !(event & 0x10)); | ||
520 | } | ||
521 | |||
522 | static void cmpc_keys_idev_init(struct input_dev *inputdev) | ||
523 | { | ||
524 | int i; | ||
525 | |||
526 | set_bit(EV_KEY, inputdev->evbit); | ||
527 | for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++) | ||
528 | set_bit(cmpc_keys_codes[i], inputdev->keybit); | ||
529 | } | ||
530 | |||
531 | static int cmpc_keys_add(struct acpi_device *acpi) | ||
532 | { | ||
533 | return cmpc_add_acpi_notify_device(acpi, "cmpc_keys", | ||
534 | cmpc_keys_idev_init); | ||
535 | } | ||
536 | |||
537 | static int cmpc_keys_remove(struct acpi_device *acpi, int type) | ||
538 | { | ||
539 | return cmpc_remove_acpi_notify_device(acpi); | ||
540 | } | ||
541 | |||
542 | static const struct acpi_device_id cmpc_keys_device_ids[] = { | ||
543 | {"FnBT0000", 0}, | ||
544 | {"", 0} | ||
545 | }; | ||
546 | MODULE_DEVICE_TABLE(acpi, cmpc_keys_device_ids); | ||
547 | |||
548 | static struct acpi_driver cmpc_keys_acpi_driver = { | ||
549 | .owner = THIS_MODULE, | ||
550 | .name = "cmpc_keys", | ||
551 | .class = "cmpc_keys", | ||
552 | .ids = cmpc_keys_device_ids, | ||
553 | .ops = { | ||
554 | .add = cmpc_keys_add, | ||
555 | .remove = cmpc_keys_remove, | ||
556 | .notify = cmpc_keys_handler, | ||
557 | } | ||
558 | }; | ||
559 | |||
560 | |||
561 | /* | ||
562 | * General init/exit code. | ||
563 | */ | ||
564 | |||
565 | static int cmpc_init(void) | ||
566 | { | ||
567 | int r; | ||
568 | |||
569 | r = acpi_bus_register_driver(&cmpc_keys_acpi_driver); | ||
570 | if (r) | ||
571 | goto failed_keys; | ||
572 | |||
573 | r = acpi_bus_register_driver(&cmpc_bl_acpi_driver); | ||
574 | if (r) | ||
575 | goto failed_bl; | ||
576 | |||
577 | r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver); | ||
578 | if (r) | ||
579 | goto failed_tablet; | ||
580 | |||
581 | r = acpi_bus_register_driver(&cmpc_accel_acpi_driver); | ||
582 | if (r) | ||
583 | goto failed_accel; | ||
584 | |||
585 | return r; | ||
586 | |||
587 | failed_accel: | ||
588 | acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); | ||
589 | |||
590 | failed_tablet: | ||
591 | acpi_bus_unregister_driver(&cmpc_bl_acpi_driver); | ||
592 | |||
593 | failed_bl: | ||
594 | acpi_bus_unregister_driver(&cmpc_keys_acpi_driver); | ||
595 | |||
596 | failed_keys: | ||
597 | return r; | ||
598 | } | ||
599 | |||
600 | static void cmpc_exit(void) | ||
601 | { | ||
602 | acpi_bus_unregister_driver(&cmpc_accel_acpi_driver); | ||
603 | acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); | ||
604 | acpi_bus_unregister_driver(&cmpc_bl_acpi_driver); | ||
605 | acpi_bus_unregister_driver(&cmpc_keys_acpi_driver); | ||
606 | } | ||
607 | |||
608 | module_init(cmpc_init); | ||
609 | module_exit(cmpc_exit); | ||
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 3c2d0384b43b..5f3320d468f6 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c | |||
@@ -164,7 +164,7 @@ struct fujitsu_hotkey_t { | |||
164 | struct input_dev *input; | 164 | struct input_dev *input; |
165 | char phys[32]; | 165 | char phys[32]; |
166 | struct platform_device *pf_device; | 166 | struct platform_device *pf_device; |
167 | struct kfifo *fifo; | 167 | struct kfifo fifo; |
168 | spinlock_t fifo_lock; | 168 | spinlock_t fifo_lock; |
169 | int rfkill_supported; | 169 | int rfkill_supported; |
170 | int rfkill_state; | 170 | int rfkill_state; |
@@ -824,12 +824,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
824 | 824 | ||
825 | /* kfifo */ | 825 | /* kfifo */ |
826 | spin_lock_init(&fujitsu_hotkey->fifo_lock); | 826 | spin_lock_init(&fujitsu_hotkey->fifo_lock); |
827 | fujitsu_hotkey->fifo = | 827 | error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int), |
828 | kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL, | 828 | GFP_KERNEL); |
829 | &fujitsu_hotkey->fifo_lock); | 829 | if (error) { |
830 | if (IS_ERR(fujitsu_hotkey->fifo)) { | ||
831 | printk(KERN_ERR "kfifo_alloc failed\n"); | 830 | printk(KERN_ERR "kfifo_alloc failed\n"); |
832 | error = PTR_ERR(fujitsu_hotkey->fifo); | ||
833 | goto err_stop; | 831 | goto err_stop; |
834 | } | 832 | } |
835 | 833 | ||
@@ -934,7 +932,7 @@ err_unregister_input_dev: | |||
934 | err_free_input_dev: | 932 | err_free_input_dev: |
935 | input_free_device(input); | 933 | input_free_device(input); |
936 | err_free_fifo: | 934 | err_free_fifo: |
937 | kfifo_free(fujitsu_hotkey->fifo); | 935 | kfifo_free(&fujitsu_hotkey->fifo); |
938 | err_stop: | 936 | err_stop: |
939 | return result; | 937 | return result; |
940 | } | 938 | } |
@@ -956,7 +954,7 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type) | |||
956 | 954 | ||
957 | input_free_device(input); | 955 | input_free_device(input); |
958 | 956 | ||
959 | kfifo_free(fujitsu_hotkey->fifo); | 957 | kfifo_free(&fujitsu_hotkey->fifo); |
960 | 958 | ||
961 | fujitsu_hotkey->acpi_handle = NULL; | 959 | fujitsu_hotkey->acpi_handle = NULL; |
962 | 960 | ||
@@ -1008,9 +1006,10 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) | |||
1008 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 1006 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
1009 | "Push keycode into ringbuffer [%d]\n", | 1007 | "Push keycode into ringbuffer [%d]\n", |
1010 | keycode); | 1008 | keycode); |
1011 | status = kfifo_put(fujitsu_hotkey->fifo, | 1009 | status = kfifo_in_locked(&fujitsu_hotkey->fifo, |
1012 | (unsigned char *)&keycode, | 1010 | (unsigned char *)&keycode, |
1013 | sizeof(keycode)); | 1011 | sizeof(keycode), |
1012 | &fujitsu_hotkey->fifo_lock); | ||
1014 | if (status != sizeof(keycode)) { | 1013 | if (status != sizeof(keycode)) { |
1015 | vdbg_printk(FUJLAPTOP_DBG_WARN, | 1014 | vdbg_printk(FUJLAPTOP_DBG_WARN, |
1016 | "Could not push keycode [0x%x]\n", | 1015 | "Could not push keycode [0x%x]\n", |
@@ -1021,11 +1020,12 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) | |||
1021 | } | 1020 | } |
1022 | } else if (keycode == 0) { | 1021 | } else if (keycode == 0) { |
1023 | while ((status = | 1022 | while ((status = |
1024 | kfifo_get | 1023 | kfifo_out_locked( |
1025 | (fujitsu_hotkey->fifo, (unsigned char *) | 1024 | &fujitsu_hotkey->fifo, |
1026 | &keycode_r, | 1025 | (unsigned char *) &keycode_r, |
1027 | sizeof | 1026 | sizeof(keycode_r), |
1028 | (keycode_r))) == sizeof(keycode_r)) { | 1027 | &fujitsu_hotkey->fifo_lock)) |
1028 | == sizeof(keycode_r)) { | ||
1029 | input_report_key(input, keycode_r, 0); | 1029 | input_report_key(input, keycode_r, 0); |
1030 | input_sync(input); | 1030 | input_sync(input); |
1031 | vdbg_printk(FUJLAPTOP_DBG_TRACE, | 1031 | vdbg_printk(FUJLAPTOP_DBG_TRACE, |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 7a2cc8a5c975..5af53340da6f 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -131,6 +131,7 @@ enum sony_nc_rfkill { | |||
131 | N_SONY_RFKILL, | 131 | N_SONY_RFKILL, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static int sony_rfkill_handle; | ||
134 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; | 135 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
135 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; | 136 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
136 | static void sony_nc_rfkill_update(void); | 137 | static void sony_nc_rfkill_update(void); |
@@ -142,7 +143,7 @@ struct sony_laptop_input_s { | |||
142 | atomic_t users; | 143 | atomic_t users; |
143 | struct input_dev *jog_dev; | 144 | struct input_dev *jog_dev; |
144 | struct input_dev *key_dev; | 145 | struct input_dev *key_dev; |
145 | struct kfifo *fifo; | 146 | struct kfifo fifo; |
146 | spinlock_t fifo_lock; | 147 | spinlock_t fifo_lock; |
147 | struct workqueue_struct *wq; | 148 | struct workqueue_struct *wq; |
148 | }; | 149 | }; |
@@ -232,6 +233,7 @@ static int sony_laptop_input_index[] = { | |||
232 | 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ | 233 | 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ |
233 | 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ | 234 | 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ |
234 | -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ | 235 | -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ |
236 | 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */ | ||
235 | }; | 237 | }; |
236 | 238 | ||
237 | static int sony_laptop_input_keycode_map[] = { | 239 | static int sony_laptop_input_keycode_map[] = { |
@@ -293,6 +295,7 @@ static int sony_laptop_input_keycode_map[] = { | |||
293 | KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ | 295 | KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ |
294 | KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ | 296 | KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ |
295 | KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ | 297 | KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ |
298 | KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */ | ||
296 | }; | 299 | }; |
297 | 300 | ||
298 | /* release buttons after a short delay if pressed */ | 301 | /* release buttons after a short delay if pressed */ |
@@ -300,8 +303,9 @@ static void do_sony_laptop_release_key(struct work_struct *work) | |||
300 | { | 303 | { |
301 | struct sony_laptop_keypress kp; | 304 | struct sony_laptop_keypress kp; |
302 | 305 | ||
303 | while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, | 306 | while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp, |
304 | sizeof(kp)) == sizeof(kp)) { | 307 | sizeof(kp), &sony_laptop_input.fifo_lock) |
308 | == sizeof(kp)) { | ||
305 | msleep(10); | 309 | msleep(10); |
306 | input_report_key(kp.dev, kp.key, 0); | 310 | input_report_key(kp.dev, kp.key, 0); |
307 | input_sync(kp.dev); | 311 | input_sync(kp.dev); |
@@ -362,8 +366,9 @@ static void sony_laptop_report_input_event(u8 event) | |||
362 | /* we emit the scancode so we can always remap the key */ | 366 | /* we emit the scancode so we can always remap the key */ |
363 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); | 367 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); |
364 | input_sync(kp.dev); | 368 | input_sync(kp.dev); |
365 | kfifo_put(sony_laptop_input.fifo, | 369 | kfifo_in_locked(&sony_laptop_input.fifo, |
366 | (unsigned char *)&kp, sizeof(kp)); | 370 | (unsigned char *)&kp, sizeof(kp), |
371 | &sony_laptop_input.fifo_lock); | ||
367 | 372 | ||
368 | if (!work_pending(&sony_laptop_release_key_work)) | 373 | if (!work_pending(&sony_laptop_release_key_work)) |
369 | queue_work(sony_laptop_input.wq, | 374 | queue_work(sony_laptop_input.wq, |
@@ -385,12 +390,10 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) | |||
385 | 390 | ||
386 | /* kfifo */ | 391 | /* kfifo */ |
387 | spin_lock_init(&sony_laptop_input.fifo_lock); | 392 | spin_lock_init(&sony_laptop_input.fifo_lock); |
388 | sony_laptop_input.fifo = | 393 | error = |
389 | kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | 394 | kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); |
390 | &sony_laptop_input.fifo_lock); | 395 | if (error) { |
391 | if (IS_ERR(sony_laptop_input.fifo)) { | ||
392 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 396 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); |
393 | error = PTR_ERR(sony_laptop_input.fifo); | ||
394 | goto err_dec_users; | 397 | goto err_dec_users; |
395 | } | 398 | } |
396 | 399 | ||
@@ -474,7 +477,7 @@ err_destroy_wq: | |||
474 | destroy_workqueue(sony_laptop_input.wq); | 477 | destroy_workqueue(sony_laptop_input.wq); |
475 | 478 | ||
476 | err_free_kfifo: | 479 | err_free_kfifo: |
477 | kfifo_free(sony_laptop_input.fifo); | 480 | kfifo_free(&sony_laptop_input.fifo); |
478 | 481 | ||
479 | err_dec_users: | 482 | err_dec_users: |
480 | atomic_dec(&sony_laptop_input.users); | 483 | atomic_dec(&sony_laptop_input.users); |
@@ -500,7 +503,7 @@ static void sony_laptop_remove_input(void) | |||
500 | } | 503 | } |
501 | 504 | ||
502 | destroy_workqueue(sony_laptop_input.wq); | 505 | destroy_workqueue(sony_laptop_input.wq); |
503 | kfifo_free(sony_laptop_input.fifo); | 506 | kfifo_free(&sony_laptop_input.fifo); |
504 | } | 507 | } |
505 | 508 | ||
506 | /*********** Platform Device ***********/ | 509 | /*********** Platform Device ***********/ |
@@ -890,6 +893,8 @@ static struct sony_nc_event sony_100_events[] = { | |||
890 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | 893 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, |
891 | { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, | 894 | { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, |
892 | { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, | 895 | { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, |
896 | { 0xa1, SONYPI_EVENT_MEDIA_PRESSED }, | ||
897 | { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED }, | ||
893 | { 0, 0 }, | 898 | { 0, 0 }, |
894 | }; | 899 | }; |
895 | 900 | ||
@@ -961,7 +966,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) | |||
961 | else | 966 | else |
962 | sony_laptop_report_input_event(ev); | 967 | sony_laptop_report_input_event(ev); |
963 | } | 968 | } |
964 | } else if (sony_find_snc_handle(0x124) == ev) { | 969 | } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) { |
965 | sony_nc_rfkill_update(); | 970 | sony_nc_rfkill_update(); |
966 | return; | 971 | return; |
967 | } | 972 | } |
@@ -1067,7 +1072,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked) | |||
1067 | if (!blocked) | 1072 | if (!blocked) |
1068 | argument |= 0xff0000; | 1073 | argument |= 0xff0000; |
1069 | 1074 | ||
1070 | return sony_call_snc_handle(0x124, argument, &result); | 1075 | return sony_call_snc_handle(sony_rfkill_handle, argument, &result); |
1071 | } | 1076 | } |
1072 | 1077 | ||
1073 | static const struct rfkill_ops sony_rfkill_ops = { | 1078 | static const struct rfkill_ops sony_rfkill_ops = { |
@@ -1110,7 +1115,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, | |||
1110 | if (!rfk) | 1115 | if (!rfk) |
1111 | return -ENOMEM; | 1116 | return -ENOMEM; |
1112 | 1117 | ||
1113 | sony_call_snc_handle(0x124, 0x200, &result); | 1118 | sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); |
1114 | hwblock = !(result & 0x1); | 1119 | hwblock = !(result & 0x1); |
1115 | rfkill_set_hw_state(rfk, hwblock); | 1120 | rfkill_set_hw_state(rfk, hwblock); |
1116 | 1121 | ||
@@ -1129,7 +1134,7 @@ static void sony_nc_rfkill_update() | |||
1129 | int result; | 1134 | int result; |
1130 | bool hwblock; | 1135 | bool hwblock; |
1131 | 1136 | ||
1132 | sony_call_snc_handle(0x124, 0x200, &result); | 1137 | sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); |
1133 | hwblock = !(result & 0x1); | 1138 | hwblock = !(result & 0x1); |
1134 | 1139 | ||
1135 | for (i = 0; i < N_SONY_RFKILL; i++) { | 1140 | for (i = 0; i < N_SONY_RFKILL; i++) { |
@@ -1145,36 +1150,79 @@ static void sony_nc_rfkill_update() | |||
1145 | continue; | 1150 | continue; |
1146 | } | 1151 | } |
1147 | 1152 | ||
1148 | sony_call_snc_handle(0x124, argument, &result); | 1153 | sony_call_snc_handle(sony_rfkill_handle, argument, &result); |
1149 | rfkill_set_states(sony_rfkill_devices[i], | 1154 | rfkill_set_states(sony_rfkill_devices[i], |
1150 | !(result & 0xf), false); | 1155 | !(result & 0xf), false); |
1151 | } | 1156 | } |
1152 | } | 1157 | } |
1153 | 1158 | ||
1154 | static int sony_nc_rfkill_setup(struct acpi_device *device) | 1159 | static void sony_nc_rfkill_setup(struct acpi_device *device) |
1155 | { | 1160 | { |
1156 | int result, ret; | 1161 | int offset; |
1162 | u8 dev_code, i; | ||
1163 | acpi_status status; | ||
1164 | struct acpi_object_list params; | ||
1165 | union acpi_object in_obj; | ||
1166 | union acpi_object *device_enum; | ||
1167 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1157 | 1168 | ||
1158 | if (sony_find_snc_handle(0x124) == -1) | 1169 | offset = sony_find_snc_handle(0x124); |
1159 | return -1; | 1170 | if (offset == -1) { |
1171 | offset = sony_find_snc_handle(0x135); | ||
1172 | if (offset == -1) | ||
1173 | return; | ||
1174 | else | ||
1175 | sony_rfkill_handle = 0x135; | ||
1176 | } else | ||
1177 | sony_rfkill_handle = 0x124; | ||
1178 | dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle); | ||
1160 | 1179 | ||
1161 | ret = sony_call_snc_handle(0x124, 0xb00, &result); | 1180 | /* need to read the whole buffer returned by the acpi call to SN06 |
1162 | if (ret) { | 1181 | * here otherwise we may miss some features |
1163 | printk(KERN_INFO DRV_PFX | 1182 | */ |
1164 | "Unable to enumerate rfkill devices: %x\n", ret); | 1183 | params.count = 1; |
1165 | return ret; | 1184 | params.pointer = &in_obj; |
1185 | in_obj.type = ACPI_TYPE_INTEGER; | ||
1186 | in_obj.integer.value = offset; | ||
1187 | status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, | ||
1188 | &buffer); | ||
1189 | if (ACPI_FAILURE(status)) { | ||
1190 | dprintk("Radio device enumeration failed\n"); | ||
1191 | return; | ||
1192 | } | ||
1193 | |||
1194 | device_enum = (union acpi_object *) buffer.pointer; | ||
1195 | if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) { | ||
1196 | printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n", | ||
1197 | device_enum->type); | ||
1198 | goto out_no_enum; | ||
1166 | } | 1199 | } |
1167 | 1200 | ||
1168 | if (result & 0x1) | 1201 | /* the buffer is filled with magic numbers describing the devices |
1169 | sony_nc_setup_rfkill(device, SONY_WIFI); | 1202 | * available, 0xff terminates the enumeration |
1170 | if (result & 0x2) | 1203 | */ |
1171 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); | 1204 | while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff && |
1172 | if (result & 0x1c) | 1205 | i < device_enum->buffer.length) { |
1173 | sony_nc_setup_rfkill(device, SONY_WWAN); | 1206 | i++; |
1174 | if (result & 0x20) | 1207 | dprintk("Radio devices, looking at 0x%.2x\n", dev_code); |
1175 | sony_nc_setup_rfkill(device, SONY_WIMAX); | ||
1176 | 1208 | ||
1177 | return 0; | 1209 | if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) |
1210 | sony_nc_setup_rfkill(device, SONY_WIFI); | ||
1211 | |||
1212 | if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) | ||
1213 | sony_nc_setup_rfkill(device, SONY_BLUETOOTH); | ||
1214 | |||
1215 | if ((0xf0 & dev_code) == 0x20 && | ||
1216 | !sony_rfkill_devices[SONY_WWAN]) | ||
1217 | sony_nc_setup_rfkill(device, SONY_WWAN); | ||
1218 | |||
1219 | if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) | ||
1220 | sony_nc_setup_rfkill(device, SONY_WIMAX); | ||
1221 | } | ||
1222 | |||
1223 | out_no_enum: | ||
1224 | kfree(buffer.pointer); | ||
1225 | return; | ||
1178 | } | 1226 | } |
1179 | 1227 | ||
1180 | static int sony_nc_add(struct acpi_device *device) | 1228 | static int sony_nc_add(struct acpi_device *device) |
@@ -2079,7 +2127,7 @@ static struct attribute_group spic_attribute_group = { | |||
2079 | 2127 | ||
2080 | struct sonypi_compat_s { | 2128 | struct sonypi_compat_s { |
2081 | struct fasync_struct *fifo_async; | 2129 | struct fasync_struct *fifo_async; |
2082 | struct kfifo *fifo; | 2130 | struct kfifo fifo; |
2083 | spinlock_t fifo_lock; | 2131 | spinlock_t fifo_lock; |
2084 | wait_queue_head_t fifo_proc_list; | 2132 | wait_queue_head_t fifo_proc_list; |
2085 | atomic_t open_count; | 2133 | atomic_t open_count; |
@@ -2104,12 +2152,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file) | |||
2104 | /* Flush input queue on first open */ | 2152 | /* Flush input queue on first open */ |
2105 | unsigned long flags; | 2153 | unsigned long flags; |
2106 | 2154 | ||
2107 | spin_lock_irqsave(sonypi_compat.fifo->lock, flags); | 2155 | spin_lock_irqsave(&sonypi_compat.fifo_lock, flags); |
2108 | 2156 | ||
2109 | if (atomic_inc_return(&sonypi_compat.open_count) == 1) | 2157 | if (atomic_inc_return(&sonypi_compat.open_count) == 1) |
2110 | __kfifo_reset(sonypi_compat.fifo); | 2158 | kfifo_reset(&sonypi_compat.fifo); |
2111 | 2159 | ||
2112 | spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags); | 2160 | spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags); |
2113 | 2161 | ||
2114 | return 0; | 2162 | return 0; |
2115 | } | 2163 | } |
@@ -2120,17 +2168,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf, | |||
2120 | ssize_t ret; | 2168 | ssize_t ret; |
2121 | unsigned char c; | 2169 | unsigned char c; |
2122 | 2170 | ||
2123 | if ((kfifo_len(sonypi_compat.fifo) == 0) && | 2171 | if ((kfifo_len(&sonypi_compat.fifo) == 0) && |
2124 | (file->f_flags & O_NONBLOCK)) | 2172 | (file->f_flags & O_NONBLOCK)) |
2125 | return -EAGAIN; | 2173 | return -EAGAIN; |
2126 | 2174 | ||
2127 | ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, | 2175 | ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, |
2128 | kfifo_len(sonypi_compat.fifo) != 0); | 2176 | kfifo_len(&sonypi_compat.fifo) != 0); |
2129 | if (ret) | 2177 | if (ret) |
2130 | return ret; | 2178 | return ret; |
2131 | 2179 | ||
2132 | while (ret < count && | 2180 | while (ret < count && |
2133 | (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { | 2181 | (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c), |
2182 | &sonypi_compat.fifo_lock) == sizeof(c))) { | ||
2134 | if (put_user(c, buf++)) | 2183 | if (put_user(c, buf++)) |
2135 | return -EFAULT; | 2184 | return -EFAULT; |
2136 | ret++; | 2185 | ret++; |
@@ -2147,7 +2196,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf, | |||
2147 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) | 2196 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) |
2148 | { | 2197 | { |
2149 | poll_wait(file, &sonypi_compat.fifo_proc_list, wait); | 2198 | poll_wait(file, &sonypi_compat.fifo_proc_list, wait); |
2150 | if (kfifo_len(sonypi_compat.fifo)) | 2199 | if (kfifo_len(&sonypi_compat.fifo)) |
2151 | return POLLIN | POLLRDNORM; | 2200 | return POLLIN | POLLRDNORM; |
2152 | return 0; | 2201 | return 0; |
2153 | } | 2202 | } |
@@ -2309,7 +2358,8 @@ static struct miscdevice sonypi_misc_device = { | |||
2309 | 2358 | ||
2310 | static void sonypi_compat_report_event(u8 event) | 2359 | static void sonypi_compat_report_event(u8 event) |
2311 | { | 2360 | { |
2312 | kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); | 2361 | kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event, |
2362 | sizeof(event), &sonypi_compat.fifo_lock); | ||
2313 | kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); | 2363 | kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); |
2314 | wake_up_interruptible(&sonypi_compat.fifo_proc_list); | 2364 | wake_up_interruptible(&sonypi_compat.fifo_proc_list); |
2315 | } | 2365 | } |
@@ -2319,11 +2369,11 @@ static int sonypi_compat_init(void) | |||
2319 | int error; | 2369 | int error; |
2320 | 2370 | ||
2321 | spin_lock_init(&sonypi_compat.fifo_lock); | 2371 | spin_lock_init(&sonypi_compat.fifo_lock); |
2322 | sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | 2372 | error = |
2323 | &sonypi_compat.fifo_lock); | 2373 | kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); |
2324 | if (IS_ERR(sonypi_compat.fifo)) { | 2374 | if (error) { |
2325 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 2375 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); |
2326 | return PTR_ERR(sonypi_compat.fifo); | 2376 | return error; |
2327 | } | 2377 | } |
2328 | 2378 | ||
2329 | init_waitqueue_head(&sonypi_compat.fifo_proc_list); | 2379 | init_waitqueue_head(&sonypi_compat.fifo_proc_list); |
@@ -2342,14 +2392,14 @@ static int sonypi_compat_init(void) | |||
2342 | return 0; | 2392 | return 0; |
2343 | 2393 | ||
2344 | err_free_kfifo: | 2394 | err_free_kfifo: |
2345 | kfifo_free(sonypi_compat.fifo); | 2395 | kfifo_free(&sonypi_compat.fifo); |
2346 | return error; | 2396 | return error; |
2347 | } | 2397 | } |
2348 | 2398 | ||
2349 | static void sonypi_compat_exit(void) | 2399 | static void sonypi_compat_exit(void) |
2350 | { | 2400 | { |
2351 | misc_deregister(&sonypi_misc_device); | 2401 | misc_deregister(&sonypi_misc_device); |
2352 | kfifo_free(sonypi_compat.fifo); | 2402 | kfifo_free(&sonypi_compat.fifo); |
2353 | } | 2403 | } |
2354 | #else | 2404 | #else |
2355 | static int sonypi_compat_init(void) { return 0; } | 2405 | static int sonypi_compat_init(void) { return 0; } |
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index 44166003d4ef..dd33b51c3486 100644 --- a/drivers/platform/x86/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c | |||
@@ -47,22 +47,6 @@ MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras"); | |||
47 | MODULE_LICENSE("GPL"); | 47 | MODULE_LICENSE("GPL"); |
48 | MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505"); | 48 | MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505"); |
49 | 49 | ||
50 | static int tc1100_probe(struct platform_device *device); | ||
51 | static int tc1100_remove(struct platform_device *device); | ||
52 | static int tc1100_suspend(struct platform_device *device, pm_message_t state); | ||
53 | static int tc1100_resume(struct platform_device *device); | ||
54 | |||
55 | static struct platform_driver tc1100_driver = { | ||
56 | .driver = { | ||
57 | .name = "tc1100-wmi", | ||
58 | .owner = THIS_MODULE, | ||
59 | }, | ||
60 | .probe = tc1100_probe, | ||
61 | .remove = tc1100_remove, | ||
62 | .suspend = tc1100_suspend, | ||
63 | .resume = tc1100_resume, | ||
64 | }; | ||
65 | |||
66 | static struct platform_device *tc1100_device; | 50 | static struct platform_device *tc1100_device; |
67 | 51 | ||
68 | struct tc1100_data { | 52 | struct tc1100_data { |
@@ -183,51 +167,35 @@ static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ | |||
183 | show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); | 167 | show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); |
184 | show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL); | 168 | show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL); |
185 | 169 | ||
186 | static void remove_fs(void) | 170 | static struct attribute *tc1100_attributes[] = { |
187 | { | 171 | &dev_attr_wireless.attr, |
188 | device_remove_file(&tc1100_device->dev, &dev_attr_wireless); | 172 | &dev_attr_jogdial.attr, |
189 | device_remove_file(&tc1100_device->dev, &dev_attr_jogdial); | 173 | NULL |
190 | } | 174 | }; |
191 | |||
192 | static int add_fs(void) | ||
193 | { | ||
194 | int ret; | ||
195 | |||
196 | ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless); | ||
197 | if (ret) | ||
198 | goto add_sysfs_error; | ||
199 | |||
200 | ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial); | ||
201 | if (ret) | ||
202 | goto add_sysfs_error; | ||
203 | |||
204 | return ret; | ||
205 | 175 | ||
206 | add_sysfs_error: | 176 | static struct attribute_group tc1100_attribute_group = { |
207 | remove_fs(); | 177 | .attrs = tc1100_attributes, |
208 | return ret; | 178 | }; |
209 | } | ||
210 | 179 | ||
211 | /* -------------------------------------------------------------------------- | 180 | /* -------------------------------------------------------------------------- |
212 | Driver Model | 181 | Driver Model |
213 | -------------------------------------------------------------------------- */ | 182 | -------------------------------------------------------------------------- */ |
214 | 183 | ||
215 | static int tc1100_probe(struct platform_device *device) | 184 | static int __init tc1100_probe(struct platform_device *device) |
216 | { | 185 | { |
217 | int result = 0; | 186 | return sysfs_create_group(&device->dev.kobj, &tc1100_attribute_group); |
218 | |||
219 | result = add_fs(); | ||
220 | return result; | ||
221 | } | 187 | } |
222 | 188 | ||
223 | 189 | ||
224 | static int tc1100_remove(struct platform_device *device) | 190 | static int __devexit tc1100_remove(struct platform_device *device) |
225 | { | 191 | { |
226 | remove_fs(); | 192 | sysfs_remove_group(&device->dev.kobj, &tc1100_attribute_group); |
193 | |||
227 | return 0; | 194 | return 0; |
228 | } | 195 | } |
229 | 196 | ||
230 | static int tc1100_suspend(struct platform_device *dev, pm_message_t state) | 197 | #ifdef CONFIG_PM |
198 | static int tc1100_suspend(struct device *dev) | ||
231 | { | 199 | { |
232 | int ret; | 200 | int ret; |
233 | 201 | ||
@@ -239,10 +207,10 @@ static int tc1100_suspend(struct platform_device *dev, pm_message_t state) | |||
239 | if (ret) | 207 | if (ret) |
240 | return ret; | 208 | return ret; |
241 | 209 | ||
242 | return ret; | 210 | return 0; |
243 | } | 211 | } |
244 | 212 | ||
245 | static int tc1100_resume(struct platform_device *dev) | 213 | static int tc1100_resume(struct device *dev) |
246 | { | 214 | { |
247 | int ret; | 215 | int ret; |
248 | 216 | ||
@@ -254,34 +222,61 @@ static int tc1100_resume(struct platform_device *dev) | |||
254 | if (ret) | 222 | if (ret) |
255 | return ret; | 223 | return ret; |
256 | 224 | ||
257 | return ret; | 225 | return 0; |
258 | } | 226 | } |
259 | 227 | ||
228 | static const struct dev_pm_ops tc1100_pm_ops = { | ||
229 | .suspend = tc1100_suspend, | ||
230 | .resume = tc1100_resume, | ||
231 | .freeze = tc1100_suspend, | ||
232 | .restore = tc1100_resume, | ||
233 | }; | ||
234 | #endif | ||
235 | |||
236 | static struct platform_driver tc1100_driver = { | ||
237 | .driver = { | ||
238 | .name = "tc1100-wmi", | ||
239 | .owner = THIS_MODULE, | ||
240 | #ifdef CONFIG_PM | ||
241 | .pm = &tc1100_pm_ops, | ||
242 | #endif | ||
243 | }, | ||
244 | .remove = __devexit_p(tc1100_remove), | ||
245 | }; | ||
246 | |||
260 | static int __init tc1100_init(void) | 247 | static int __init tc1100_init(void) |
261 | { | 248 | { |
262 | int result = 0; | 249 | int error; |
263 | 250 | ||
264 | if (!wmi_has_guid(GUID)) | 251 | if (!wmi_has_guid(GUID)) |
265 | return -ENODEV; | 252 | return -ENODEV; |
266 | 253 | ||
267 | result = platform_driver_register(&tc1100_driver); | ||
268 | if (result) | ||
269 | return result; | ||
270 | |||
271 | tc1100_device = platform_device_alloc("tc1100-wmi", -1); | 254 | tc1100_device = platform_device_alloc("tc1100-wmi", -1); |
272 | platform_device_add(tc1100_device); | 255 | if (!tc1100_device) |
256 | return -ENOMEM; | ||
257 | |||
258 | error = platform_device_add(tc1100_device); | ||
259 | if (error) | ||
260 | goto err_device_put; | ||
261 | |||
262 | error = platform_driver_probe(&tc1100_driver, tc1100_probe); | ||
263 | if (error) | ||
264 | goto err_device_del; | ||
273 | 265 | ||
274 | printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n"); | 266 | printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n"); |
267 | return 0; | ||
275 | 268 | ||
276 | return result; | 269 | err_device_del: |
270 | platform_device_del(tc1100_device); | ||
271 | err_device_put: | ||
272 | platform_device_put(tc1100_device); | ||
273 | return error; | ||
277 | } | 274 | } |
278 | 275 | ||
279 | static void __exit tc1100_exit(void) | 276 | static void __exit tc1100_exit(void) |
280 | { | 277 | { |
281 | platform_device_del(tc1100_device); | 278 | platform_device_unregister(tc1100_device); |
282 | platform_driver_unregister(&tc1100_driver); | 279 | platform_driver_unregister(&tc1100_driver); |
283 | |||
284 | printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n"); | ||
285 | } | 280 | } |
286 | 281 | ||
287 | module_init(tc1100_init); | 282 | module_init(tc1100_init); |