2 * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
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.
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.
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.
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/workqueue.h>
24 #include <linux/acpi.h>
25 #include <linux/backlight.h>
26 #include <linux/input.h>
27 #include <linux/rfkill.h>
29 MODULE_LICENSE("GPL");
37 #define CMPC_ACCEL_DEV_STATE_CLOSED 0
38 #define CMPC_ACCEL_DEV_STATE_OPEN 1
40 #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
41 #define CMPC_ACCEL_G_SELECT_DEFAULT 0
43 #define CMPC_ACCEL_HID "ACCE0000"
44 #define CMPC_ACCEL_HID_V4 "ACCE0001"
45 #define CMPC_TABLET_HID "TBLT0000"
46 #define CMPC_IPML_HID "IPML200"
47 #define CMPC_KEYS_HID "FNBT0000"
50 * Generic input device code.
53 typedef void (*input_device_init
)(struct input_dev
*dev
);
55 static int cmpc_add_acpi_notify_device(struct acpi_device
*acpi
, char *name
,
56 input_device_init idev_init
)
58 struct input_dev
*inputdev
;
61 inputdev
= input_allocate_device();
64 inputdev
->name
= name
;
65 inputdev
->dev
.parent
= &acpi
->dev
;
67 error
= input_register_device(inputdev
);
69 input_free_device(inputdev
);
72 dev_set_drvdata(&acpi
->dev
, inputdev
);
76 static int cmpc_remove_acpi_notify_device(struct acpi_device
*acpi
)
78 struct input_dev
*inputdev
= dev_get_drvdata(&acpi
->dev
);
79 input_unregister_device(inputdev
);
84 * Accelerometer code for Classmate V4
86 static acpi_status
cmpc_start_accel_v4(acpi_handle handle
)
88 union acpi_object param
[4];
89 struct acpi_object_list input
;
92 param
[0].type
= ACPI_TYPE_INTEGER
;
93 param
[0].integer
.value
= 0x3;
94 param
[1].type
= ACPI_TYPE_INTEGER
;
95 param
[1].integer
.value
= 0;
96 param
[2].type
= ACPI_TYPE_INTEGER
;
97 param
[2].integer
.value
= 0;
98 param
[3].type
= ACPI_TYPE_INTEGER
;
99 param
[3].integer
.value
= 0;
101 input
.pointer
= param
;
102 status
= acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
106 static acpi_status
cmpc_stop_accel_v4(acpi_handle handle
)
108 union acpi_object param
[4];
109 struct acpi_object_list input
;
112 param
[0].type
= ACPI_TYPE_INTEGER
;
113 param
[0].integer
.value
= 0x4;
114 param
[1].type
= ACPI_TYPE_INTEGER
;
115 param
[1].integer
.value
= 0;
116 param
[2].type
= ACPI_TYPE_INTEGER
;
117 param
[2].integer
.value
= 0;
118 param
[3].type
= ACPI_TYPE_INTEGER
;
119 param
[3].integer
.value
= 0;
121 input
.pointer
= param
;
122 status
= acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
126 static acpi_status
cmpc_accel_set_sensitivity_v4(acpi_handle handle
, int val
)
128 union acpi_object param
[4];
129 struct acpi_object_list input
;
131 param
[0].type
= ACPI_TYPE_INTEGER
;
132 param
[0].integer
.value
= 0x02;
133 param
[1].type
= ACPI_TYPE_INTEGER
;
134 param
[1].integer
.value
= val
;
135 param
[2].type
= ACPI_TYPE_INTEGER
;
136 param
[2].integer
.value
= 0;
137 param
[3].type
= ACPI_TYPE_INTEGER
;
138 param
[3].integer
.value
= 0;
140 input
.pointer
= param
;
141 return acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
144 static acpi_status
cmpc_accel_set_g_select_v4(acpi_handle handle
, int val
)
146 union acpi_object param
[4];
147 struct acpi_object_list input
;
149 param
[0].type
= ACPI_TYPE_INTEGER
;
150 param
[0].integer
.value
= 0x05;
151 param
[1].type
= ACPI_TYPE_INTEGER
;
152 param
[1].integer
.value
= val
;
153 param
[2].type
= ACPI_TYPE_INTEGER
;
154 param
[2].integer
.value
= 0;
155 param
[3].type
= ACPI_TYPE_INTEGER
;
156 param
[3].integer
.value
= 0;
158 input
.pointer
= param
;
159 return acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
162 static acpi_status
cmpc_get_accel_v4(acpi_handle handle
,
167 union acpi_object param
[4];
168 struct acpi_object_list input
;
169 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
173 param
[0].type
= ACPI_TYPE_INTEGER
;
174 param
[0].integer
.value
= 0x01;
175 param
[1].type
= ACPI_TYPE_INTEGER
;
176 param
[1].integer
.value
= 0;
177 param
[2].type
= ACPI_TYPE_INTEGER
;
178 param
[2].integer
.value
= 0;
179 param
[3].type
= ACPI_TYPE_INTEGER
;
180 param
[3].integer
.value
= 0;
182 input
.pointer
= param
;
183 status
= acpi_evaluate_object(handle
, "ACMD", &input
, &output
);
184 if (ACPI_SUCCESS(status
)) {
185 union acpi_object
*obj
;
186 obj
= output
.pointer
;
187 locs
= (int16_t *) obj
->buffer
.pointer
;
191 kfree(output
.pointer
);
196 static void cmpc_accel_handler_v4(struct acpi_device
*dev
, u32 event
)
202 status
= cmpc_get_accel_v4(dev
->handle
, &x
, &y
, &z
);
203 if (ACPI_SUCCESS(status
)) {
204 struct input_dev
*inputdev
= dev_get_drvdata(&dev
->dev
);
206 input_report_abs(inputdev
, ABS_X
, x
);
207 input_report_abs(inputdev
, ABS_Y
, y
);
208 input_report_abs(inputdev
, ABS_Z
, z
);
209 input_sync(inputdev
);
214 static ssize_t
cmpc_accel_sensitivity_show_v4(struct device
*dev
,
215 struct device_attribute
*attr
,
218 struct acpi_device
*acpi
;
219 struct input_dev
*inputdev
;
220 struct cmpc_accel
*accel
;
222 acpi
= to_acpi_device(dev
);
223 inputdev
= dev_get_drvdata(&acpi
->dev
);
224 accel
= dev_get_drvdata(&inputdev
->dev
);
226 return sprintf(buf
, "%d\n", accel
->sensitivity
);
229 static ssize_t
cmpc_accel_sensitivity_store_v4(struct device
*dev
,
230 struct device_attribute
*attr
,
231 const char *buf
, size_t count
)
233 struct acpi_device
*acpi
;
234 struct input_dev
*inputdev
;
235 struct cmpc_accel
*accel
;
236 unsigned long sensitivity
;
239 acpi
= to_acpi_device(dev
);
240 inputdev
= dev_get_drvdata(&acpi
->dev
);
241 accel
= dev_get_drvdata(&inputdev
->dev
);
243 r
= kstrtoul(buf
, 0, &sensitivity
);
247 /* sensitivity must be between 1 and 127 */
248 if (sensitivity
< 1 || sensitivity
> 127)
251 accel
->sensitivity
= sensitivity
;
252 cmpc_accel_set_sensitivity_v4(acpi
->handle
, sensitivity
);
254 return strnlen(buf
, count
);
257 static struct device_attribute cmpc_accel_sensitivity_attr_v4
= {
258 .attr
= { .name
= "sensitivity", .mode
= 0660 },
259 .show
= cmpc_accel_sensitivity_show_v4
,
260 .store
= cmpc_accel_sensitivity_store_v4
263 static ssize_t
cmpc_accel_g_select_show_v4(struct device
*dev
,
264 struct device_attribute
*attr
,
267 struct acpi_device
*acpi
;
268 struct input_dev
*inputdev
;
269 struct cmpc_accel
*accel
;
271 acpi
= to_acpi_device(dev
);
272 inputdev
= dev_get_drvdata(&acpi
->dev
);
273 accel
= dev_get_drvdata(&inputdev
->dev
);
275 return sprintf(buf
, "%d\n", accel
->g_select
);
278 static ssize_t
cmpc_accel_g_select_store_v4(struct device
*dev
,
279 struct device_attribute
*attr
,
280 const char *buf
, size_t count
)
282 struct acpi_device
*acpi
;
283 struct input_dev
*inputdev
;
284 struct cmpc_accel
*accel
;
285 unsigned long g_select
;
288 acpi
= to_acpi_device(dev
);
289 inputdev
= dev_get_drvdata(&acpi
->dev
);
290 accel
= dev_get_drvdata(&inputdev
->dev
);
292 r
= kstrtoul(buf
, 0, &g_select
);
296 /* 0 means 1.5g, 1 means 6g, everything else is wrong */
297 if (g_select
!= 0 && g_select
!= 1)
300 accel
->g_select
= g_select
;
301 cmpc_accel_set_g_select_v4(acpi
->handle
, g_select
);
303 return strnlen(buf
, count
);
306 static struct device_attribute cmpc_accel_g_select_attr_v4
= {
307 .attr
= { .name
= "g_select", .mode
= 0660 },
308 .show
= cmpc_accel_g_select_show_v4
,
309 .store
= cmpc_accel_g_select_store_v4
312 static int cmpc_accel_open_v4(struct input_dev
*input
)
314 struct acpi_device
*acpi
;
315 struct cmpc_accel
*accel
;
317 acpi
= to_acpi_device(input
->dev
.parent
);
318 accel
= dev_get_drvdata(&input
->dev
);
320 cmpc_accel_set_sensitivity_v4(acpi
->handle
, accel
->sensitivity
);
321 cmpc_accel_set_g_select_v4(acpi
->handle
, accel
->g_select
);
323 if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi
->handle
))) {
324 accel
->inputdev_state
= CMPC_ACCEL_DEV_STATE_OPEN
;
330 static void cmpc_accel_close_v4(struct input_dev
*input
)
332 struct acpi_device
*acpi
;
333 struct cmpc_accel
*accel
;
335 acpi
= to_acpi_device(input
->dev
.parent
);
336 accel
= dev_get_drvdata(&input
->dev
);
338 cmpc_stop_accel_v4(acpi
->handle
);
339 accel
->inputdev_state
= CMPC_ACCEL_DEV_STATE_CLOSED
;
342 static void cmpc_accel_idev_init_v4(struct input_dev
*inputdev
)
344 set_bit(EV_ABS
, inputdev
->evbit
);
345 input_set_abs_params(inputdev
, ABS_X
, -255, 255, 16, 0);
346 input_set_abs_params(inputdev
, ABS_Y
, -255, 255, 16, 0);
347 input_set_abs_params(inputdev
, ABS_Z
, -255, 255, 16, 0);
348 inputdev
->open
= cmpc_accel_open_v4
;
349 inputdev
->close
= cmpc_accel_close_v4
;
352 #ifdef CONFIG_PM_SLEEP
353 static int cmpc_accel_suspend_v4(struct device
*dev
)
355 struct input_dev
*inputdev
;
356 struct cmpc_accel
*accel
;
358 inputdev
= dev_get_drvdata(dev
);
359 accel
= dev_get_drvdata(&inputdev
->dev
);
361 if (accel
->inputdev_state
== CMPC_ACCEL_DEV_STATE_OPEN
)
362 return cmpc_stop_accel_v4(to_acpi_device(dev
)->handle
);
367 static int cmpc_accel_resume_v4(struct device
*dev
)
369 struct input_dev
*inputdev
;
370 struct cmpc_accel
*accel
;
372 inputdev
= dev_get_drvdata(dev
);
373 accel
= dev_get_drvdata(&inputdev
->dev
);
375 if (accel
->inputdev_state
== CMPC_ACCEL_DEV_STATE_OPEN
) {
376 cmpc_accel_set_sensitivity_v4(to_acpi_device(dev
)->handle
,
378 cmpc_accel_set_g_select_v4(to_acpi_device(dev
)->handle
,
381 if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev
)->handle
)))
389 static int cmpc_accel_add_v4(struct acpi_device
*acpi
)
392 struct input_dev
*inputdev
;
393 struct cmpc_accel
*accel
;
395 accel
= kmalloc(sizeof(*accel
), GFP_KERNEL
);
399 accel
->inputdev_state
= CMPC_ACCEL_DEV_STATE_CLOSED
;
401 accel
->sensitivity
= CMPC_ACCEL_SENSITIVITY_DEFAULT
;
402 cmpc_accel_set_sensitivity_v4(acpi
->handle
, accel
->sensitivity
);
404 error
= device_create_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr_v4
);
406 goto failed_sensitivity
;
408 accel
->g_select
= CMPC_ACCEL_G_SELECT_DEFAULT
;
409 cmpc_accel_set_g_select_v4(acpi
->handle
, accel
->g_select
);
411 error
= device_create_file(&acpi
->dev
, &cmpc_accel_g_select_attr_v4
);
413 goto failed_g_select
;
415 error
= cmpc_add_acpi_notify_device(acpi
, "cmpc_accel_v4",
416 cmpc_accel_idev_init_v4
);
420 inputdev
= dev_get_drvdata(&acpi
->dev
);
421 dev_set_drvdata(&inputdev
->dev
, accel
);
426 device_remove_file(&acpi
->dev
, &cmpc_accel_g_select_attr_v4
);
428 device_remove_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr_v4
);
434 static int cmpc_accel_remove_v4(struct acpi_device
*acpi
)
436 struct input_dev
*inputdev
;
437 struct cmpc_accel
*accel
;
439 inputdev
= dev_get_drvdata(&acpi
->dev
);
440 accel
= dev_get_drvdata(&inputdev
->dev
);
442 device_remove_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr_v4
);
443 device_remove_file(&acpi
->dev
, &cmpc_accel_g_select_attr_v4
);
444 return cmpc_remove_acpi_notify_device(acpi
);
447 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm
, cmpc_accel_suspend_v4
,
448 cmpc_accel_resume_v4
);
450 static const struct acpi_device_id cmpc_accel_device_ids_v4
[] = {
451 {CMPC_ACCEL_HID_V4
, 0},
455 static struct acpi_driver cmpc_accel_acpi_driver_v4
= {
456 .owner
= THIS_MODULE
,
457 .name
= "cmpc_accel_v4",
458 .class = "cmpc_accel_v4",
459 .ids
= cmpc_accel_device_ids_v4
,
461 .add
= cmpc_accel_add_v4
,
462 .remove
= cmpc_accel_remove_v4
,
463 .notify
= cmpc_accel_handler_v4
,
465 .drv
.pm
= &cmpc_accel_pm
,
470 * Accelerometer code for Classmate versions prior to V4
472 static acpi_status
cmpc_start_accel(acpi_handle handle
)
474 union acpi_object param
[2];
475 struct acpi_object_list input
;
478 param
[0].type
= ACPI_TYPE_INTEGER
;
479 param
[0].integer
.value
= 0x3;
480 param
[1].type
= ACPI_TYPE_INTEGER
;
482 input
.pointer
= param
;
483 status
= acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
487 static acpi_status
cmpc_stop_accel(acpi_handle handle
)
489 union acpi_object param
[2];
490 struct acpi_object_list input
;
493 param
[0].type
= ACPI_TYPE_INTEGER
;
494 param
[0].integer
.value
= 0x4;
495 param
[1].type
= ACPI_TYPE_INTEGER
;
497 input
.pointer
= param
;
498 status
= acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
502 static acpi_status
cmpc_accel_set_sensitivity(acpi_handle handle
, int val
)
504 union acpi_object param
[2];
505 struct acpi_object_list input
;
507 param
[0].type
= ACPI_TYPE_INTEGER
;
508 param
[0].integer
.value
= 0x02;
509 param
[1].type
= ACPI_TYPE_INTEGER
;
510 param
[1].integer
.value
= val
;
512 input
.pointer
= param
;
513 return acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
516 static acpi_status
cmpc_get_accel(acpi_handle handle
,
521 union acpi_object param
[2];
522 struct acpi_object_list input
;
523 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, 0 };
527 param
[0].type
= ACPI_TYPE_INTEGER
;
528 param
[0].integer
.value
= 0x01;
529 param
[1].type
= ACPI_TYPE_INTEGER
;
531 input
.pointer
= param
;
532 status
= acpi_evaluate_object(handle
, "ACMD", &input
, &output
);
533 if (ACPI_SUCCESS(status
)) {
534 union acpi_object
*obj
;
535 obj
= output
.pointer
;
536 locs
= obj
->buffer
.pointer
;
540 kfree(output
.pointer
);
545 static void cmpc_accel_handler(struct acpi_device
*dev
, u32 event
)
548 unsigned char x
, y
, z
;
551 status
= cmpc_get_accel(dev
->handle
, &x
, &y
, &z
);
552 if (ACPI_SUCCESS(status
)) {
553 struct input_dev
*inputdev
= dev_get_drvdata(&dev
->dev
);
555 input_report_abs(inputdev
, ABS_X
, x
);
556 input_report_abs(inputdev
, ABS_Y
, y
);
557 input_report_abs(inputdev
, ABS_Z
, z
);
558 input_sync(inputdev
);
563 static ssize_t
cmpc_accel_sensitivity_show(struct device
*dev
,
564 struct device_attribute
*attr
,
567 struct acpi_device
*acpi
;
568 struct input_dev
*inputdev
;
569 struct cmpc_accel
*accel
;
571 acpi
= to_acpi_device(dev
);
572 inputdev
= dev_get_drvdata(&acpi
->dev
);
573 accel
= dev_get_drvdata(&inputdev
->dev
);
575 return sprintf(buf
, "%d\n", accel
->sensitivity
);
578 static ssize_t
cmpc_accel_sensitivity_store(struct device
*dev
,
579 struct device_attribute
*attr
,
580 const char *buf
, size_t count
)
582 struct acpi_device
*acpi
;
583 struct input_dev
*inputdev
;
584 struct cmpc_accel
*accel
;
585 unsigned long sensitivity
;
588 acpi
= to_acpi_device(dev
);
589 inputdev
= dev_get_drvdata(&acpi
->dev
);
590 accel
= dev_get_drvdata(&inputdev
->dev
);
592 r
= kstrtoul(buf
, 0, &sensitivity
);
596 accel
->sensitivity
= sensitivity
;
597 cmpc_accel_set_sensitivity(acpi
->handle
, sensitivity
);
599 return strnlen(buf
, count
);
602 static struct device_attribute cmpc_accel_sensitivity_attr
= {
603 .attr
= { .name
= "sensitivity", .mode
= 0660 },
604 .show
= cmpc_accel_sensitivity_show
,
605 .store
= cmpc_accel_sensitivity_store
608 static int cmpc_accel_open(struct input_dev
*input
)
610 struct acpi_device
*acpi
;
612 acpi
= to_acpi_device(input
->dev
.parent
);
613 if (ACPI_SUCCESS(cmpc_start_accel(acpi
->handle
)))
618 static void cmpc_accel_close(struct input_dev
*input
)
620 struct acpi_device
*acpi
;
622 acpi
= to_acpi_device(input
->dev
.parent
);
623 cmpc_stop_accel(acpi
->handle
);
626 static void cmpc_accel_idev_init(struct input_dev
*inputdev
)
628 set_bit(EV_ABS
, inputdev
->evbit
);
629 input_set_abs_params(inputdev
, ABS_X
, 0, 255, 8, 0);
630 input_set_abs_params(inputdev
, ABS_Y
, 0, 255, 8, 0);
631 input_set_abs_params(inputdev
, ABS_Z
, 0, 255, 8, 0);
632 inputdev
->open
= cmpc_accel_open
;
633 inputdev
->close
= cmpc_accel_close
;
636 static int cmpc_accel_add(struct acpi_device
*acpi
)
639 struct input_dev
*inputdev
;
640 struct cmpc_accel
*accel
;
642 accel
= kmalloc(sizeof(*accel
), GFP_KERNEL
);
646 accel
->sensitivity
= CMPC_ACCEL_SENSITIVITY_DEFAULT
;
647 cmpc_accel_set_sensitivity(acpi
->handle
, accel
->sensitivity
);
649 error
= device_create_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr
);
653 error
= cmpc_add_acpi_notify_device(acpi
, "cmpc_accel",
654 cmpc_accel_idev_init
);
658 inputdev
= dev_get_drvdata(&acpi
->dev
);
659 dev_set_drvdata(&inputdev
->dev
, accel
);
664 device_remove_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr
);
670 static int cmpc_accel_remove(struct acpi_device
*acpi
)
672 struct input_dev
*inputdev
;
673 struct cmpc_accel
*accel
;
675 inputdev
= dev_get_drvdata(&acpi
->dev
);
676 accel
= dev_get_drvdata(&inputdev
->dev
);
678 device_remove_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr
);
679 return cmpc_remove_acpi_notify_device(acpi
);
682 static const struct acpi_device_id cmpc_accel_device_ids
[] = {
687 static struct acpi_driver cmpc_accel_acpi_driver
= {
688 .owner
= THIS_MODULE
,
689 .name
= "cmpc_accel",
690 .class = "cmpc_accel",
691 .ids
= cmpc_accel_device_ids
,
693 .add
= cmpc_accel_add
,
694 .remove
= cmpc_accel_remove
,
695 .notify
= cmpc_accel_handler
,
703 static acpi_status
cmpc_get_tablet(acpi_handle handle
,
704 unsigned long long *value
)
706 union acpi_object param
;
707 struct acpi_object_list input
;
708 unsigned long long output
;
711 param
.type
= ACPI_TYPE_INTEGER
;
712 param
.integer
.value
= 0x01;
714 input
.pointer
= ¶m
;
715 status
= acpi_evaluate_integer(handle
, "TCMD", &input
, &output
);
716 if (ACPI_SUCCESS(status
))
721 static void cmpc_tablet_handler(struct acpi_device
*dev
, u32 event
)
723 unsigned long long val
= 0;
724 struct input_dev
*inputdev
= dev_get_drvdata(&dev
->dev
);
727 if (ACPI_SUCCESS(cmpc_get_tablet(dev
->handle
, &val
))) {
728 input_report_switch(inputdev
, SW_TABLET_MODE
, !val
);
729 input_sync(inputdev
);
734 static void cmpc_tablet_idev_init(struct input_dev
*inputdev
)
736 unsigned long long val
= 0;
737 struct acpi_device
*acpi
;
739 set_bit(EV_SW
, inputdev
->evbit
);
740 set_bit(SW_TABLET_MODE
, inputdev
->swbit
);
742 acpi
= to_acpi_device(inputdev
->dev
.parent
);
743 if (ACPI_SUCCESS(cmpc_get_tablet(acpi
->handle
, &val
))) {
744 input_report_switch(inputdev
, SW_TABLET_MODE
, !val
);
745 input_sync(inputdev
);
749 static int cmpc_tablet_add(struct acpi_device
*acpi
)
751 return cmpc_add_acpi_notify_device(acpi
, "cmpc_tablet",
752 cmpc_tablet_idev_init
);
755 static int cmpc_tablet_remove(struct acpi_device
*acpi
)
757 return cmpc_remove_acpi_notify_device(acpi
);
760 #ifdef CONFIG_PM_SLEEP
761 static int cmpc_tablet_resume(struct device
*dev
)
763 struct input_dev
*inputdev
= dev_get_drvdata(dev
);
765 unsigned long long val
= 0;
766 if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev
)->handle
, &val
))) {
767 input_report_switch(inputdev
, SW_TABLET_MODE
, !val
);
768 input_sync(inputdev
);
774 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm
, NULL
, cmpc_tablet_resume
);
776 static const struct acpi_device_id cmpc_tablet_device_ids
[] = {
777 {CMPC_TABLET_HID
, 0},
781 static struct acpi_driver cmpc_tablet_acpi_driver
= {
782 .owner
= THIS_MODULE
,
783 .name
= "cmpc_tablet",
784 .class = "cmpc_tablet",
785 .ids
= cmpc_tablet_device_ids
,
787 .add
= cmpc_tablet_add
,
788 .remove
= cmpc_tablet_remove
,
789 .notify
= cmpc_tablet_handler
,
791 .drv
.pm
= &cmpc_tablet_pm
,
799 static acpi_status
cmpc_get_brightness(acpi_handle handle
,
800 unsigned long long *value
)
802 union acpi_object param
;
803 struct acpi_object_list input
;
804 unsigned long long output
;
807 param
.type
= ACPI_TYPE_INTEGER
;
808 param
.integer
.value
= 0xC0;
810 input
.pointer
= ¶m
;
811 status
= acpi_evaluate_integer(handle
, "GRDI", &input
, &output
);
812 if (ACPI_SUCCESS(status
))
817 static acpi_status
cmpc_set_brightness(acpi_handle handle
,
818 unsigned long long value
)
820 union acpi_object param
[2];
821 struct acpi_object_list input
;
823 unsigned long long output
;
825 param
[0].type
= ACPI_TYPE_INTEGER
;
826 param
[0].integer
.value
= 0xC0;
827 param
[1].type
= ACPI_TYPE_INTEGER
;
828 param
[1].integer
.value
= value
;
830 input
.pointer
= param
;
831 status
= acpi_evaluate_integer(handle
, "GWRI", &input
, &output
);
835 static int cmpc_bl_get_brightness(struct backlight_device
*bd
)
839 unsigned long long brightness
;
841 handle
= bl_get_data(bd
);
842 status
= cmpc_get_brightness(handle
, &brightness
);
843 if (ACPI_SUCCESS(status
))
849 static int cmpc_bl_update_status(struct backlight_device
*bd
)
854 handle
= bl_get_data(bd
);
855 status
= cmpc_set_brightness(handle
, bd
->props
.brightness
);
856 if (ACPI_SUCCESS(status
))
862 static const struct backlight_ops cmpc_bl_ops
= {
863 .get_brightness
= cmpc_bl_get_brightness
,
864 .update_status
= cmpc_bl_update_status
871 static acpi_status
cmpc_get_rfkill_wlan(acpi_handle handle
,
872 unsigned long long *value
)
874 union acpi_object param
;
875 struct acpi_object_list input
;
876 unsigned long long output
;
879 param
.type
= ACPI_TYPE_INTEGER
;
880 param
.integer
.value
= 0xC1;
882 input
.pointer
= ¶m
;
883 status
= acpi_evaluate_integer(handle
, "GRDI", &input
, &output
);
884 if (ACPI_SUCCESS(status
))
889 static acpi_status
cmpc_set_rfkill_wlan(acpi_handle handle
,
890 unsigned long long value
)
892 union acpi_object param
[2];
893 struct acpi_object_list input
;
895 unsigned long long output
;
897 param
[0].type
= ACPI_TYPE_INTEGER
;
898 param
[0].integer
.value
= 0xC1;
899 param
[1].type
= ACPI_TYPE_INTEGER
;
900 param
[1].integer
.value
= value
;
902 input
.pointer
= param
;
903 status
= acpi_evaluate_integer(handle
, "GWRI", &input
, &output
);
907 static void cmpc_rfkill_query(struct rfkill
*rfkill
, void *data
)
911 unsigned long long state
;
915 status
= cmpc_get_rfkill_wlan(handle
, &state
);
916 if (ACPI_SUCCESS(status
)) {
917 blocked
= state
& 1 ? false : true;
918 rfkill_set_sw_state(rfkill
, blocked
);
922 static int cmpc_rfkill_block(void *data
, bool blocked
)
926 unsigned long long state
;
930 status
= cmpc_get_rfkill_wlan(handle
, &state
);
931 if (ACPI_FAILURE(status
))
933 /* Check if we really need to call cmpc_set_rfkill_wlan */
934 is_blocked
= state
& 1 ? false : true;
935 if (is_blocked
!= blocked
) {
936 state
= blocked
? 0 : 1;
937 status
= cmpc_set_rfkill_wlan(handle
, state
);
938 if (ACPI_FAILURE(status
))
944 static const struct rfkill_ops cmpc_rfkill_ops
= {
945 .query
= cmpc_rfkill_query
,
946 .set_block
= cmpc_rfkill_block
,
950 * Common backlight and rfkill code.
954 struct backlight_device
*bd
;
958 static int cmpc_ipml_add(struct acpi_device
*acpi
)
961 struct ipml200_dev
*ipml
;
962 struct backlight_properties props
;
964 ipml
= kmalloc(sizeof(*ipml
), GFP_KERNEL
);
968 memset(&props
, 0, sizeof(struct backlight_properties
));
969 props
.type
= BACKLIGHT_PLATFORM
;
970 props
.max_brightness
= 7;
971 ipml
->bd
= backlight_device_register("cmpc_bl", &acpi
->dev
,
972 acpi
->handle
, &cmpc_bl_ops
,
974 if (IS_ERR(ipml
->bd
)) {
975 retval
= PTR_ERR(ipml
->bd
);
979 ipml
->rf
= rfkill_alloc("cmpc_rfkill", &acpi
->dev
, RFKILL_TYPE_WLAN
,
980 &cmpc_rfkill_ops
, acpi
->handle
);
982 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
983 * This is OK, however, since all other uses of the device will not
987 retval
= rfkill_register(ipml
->rf
);
989 rfkill_destroy(ipml
->rf
);
994 dev_set_drvdata(&acpi
->dev
, ipml
);
1002 static int cmpc_ipml_remove(struct acpi_device
*acpi
)
1004 struct ipml200_dev
*ipml
;
1006 ipml
= dev_get_drvdata(&acpi
->dev
);
1008 backlight_device_unregister(ipml
->bd
);
1011 rfkill_unregister(ipml
->rf
);
1012 rfkill_destroy(ipml
->rf
);
1020 static const struct acpi_device_id cmpc_ipml_device_ids
[] = {
1025 static struct acpi_driver cmpc_ipml_acpi_driver
= {
1026 .owner
= THIS_MODULE
,
1029 .ids
= cmpc_ipml_device_ids
,
1031 .add
= cmpc_ipml_add
,
1032 .remove
= cmpc_ipml_remove
1040 static int cmpc_keys_codes
[] = {
1043 KEY_SWITCHVIDEOMODE
,
1054 static void cmpc_keys_handler(struct acpi_device
*dev
, u32 event
)
1056 struct input_dev
*inputdev
;
1059 if ((event
& 0x0F) < ARRAY_SIZE(cmpc_keys_codes
))
1060 code
= cmpc_keys_codes
[event
& 0x0F];
1061 inputdev
= dev_get_drvdata(&dev
->dev
);
1062 input_report_key(inputdev
, code
, !(event
& 0x10));
1063 input_sync(inputdev
);
1066 static void cmpc_keys_idev_init(struct input_dev
*inputdev
)
1070 set_bit(EV_KEY
, inputdev
->evbit
);
1071 for (i
= 0; cmpc_keys_codes
[i
] != KEY_MAX
; i
++)
1072 set_bit(cmpc_keys_codes
[i
], inputdev
->keybit
);
1075 static int cmpc_keys_add(struct acpi_device
*acpi
)
1077 return cmpc_add_acpi_notify_device(acpi
, "cmpc_keys",
1078 cmpc_keys_idev_init
);
1081 static int cmpc_keys_remove(struct acpi_device
*acpi
)
1083 return cmpc_remove_acpi_notify_device(acpi
);
1086 static const struct acpi_device_id cmpc_keys_device_ids
[] = {
1091 static struct acpi_driver cmpc_keys_acpi_driver
= {
1092 .owner
= THIS_MODULE
,
1093 .name
= "cmpc_keys",
1094 .class = "cmpc_keys",
1095 .ids
= cmpc_keys_device_ids
,
1097 .add
= cmpc_keys_add
,
1098 .remove
= cmpc_keys_remove
,
1099 .notify
= cmpc_keys_handler
,
1105 * General init/exit code.
1108 static int cmpc_init(void)
1112 r
= acpi_bus_register_driver(&cmpc_keys_acpi_driver
);
1116 r
= acpi_bus_register_driver(&cmpc_ipml_acpi_driver
);
1120 r
= acpi_bus_register_driver(&cmpc_tablet_acpi_driver
);
1124 r
= acpi_bus_register_driver(&cmpc_accel_acpi_driver
);
1128 r
= acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4
);
1130 goto failed_accel_v4
;
1135 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver
);
1138 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver
);
1141 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver
);
1144 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver
);
1150 static void cmpc_exit(void)
1152 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4
);
1153 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver
);
1154 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver
);
1155 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver
);
1156 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver
);
1159 module_init(cmpc_init
);
1160 module_exit(cmpc_exit
);
1162 static const struct acpi_device_id cmpc_device_ids
[] = {
1163 {CMPC_ACCEL_HID
, 0},
1164 {CMPC_ACCEL_HID_V4
, 0},
1165 {CMPC_TABLET_HID
, 0},
1171 MODULE_DEVICE_TABLE(acpi
, cmpc_device_ids
);