]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/platform/x86/classmate-laptop.c
cgroup: fix cgroup post-order descendant walk of empty subtree
[karo-tx-linux.git] / 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 #ifdef CONFIG_PM_SLEEP
354 static int cmpc_accel_suspend_v4(struct device *dev)
355 {
356         struct input_dev *inputdev;
357         struct cmpc_accel *accel;
358
359         inputdev = dev_get_drvdata(dev);
360         accel = dev_get_drvdata(&inputdev->dev);
361
362         if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
363                 return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
364
365         return 0;
366 }
367
368 static int cmpc_accel_resume_v4(struct device *dev)
369 {
370         struct input_dev *inputdev;
371         struct cmpc_accel *accel;
372
373         inputdev = dev_get_drvdata(dev);
374         accel = dev_get_drvdata(&inputdev->dev);
375
376         if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
377                 cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
378                                               accel->sensitivity);
379                 cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
380                                            accel->g_select);
381
382                 if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
383                         return -EIO;
384         }
385
386         return 0;
387 }
388 #endif
389
390 static int cmpc_accel_add_v4(struct acpi_device *acpi)
391 {
392         int error;
393         struct input_dev *inputdev;
394         struct cmpc_accel *accel;
395
396         accel = kmalloc(sizeof(*accel), GFP_KERNEL);
397         if (!accel)
398                 return -ENOMEM;
399
400         accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
401
402         accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
403         cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
404
405         error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
406         if (error)
407                 goto failed_sensitivity;
408
409         accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
410         cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
411
412         error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
413         if (error)
414                 goto failed_g_select;
415
416         error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
417                                             cmpc_accel_idev_init_v4);
418         if (error)
419                 goto failed_input;
420
421         inputdev = dev_get_drvdata(&acpi->dev);
422         dev_set_drvdata(&inputdev->dev, accel);
423
424         return 0;
425
426 failed_input:
427         device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
428 failed_g_select:
429         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
430 failed_sensitivity:
431         kfree(accel);
432         return error;
433 }
434
435 static int cmpc_accel_remove_v4(struct acpi_device *acpi)
436 {
437         struct input_dev *inputdev;
438         struct cmpc_accel *accel;
439
440         inputdev = dev_get_drvdata(&acpi->dev);
441         accel = dev_get_drvdata(&inputdev->dev);
442
443         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
444         device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
445         return cmpc_remove_acpi_notify_device(acpi);
446 }
447
448 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
449                          cmpc_accel_resume_v4);
450
451 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
452         {CMPC_ACCEL_HID_V4, 0},
453         {"", 0}
454 };
455
456 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
457         .owner = THIS_MODULE,
458         .name = "cmpc_accel_v4",
459         .class = "cmpc_accel_v4",
460         .ids = cmpc_accel_device_ids_v4,
461         .ops = {
462                 .add = cmpc_accel_add_v4,
463                 .remove = cmpc_accel_remove_v4,
464                 .notify = cmpc_accel_handler_v4,
465         },
466         .drv.pm = &cmpc_accel_pm,
467 };
468
469
470 /*
471  * Accelerometer code for Classmate versions prior to V4
472  */
473 static acpi_status cmpc_start_accel(acpi_handle handle)
474 {
475         union acpi_object param[2];
476         struct acpi_object_list input;
477         acpi_status status;
478
479         param[0].type = ACPI_TYPE_INTEGER;
480         param[0].integer.value = 0x3;
481         param[1].type = ACPI_TYPE_INTEGER;
482         input.count = 2;
483         input.pointer = param;
484         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
485         return status;
486 }
487
488 static acpi_status cmpc_stop_accel(acpi_handle handle)
489 {
490         union acpi_object param[2];
491         struct acpi_object_list input;
492         acpi_status status;
493
494         param[0].type = ACPI_TYPE_INTEGER;
495         param[0].integer.value = 0x4;
496         param[1].type = ACPI_TYPE_INTEGER;
497         input.count = 2;
498         input.pointer = param;
499         status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
500         return status;
501 }
502
503 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
504 {
505         union acpi_object param[2];
506         struct acpi_object_list input;
507
508         param[0].type = ACPI_TYPE_INTEGER;
509         param[0].integer.value = 0x02;
510         param[1].type = ACPI_TYPE_INTEGER;
511         param[1].integer.value = val;
512         input.count = 2;
513         input.pointer = param;
514         return acpi_evaluate_object(handle, "ACMD", &input, NULL);
515 }
516
517 static acpi_status cmpc_get_accel(acpi_handle handle,
518                                   unsigned char *x,
519                                   unsigned char *y,
520                                   unsigned char *z)
521 {
522         union acpi_object param[2];
523         struct acpi_object_list input;
524         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
525         unsigned char *locs;
526         acpi_status status;
527
528         param[0].type = ACPI_TYPE_INTEGER;
529         param[0].integer.value = 0x01;
530         param[1].type = ACPI_TYPE_INTEGER;
531         input.count = 2;
532         input.pointer = param;
533         status = acpi_evaluate_object(handle, "ACMD", &input, &output);
534         if (ACPI_SUCCESS(status)) {
535                 union acpi_object *obj;
536                 obj = output.pointer;
537                 locs = obj->buffer.pointer;
538                 *x = locs[0];
539                 *y = locs[1];
540                 *z = locs[2];
541                 kfree(output.pointer);
542         }
543         return status;
544 }
545
546 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
547 {
548         if (event == 0x81) {
549                 unsigned char x, y, z;
550                 acpi_status status;
551
552                 status = cmpc_get_accel(dev->handle, &x, &y, &z);
553                 if (ACPI_SUCCESS(status)) {
554                         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
555
556                         input_report_abs(inputdev, ABS_X, x);
557                         input_report_abs(inputdev, ABS_Y, y);
558                         input_report_abs(inputdev, ABS_Z, z);
559                         input_sync(inputdev);
560                 }
561         }
562 }
563
564 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
565                                            struct device_attribute *attr,
566                                            char *buf)
567 {
568         struct acpi_device *acpi;
569         struct input_dev *inputdev;
570         struct cmpc_accel *accel;
571
572         acpi = to_acpi_device(dev);
573         inputdev = dev_get_drvdata(&acpi->dev);
574         accel = dev_get_drvdata(&inputdev->dev);
575
576         return sprintf(buf, "%d\n", accel->sensitivity);
577 }
578
579 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
580                                             struct device_attribute *attr,
581                                             const char *buf, size_t count)
582 {
583         struct acpi_device *acpi;
584         struct input_dev *inputdev;
585         struct cmpc_accel *accel;
586         unsigned long sensitivity;
587         int r;
588
589         acpi = to_acpi_device(dev);
590         inputdev = dev_get_drvdata(&acpi->dev);
591         accel = dev_get_drvdata(&inputdev->dev);
592
593         r = strict_strtoul(buf, 0, &sensitivity);
594         if (r)
595                 return r;
596
597         accel->sensitivity = sensitivity;
598         cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
599
600         return strnlen(buf, count);
601 }
602
603 static struct device_attribute cmpc_accel_sensitivity_attr = {
604         .attr = { .name = "sensitivity", .mode = 0660 },
605         .show = cmpc_accel_sensitivity_show,
606         .store = cmpc_accel_sensitivity_store
607 };
608
609 static int cmpc_accel_open(struct input_dev *input)
610 {
611         struct acpi_device *acpi;
612
613         acpi = to_acpi_device(input->dev.parent);
614         if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
615                 return 0;
616         return -EIO;
617 }
618
619 static void cmpc_accel_close(struct input_dev *input)
620 {
621         struct acpi_device *acpi;
622
623         acpi = to_acpi_device(input->dev.parent);
624         cmpc_stop_accel(acpi->handle);
625 }
626
627 static void cmpc_accel_idev_init(struct input_dev *inputdev)
628 {
629         set_bit(EV_ABS, inputdev->evbit);
630         input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
631         input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
632         input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
633         inputdev->open = cmpc_accel_open;
634         inputdev->close = cmpc_accel_close;
635 }
636
637 static int cmpc_accel_add(struct acpi_device *acpi)
638 {
639         int error;
640         struct input_dev *inputdev;
641         struct cmpc_accel *accel;
642
643         accel = kmalloc(sizeof(*accel), GFP_KERNEL);
644         if (!accel)
645                 return -ENOMEM;
646
647         accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
648         cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
649
650         error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
651         if (error)
652                 goto failed_file;
653
654         error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
655                                             cmpc_accel_idev_init);
656         if (error)
657                 goto failed_input;
658
659         inputdev = dev_get_drvdata(&acpi->dev);
660         dev_set_drvdata(&inputdev->dev, accel);
661
662         return 0;
663
664 failed_input:
665         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
666 failed_file:
667         kfree(accel);
668         return error;
669 }
670
671 static int cmpc_accel_remove(struct acpi_device *acpi)
672 {
673         struct input_dev *inputdev;
674         struct cmpc_accel *accel;
675
676         inputdev = dev_get_drvdata(&acpi->dev);
677         accel = dev_get_drvdata(&inputdev->dev);
678
679         device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
680         return cmpc_remove_acpi_notify_device(acpi);
681 }
682
683 static const struct acpi_device_id cmpc_accel_device_ids[] = {
684         {CMPC_ACCEL_HID, 0},
685         {"", 0}
686 };
687
688 static struct acpi_driver cmpc_accel_acpi_driver = {
689         .owner = THIS_MODULE,
690         .name = "cmpc_accel",
691         .class = "cmpc_accel",
692         .ids = cmpc_accel_device_ids,
693         .ops = {
694                 .add = cmpc_accel_add,
695                 .remove = cmpc_accel_remove,
696                 .notify = cmpc_accel_handler,
697         }
698 };
699
700
701 /*
702  * Tablet mode code.
703  */
704 static acpi_status cmpc_get_tablet(acpi_handle handle,
705                                    unsigned long long *value)
706 {
707         union acpi_object param;
708         struct acpi_object_list input;
709         unsigned long long output;
710         acpi_status status;
711
712         param.type = ACPI_TYPE_INTEGER;
713         param.integer.value = 0x01;
714         input.count = 1;
715         input.pointer = &param;
716         status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
717         if (ACPI_SUCCESS(status))
718                 *value = output;
719         return status;
720 }
721
722 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
723 {
724         unsigned long long val = 0;
725         struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
726
727         if (event == 0x81) {
728                 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
729                         input_report_switch(inputdev, SW_TABLET_MODE, !val);
730                         input_sync(inputdev);
731                 }
732         }
733 }
734
735 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
736 {
737         unsigned long long val = 0;
738         struct acpi_device *acpi;
739
740         set_bit(EV_SW, inputdev->evbit);
741         set_bit(SW_TABLET_MODE, inputdev->swbit);
742
743         acpi = to_acpi_device(inputdev->dev.parent);
744         if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
745                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
746                 input_sync(inputdev);
747         }
748 }
749
750 static int cmpc_tablet_add(struct acpi_device *acpi)
751 {
752         return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
753                                            cmpc_tablet_idev_init);
754 }
755
756 static int cmpc_tablet_remove(struct acpi_device *acpi)
757 {
758         return cmpc_remove_acpi_notify_device(acpi);
759 }
760
761 #ifdef CONFIG_PM_SLEEP
762 static int cmpc_tablet_resume(struct device *dev)
763 {
764         struct input_dev *inputdev = dev_get_drvdata(dev);
765
766         unsigned long long val = 0;
767         if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
768                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
769                 input_sync(inputdev);
770         }
771         return 0;
772 }
773 #endif
774
775 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
776
777 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
778         {CMPC_TABLET_HID, 0},
779         {"", 0}
780 };
781
782 static struct acpi_driver cmpc_tablet_acpi_driver = {
783         .owner = THIS_MODULE,
784         .name = "cmpc_tablet",
785         .class = "cmpc_tablet",
786         .ids = cmpc_tablet_device_ids,
787         .ops = {
788                 .add = cmpc_tablet_add,
789                 .remove = cmpc_tablet_remove,
790                 .notify = cmpc_tablet_handler,
791         },
792         .drv.pm = &cmpc_tablet_pm,
793 };
794
795
796 /*
797  * Backlight code.
798  */
799
800 static acpi_status cmpc_get_brightness(acpi_handle handle,
801                                        unsigned long long *value)
802 {
803         union acpi_object param;
804         struct acpi_object_list input;
805         unsigned long long output;
806         acpi_status status;
807
808         param.type = ACPI_TYPE_INTEGER;
809         param.integer.value = 0xC0;
810         input.count = 1;
811         input.pointer = &param;
812         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
813         if (ACPI_SUCCESS(status))
814                 *value = output;
815         return status;
816 }
817
818 static acpi_status cmpc_set_brightness(acpi_handle handle,
819                                        unsigned long long value)
820 {
821         union acpi_object param[2];
822         struct acpi_object_list input;
823         acpi_status status;
824         unsigned long long output;
825
826         param[0].type = ACPI_TYPE_INTEGER;
827         param[0].integer.value = 0xC0;
828         param[1].type = ACPI_TYPE_INTEGER;
829         param[1].integer.value = value;
830         input.count = 2;
831         input.pointer = param;
832         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
833         return status;
834 }
835
836 static int cmpc_bl_get_brightness(struct backlight_device *bd)
837 {
838         acpi_status status;
839         acpi_handle handle;
840         unsigned long long brightness;
841
842         handle = bl_get_data(bd);
843         status = cmpc_get_brightness(handle, &brightness);
844         if (ACPI_SUCCESS(status))
845                 return brightness;
846         else
847                 return -1;
848 }
849
850 static int cmpc_bl_update_status(struct backlight_device *bd)
851 {
852         acpi_status status;
853         acpi_handle handle;
854
855         handle = bl_get_data(bd);
856         status = cmpc_set_brightness(handle, bd->props.brightness);
857         if (ACPI_SUCCESS(status))
858                 return 0;
859         else
860                 return -1;
861 }
862
863 static const struct backlight_ops cmpc_bl_ops = {
864         .get_brightness = cmpc_bl_get_brightness,
865         .update_status = cmpc_bl_update_status
866 };
867
868 /*
869  * RFKILL code.
870  */
871
872 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
873                                         unsigned long long *value)
874 {
875         union acpi_object param;
876         struct acpi_object_list input;
877         unsigned long long output;
878         acpi_status status;
879
880         param.type = ACPI_TYPE_INTEGER;
881         param.integer.value = 0xC1;
882         input.count = 1;
883         input.pointer = &param;
884         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
885         if (ACPI_SUCCESS(status))
886                 *value = output;
887         return status;
888 }
889
890 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
891                                         unsigned long long value)
892 {
893         union acpi_object param[2];
894         struct acpi_object_list input;
895         acpi_status status;
896         unsigned long long output;
897
898         param[0].type = ACPI_TYPE_INTEGER;
899         param[0].integer.value = 0xC1;
900         param[1].type = ACPI_TYPE_INTEGER;
901         param[1].integer.value = value;
902         input.count = 2;
903         input.pointer = param;
904         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
905         return status;
906 }
907
908 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
909 {
910         acpi_status status;
911         acpi_handle handle;
912         unsigned long long state;
913         bool blocked;
914
915         handle = data;
916         status = cmpc_get_rfkill_wlan(handle, &state);
917         if (ACPI_SUCCESS(status)) {
918                 blocked = state & 1 ? false : true;
919                 rfkill_set_sw_state(rfkill, blocked);
920         }
921 }
922
923 static int cmpc_rfkill_block(void *data, bool blocked)
924 {
925         acpi_status status;
926         acpi_handle handle;
927         unsigned long long state;
928         bool is_blocked;
929
930         handle = data;
931         status = cmpc_get_rfkill_wlan(handle, &state);
932         if (ACPI_FAILURE(status))
933                 return -ENODEV;
934         /* Check if we really need to call cmpc_set_rfkill_wlan */
935         is_blocked = state & 1 ? false : true;
936         if (is_blocked != blocked) {
937                 state = blocked ? 0 : 1;
938                 status = cmpc_set_rfkill_wlan(handle, state);
939                 if (ACPI_FAILURE(status))
940                         return -ENODEV;
941         }
942         return 0;
943 }
944
945 static const struct rfkill_ops cmpc_rfkill_ops = {
946         .query = cmpc_rfkill_query,
947         .set_block = cmpc_rfkill_block,
948 };
949
950 /*
951  * Common backlight and rfkill code.
952  */
953
954 struct ipml200_dev {
955         struct backlight_device *bd;
956         struct rfkill *rf;
957 };
958
959 static int cmpc_ipml_add(struct acpi_device *acpi)
960 {
961         int retval;
962         struct ipml200_dev *ipml;
963         struct backlight_properties props;
964
965         ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
966         if (ipml == NULL)
967                 return -ENOMEM;
968
969         memset(&props, 0, sizeof(struct backlight_properties));
970         props.type = BACKLIGHT_PLATFORM;
971         props.max_brightness = 7;
972         ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
973                                              acpi->handle, &cmpc_bl_ops,
974                                              &props);
975         if (IS_ERR(ipml->bd)) {
976                 retval = PTR_ERR(ipml->bd);
977                 goto out_bd;
978         }
979
980         ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
981                                 &cmpc_rfkill_ops, acpi->handle);
982         /*
983          * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
984          * This is OK, however, since all other uses of the device will not
985          * derefence it.
986          */
987         if (ipml->rf) {
988                 retval = rfkill_register(ipml->rf);
989                 if (retval) {
990                         rfkill_destroy(ipml->rf);
991                         ipml->rf = NULL;
992                 }
993         }
994
995         dev_set_drvdata(&acpi->dev, ipml);
996         return 0;
997
998 out_bd:
999         kfree(ipml);
1000         return retval;
1001 }
1002
1003 static int cmpc_ipml_remove(struct acpi_device *acpi)
1004 {
1005         struct ipml200_dev *ipml;
1006
1007         ipml = dev_get_drvdata(&acpi->dev);
1008
1009         backlight_device_unregister(ipml->bd);
1010
1011         if (ipml->rf) {
1012                 rfkill_unregister(ipml->rf);
1013                 rfkill_destroy(ipml->rf);
1014         }
1015
1016         kfree(ipml);
1017
1018         return 0;
1019 }
1020
1021 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
1022         {CMPC_IPML_HID, 0},
1023         {"", 0}
1024 };
1025
1026 static struct acpi_driver cmpc_ipml_acpi_driver = {
1027         .owner = THIS_MODULE,
1028         .name = "cmpc",
1029         .class = "cmpc",
1030         .ids = cmpc_ipml_device_ids,
1031         .ops = {
1032                 .add = cmpc_ipml_add,
1033                 .remove = cmpc_ipml_remove
1034         }
1035 };
1036
1037
1038 /*
1039  * Extra keys code.
1040  */
1041 static int cmpc_keys_codes[] = {
1042         KEY_UNKNOWN,
1043         KEY_WLAN,
1044         KEY_SWITCHVIDEOMODE,
1045         KEY_BRIGHTNESSDOWN,
1046         KEY_BRIGHTNESSUP,
1047         KEY_VENDOR,
1048         KEY_UNKNOWN,
1049         KEY_CAMERA,
1050         KEY_BACK,
1051         KEY_FORWARD,
1052         KEY_MAX
1053 };
1054
1055 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1056 {
1057         struct input_dev *inputdev;
1058         int code = KEY_MAX;
1059
1060         if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1061                 code = cmpc_keys_codes[event & 0x0F];
1062         inputdev = dev_get_drvdata(&dev->dev);
1063         input_report_key(inputdev, code, !(event & 0x10));
1064         input_sync(inputdev);
1065 }
1066
1067 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1068 {
1069         int i;
1070
1071         set_bit(EV_KEY, inputdev->evbit);
1072         for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1073                 set_bit(cmpc_keys_codes[i], inputdev->keybit);
1074 }
1075
1076 static int cmpc_keys_add(struct acpi_device *acpi)
1077 {
1078         return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1079                                            cmpc_keys_idev_init);
1080 }
1081
1082 static int cmpc_keys_remove(struct acpi_device *acpi)
1083 {
1084         return cmpc_remove_acpi_notify_device(acpi);
1085 }
1086
1087 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1088         {CMPC_KEYS_HID, 0},
1089         {"", 0}
1090 };
1091
1092 static struct acpi_driver cmpc_keys_acpi_driver = {
1093         .owner = THIS_MODULE,
1094         .name = "cmpc_keys",
1095         .class = "cmpc_keys",
1096         .ids = cmpc_keys_device_ids,
1097         .ops = {
1098                 .add = cmpc_keys_add,
1099                 .remove = cmpc_keys_remove,
1100                 .notify = cmpc_keys_handler,
1101         }
1102 };
1103
1104
1105 /*
1106  * General init/exit code.
1107  */
1108
1109 static int cmpc_init(void)
1110 {
1111         int r;
1112
1113         r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1114         if (r)
1115                 goto failed_keys;
1116
1117         r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1118         if (r)
1119                 goto failed_bl;
1120
1121         r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1122         if (r)
1123                 goto failed_tablet;
1124
1125         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1126         if (r)
1127                 goto failed_accel;
1128
1129         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1130         if (r)
1131                 goto failed_accel_v4;
1132
1133         return r;
1134
1135 failed_accel_v4:
1136         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1137
1138 failed_accel:
1139         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1140
1141 failed_tablet:
1142         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1143
1144 failed_bl:
1145         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1146
1147 failed_keys:
1148         return r;
1149 }
1150
1151 static void cmpc_exit(void)
1152 {
1153         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1154         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1155         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1156         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1157         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1158 }
1159
1160 module_init(cmpc_init);
1161 module_exit(cmpc_exit);
1162
1163 static const struct acpi_device_id cmpc_device_ids[] = {
1164         {CMPC_ACCEL_HID, 0},
1165         {CMPC_ACCEL_HID_V4, 0},
1166         {CMPC_TABLET_HID, 0},
1167         {CMPC_IPML_HID, 0},
1168         {CMPC_KEYS_HID, 0},
1169         {"", 0}
1170 };
1171
1172 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);