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