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 <acpi/acpi_drivers.h>
25 #include <linux/backlight.h>
26 #include <linux/input.h>
27 #include <linux/rfkill.h>
29 MODULE_LICENSE("GPL");
36 #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
39 #define CMPC_ACCEL_HID "ACCE0000"
40 #define CMPC_TABLET_HID "TBLT0000"
41 #define CMPC_IPML_HID "IPML200"
42 #define CMPC_KEYS_HID "FnBT0000"
45 * Generic input device code.
48 typedef void (*input_device_init
)(struct input_dev
*dev
);
50 static int cmpc_add_acpi_notify_device(struct acpi_device
*acpi
, char *name
,
51 input_device_init idev_init
)
53 struct input_dev
*inputdev
;
56 inputdev
= input_allocate_device();
59 inputdev
->name
= name
;
60 inputdev
->dev
.parent
= &acpi
->dev
;
62 error
= input_register_device(inputdev
);
64 input_free_device(inputdev
);
67 dev_set_drvdata(&acpi
->dev
, inputdev
);
71 static int cmpc_remove_acpi_notify_device(struct acpi_device
*acpi
)
73 struct input_dev
*inputdev
= dev_get_drvdata(&acpi
->dev
);
74 input_unregister_device(inputdev
);
81 static acpi_status
cmpc_start_accel(acpi_handle handle
)
83 union acpi_object param
[2];
84 struct acpi_object_list input
;
87 param
[0].type
= ACPI_TYPE_INTEGER
;
88 param
[0].integer
.value
= 0x3;
89 param
[1].type
= ACPI_TYPE_INTEGER
;
91 input
.pointer
= param
;
92 status
= acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
96 static acpi_status
cmpc_stop_accel(acpi_handle handle
)
98 union acpi_object param
[2];
99 struct acpi_object_list input
;
102 param
[0].type
= ACPI_TYPE_INTEGER
;
103 param
[0].integer
.value
= 0x4;
104 param
[1].type
= ACPI_TYPE_INTEGER
;
106 input
.pointer
= param
;
107 status
= acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
111 static acpi_status
cmpc_accel_set_sensitivity(acpi_handle handle
, int val
)
113 union acpi_object param
[2];
114 struct acpi_object_list input
;
116 param
[0].type
= ACPI_TYPE_INTEGER
;
117 param
[0].integer
.value
= 0x02;
118 param
[1].type
= ACPI_TYPE_INTEGER
;
119 param
[1].integer
.value
= val
;
121 input
.pointer
= param
;
122 return acpi_evaluate_object(handle
, "ACMD", &input
, NULL
);
125 static acpi_status
cmpc_get_accel(acpi_handle handle
,
130 union acpi_object param
[2];
131 struct acpi_object_list input
;
132 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, 0 };
136 param
[0].type
= ACPI_TYPE_INTEGER
;
137 param
[0].integer
.value
= 0x01;
138 param
[1].type
= ACPI_TYPE_INTEGER
;
140 input
.pointer
= param
;
141 status
= acpi_evaluate_object(handle
, "ACMD", &input
, &output
);
142 if (ACPI_SUCCESS(status
)) {
143 union acpi_object
*obj
;
144 obj
= output
.pointer
;
145 locs
= obj
->buffer
.pointer
;
149 kfree(output
.pointer
);
154 static void cmpc_accel_handler(struct acpi_device
*dev
, u32 event
)
157 unsigned char x
, y
, z
;
160 status
= cmpc_get_accel(dev
->handle
, &x
, &y
, &z
);
161 if (ACPI_SUCCESS(status
)) {
162 struct input_dev
*inputdev
= dev_get_drvdata(&dev
->dev
);
164 input_report_abs(inputdev
, ABS_X
, x
);
165 input_report_abs(inputdev
, ABS_Y
, y
);
166 input_report_abs(inputdev
, ABS_Z
, z
);
167 input_sync(inputdev
);
172 static ssize_t
cmpc_accel_sensitivity_show(struct device
*dev
,
173 struct device_attribute
*attr
,
176 struct acpi_device
*acpi
;
177 struct input_dev
*inputdev
;
178 struct cmpc_accel
*accel
;
180 acpi
= to_acpi_device(dev
);
181 inputdev
= dev_get_drvdata(&acpi
->dev
);
182 accel
= dev_get_drvdata(&inputdev
->dev
);
184 return sprintf(buf
, "%d\n", accel
->sensitivity
);
187 static ssize_t
cmpc_accel_sensitivity_store(struct device
*dev
,
188 struct device_attribute
*attr
,
189 const char *buf
, size_t count
)
191 struct acpi_device
*acpi
;
192 struct input_dev
*inputdev
;
193 struct cmpc_accel
*accel
;
194 unsigned long sensitivity
;
197 acpi
= to_acpi_device(dev
);
198 inputdev
= dev_get_drvdata(&acpi
->dev
);
199 accel
= dev_get_drvdata(&inputdev
->dev
);
201 r
= strict_strtoul(buf
, 0, &sensitivity
);
205 accel
->sensitivity
= sensitivity
;
206 cmpc_accel_set_sensitivity(acpi
->handle
, sensitivity
);
208 return strnlen(buf
, count
);
211 static struct device_attribute cmpc_accel_sensitivity_attr
= {
212 .attr
= { .name
= "sensitivity", .mode
= 0660 },
213 .show
= cmpc_accel_sensitivity_show
,
214 .store
= cmpc_accel_sensitivity_store
217 static int cmpc_accel_open(struct input_dev
*input
)
219 struct acpi_device
*acpi
;
221 acpi
= to_acpi_device(input
->dev
.parent
);
222 if (ACPI_SUCCESS(cmpc_start_accel(acpi
->handle
)))
227 static void cmpc_accel_close(struct input_dev
*input
)
229 struct acpi_device
*acpi
;
231 acpi
= to_acpi_device(input
->dev
.parent
);
232 cmpc_stop_accel(acpi
->handle
);
235 static void cmpc_accel_idev_init(struct input_dev
*inputdev
)
237 set_bit(EV_ABS
, inputdev
->evbit
);
238 input_set_abs_params(inputdev
, ABS_X
, 0, 255, 8, 0);
239 input_set_abs_params(inputdev
, ABS_Y
, 0, 255, 8, 0);
240 input_set_abs_params(inputdev
, ABS_Z
, 0, 255, 8, 0);
241 inputdev
->open
= cmpc_accel_open
;
242 inputdev
->close
= cmpc_accel_close
;
245 static int cmpc_accel_add(struct acpi_device
*acpi
)
248 struct input_dev
*inputdev
;
249 struct cmpc_accel
*accel
;
251 accel
= kmalloc(sizeof(*accel
), GFP_KERNEL
);
255 accel
->sensitivity
= CMPC_ACCEL_SENSITIVITY_DEFAULT
;
256 cmpc_accel_set_sensitivity(acpi
->handle
, accel
->sensitivity
);
258 error
= device_create_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr
);
262 error
= cmpc_add_acpi_notify_device(acpi
, "cmpc_accel",
263 cmpc_accel_idev_init
);
267 inputdev
= dev_get_drvdata(&acpi
->dev
);
268 dev_set_drvdata(&inputdev
->dev
, accel
);
273 device_remove_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr
);
279 static int cmpc_accel_remove(struct acpi_device
*acpi
, int type
)
281 struct input_dev
*inputdev
;
282 struct cmpc_accel
*accel
;
284 inputdev
= dev_get_drvdata(&acpi
->dev
);
285 accel
= dev_get_drvdata(&inputdev
->dev
);
287 device_remove_file(&acpi
->dev
, &cmpc_accel_sensitivity_attr
);
288 return cmpc_remove_acpi_notify_device(acpi
);
291 static const struct acpi_device_id cmpc_accel_device_ids
[] = {
296 static struct acpi_driver cmpc_accel_acpi_driver
= {
297 .owner
= THIS_MODULE
,
298 .name
= "cmpc_accel",
299 .class = "cmpc_accel",
300 .ids
= cmpc_accel_device_ids
,
302 .add
= cmpc_accel_add
,
303 .remove
= cmpc_accel_remove
,
304 .notify
= cmpc_accel_handler
,
312 static acpi_status
cmpc_get_tablet(acpi_handle handle
,
313 unsigned long long *value
)
315 union acpi_object param
;
316 struct acpi_object_list input
;
317 unsigned long long output
;
320 param
.type
= ACPI_TYPE_INTEGER
;
321 param
.integer
.value
= 0x01;
323 input
.pointer
= ¶m
;
324 status
= acpi_evaluate_integer(handle
, "TCMD", &input
, &output
);
325 if (ACPI_SUCCESS(status
))
330 static void cmpc_tablet_handler(struct acpi_device
*dev
, u32 event
)
332 unsigned long long val
= 0;
333 struct input_dev
*inputdev
= dev_get_drvdata(&dev
->dev
);
336 if (ACPI_SUCCESS(cmpc_get_tablet(dev
->handle
, &val
)))
337 input_report_switch(inputdev
, SW_TABLET_MODE
, !val
);
341 static void cmpc_tablet_idev_init(struct input_dev
*inputdev
)
343 unsigned long long val
= 0;
344 struct acpi_device
*acpi
;
346 set_bit(EV_SW
, inputdev
->evbit
);
347 set_bit(SW_TABLET_MODE
, inputdev
->swbit
);
349 acpi
= to_acpi_device(inputdev
->dev
.parent
);
350 if (ACPI_SUCCESS(cmpc_get_tablet(acpi
->handle
, &val
)))
351 input_report_switch(inputdev
, SW_TABLET_MODE
, !val
);
354 static int cmpc_tablet_add(struct acpi_device
*acpi
)
356 return cmpc_add_acpi_notify_device(acpi
, "cmpc_tablet",
357 cmpc_tablet_idev_init
);
360 static int cmpc_tablet_remove(struct acpi_device
*acpi
, int type
)
362 return cmpc_remove_acpi_notify_device(acpi
);
365 static int cmpc_tablet_resume(struct acpi_device
*acpi
)
367 struct input_dev
*inputdev
= dev_get_drvdata(&acpi
->dev
);
368 unsigned long long val
= 0;
369 if (ACPI_SUCCESS(cmpc_get_tablet(acpi
->handle
, &val
)))
370 input_report_switch(inputdev
, SW_TABLET_MODE
, !val
);
374 static const struct acpi_device_id cmpc_tablet_device_ids
[] = {
375 {CMPC_TABLET_HID
, 0},
379 static struct acpi_driver cmpc_tablet_acpi_driver
= {
380 .owner
= THIS_MODULE
,
381 .name
= "cmpc_tablet",
382 .class = "cmpc_tablet",
383 .ids
= cmpc_tablet_device_ids
,
385 .add
= cmpc_tablet_add
,
386 .remove
= cmpc_tablet_remove
,
387 .resume
= cmpc_tablet_resume
,
388 .notify
= cmpc_tablet_handler
,
397 static acpi_status
cmpc_get_brightness(acpi_handle handle
,
398 unsigned long long *value
)
400 union acpi_object param
;
401 struct acpi_object_list input
;
402 unsigned long long output
;
405 param
.type
= ACPI_TYPE_INTEGER
;
406 param
.integer
.value
= 0xC0;
408 input
.pointer
= ¶m
;
409 status
= acpi_evaluate_integer(handle
, "GRDI", &input
, &output
);
410 if (ACPI_SUCCESS(status
))
415 static acpi_status
cmpc_set_brightness(acpi_handle handle
,
416 unsigned long long value
)
418 union acpi_object param
[2];
419 struct acpi_object_list input
;
421 unsigned long long output
;
423 param
[0].type
= ACPI_TYPE_INTEGER
;
424 param
[0].integer
.value
= 0xC0;
425 param
[1].type
= ACPI_TYPE_INTEGER
;
426 param
[1].integer
.value
= value
;
428 input
.pointer
= param
;
429 status
= acpi_evaluate_integer(handle
, "GWRI", &input
, &output
);
433 static int cmpc_bl_get_brightness(struct backlight_device
*bd
)
437 unsigned long long brightness
;
439 handle
= bl_get_data(bd
);
440 status
= cmpc_get_brightness(handle
, &brightness
);
441 if (ACPI_SUCCESS(status
))
447 static int cmpc_bl_update_status(struct backlight_device
*bd
)
452 handle
= bl_get_data(bd
);
453 status
= cmpc_set_brightness(handle
, bd
->props
.brightness
);
454 if (ACPI_SUCCESS(status
))
460 static const struct backlight_ops cmpc_bl_ops
= {
461 .get_brightness
= cmpc_bl_get_brightness
,
462 .update_status
= cmpc_bl_update_status
469 static acpi_status
cmpc_get_rfkill_wlan(acpi_handle handle
,
470 unsigned long long *value
)
472 union acpi_object param
;
473 struct acpi_object_list input
;
474 unsigned long long output
;
477 param
.type
= ACPI_TYPE_INTEGER
;
478 param
.integer
.value
= 0xC1;
480 input
.pointer
= ¶m
;
481 status
= acpi_evaluate_integer(handle
, "GRDI", &input
, &output
);
482 if (ACPI_SUCCESS(status
))
487 static acpi_status
cmpc_set_rfkill_wlan(acpi_handle handle
,
488 unsigned long long value
)
490 union acpi_object param
[2];
491 struct acpi_object_list input
;
493 unsigned long long output
;
495 param
[0].type
= ACPI_TYPE_INTEGER
;
496 param
[0].integer
.value
= 0xC1;
497 param
[1].type
= ACPI_TYPE_INTEGER
;
498 param
[1].integer
.value
= value
;
500 input
.pointer
= param
;
501 status
= acpi_evaluate_integer(handle
, "GWRI", &input
, &output
);
505 static void cmpc_rfkill_query(struct rfkill
*rfkill
, void *data
)
509 unsigned long long state
;
513 status
= cmpc_get_rfkill_wlan(handle
, &state
);
514 if (ACPI_SUCCESS(status
)) {
515 blocked
= state
& 1 ? false : true;
516 rfkill_set_sw_state(rfkill
, blocked
);
520 static int cmpc_rfkill_block(void *data
, bool blocked
)
524 unsigned long long state
;
528 status
= cmpc_get_rfkill_wlan(handle
, &state
);
529 if (ACPI_FAILURE(status
))
531 /* Check if we really need to call cmpc_set_rfkill_wlan */
532 is_blocked
= state
& 1 ? false : true;
533 if (is_blocked
!= blocked
) {
534 state
= blocked
? 0 : 1;
535 status
= cmpc_set_rfkill_wlan(handle
, state
);
536 if (ACPI_FAILURE(status
))
542 static const struct rfkill_ops cmpc_rfkill_ops
= {
543 .query
= cmpc_rfkill_query
,
544 .set_block
= cmpc_rfkill_block
,
548 * Common backlight and rfkill code.
552 struct backlight_device
*bd
;
556 static int cmpc_ipml_add(struct acpi_device
*acpi
)
559 struct ipml200_dev
*ipml
;
560 struct backlight_properties props
;
562 ipml
= kmalloc(sizeof(*ipml
), GFP_KERNEL
);
566 memset(&props
, 0, sizeof(struct backlight_properties
));
567 props
.type
= BACKLIGHT_PLATFORM
;
568 props
.max_brightness
= 7;
569 ipml
->bd
= backlight_device_register("cmpc_bl", &acpi
->dev
,
570 acpi
->handle
, &cmpc_bl_ops
,
572 if (IS_ERR(ipml
->bd
)) {
573 retval
= PTR_ERR(ipml
->bd
);
577 ipml
->rf
= rfkill_alloc("cmpc_rfkill", &acpi
->dev
, RFKILL_TYPE_WLAN
,
578 &cmpc_rfkill_ops
, acpi
->handle
);
580 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
581 * This is OK, however, since all other uses of the device will not
585 retval
= rfkill_register(ipml
->rf
);
587 rfkill_destroy(ipml
->rf
);
592 dev_set_drvdata(&acpi
->dev
, ipml
);
600 static int cmpc_ipml_remove(struct acpi_device
*acpi
, int type
)
602 struct ipml200_dev
*ipml
;
604 ipml
= dev_get_drvdata(&acpi
->dev
);
606 backlight_device_unregister(ipml
->bd
);
609 rfkill_unregister(ipml
->rf
);
610 rfkill_destroy(ipml
->rf
);
618 static const struct acpi_device_id cmpc_ipml_device_ids
[] = {
623 static struct acpi_driver cmpc_ipml_acpi_driver
= {
624 .owner
= THIS_MODULE
,
627 .ids
= cmpc_ipml_device_ids
,
629 .add
= cmpc_ipml_add
,
630 .remove
= cmpc_ipml_remove
638 static int cmpc_keys_codes
[] = {
652 static void cmpc_keys_handler(struct acpi_device
*dev
, u32 event
)
654 struct input_dev
*inputdev
;
657 if ((event
& 0x0F) < ARRAY_SIZE(cmpc_keys_codes
))
658 code
= cmpc_keys_codes
[event
& 0x0F];
659 inputdev
= dev_get_drvdata(&dev
->dev
);
660 input_report_key(inputdev
, code
, !(event
& 0x10));
661 input_sync(inputdev
);
664 static void cmpc_keys_idev_init(struct input_dev
*inputdev
)
668 set_bit(EV_KEY
, inputdev
->evbit
);
669 for (i
= 0; cmpc_keys_codes
[i
] != KEY_MAX
; i
++)
670 set_bit(cmpc_keys_codes
[i
], inputdev
->keybit
);
673 static int cmpc_keys_add(struct acpi_device
*acpi
)
675 return cmpc_add_acpi_notify_device(acpi
, "cmpc_keys",
676 cmpc_keys_idev_init
);
679 static int cmpc_keys_remove(struct acpi_device
*acpi
, int type
)
681 return cmpc_remove_acpi_notify_device(acpi
);
684 static const struct acpi_device_id cmpc_keys_device_ids
[] = {
689 static struct acpi_driver cmpc_keys_acpi_driver
= {
690 .owner
= THIS_MODULE
,
692 .class = "cmpc_keys",
693 .ids
= cmpc_keys_device_ids
,
695 .add
= cmpc_keys_add
,
696 .remove
= cmpc_keys_remove
,
697 .notify
= cmpc_keys_handler
,
703 * General init/exit code.
706 static int cmpc_init(void)
710 r
= acpi_bus_register_driver(&cmpc_keys_acpi_driver
);
714 r
= acpi_bus_register_driver(&cmpc_ipml_acpi_driver
);
718 r
= acpi_bus_register_driver(&cmpc_tablet_acpi_driver
);
722 r
= acpi_bus_register_driver(&cmpc_accel_acpi_driver
);
729 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver
);
732 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver
);
735 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver
);
741 static void cmpc_exit(void)
743 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver
);
744 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver
);
745 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver
);
746 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver
);
749 module_init(cmpc_init
);
750 module_exit(cmpc_exit
);
752 static const struct acpi_device_id cmpc_device_ids
[] = {
754 {CMPC_TABLET_HID
, 0},
760 MODULE_DEVICE_TABLE(acpi
, cmpc_device_ids
);