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 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;
527 status = cmpc_get_rfkill_wlan(handle, &state);
528 if (ACPI_FAILURE(status))
534 status = cmpc_set_rfkill_wlan(handle, state);
535 if (ACPI_FAILURE(status))
540 static const struct rfkill_ops cmpc_rfkill_ops = {
541 .query = cmpc_rfkill_query,
542 .set_block = cmpc_rfkill_block,
546 * Common backlight and rfkill code.
550 struct backlight_device *bd;
554 static int cmpc_ipml_add(struct acpi_device *acpi)
557 struct ipml200_dev *ipml;
558 struct backlight_properties props;
560 ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
564 memset(&props, 0, sizeof(struct backlight_properties));
565 props.max_brightness = 7;
566 ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
567 acpi->handle, &cmpc_bl_ops,
569 if (IS_ERR(ipml->bd)) {
570 retval = PTR_ERR(ipml->bd);
574 ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
575 &cmpc_rfkill_ops, acpi->handle);
576 /* rfkill_alloc may fail if RFKILL is disabled. We should still work
578 if (!IS_ERR(ipml->rf)) {
579 retval = rfkill_register(ipml->rf);
581 rfkill_destroy(ipml->rf);
588 dev_set_drvdata(&acpi->dev, ipml);
596 static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
598 struct ipml200_dev *ipml;
600 ipml = dev_get_drvdata(&acpi->dev);
602 backlight_device_unregister(ipml->bd);
605 rfkill_unregister(ipml->rf);
606 rfkill_destroy(ipml->rf);
614 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
619 static struct acpi_driver cmpc_ipml_acpi_driver = {
620 .owner = THIS_MODULE,
623 .ids = cmpc_ipml_device_ids,
625 .add = cmpc_ipml_add,
626 .remove = cmpc_ipml_remove
634 static int cmpc_keys_codes[] = {
648 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
650 struct input_dev *inputdev;
653 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
654 code = cmpc_keys_codes[event & 0x0F];
655 inputdev = dev_get_drvdata(&dev->dev);;
656 input_report_key(inputdev, code, !(event & 0x10));
659 static void cmpc_keys_idev_init(struct input_dev *inputdev)
663 set_bit(EV_KEY, inputdev->evbit);
664 for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
665 set_bit(cmpc_keys_codes[i], inputdev->keybit);
668 static int cmpc_keys_add(struct acpi_device *acpi)
670 return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
671 cmpc_keys_idev_init);
674 static int cmpc_keys_remove(struct acpi_device *acpi, int type)
676 return cmpc_remove_acpi_notify_device(acpi);
679 static const struct acpi_device_id cmpc_keys_device_ids[] = {
684 static struct acpi_driver cmpc_keys_acpi_driver = {
685 .owner = THIS_MODULE,
687 .class = "cmpc_keys",
688 .ids = cmpc_keys_device_ids,
690 .add = cmpc_keys_add,
691 .remove = cmpc_keys_remove,
692 .notify = cmpc_keys_handler,
698 * General init/exit code.
701 static int cmpc_init(void)
705 r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
709 r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
713 r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
717 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
724 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
727 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
730 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
736 static void cmpc_exit(void)
738 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
739 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
740 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
741 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
744 module_init(cmpc_init);
745 module_exit(cmpc_exit);
747 static const struct acpi_device_id cmpc_device_ids[] = {
749 {CMPC_TABLET_HID, 0},
755 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);