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/workqueue.h>
23 #include <acpi/acpi_drivers.h>
24 #include <linux/backlight.h>
25 #include <linux/input.h>
27 MODULE_LICENSE("GPL");
34 #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
38 * Generic input device code.
41 typedef void (*input_device_init)(struct input_dev *dev);
43 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
44 input_device_init idev_init)
46 struct input_dev *inputdev;
49 inputdev = input_allocate_device();
52 inputdev->name = name;
53 inputdev->dev.parent = &acpi->dev;
55 error = input_register_device(inputdev);
57 input_free_device(inputdev);
60 dev_set_drvdata(&acpi->dev, inputdev);
64 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
66 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
67 input_unregister_device(inputdev);
74 static acpi_status cmpc_start_accel(acpi_handle handle)
76 union acpi_object param[2];
77 struct acpi_object_list input;
80 param[0].type = ACPI_TYPE_INTEGER;
81 param[0].integer.value = 0x3;
82 param[1].type = ACPI_TYPE_INTEGER;
84 input.pointer = param;
85 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
89 static acpi_status cmpc_stop_accel(acpi_handle handle)
91 union acpi_object param[2];
92 struct acpi_object_list input;
95 param[0].type = ACPI_TYPE_INTEGER;
96 param[0].integer.value = 0x4;
97 param[1].type = ACPI_TYPE_INTEGER;
99 input.pointer = param;
100 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
104 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
106 union acpi_object param[2];
107 struct acpi_object_list input;
109 param[0].type = ACPI_TYPE_INTEGER;
110 param[0].integer.value = 0x02;
111 param[1].type = ACPI_TYPE_INTEGER;
112 param[1].integer.value = val;
114 input.pointer = param;
115 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
118 static acpi_status cmpc_get_accel(acpi_handle handle,
123 union acpi_object param[2];
124 struct acpi_object_list input;
125 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
129 param[0].type = ACPI_TYPE_INTEGER;
130 param[0].integer.value = 0x01;
131 param[1].type = ACPI_TYPE_INTEGER;
133 input.pointer = param;
134 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
135 if (ACPI_SUCCESS(status)) {
136 union acpi_object *obj;
137 obj = output.pointer;
138 locs = obj->buffer.pointer;
142 kfree(output.pointer);
147 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
150 unsigned char x, y, z;
153 status = cmpc_get_accel(dev->handle, &x, &y, &z);
154 if (ACPI_SUCCESS(status)) {
155 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
157 input_report_abs(inputdev, ABS_X, x);
158 input_report_abs(inputdev, ABS_Y, y);
159 input_report_abs(inputdev, ABS_Z, z);
160 input_sync(inputdev);
165 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
166 struct device_attribute *attr,
169 struct acpi_device *acpi;
170 struct input_dev *inputdev;
171 struct cmpc_accel *accel;
173 acpi = to_acpi_device(dev);
174 inputdev = dev_get_drvdata(&acpi->dev);
175 accel = dev_get_drvdata(&inputdev->dev);
177 return sprintf(buf, "%d\n", accel->sensitivity);
180 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
181 struct device_attribute *attr,
182 const char *buf, size_t count)
184 struct acpi_device *acpi;
185 struct input_dev *inputdev;
186 struct cmpc_accel *accel;
187 unsigned long sensitivity;
190 acpi = to_acpi_device(dev);
191 inputdev = dev_get_drvdata(&acpi->dev);
192 accel = dev_get_drvdata(&inputdev->dev);
194 r = strict_strtoul(buf, 0, &sensitivity);
198 accel->sensitivity = sensitivity;
199 cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
201 return strnlen(buf, count);
204 struct device_attribute cmpc_accel_sensitivity_attr = {
205 .attr = { .name = "sensitivity", .mode = 0660 },
206 .show = cmpc_accel_sensitivity_show,
207 .store = cmpc_accel_sensitivity_store
210 static int cmpc_accel_open(struct input_dev *input)
212 struct acpi_device *acpi;
214 acpi = to_acpi_device(input->dev.parent);
215 if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
220 static void cmpc_accel_close(struct input_dev *input)
222 struct acpi_device *acpi;
224 acpi = to_acpi_device(input->dev.parent);
225 cmpc_stop_accel(acpi->handle);
228 static void cmpc_accel_idev_init(struct input_dev *inputdev)
230 set_bit(EV_ABS, inputdev->evbit);
231 input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
232 input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
233 input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
234 inputdev->open = cmpc_accel_open;
235 inputdev->close = cmpc_accel_close;
238 static int cmpc_accel_add(struct acpi_device *acpi)
241 struct input_dev *inputdev;
242 struct cmpc_accel *accel;
244 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
248 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
249 cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
251 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
255 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
256 cmpc_accel_idev_init);
260 inputdev = dev_get_drvdata(&acpi->dev);
261 dev_set_drvdata(&inputdev->dev, accel);
266 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
272 static int cmpc_accel_remove(struct acpi_device *acpi, int type)
274 struct input_dev *inputdev;
275 struct cmpc_accel *accel;
277 inputdev = dev_get_drvdata(&acpi->dev);
278 accel = dev_get_drvdata(&inputdev->dev);
280 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
281 return cmpc_remove_acpi_notify_device(acpi);
284 static const struct acpi_device_id cmpc_accel_device_ids[] = {
288 MODULE_DEVICE_TABLE(acpi, cmpc_accel_device_ids);
290 static struct acpi_driver cmpc_accel_acpi_driver = {
291 .owner = THIS_MODULE,
292 .name = "cmpc_accel",
293 .class = "cmpc_accel",
294 .ids = cmpc_accel_device_ids,
296 .add = cmpc_accel_add,
297 .remove = cmpc_accel_remove,
298 .notify = cmpc_accel_handler,
306 static acpi_status cmpc_get_tablet(acpi_handle handle,
307 unsigned long long *value)
309 union acpi_object param;
310 struct acpi_object_list input;
311 unsigned long long output;
314 param.type = ACPI_TYPE_INTEGER;
315 param.integer.value = 0x01;
317 input.pointer = ¶m;
318 status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
319 if (ACPI_SUCCESS(status))
324 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
326 unsigned long long val = 0;
327 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
330 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val)))
331 input_report_switch(inputdev, SW_TABLET_MODE, !val);
335 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
337 unsigned long long val = 0;
338 struct acpi_device *acpi;
340 set_bit(EV_SW, inputdev->evbit);
341 set_bit(SW_TABLET_MODE, inputdev->swbit);
343 acpi = to_acpi_device(inputdev->dev.parent);
344 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
345 input_report_switch(inputdev, SW_TABLET_MODE, !val);
348 static int cmpc_tablet_add(struct acpi_device *acpi)
350 return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
351 cmpc_tablet_idev_init);
354 static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
356 return cmpc_remove_acpi_notify_device(acpi);
359 static int cmpc_tablet_resume(struct acpi_device *acpi)
361 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
362 unsigned long long val = 0;
363 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
364 input_report_switch(inputdev, SW_TABLET_MODE, !val);
368 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
372 MODULE_DEVICE_TABLE(acpi, cmpc_tablet_device_ids);
374 static struct acpi_driver cmpc_tablet_acpi_driver = {
375 .owner = THIS_MODULE,
376 .name = "cmpc_tablet",
377 .class = "cmpc_tablet",
378 .ids = cmpc_tablet_device_ids,
380 .add = cmpc_tablet_add,
381 .remove = cmpc_tablet_remove,
382 .resume = cmpc_tablet_resume,
383 .notify = cmpc_tablet_handler,
392 static acpi_status cmpc_get_brightness(acpi_handle handle,
393 unsigned long long *value)
395 union acpi_object param;
396 struct acpi_object_list input;
397 unsigned long long output;
400 param.type = ACPI_TYPE_INTEGER;
401 param.integer.value = 0xC0;
403 input.pointer = ¶m;
404 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
405 if (ACPI_SUCCESS(status))
410 static acpi_status cmpc_set_brightness(acpi_handle handle,
411 unsigned long long value)
413 union acpi_object param[2];
414 struct acpi_object_list input;
416 unsigned long long output;
418 param[0].type = ACPI_TYPE_INTEGER;
419 param[0].integer.value = 0xC0;
420 param[1].type = ACPI_TYPE_INTEGER;
421 param[1].integer.value = value;
423 input.pointer = param;
424 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
428 static int cmpc_bl_get_brightness(struct backlight_device *bd)
432 unsigned long long brightness;
434 handle = bl_get_data(bd);
435 status = cmpc_get_brightness(handle, &brightness);
436 if (ACPI_SUCCESS(status))
442 static int cmpc_bl_update_status(struct backlight_device *bd)
447 handle = bl_get_data(bd);
448 status = cmpc_set_brightness(handle, bd->props.brightness);
449 if (ACPI_SUCCESS(status))
455 static struct backlight_ops cmpc_bl_ops = {
456 .get_brightness = cmpc_bl_get_brightness,
457 .update_status = cmpc_bl_update_status
460 static int cmpc_bl_add(struct acpi_device *acpi)
462 struct backlight_device *bd;
464 bd = backlight_device_register("cmpc_bl", &acpi->dev,
465 acpi->handle, &cmpc_bl_ops);
466 bd->props.max_brightness = 7;
467 dev_set_drvdata(&acpi->dev, bd);
471 static int cmpc_bl_remove(struct acpi_device *acpi, int type)
473 struct backlight_device *bd;
475 bd = dev_get_drvdata(&acpi->dev);
476 backlight_device_unregister(bd);
480 static const struct acpi_device_id cmpc_device_ids[] = {
484 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
486 static struct acpi_driver cmpc_bl_acpi_driver = {
487 .owner = THIS_MODULE,
490 .ids = cmpc_device_ids,
493 .remove = cmpc_bl_remove
501 static int cmpc_keys_codes[] = {
511 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
513 struct input_dev *inputdev;
516 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
517 code = cmpc_keys_codes[event & 0x0F];
518 inputdev = dev_get_drvdata(&dev->dev);;
519 input_report_key(inputdev, code, !(event & 0x10));
522 static void cmpc_keys_idev_init(struct input_dev *inputdev)
526 set_bit(EV_KEY, inputdev->evbit);
527 for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
528 set_bit(cmpc_keys_codes[i], inputdev->keybit);
531 static int cmpc_keys_add(struct acpi_device *acpi)
533 return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
534 cmpc_keys_idev_init);
537 static int cmpc_keys_remove(struct acpi_device *acpi, int type)
539 return cmpc_remove_acpi_notify_device(acpi);
542 static const struct acpi_device_id cmpc_keys_device_ids[] = {
546 MODULE_DEVICE_TABLE(acpi, cmpc_keys_device_ids);
548 static struct acpi_driver cmpc_keys_acpi_driver = {
549 .owner = THIS_MODULE,
551 .class = "cmpc_keys",
552 .ids = cmpc_keys_device_ids,
554 .add = cmpc_keys_add,
555 .remove = cmpc_keys_remove,
556 .notify = cmpc_keys_handler,
562 * General init/exit code.
565 static int cmpc_init(void)
569 r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
573 r = acpi_bus_register_driver(&cmpc_bl_acpi_driver);
577 r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
581 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
588 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
591 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
594 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
600 static void cmpc_exit(void)
602 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
603 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
604 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
605 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
608 module_init(cmpc_init);
609 module_exit(cmpc_exit);