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