]> Pileus Git - ~andy/linux/blob - drivers/platform/x86/classmate-laptop.c
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211
[~andy/linux] / drivers / platform / x86 / classmate-laptop.c
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/slab.h>
23 #include <linux/workqueue.h>
24 #include <acpi/acpi_drivers.h>
25 #include <linux/backlight.h>
26 #include <linux/input.h>
27 #include <linux/rfkill.h>
28
29 MODULE_LICENSE("GPL");
30
31
32 struct cmpc_accel {
33         int sensitivity;
34         int g_select;
35         int inputdev_state;
36 };
37
38 #define CMPC_ACCEL_DEV_STATE_CLOSED     0
39 #define CMPC_ACCEL_DEV_STATE_OPEN       1
40
41 #define CMPC_ACCEL_SENSITIVITY_DEFAULT          5
42 #define CMPC_ACCEL_G_SELECT_DEFAULT             0
43
44 #define CMPC_ACCEL_HID          "ACCE0000"
45 #define CMPC_ACCEL_HID_V4       "ACCE0001"
46 #define CMPC_TABLET_HID         "TBLT0000"
47 #define CMPC_IPML_HID   "IPML200"
48 #define CMPC_KEYS_HID           "FNBT0000"
49
50 /*
51  * Generic input device code.
52  */
53
54 typedef void (*input_device_init)(struct input_dev *dev);
55
56 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
57                                        input_device_init idev_init)
58 {
59         struct input_dev *inputdev;
60         int error;
61
62         inputdev = input_allocate_device();
63         if (!inputdev)
64                 return -ENOMEM;
65         inputdev->name = name;
66         inputdev->dev.parent = &acpi->dev;
67         idev_init(inputdev);
68         error = input_register_device(inputdev);
69         if (error) {
70                 input_free_device(inputdev);
71                 return error;
72         }
73         dev_set_drvdata(&acpi->dev, inputdev);
74         return 0;
75 }
76
77 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
78 {
79         struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
80         input_unregister_device(inputdev);
81         return 0;
82 }
83
84 /*
85  * Accelerometer code for Classmate V4
86  */
87 static acpi_status cmpc_start_accel_v4(acpi_handle handle)
88 {
89         union acpi_object param[4];
90         struct acpi_object_list input;
91         acpi_status status;
92
93         param[0].type = ACPI_TYPE_INTEGER;
94         param[0].integer.value = 0x3;
95         param[1].type = ACPI_TYPE_INTEGER;
96         param[1].integer.value = 0;
97         param[2].type = ACPI_TYPE_INTEGER;
98         param[2].integer.value = 0;
99         param[3].type = ACPI_TYPE_INTEGER;
100         param[3].integer.value = 0;
101         input.count = 4;
102         input.pointer = param;
103         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
104         return status;
105 }
106
107 static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
108 {
109         union acpi_object param[4];
110         struct acpi_object_list input;
111         acpi_status status;
112
113         param[0].type = ACPI_TYPE_INTEGER;
114         param[0].integer.value = 0x4;
115         param[1].type = ACPI_TYPE_INTEGER;
116         param[1].integer.value = 0;
117         param[2].type = ACPI_TYPE_INTEGER;
118         param[2].integer.value = 0;
119         param[3].type = ACPI_TYPE_INTEGER;
120         param[3].integer.value = 0;
121         input.count = 4;
122         input.pointer = param;
123         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
124         return status;
125 }
126
127 static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
128 {
129         union acpi_object param[4];
130         struct acpi_object_list input;
131
132         param[0].type = ACPI_TYPE_INTEGER;
133         param[0].integer.value = 0x02;
134         param[1].type = ACPI_TYPE_INTEGER;
135         param[1].integer.value = val;
136         param[2].type = ACPI_TYPE_INTEGER;
137         param[2].integer.value = 0;
138         param[3].type = ACPI_TYPE_INTEGER;
139         param[3].integer.value = 0;
140         input.count = 4;
141         input.pointer = param;
142         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
143 }
144
145 static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
146 {
147         union acpi_object param[4];
148         struct acpi_object_list input;
149
150         param[0].type = ACPI_TYPE_INTEGER;
151         param[0].integer.value = 0x05;
152         param[1].type = ACPI_TYPE_INTEGER;
153         param[1].integer.value = val;
154         param[2].type = ACPI_TYPE_INTEGER;
155         param[2].integer.value = 0;
156         param[3].type = ACPI_TYPE_INTEGER;
157         param[3].integer.value = 0;
158         input.count = 4;
159         input.pointer = param;
160         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
161 }
162
163 static acpi_status cmpc_get_accel_v4(acpi_handle handle,
164                                      int16_t *x,
165                                      int16_t *y,
166                                      int16_t *z)
167 {
168         union acpi_object param[4];
169         struct acpi_object_list input;
170         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
171         int16_t *locs;
172         acpi_status status;
173
174         param[0].type = ACPI_TYPE_INTEGER;
175         param[0].integer.value = 0x01;
176         param[1].type = ACPI_TYPE_INTEGER;
177         param[1].integer.value = 0;
178         param[2].type = ACPI_TYPE_INTEGER;
179         param[2].integer.value = 0;
180         param[3].type = ACPI_TYPE_INTEGER;
181         param[3].integer.value = 0;
182         input.count = 4;
183         input.pointer = param;
184         status = acpi_evaluate_object(handle, "ACMD", &input, &output);
185         if (ACPI_SUCCESS(status)) {
186                 union acpi_object *obj;
187                 obj = output.pointer;
188                 locs = (int16_t *) obj->buffer.pointer;
189                 *x = locs[0];
190                 *y = locs[1];
191                 *z = locs[2];
192                 kfree(output.pointer);
193         }
194         return status;
195 }
196
197 static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
198 {
199         if (event == 0x81) {
200                 int16_t x, y, z;
201                 acpi_status status;
202
203                 status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
204                 if (ACPI_SUCCESS(status)) {
205                         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
206
207                         input_report_abs(inputdev, ABS_X, x);
208                         input_report_abs(inputdev, ABS_Y, y);
209                         input_report_abs(inputdev, ABS_Z, z);
210                         input_sync(inputdev);
211                 }
212         }
213 }
214
215 static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
216                                               struct device_attribute *attr,
217                                               char *buf)
218 {
219         struct acpi_device *acpi;
220         struct input_dev *inputdev;
221         struct cmpc_accel *accel;
222
223         acpi = to_acpi_device(dev);
224         inputdev = dev_get_drvdata(&acpi->dev);
225         accel = dev_get_drvdata(&inputdev->dev);
226
227         return sprintf(buf, "%d\n", accel->sensitivity);
228 }
229
230 static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
231                                                struct device_attribute *attr,
232                                                const char *buf, size_t count)
233 {
234         struct acpi_device *acpi;
235         struct input_dev *inputdev;
236         struct cmpc_accel *accel;
237         unsigned long sensitivity;
238         int r;
239
240         acpi = to_acpi_device(dev);
241         inputdev = dev_get_drvdata(&acpi->dev);
242         accel = dev_get_drvdata(&inputdev->dev);
243
244         r = kstrtoul(buf, 0, &sensitivity);
245         if (r)
246                 return r;
247
248         /* sensitivity must be between 1 and 127 */
249         if (sensitivity < 1 || sensitivity > 127)
250                 return -EINVAL;
251
252         accel->sensitivity = sensitivity;
253         cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
254
255         return strnlen(buf, count);
256 }
257
258 static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
259         .attr = { .name = "sensitivity", .mode = 0660 },
260         .show = cmpc_accel_sensitivity_show_v4,
261         .store = cmpc_accel_sensitivity_store_v4
262 };
263
264 static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
265                                            struct device_attribute *attr,
266                                            char *buf)
267 {
268         struct acpi_device *acpi;
269         struct input_dev *inputdev;
270         struct cmpc_accel *accel;
271
272         acpi = to_acpi_device(dev);
273         inputdev = dev_get_drvdata(&acpi->dev);
274         accel = dev_get_drvdata(&inputdev->dev);
275
276         return sprintf(buf, "%d\n", accel->g_select);
277 }
278
279 static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
280                                             struct device_attribute *attr,
281                                             const char *buf, size_t count)
282 {
283         struct acpi_device *acpi;
284         struct input_dev *inputdev;
285         struct cmpc_accel *accel;
286         unsigned long g_select;
287         int r;
288
289         acpi = to_acpi_device(dev);
290         inputdev = dev_get_drvdata(&acpi->dev);
291         accel = dev_get_drvdata(&inputdev->dev);
292
293         r = kstrtoul(buf, 0, &g_select);
294         if (r)
295                 return r;
296
297         /* 0 means 1.5g, 1 means 6g, everything else is wrong */
298         if (g_select != 0 && g_select != 1)
299                 return -EINVAL;
300
301         accel->g_select = g_select;
302         cmpc_accel_set_g_select_v4(acpi->handle, g_select);
303
304         return strnlen(buf, count);
305 }
306
307 static struct device_attribute cmpc_accel_g_select_attr_v4 = {
308         .attr = { .name = "g_select", .mode = 0660 },
309         .show = cmpc_accel_g_select_show_v4,
310         .store = cmpc_accel_g_select_store_v4
311 };
312
313 static int cmpc_accel_open_v4(struct input_dev *input)
314 {
315         struct acpi_device *acpi;
316         struct cmpc_accel *accel;
317
318         acpi = to_acpi_device(input->dev.parent);
319         accel = dev_get_drvdata(&input->dev);
320
321         cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
322         cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
323
324         if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
325                 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
326                 return 0;
327         }
328         return -EIO;
329 }
330
331 static void cmpc_accel_close_v4(struct input_dev *input)
332 {
333         struct acpi_device *acpi;
334         struct cmpc_accel *accel;
335
336         acpi = to_acpi_device(input->dev.parent);
337         accel = dev_get_drvdata(&input->dev);
338
339         cmpc_stop_accel_v4(acpi->handle);
340         accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
341 }
342
343 static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
344 {
345         set_bit(EV_ABS, inputdev->evbit);
346         input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
347         input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
348         input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
349         inputdev->open = cmpc_accel_open_v4;
350         inputdev->close = cmpc_accel_close_v4;
351 }
352
353 static int cmpc_accel_suspend_v4(struct device *dev)
354 {
355         struct input_dev *inputdev;
356         struct cmpc_accel *accel;
357
358         inputdev = dev_get_drvdata(dev);
359         accel = dev_get_drvdata(&inputdev->dev);
360
361         if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
362                 return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
363
364         return 0;
365 }
366
367 static int cmpc_accel_resume_v4(struct device *dev)
368 {
369         struct input_dev *inputdev;
370         struct cmpc_accel *accel;
371
372         inputdev = dev_get_drvdata(dev);
373         accel = dev_get_drvdata(&inputdev->dev);
374
375         if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
376                 cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
377                                               accel->sensitivity);
378                 cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
379                                            accel->g_select);
380
381                 if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
382                         return -EIO;
383         }
384
385         return 0;
386 }
387
388 static int cmpc_accel_add_v4(struct acpi_device *acpi)
389 {
390         int error;
391         struct input_dev *inputdev;
392         struct cmpc_accel *accel;
393
394         accel = kmalloc(sizeof(*accel), GFP_KERNEL);
395         if (!accel)
396                 return -ENOMEM;
397
398         accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
399
400         accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
401         cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
402
403         error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
404         if (error)
405                 goto failed_sensitivity;
406
407         accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
408         cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
409
410         error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
411         if (error)
412                 goto failed_g_select;
413
414         error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
415                                             cmpc_accel_idev_init_v4);
416         if (error)
417                 goto failed_input;
418
419         inputdev = dev_get_drvdata(&acpi->dev);
420         dev_set_drvdata(&inputdev->dev, accel);
421
422         return 0;
423
424 failed_input:
425         device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
426 failed_g_select:
427         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
428 failed_sensitivity:
429         kfree(accel);
430         return error;
431 }
432
433 static int cmpc_accel_remove_v4(struct acpi_device *acpi, int type)
434 {
435         struct input_dev *inputdev;
436         struct cmpc_accel *accel;
437
438         inputdev = dev_get_drvdata(&acpi->dev);
439         accel = dev_get_drvdata(&inputdev->dev);
440
441         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
442         device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
443         return cmpc_remove_acpi_notify_device(acpi);
444 }
445
446 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
447                          cmpc_accel_resume_v4);
448
449 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
450         {CMPC_ACCEL_HID_V4, 0},
451         {"", 0}
452 };
453
454 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
455         .owner = THIS_MODULE,
456         .name = "cmpc_accel_v4",
457         .class = "cmpc_accel_v4",
458         .ids = cmpc_accel_device_ids_v4,
459         .ops = {
460                 .add = cmpc_accel_add_v4,
461                 .remove = cmpc_accel_remove_v4,
462                 .notify = cmpc_accel_handler_v4,
463         },
464         .drv.pm = &cmpc_accel_pm,
465 };
466
467
468 /*
469  * Accelerometer code for Classmate versions prior to V4
470  */
471 static acpi_status cmpc_start_accel(acpi_handle handle)
472 {
473         union acpi_object param[2];
474         struct acpi_object_list input;
475         acpi_status status;
476
477         param[0].type = ACPI_TYPE_INTEGER;
478         param[0].integer.value = 0x3;
479         param[1].type = ACPI_TYPE_INTEGER;
480         input.count = 2;
481         input.pointer = param;
482         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
483         return status;
484 }
485
486 static acpi_status cmpc_stop_accel(acpi_handle handle)
487 {
488         union acpi_object param[2];
489         struct acpi_object_list input;
490         acpi_status status;
491
492         param[0].type = ACPI_TYPE_INTEGER;
493         param[0].integer.value = 0x4;
494         param[1].type = ACPI_TYPE_INTEGER;
495         input.count = 2;
496         input.pointer = param;
497         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
498         return status;
499 }
500
501 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
502 {
503         union acpi_object param[2];
504         struct acpi_object_list input;
505
506         param[0].type = ACPI_TYPE_INTEGER;
507         param[0].integer.value = 0x02;
508         param[1].type = ACPI_TYPE_INTEGER;
509         param[1].integer.value = val;
510         input.count = 2;
511         input.pointer = param;
512         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
513 }
514
515 static acpi_status cmpc_get_accel(acpi_handle handle,
516                                   unsigned char *x,
517                                   unsigned char *y,
518                                   unsigned char *z)
519 {
520         union acpi_object param[2];
521         struct acpi_object_list input;
522         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
523         unsigned char *locs;
524         acpi_status status;
525
526         param[0].type = ACPI_TYPE_INTEGER;
527         param[0].integer.value = 0x01;
528         param[1].type = ACPI_TYPE_INTEGER;
529         input.count = 2;
530         input.pointer = param;
531         status = acpi_evaluate_object(handle, "ACMD", &input, &output);
532         if (ACPI_SUCCESS(status)) {
533                 union acpi_object *obj;
534                 obj = output.pointer;
535                 locs = obj->buffer.pointer;
536                 *x = locs[0];
537                 *y = locs[1];
538                 *z = locs[2];
539                 kfree(output.pointer);
540         }
541         return status;
542 }
543
544 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
545 {
546         if (event == 0x81) {
547                 unsigned char x, y, z;
548                 acpi_status status;
549
550                 status = cmpc_get_accel(dev->handle, &x, &y, &z);
551                 if (ACPI_SUCCESS(status)) {
552                         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
553
554                         input_report_abs(inputdev, ABS_X, x);
555                         input_report_abs(inputdev, ABS_Y, y);
556                         input_report_abs(inputdev, ABS_Z, z);
557                         input_sync(inputdev);
558                 }
559         }
560 }
561
562 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
563                                            struct device_attribute *attr,
564                                            char *buf)
565 {
566         struct acpi_device *acpi;
567         struct input_dev *inputdev;
568         struct cmpc_accel *accel;
569
570         acpi = to_acpi_device(dev);
571         inputdev = dev_get_drvdata(&acpi->dev);
572         accel = dev_get_drvdata(&inputdev->dev);
573
574         return sprintf(buf, "%d\n", accel->sensitivity);
575 }
576
577 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
578                                             struct device_attribute *attr,
579                                             const char *buf, size_t count)
580 {
581         struct acpi_device *acpi;
582         struct input_dev *inputdev;
583         struct cmpc_accel *accel;
584         unsigned long sensitivity;
585         int r;
586
587         acpi = to_acpi_device(dev);
588         inputdev = dev_get_drvdata(&acpi->dev);
589         accel = dev_get_drvdata(&inputdev->dev);
590
591         r = strict_strtoul(buf, 0, &sensitivity);
592         if (r)
593                 return r;
594
595         accel->sensitivity = sensitivity;
596         cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
597
598         return strnlen(buf, count);
599 }
600
601 static struct device_attribute cmpc_accel_sensitivity_attr = {
602         .attr = { .name = "sensitivity", .mode = 0660 },
603         .show = cmpc_accel_sensitivity_show,
604         .store = cmpc_accel_sensitivity_store
605 };
606
607 static int cmpc_accel_open(struct input_dev *input)
608 {
609         struct acpi_device *acpi;
610
611         acpi = to_acpi_device(input->dev.parent);
612         if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
613                 return 0;
614         return -EIO;
615 }
616
617 static void cmpc_accel_close(struct input_dev *input)
618 {
619         struct acpi_device *acpi;
620
621         acpi = to_acpi_device(input->dev.parent);
622         cmpc_stop_accel(acpi->handle);
623 }
624
625 static void cmpc_accel_idev_init(struct input_dev *inputdev)
626 {
627         set_bit(EV_ABS, inputdev->evbit);
628         input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
629         input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
630         input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
631         inputdev->open = cmpc_accel_open;
632         inputdev->close = cmpc_accel_close;
633 }
634
635 static int cmpc_accel_add(struct acpi_device *acpi)
636 {
637         int error;
638         struct input_dev *inputdev;
639         struct cmpc_accel *accel;
640
641         accel = kmalloc(sizeof(*accel), GFP_KERNEL);
642         if (!accel)
643                 return -ENOMEM;
644
645         accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
646         cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
647
648         error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
649         if (error)
650                 goto failed_file;
651
652         error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
653                                             cmpc_accel_idev_init);
654         if (error)
655                 goto failed_input;
656
657         inputdev = dev_get_drvdata(&acpi->dev);
658         dev_set_drvdata(&inputdev->dev, accel);
659
660         return 0;
661
662 failed_input:
663         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
664 failed_file:
665         kfree(accel);
666         return error;
667 }
668
669 static int cmpc_accel_remove(struct acpi_device *acpi, int type)
670 {
671         struct input_dev *inputdev;
672         struct cmpc_accel *accel;
673
674         inputdev = dev_get_drvdata(&acpi->dev);
675         accel = dev_get_drvdata(&inputdev->dev);
676
677         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
678         return cmpc_remove_acpi_notify_device(acpi);
679 }
680
681 static const struct acpi_device_id cmpc_accel_device_ids[] = {
682         {CMPC_ACCEL_HID, 0},
683         {"", 0}
684 };
685
686 static struct acpi_driver cmpc_accel_acpi_driver = {
687         .owner = THIS_MODULE,
688         .name = "cmpc_accel",
689         .class = "cmpc_accel",
690         .ids = cmpc_accel_device_ids,
691         .ops = {
692                 .add = cmpc_accel_add,
693                 .remove = cmpc_accel_remove,
694                 .notify = cmpc_accel_handler,
695         }
696 };
697
698
699 /*
700  * Tablet mode code.
701  */
702 static acpi_status cmpc_get_tablet(acpi_handle handle,
703                                    unsigned long long *value)
704 {
705         union acpi_object param;
706         struct acpi_object_list input;
707         unsigned long long output;
708         acpi_status status;
709
710         param.type = ACPI_TYPE_INTEGER;
711         param.integer.value = 0x01;
712         input.count = 1;
713         input.pointer = &param;
714         status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
715         if (ACPI_SUCCESS(status))
716                 *value = output;
717         return status;
718 }
719
720 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
721 {
722         unsigned long long val = 0;
723         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
724
725         if (event == 0x81) {
726                 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val)))
727                         input_report_switch(inputdev, SW_TABLET_MODE, !val);
728         }
729 }
730
731 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
732 {
733         unsigned long long val = 0;
734         struct acpi_device *acpi;
735
736         set_bit(EV_SW, inputdev->evbit);
737         set_bit(SW_TABLET_MODE, inputdev->swbit);
738
739         acpi = to_acpi_device(inputdev->dev.parent);
740         if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
741                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
742 }
743
744 static int cmpc_tablet_add(struct acpi_device *acpi)
745 {
746         return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
747                                            cmpc_tablet_idev_init);
748 }
749
750 static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
751 {
752         return cmpc_remove_acpi_notify_device(acpi);
753 }
754
755 static int cmpc_tablet_resume(struct device *dev)
756 {
757         struct input_dev *inputdev = dev_get_drvdata(dev);
758
759         unsigned long long val = 0;
760         if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val)))
761                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
762         return 0;
763 }
764
765 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
766
767 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
768         {CMPC_TABLET_HID, 0},
769         {"", 0}
770 };
771
772 static struct acpi_driver cmpc_tablet_acpi_driver = {
773         .owner = THIS_MODULE,
774         .name = "cmpc_tablet",
775         .class = "cmpc_tablet",
776         .ids = cmpc_tablet_device_ids,
777         .ops = {
778                 .add = cmpc_tablet_add,
779                 .remove = cmpc_tablet_remove,
780                 .notify = cmpc_tablet_handler,
781         },
782         .drv.pm = &cmpc_tablet_pm,
783 };
784
785
786 /*
787  * Backlight code.
788  */
789
790 static acpi_status cmpc_get_brightness(acpi_handle handle,
791                                        unsigned long long *value)
792 {
793         union acpi_object param;
794         struct acpi_object_list input;
795         unsigned long long output;
796         acpi_status status;
797
798         param.type = ACPI_TYPE_INTEGER;
799         param.integer.value = 0xC0;
800         input.count = 1;
801         input.pointer = &param;
802         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
803         if (ACPI_SUCCESS(status))
804                 *value = output;
805         return status;
806 }
807
808 static acpi_status cmpc_set_brightness(acpi_handle handle,
809                                        unsigned long long value)
810 {
811         union acpi_object param[2];
812         struct acpi_object_list input;
813         acpi_status status;
814         unsigned long long output;
815
816         param[0].type = ACPI_TYPE_INTEGER;
817         param[0].integer.value = 0xC0;
818         param[1].type = ACPI_TYPE_INTEGER;
819         param[1].integer.value = value;
820         input.count = 2;
821         input.pointer = param;
822         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
823         return status;
824 }
825
826 static int cmpc_bl_get_brightness(struct backlight_device *bd)
827 {
828         acpi_status status;
829         acpi_handle handle;
830         unsigned long long brightness;
831
832         handle = bl_get_data(bd);
833         status = cmpc_get_brightness(handle, &brightness);
834         if (ACPI_SUCCESS(status))
835                 return brightness;
836         else
837                 return -1;
838 }
839
840 static int cmpc_bl_update_status(struct backlight_device *bd)
841 {
842         acpi_status status;
843         acpi_handle handle;
844
845         handle = bl_get_data(bd);
846         status = cmpc_set_brightness(handle, bd->props.brightness);
847         if (ACPI_SUCCESS(status))
848                 return 0;
849         else
850                 return -1;
851 }
852
853 static const struct backlight_ops cmpc_bl_ops = {
854         .get_brightness = cmpc_bl_get_brightness,
855         .update_status = cmpc_bl_update_status
856 };
857
858 /*
859  * RFKILL code.
860  */
861
862 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
863                                         unsigned long long *value)
864 {
865         union acpi_object param;
866         struct acpi_object_list input;
867         unsigned long long output;
868         acpi_status status;
869
870         param.type = ACPI_TYPE_INTEGER;
871         param.integer.value = 0xC1;
872         input.count = 1;
873         input.pointer = &param;
874         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
875         if (ACPI_SUCCESS(status))
876                 *value = output;
877         return status;
878 }
879
880 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
881                                         unsigned long long value)
882 {
883         union acpi_object param[2];
884         struct acpi_object_list input;
885         acpi_status status;
886         unsigned long long output;
887
888         param[0].type = ACPI_TYPE_INTEGER;
889         param[0].integer.value = 0xC1;
890         param[1].type = ACPI_TYPE_INTEGER;
891         param[1].integer.value = value;
892         input.count = 2;
893         input.pointer = param;
894         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
895         return status;
896 }
897
898 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
899 {
900         acpi_status status;
901         acpi_handle handle;
902         unsigned long long state;
903         bool blocked;
904
905         handle = data;
906         status = cmpc_get_rfkill_wlan(handle, &state);
907         if (ACPI_SUCCESS(status)) {
908                 blocked = state & 1 ? false : true;
909                 rfkill_set_sw_state(rfkill, blocked);
910         }
911 }
912
913 static int cmpc_rfkill_block(void *data, bool blocked)
914 {
915         acpi_status status;
916         acpi_handle handle;
917         unsigned long long state;
918         bool is_blocked;
919
920         handle = data;
921         status = cmpc_get_rfkill_wlan(handle, &state);
922         if (ACPI_FAILURE(status))
923                 return -ENODEV;
924         /* Check if we really need to call cmpc_set_rfkill_wlan */
925         is_blocked = state & 1 ? false : true;
926         if (is_blocked != blocked) {
927                 state = blocked ? 0 : 1;
928                 status = cmpc_set_rfkill_wlan(handle, state);
929                 if (ACPI_FAILURE(status))
930                         return -ENODEV;
931         }
932         return 0;
933 }
934
935 static const struct rfkill_ops cmpc_rfkill_ops = {
936         .query = cmpc_rfkill_query,
937         .set_block = cmpc_rfkill_block,
938 };
939
940 /*
941  * Common backlight and rfkill code.
942  */
943
944 struct ipml200_dev {
945         struct backlight_device *bd;
946         struct rfkill *rf;
947 };
948
949 static int cmpc_ipml_add(struct acpi_device *acpi)
950 {
951         int retval;
952         struct ipml200_dev *ipml;
953         struct backlight_properties props;
954
955         ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
956         if (ipml == NULL)
957                 return -ENOMEM;
958
959         memset(&props, 0, sizeof(struct backlight_properties));
960         props.type = BACKLIGHT_PLATFORM;
961         props.max_brightness = 7;
962         ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
963                                              acpi->handle, &cmpc_bl_ops,
964                                              &props);
965         if (IS_ERR(ipml->bd)) {
966                 retval = PTR_ERR(ipml->bd);
967                 goto out_bd;
968         }
969
970         ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
971                                 &cmpc_rfkill_ops, acpi->handle);
972         /*
973          * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
974          * This is OK, however, since all other uses of the device will not
975          * derefence it.
976          */
977         if (ipml->rf) {
978                 retval = rfkill_register(ipml->rf);
979                 if (retval) {
980                         rfkill_destroy(ipml->rf);
981                         ipml->rf = NULL;
982                 }
983         }
984
985         dev_set_drvdata(&acpi->dev, ipml);
986         return 0;
987
988 out_bd:
989         kfree(ipml);
990         return retval;
991 }
992
993 static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
994 {
995         struct ipml200_dev *ipml;
996
997         ipml = dev_get_drvdata(&acpi->dev);
998
999         backlight_device_unregister(ipml->bd);
1000
1001         if (ipml->rf) {
1002                 rfkill_unregister(ipml->rf);
1003                 rfkill_destroy(ipml->rf);
1004         }
1005
1006         kfree(ipml);
1007
1008         return 0;
1009 }
1010
1011 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
1012         {CMPC_IPML_HID, 0},
1013         {"", 0}
1014 };
1015
1016 static struct acpi_driver cmpc_ipml_acpi_driver = {
1017         .owner = THIS_MODULE,
1018         .name = "cmpc",
1019         .class = "cmpc",
1020         .ids = cmpc_ipml_device_ids,
1021         .ops = {
1022                 .add = cmpc_ipml_add,
1023                 .remove = cmpc_ipml_remove
1024         }
1025 };
1026
1027
1028 /*
1029  * Extra keys code.
1030  */
1031 static int cmpc_keys_codes[] = {
1032         KEY_UNKNOWN,
1033         KEY_WLAN,
1034         KEY_SWITCHVIDEOMODE,
1035         KEY_BRIGHTNESSDOWN,
1036         KEY_BRIGHTNESSUP,
1037         KEY_VENDOR,
1038         KEY_UNKNOWN,
1039         KEY_CAMERA,
1040         KEY_BACK,
1041         KEY_FORWARD,
1042         KEY_MAX
1043 };
1044
1045 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1046 {
1047         struct input_dev *inputdev;
1048         int code = KEY_MAX;
1049
1050         if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1051                 code = cmpc_keys_codes[event & 0x0F];
1052         inputdev = dev_get_drvdata(&dev->dev);
1053         input_report_key(inputdev, code, !(event & 0x10));
1054         input_sync(inputdev);
1055 }
1056
1057 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1058 {
1059         int i;
1060
1061         set_bit(EV_KEY, inputdev->evbit);
1062         for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1063                 set_bit(cmpc_keys_codes[i], inputdev->keybit);
1064 }
1065
1066 static int cmpc_keys_add(struct acpi_device *acpi)
1067 {
1068         return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1069                                            cmpc_keys_idev_init);
1070 }
1071
1072 static int cmpc_keys_remove(struct acpi_device *acpi, int type)
1073 {
1074         return cmpc_remove_acpi_notify_device(acpi);
1075 }
1076
1077 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1078         {CMPC_KEYS_HID, 0},
1079         {"", 0}
1080 };
1081
1082 static struct acpi_driver cmpc_keys_acpi_driver = {
1083         .owner = THIS_MODULE,
1084         .name = "cmpc_keys",
1085         .class = "cmpc_keys",
1086         .ids = cmpc_keys_device_ids,
1087         .ops = {
1088                 .add = cmpc_keys_add,
1089                 .remove = cmpc_keys_remove,
1090                 .notify = cmpc_keys_handler,
1091         }
1092 };
1093
1094
1095 /*
1096  * General init/exit code.
1097  */
1098
1099 static int cmpc_init(void)
1100 {
1101         int r;
1102
1103         r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1104         if (r)
1105                 goto failed_keys;
1106
1107         r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1108         if (r)
1109                 goto failed_bl;
1110
1111         r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1112         if (r)
1113                 goto failed_tablet;
1114
1115         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1116         if (r)
1117                 goto failed_accel;
1118
1119         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1120         if (r)
1121                 goto failed_accel_v4;
1122
1123         return r;
1124
1125 failed_accel_v4:
1126         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1127
1128 failed_accel:
1129         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1130
1131 failed_tablet:
1132         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1133
1134 failed_bl:
1135         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1136
1137 failed_keys:
1138         return r;
1139 }
1140
1141 static void cmpc_exit(void)
1142 {
1143         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1144         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1145         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1146         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1147         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1148 }
1149
1150 module_init(cmpc_init);
1151 module_exit(cmpc_exit);
1152
1153 static const struct acpi_device_id cmpc_device_ids[] = {
1154         {CMPC_ACCEL_HID, 0},
1155         {CMPC_ACCEL_HID_V4, 0},
1156         {CMPC_TABLET_HID, 0},
1157         {CMPC_IPML_HID, 0},
1158         {CMPC_KEYS_HID, 0},
1159         {"", 0}
1160 };
1161
1162 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);