1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
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 #include <linux/sysfs.h>
16
17 struct cmpc_accel {
18 int sensitivity;
19 int g_select;
20 int inputdev_state;
21 };
22
23 #define CMPC_ACCEL_DEV_STATE_CLOSED 0
24 #define CMPC_ACCEL_DEV_STATE_OPEN 1
25
26 #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
27 #define CMPC_ACCEL_G_SELECT_DEFAULT 0
28
29 #define CMPC_ACCEL_HID "ACCE0000"
30 #define CMPC_ACCEL_HID_V4 "ACCE0001"
31 #define CMPC_TABLET_HID "TBLT0000"
32 #define CMPC_IPML_HID "IPML200"
33 #define CMPC_KEYS_HID "FNBT0000"
34
35 /*
36 * Generic input device code.
37 */
38
39 typedef void (*input_device_init)(struct input_dev *dev);
40
cmpc_add_acpi_notify_device(struct acpi_device * acpi,char * name,input_device_init idev_init)41 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
42 input_device_init idev_init)
43 {
44 struct input_dev *inputdev;
45 int error;
46
47 inputdev = input_allocate_device();
48 if (!inputdev)
49 return -ENOMEM;
50 inputdev->name = name;
51 inputdev->dev.parent = &acpi->dev;
52 idev_init(inputdev);
53 error = input_register_device(inputdev);
54 if (error) {
55 input_free_device(inputdev);
56 return error;
57 }
58 dev_set_drvdata(&acpi->dev, inputdev);
59 return 0;
60 }
61
cmpc_remove_acpi_notify_device(struct acpi_device * acpi)62 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
63 {
64 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
65 input_unregister_device(inputdev);
66 return 0;
67 }
68
69 /*
70 * Accelerometer code for Classmate V4
71 */
cmpc_start_accel_v4(acpi_handle handle)72 static acpi_status cmpc_start_accel_v4(acpi_handle handle)
73 {
74 union acpi_object param[4];
75 struct acpi_object_list input;
76 acpi_status status;
77
78 param[0].type = ACPI_TYPE_INTEGER;
79 param[0].integer.value = 0x3;
80 param[1].type = ACPI_TYPE_INTEGER;
81 param[1].integer.value = 0;
82 param[2].type = ACPI_TYPE_INTEGER;
83 param[2].integer.value = 0;
84 param[3].type = ACPI_TYPE_INTEGER;
85 param[3].integer.value = 0;
86 input.count = 4;
87 input.pointer = param;
88 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
89 return status;
90 }
91
cmpc_stop_accel_v4(acpi_handle handle)92 static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
93 {
94 union acpi_object param[4];
95 struct acpi_object_list input;
96 acpi_status status;
97
98 param[0].type = ACPI_TYPE_INTEGER;
99 param[0].integer.value = 0x4;
100 param[1].type = ACPI_TYPE_INTEGER;
101 param[1].integer.value = 0;
102 param[2].type = ACPI_TYPE_INTEGER;
103 param[2].integer.value = 0;
104 param[3].type = ACPI_TYPE_INTEGER;
105 param[3].integer.value = 0;
106 input.count = 4;
107 input.pointer = param;
108 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
109 return status;
110 }
111
cmpc_accel_set_sensitivity_v4(acpi_handle handle,int val)112 static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
113 {
114 union acpi_object param[4];
115 struct acpi_object_list input;
116
117 param[0].type = ACPI_TYPE_INTEGER;
118 param[0].integer.value = 0x02;
119 param[1].type = ACPI_TYPE_INTEGER;
120 param[1].integer.value = val;
121 param[2].type = ACPI_TYPE_INTEGER;
122 param[2].integer.value = 0;
123 param[3].type = ACPI_TYPE_INTEGER;
124 param[3].integer.value = 0;
125 input.count = 4;
126 input.pointer = param;
127 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
128 }
129
cmpc_accel_set_g_select_v4(acpi_handle handle,int val)130 static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
131 {
132 union acpi_object param[4];
133 struct acpi_object_list input;
134
135 param[0].type = ACPI_TYPE_INTEGER;
136 param[0].integer.value = 0x05;
137 param[1].type = ACPI_TYPE_INTEGER;
138 param[1].integer.value = val;
139 param[2].type = ACPI_TYPE_INTEGER;
140 param[2].integer.value = 0;
141 param[3].type = ACPI_TYPE_INTEGER;
142 param[3].integer.value = 0;
143 input.count = 4;
144 input.pointer = param;
145 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
146 }
147
cmpc_get_accel_v4(acpi_handle handle,int16_t * x,int16_t * y,int16_t * z)148 static acpi_status cmpc_get_accel_v4(acpi_handle handle,
149 int16_t *x,
150 int16_t *y,
151 int16_t *z)
152 {
153 union acpi_object param[4];
154 struct acpi_object_list input;
155 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
156 int16_t *locs;
157 acpi_status status;
158
159 param[0].type = ACPI_TYPE_INTEGER;
160 param[0].integer.value = 0x01;
161 param[1].type = ACPI_TYPE_INTEGER;
162 param[1].integer.value = 0;
163 param[2].type = ACPI_TYPE_INTEGER;
164 param[2].integer.value = 0;
165 param[3].type = ACPI_TYPE_INTEGER;
166 param[3].integer.value = 0;
167 input.count = 4;
168 input.pointer = param;
169 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
170 if (ACPI_SUCCESS(status)) {
171 union acpi_object *obj;
172 obj = output.pointer;
173 locs = (int16_t *) obj->buffer.pointer;
174 *x = locs[0];
175 *y = locs[1];
176 *z = locs[2];
177 kfree(output.pointer);
178 }
179 return status;
180 }
181
cmpc_accel_handler_v4(struct acpi_device * dev,u32 event)182 static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
183 {
184 if (event == 0x81) {
185 int16_t x, y, z;
186 acpi_status status;
187
188 status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
189 if (ACPI_SUCCESS(status)) {
190 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
191
192 input_report_abs(inputdev, ABS_X, x);
193 input_report_abs(inputdev, ABS_Y, y);
194 input_report_abs(inputdev, ABS_Z, z);
195 input_sync(inputdev);
196 }
197 }
198 }
199
cmpc_accel_sensitivity_show_v4(struct device * dev,struct device_attribute * attr,char * buf)200 static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
201 struct device_attribute *attr,
202 char *buf)
203 {
204 struct acpi_device *acpi;
205 struct input_dev *inputdev;
206 struct cmpc_accel *accel;
207
208 acpi = to_acpi_device(dev);
209 inputdev = dev_get_drvdata(&acpi->dev);
210 if (!inputdev)
211 return -ENXIO;
212
213 accel = dev_get_drvdata(&inputdev->dev);
214 if (!accel)
215 return -ENXIO;
216
217 return sysfs_emit(buf, "%d\n", accel->sensitivity);
218 }
219
cmpc_accel_sensitivity_store_v4(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)220 static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
221 struct device_attribute *attr,
222 const char *buf, size_t count)
223 {
224 struct acpi_device *acpi;
225 struct input_dev *inputdev;
226 struct cmpc_accel *accel;
227 unsigned long sensitivity;
228 int r;
229
230 acpi = to_acpi_device(dev);
231 inputdev = dev_get_drvdata(&acpi->dev);
232 if (!inputdev)
233 return -ENXIO;
234
235 accel = dev_get_drvdata(&inputdev->dev);
236 if (!accel)
237 return -ENXIO;
238
239 r = kstrtoul(buf, 0, &sensitivity);
240 if (r)
241 return r;
242
243 /* sensitivity must be between 1 and 127 */
244 if (sensitivity < 1 || sensitivity > 127)
245 return -EINVAL;
246
247 accel->sensitivity = sensitivity;
248 cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
249
250 return strnlen(buf, count);
251 }
252
253 static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
254 .attr = { .name = "sensitivity", .mode = 0660 },
255 .show = cmpc_accel_sensitivity_show_v4,
256 .store = cmpc_accel_sensitivity_store_v4
257 };
258
cmpc_accel_g_select_show_v4(struct device * dev,struct device_attribute * attr,char * buf)259 static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
260 struct device_attribute *attr,
261 char *buf)
262 {
263 struct acpi_device *acpi;
264 struct input_dev *inputdev;
265 struct cmpc_accel *accel;
266
267 acpi = to_acpi_device(dev);
268 inputdev = dev_get_drvdata(&acpi->dev);
269 if (!inputdev)
270 return -ENXIO;
271
272 accel = dev_get_drvdata(&inputdev->dev);
273 if (!accel)
274 return -ENXIO;
275
276 return sysfs_emit(buf, "%d\n", accel->g_select);
277 }
278
cmpc_accel_g_select_store_v4(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)279 static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
280 struct device_attribute *attr,
281 const char *buf, size_t count)
282 {
283 struct acpi_device *acpi;
284 struct input_dev *inputdev;
285 struct cmpc_accel *accel;
286 unsigned long g_select;
287 int r;
288
289 acpi = to_acpi_device(dev);
290 inputdev = dev_get_drvdata(&acpi->dev);
291 if (!inputdev)
292 return -ENXIO;
293
294 accel = dev_get_drvdata(&inputdev->dev);
295 if (!accel)
296 return -ENXIO;
297
298 r = kstrtoul(buf, 0, &g_select);
299 if (r)
300 return r;
301
302 /* 0 means 1.5g, 1 means 6g, everything else is wrong */
303 if (g_select != 0 && g_select != 1)
304 return -EINVAL;
305
306 accel->g_select = g_select;
307 cmpc_accel_set_g_select_v4(acpi->handle, g_select);
308
309 return strnlen(buf, count);
310 }
311
312 static struct device_attribute cmpc_accel_g_select_attr_v4 = {
313 .attr = { .name = "g_select", .mode = 0660 },
314 .show = cmpc_accel_g_select_show_v4,
315 .store = cmpc_accel_g_select_store_v4
316 };
317
cmpc_accel_open_v4(struct input_dev * input)318 static int cmpc_accel_open_v4(struct input_dev *input)
319 {
320 struct acpi_device *acpi;
321 struct cmpc_accel *accel;
322
323 acpi = to_acpi_device(input->dev.parent);
324 accel = dev_get_drvdata(&input->dev);
325 if (!accel)
326 return -ENXIO;
327
328 cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
329 cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
330
331 if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
332 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
333 return 0;
334 }
335 return -EIO;
336 }
337
cmpc_accel_close_v4(struct input_dev * input)338 static void cmpc_accel_close_v4(struct input_dev *input)
339 {
340 struct acpi_device *acpi;
341 struct cmpc_accel *accel;
342
343 acpi = to_acpi_device(input->dev.parent);
344 accel = dev_get_drvdata(&input->dev);
345
346 cmpc_stop_accel_v4(acpi->handle);
347 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
348 }
349
cmpc_accel_idev_init_v4(struct input_dev * inputdev)350 static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
351 {
352 set_bit(EV_ABS, inputdev->evbit);
353 input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
354 input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
355 input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
356 inputdev->open = cmpc_accel_open_v4;
357 inputdev->close = cmpc_accel_close_v4;
358 }
359
360 #ifdef CONFIG_PM_SLEEP
cmpc_accel_suspend_v4(struct device * dev)361 static int cmpc_accel_suspend_v4(struct device *dev)
362 {
363 struct input_dev *inputdev;
364 struct cmpc_accel *accel;
365
366 inputdev = dev_get_drvdata(dev);
367 accel = dev_get_drvdata(&inputdev->dev);
368
369 if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
370 return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
371
372 return 0;
373 }
374
cmpc_accel_resume_v4(struct device * dev)375 static int cmpc_accel_resume_v4(struct device *dev)
376 {
377 struct input_dev *inputdev;
378 struct cmpc_accel *accel;
379
380 inputdev = dev_get_drvdata(dev);
381 accel = dev_get_drvdata(&inputdev->dev);
382
383 if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
384 cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
385 accel->sensitivity);
386 cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
387 accel->g_select);
388
389 if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
390 return -EIO;
391 }
392
393 return 0;
394 }
395 #endif
396
cmpc_accel_add_v4(struct acpi_device * acpi)397 static int cmpc_accel_add_v4(struct acpi_device *acpi)
398 {
399 int error;
400 struct input_dev *inputdev;
401 struct cmpc_accel *accel;
402
403 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
404 if (!accel)
405 return -ENOMEM;
406
407 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
408
409 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
410 cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
411
412 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
413 if (error)
414 goto failed_sensitivity;
415
416 accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
417 cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
418
419 error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
420 if (error)
421 goto failed_g_select;
422
423 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
424 cmpc_accel_idev_init_v4);
425 if (error)
426 goto failed_input;
427
428 inputdev = dev_get_drvdata(&acpi->dev);
429 dev_set_drvdata(&inputdev->dev, accel);
430
431 return 0;
432
433 failed_input:
434 device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
435 failed_g_select:
436 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
437 failed_sensitivity:
438 kfree(accel);
439 return error;
440 }
441
cmpc_accel_remove_v4(struct acpi_device * acpi)442 static void cmpc_accel_remove_v4(struct acpi_device *acpi)
443 {
444 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
445 device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
446 cmpc_remove_acpi_notify_device(acpi);
447 }
448
449 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
450 cmpc_accel_resume_v4);
451
452 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
453 {CMPC_ACCEL_HID_V4, 0},
454 {"", 0}
455 };
456
457 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
458 .name = "cmpc_accel_v4",
459 .class = "cmpc_accel_v4",
460 .ids = cmpc_accel_device_ids_v4,
461 .ops = {
462 .add = cmpc_accel_add_v4,
463 .remove = cmpc_accel_remove_v4,
464 .notify = cmpc_accel_handler_v4,
465 },
466 .drv.pm = &cmpc_accel_pm,
467 };
468
469
470 /*
471 * Accelerometer code for Classmate versions prior to V4
472 */
cmpc_start_accel(acpi_handle handle)473 static acpi_status cmpc_start_accel(acpi_handle handle)
474 {
475 union acpi_object param[2];
476 struct acpi_object_list input;
477 acpi_status status;
478
479 param[0].type = ACPI_TYPE_INTEGER;
480 param[0].integer.value = 0x3;
481 param[1].type = ACPI_TYPE_INTEGER;
482 input.count = 2;
483 input.pointer = param;
484 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
485 return status;
486 }
487
cmpc_stop_accel(acpi_handle handle)488 static acpi_status cmpc_stop_accel(acpi_handle handle)
489 {
490 union acpi_object param[2];
491 struct acpi_object_list input;
492 acpi_status status;
493
494 param[0].type = ACPI_TYPE_INTEGER;
495 param[0].integer.value = 0x4;
496 param[1].type = ACPI_TYPE_INTEGER;
497 input.count = 2;
498 input.pointer = param;
499 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
500 return status;
501 }
502
cmpc_accel_set_sensitivity(acpi_handle handle,int val)503 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
504 {
505 union acpi_object param[2];
506 struct acpi_object_list input;
507
508 param[0].type = ACPI_TYPE_INTEGER;
509 param[0].integer.value = 0x02;
510 param[1].type = ACPI_TYPE_INTEGER;
511 param[1].integer.value = val;
512 input.count = 2;
513 input.pointer = param;
514 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
515 }
516
cmpc_get_accel(acpi_handle handle,unsigned char * x,unsigned char * y,unsigned char * z)517 static acpi_status cmpc_get_accel(acpi_handle handle,
518 unsigned char *x,
519 unsigned char *y,
520 unsigned char *z)
521 {
522 union acpi_object param[2];
523 struct acpi_object_list input;
524 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
525 unsigned char *locs;
526 acpi_status status;
527
528 param[0].type = ACPI_TYPE_INTEGER;
529 param[0].integer.value = 0x01;
530 param[1].type = ACPI_TYPE_INTEGER;
531 input.count = 2;
532 input.pointer = param;
533 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
534 if (ACPI_SUCCESS(status)) {
535 union acpi_object *obj;
536 obj = output.pointer;
537 locs = obj->buffer.pointer;
538 *x = locs[0];
539 *y = locs[1];
540 *z = locs[2];
541 kfree(output.pointer);
542 }
543 return status;
544 }
545
cmpc_accel_handler(struct acpi_device * dev,u32 event)546 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
547 {
548 if (event == 0x81) {
549 unsigned char x, y, z;
550 acpi_status status;
551
552 status = cmpc_get_accel(dev->handle, &x, &y, &z);
553 if (ACPI_SUCCESS(status)) {
554 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
555
556 input_report_abs(inputdev, ABS_X, x);
557 input_report_abs(inputdev, ABS_Y, y);
558 input_report_abs(inputdev, ABS_Z, z);
559 input_sync(inputdev);
560 }
561 }
562 }
563
cmpc_accel_sensitivity_show(struct device * dev,struct device_attribute * attr,char * buf)564 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
565 struct device_attribute *attr,
566 char *buf)
567 {
568 struct acpi_device *acpi;
569 struct input_dev *inputdev;
570 struct cmpc_accel *accel;
571
572 acpi = to_acpi_device(dev);
573 inputdev = dev_get_drvdata(&acpi->dev);
574 if (!inputdev)
575 return -ENXIO;
576
577 accel = dev_get_drvdata(&inputdev->dev);
578 if (!accel)
579 return -ENXIO;
580
581 return sysfs_emit(buf, "%d\n", accel->sensitivity);
582 }
583
cmpc_accel_sensitivity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)584 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
585 struct device_attribute *attr,
586 const char *buf, size_t count)
587 {
588 struct acpi_device *acpi;
589 struct input_dev *inputdev;
590 struct cmpc_accel *accel;
591 unsigned long sensitivity;
592 int r;
593
594 acpi = to_acpi_device(dev);
595 inputdev = dev_get_drvdata(&acpi->dev);
596 if (!inputdev)
597 return -ENXIO;
598
599 accel = dev_get_drvdata(&inputdev->dev);
600 if (!accel)
601 return -ENXIO;
602
603 r = kstrtoul(buf, 0, &sensitivity);
604 if (r)
605 return r;
606
607 accel->sensitivity = sensitivity;
608 cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
609
610 return strnlen(buf, count);
611 }
612
613 static struct device_attribute cmpc_accel_sensitivity_attr = {
614 .attr = { .name = "sensitivity", .mode = 0660 },
615 .show = cmpc_accel_sensitivity_show,
616 .store = cmpc_accel_sensitivity_store
617 };
618
cmpc_accel_open(struct input_dev * input)619 static int cmpc_accel_open(struct input_dev *input)
620 {
621 struct acpi_device *acpi;
622
623 acpi = to_acpi_device(input->dev.parent);
624 if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
625 return 0;
626 return -EIO;
627 }
628
cmpc_accel_close(struct input_dev * input)629 static void cmpc_accel_close(struct input_dev *input)
630 {
631 struct acpi_device *acpi;
632
633 acpi = to_acpi_device(input->dev.parent);
634 cmpc_stop_accel(acpi->handle);
635 }
636
cmpc_accel_idev_init(struct input_dev * inputdev)637 static void cmpc_accel_idev_init(struct input_dev *inputdev)
638 {
639 set_bit(EV_ABS, inputdev->evbit);
640 input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
641 input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
642 input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
643 inputdev->open = cmpc_accel_open;
644 inputdev->close = cmpc_accel_close;
645 }
646
cmpc_accel_add(struct acpi_device * acpi)647 static int cmpc_accel_add(struct acpi_device *acpi)
648 {
649 int error;
650 struct input_dev *inputdev;
651 struct cmpc_accel *accel;
652
653 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
654 if (!accel)
655 return -ENOMEM;
656
657 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
658 cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
659
660 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
661 if (error)
662 goto failed_file;
663
664 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
665 cmpc_accel_idev_init);
666 if (error)
667 goto failed_input;
668
669 inputdev = dev_get_drvdata(&acpi->dev);
670 dev_set_drvdata(&inputdev->dev, accel);
671
672 return 0;
673
674 failed_input:
675 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
676 failed_file:
677 kfree(accel);
678 return error;
679 }
680
cmpc_accel_remove(struct acpi_device * acpi)681 static void cmpc_accel_remove(struct acpi_device *acpi)
682 {
683 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
684 cmpc_remove_acpi_notify_device(acpi);
685 }
686
687 static const struct acpi_device_id cmpc_accel_device_ids[] = {
688 {CMPC_ACCEL_HID, 0},
689 {"", 0}
690 };
691
692 static struct acpi_driver cmpc_accel_acpi_driver = {
693 .name = "cmpc_accel",
694 .class = "cmpc_accel",
695 .ids = cmpc_accel_device_ids,
696 .ops = {
697 .add = cmpc_accel_add,
698 .remove = cmpc_accel_remove,
699 .notify = cmpc_accel_handler,
700 }
701 };
702
703
704 /*
705 * Tablet mode code.
706 */
cmpc_get_tablet(acpi_handle handle,unsigned long long * value)707 static acpi_status cmpc_get_tablet(acpi_handle handle,
708 unsigned long long *value)
709 {
710 union acpi_object param;
711 struct acpi_object_list input;
712 unsigned long long output;
713 acpi_status status;
714
715 param.type = ACPI_TYPE_INTEGER;
716 param.integer.value = 0x01;
717 input.count = 1;
718 input.pointer = ¶m;
719 status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
720 if (ACPI_SUCCESS(status))
721 *value = output;
722 return status;
723 }
724
cmpc_tablet_handler(struct acpi_device * dev,u32 event)725 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
726 {
727 unsigned long long val = 0;
728 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
729
730 if (event == 0x81) {
731 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
732 input_report_switch(inputdev, SW_TABLET_MODE, !val);
733 input_sync(inputdev);
734 }
735 }
736 }
737
cmpc_tablet_idev_init(struct input_dev * inputdev)738 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
739 {
740 unsigned long long val = 0;
741 struct acpi_device *acpi;
742
743 set_bit(EV_SW, inputdev->evbit);
744 set_bit(SW_TABLET_MODE, inputdev->swbit);
745
746 acpi = to_acpi_device(inputdev->dev.parent);
747 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
748 input_report_switch(inputdev, SW_TABLET_MODE, !val);
749 input_sync(inputdev);
750 }
751 }
752
cmpc_tablet_add(struct acpi_device * acpi)753 static int cmpc_tablet_add(struct acpi_device *acpi)
754 {
755 return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
756 cmpc_tablet_idev_init);
757 }
758
cmpc_tablet_remove(struct acpi_device * acpi)759 static void cmpc_tablet_remove(struct acpi_device *acpi)
760 {
761 cmpc_remove_acpi_notify_device(acpi);
762 }
763
764 #ifdef CONFIG_PM_SLEEP
cmpc_tablet_resume(struct device * dev)765 static int cmpc_tablet_resume(struct device *dev)
766 {
767 struct input_dev *inputdev = dev_get_drvdata(dev);
768
769 unsigned long long val = 0;
770 if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
771 input_report_switch(inputdev, SW_TABLET_MODE, !val);
772 input_sync(inputdev);
773 }
774 return 0;
775 }
776 #endif
777
778 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
779
780 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
781 {CMPC_TABLET_HID, 0},
782 {"", 0}
783 };
784
785 static struct acpi_driver cmpc_tablet_acpi_driver = {
786 .name = "cmpc_tablet",
787 .class = "cmpc_tablet",
788 .ids = cmpc_tablet_device_ids,
789 .ops = {
790 .add = cmpc_tablet_add,
791 .remove = cmpc_tablet_remove,
792 .notify = cmpc_tablet_handler,
793 },
794 .drv.pm = &cmpc_tablet_pm,
795 };
796
797
798 /*
799 * Backlight code.
800 */
801
cmpc_get_brightness(acpi_handle handle,unsigned long long * value)802 static acpi_status cmpc_get_brightness(acpi_handle handle,
803 unsigned long long *value)
804 {
805 union acpi_object param;
806 struct acpi_object_list input;
807 unsigned long long output;
808 acpi_status status;
809
810 param.type = ACPI_TYPE_INTEGER;
811 param.integer.value = 0xC0;
812 input.count = 1;
813 input.pointer = ¶m;
814 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
815 if (ACPI_SUCCESS(status))
816 *value = output;
817 return status;
818 }
819
cmpc_set_brightness(acpi_handle handle,unsigned long long value)820 static acpi_status cmpc_set_brightness(acpi_handle handle,
821 unsigned long long value)
822 {
823 union acpi_object param[2];
824 struct acpi_object_list input;
825 acpi_status status;
826 unsigned long long output;
827
828 param[0].type = ACPI_TYPE_INTEGER;
829 param[0].integer.value = 0xC0;
830 param[1].type = ACPI_TYPE_INTEGER;
831 param[1].integer.value = value;
832 input.count = 2;
833 input.pointer = param;
834 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
835 return status;
836 }
837
cmpc_bl_get_brightness(struct backlight_device * bd)838 static int cmpc_bl_get_brightness(struct backlight_device *bd)
839 {
840 acpi_status status;
841 acpi_handle handle;
842 unsigned long long brightness;
843
844 handle = bl_get_data(bd);
845 status = cmpc_get_brightness(handle, &brightness);
846 if (ACPI_SUCCESS(status))
847 return brightness;
848 else
849 return -1;
850 }
851
cmpc_bl_update_status(struct backlight_device * bd)852 static int cmpc_bl_update_status(struct backlight_device *bd)
853 {
854 acpi_status status;
855 acpi_handle handle;
856
857 handle = bl_get_data(bd);
858 status = cmpc_set_brightness(handle, bd->props.brightness);
859 if (ACPI_SUCCESS(status))
860 return 0;
861 else
862 return -1;
863 }
864
865 static const struct backlight_ops cmpc_bl_ops = {
866 .get_brightness = cmpc_bl_get_brightness,
867 .update_status = cmpc_bl_update_status
868 };
869
870 /*
871 * RFKILL code.
872 */
873
cmpc_get_rfkill_wlan(acpi_handle handle,unsigned long long * value)874 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
875 unsigned long long *value)
876 {
877 union acpi_object param;
878 struct acpi_object_list input;
879 unsigned long long output;
880 acpi_status status;
881
882 param.type = ACPI_TYPE_INTEGER;
883 param.integer.value = 0xC1;
884 input.count = 1;
885 input.pointer = ¶m;
886 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
887 if (ACPI_SUCCESS(status))
888 *value = output;
889 return status;
890 }
891
cmpc_set_rfkill_wlan(acpi_handle handle,unsigned long long value)892 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
893 unsigned long long value)
894 {
895 union acpi_object param[2];
896 struct acpi_object_list input;
897 acpi_status status;
898 unsigned long long output;
899
900 param[0].type = ACPI_TYPE_INTEGER;
901 param[0].integer.value = 0xC1;
902 param[1].type = ACPI_TYPE_INTEGER;
903 param[1].integer.value = value;
904 input.count = 2;
905 input.pointer = param;
906 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
907 return status;
908 }
909
cmpc_rfkill_query(struct rfkill * rfkill,void * data)910 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
911 {
912 acpi_status status;
913 acpi_handle handle;
914 unsigned long long state;
915 bool blocked;
916
917 handle = data;
918 status = cmpc_get_rfkill_wlan(handle, &state);
919 if (ACPI_SUCCESS(status)) {
920 blocked = state & 1 ? false : true;
921 rfkill_set_sw_state(rfkill, blocked);
922 }
923 }
924
cmpc_rfkill_block(void * data,bool blocked)925 static int cmpc_rfkill_block(void *data, bool blocked)
926 {
927 acpi_status status;
928 acpi_handle handle;
929 unsigned long long state;
930 bool is_blocked;
931
932 handle = data;
933 status = cmpc_get_rfkill_wlan(handle, &state);
934 if (ACPI_FAILURE(status))
935 return -ENODEV;
936 /* Check if we really need to call cmpc_set_rfkill_wlan */
937 is_blocked = state & 1 ? false : true;
938 if (is_blocked != blocked) {
939 state = blocked ? 0 : 1;
940 status = cmpc_set_rfkill_wlan(handle, state);
941 if (ACPI_FAILURE(status))
942 return -ENODEV;
943 }
944 return 0;
945 }
946
947 static const struct rfkill_ops cmpc_rfkill_ops = {
948 .query = cmpc_rfkill_query,
949 .set_block = cmpc_rfkill_block,
950 };
951
952 /*
953 * Common backlight and rfkill code.
954 */
955
956 struct ipml200_dev {
957 struct backlight_device *bd;
958 struct rfkill *rf;
959 };
960
cmpc_ipml_add(struct acpi_device * acpi)961 static int cmpc_ipml_add(struct acpi_device *acpi)
962 {
963 int retval;
964 struct ipml200_dev *ipml;
965 struct backlight_properties props;
966
967 ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
968 if (ipml == NULL)
969 return -ENOMEM;
970
971 memset(&props, 0, sizeof(struct backlight_properties));
972 props.type = BACKLIGHT_PLATFORM;
973 props.max_brightness = 7;
974 ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
975 acpi->handle, &cmpc_bl_ops,
976 &props);
977 if (IS_ERR(ipml->bd)) {
978 retval = PTR_ERR(ipml->bd);
979 goto out_bd;
980 }
981
982 ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
983 &cmpc_rfkill_ops, acpi->handle);
984 /*
985 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
986 * This is OK, however, since all other uses of the device will not
987 * dereference it.
988 */
989 if (ipml->rf) {
990 retval = rfkill_register(ipml->rf);
991 if (retval) {
992 rfkill_destroy(ipml->rf);
993 ipml->rf = NULL;
994 }
995 }
996
997 dev_set_drvdata(&acpi->dev, ipml);
998 return 0;
999
1000 out_bd:
1001 kfree(ipml);
1002 return retval;
1003 }
1004
cmpc_ipml_remove(struct acpi_device * acpi)1005 static void cmpc_ipml_remove(struct acpi_device *acpi)
1006 {
1007 struct ipml200_dev *ipml;
1008
1009 ipml = dev_get_drvdata(&acpi->dev);
1010
1011 backlight_device_unregister(ipml->bd);
1012
1013 if (ipml->rf) {
1014 rfkill_unregister(ipml->rf);
1015 rfkill_destroy(ipml->rf);
1016 }
1017
1018 kfree(ipml);
1019 }
1020
1021 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
1022 {CMPC_IPML_HID, 0},
1023 {"", 0}
1024 };
1025
1026 static struct acpi_driver cmpc_ipml_acpi_driver = {
1027 .name = "cmpc",
1028 .class = "cmpc",
1029 .ids = cmpc_ipml_device_ids,
1030 .ops = {
1031 .add = cmpc_ipml_add,
1032 .remove = cmpc_ipml_remove
1033 }
1034 };
1035
1036
1037 /*
1038 * Extra keys code.
1039 */
1040 static int cmpc_keys_codes[] = {
1041 KEY_UNKNOWN,
1042 KEY_WLAN,
1043 KEY_SWITCHVIDEOMODE,
1044 KEY_BRIGHTNESSDOWN,
1045 KEY_BRIGHTNESSUP,
1046 KEY_VENDOR,
1047 KEY_UNKNOWN,
1048 KEY_CAMERA,
1049 KEY_BACK,
1050 KEY_FORWARD,
1051 KEY_UNKNOWN,
1052 KEY_WLAN, /* NL3: 0x8b (press), 0x9b (release) */
1053 KEY_MAX
1054 };
1055
cmpc_keys_handler(struct acpi_device * dev,u32 event)1056 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1057 {
1058 struct input_dev *inputdev;
1059 int code = KEY_MAX;
1060
1061 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1062 code = cmpc_keys_codes[event & 0x0F];
1063 inputdev = dev_get_drvdata(&dev->dev);
1064 input_report_key(inputdev, code, !(event & 0x10));
1065 input_sync(inputdev);
1066 }
1067
cmpc_keys_idev_init(struct input_dev * inputdev)1068 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1069 {
1070 int i;
1071
1072 set_bit(EV_KEY, inputdev->evbit);
1073 for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1074 set_bit(cmpc_keys_codes[i], inputdev->keybit);
1075 }
1076
cmpc_keys_add(struct acpi_device * acpi)1077 static int cmpc_keys_add(struct acpi_device *acpi)
1078 {
1079 return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1080 cmpc_keys_idev_init);
1081 }
1082
cmpc_keys_remove(struct acpi_device * acpi)1083 static void cmpc_keys_remove(struct acpi_device *acpi)
1084 {
1085 cmpc_remove_acpi_notify_device(acpi);
1086 }
1087
1088 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1089 {CMPC_KEYS_HID, 0},
1090 {"", 0}
1091 };
1092
1093 static struct acpi_driver cmpc_keys_acpi_driver = {
1094 .name = "cmpc_keys",
1095 .class = "cmpc_keys",
1096 .ids = cmpc_keys_device_ids,
1097 .ops = {
1098 .add = cmpc_keys_add,
1099 .remove = cmpc_keys_remove,
1100 .notify = cmpc_keys_handler,
1101 }
1102 };
1103
1104
1105 /*
1106 * General init/exit code.
1107 */
1108
cmpc_init(void)1109 static int cmpc_init(void)
1110 {
1111 int r;
1112
1113 r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1114 if (r)
1115 goto failed_keys;
1116
1117 r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1118 if (r)
1119 goto failed_bl;
1120
1121 r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1122 if (r)
1123 goto failed_tablet;
1124
1125 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1126 if (r)
1127 goto failed_accel;
1128
1129 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1130 if (r)
1131 goto failed_accel_v4;
1132
1133 return r;
1134
1135 failed_accel_v4:
1136 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1137
1138 failed_accel:
1139 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1140
1141 failed_tablet:
1142 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1143
1144 failed_bl:
1145 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1146
1147 failed_keys:
1148 return r;
1149 }
1150
cmpc_exit(void)1151 static void cmpc_exit(void)
1152 {
1153 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1154 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1155 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1156 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1157 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1158 }
1159
1160 module_init(cmpc_init);
1161 module_exit(cmpc_exit);
1162
1163 static const struct acpi_device_id cmpc_device_ids[] __maybe_unused = {
1164 {CMPC_ACCEL_HID, 0},
1165 {CMPC_ACCEL_HID_V4, 0},
1166 {CMPC_TABLET_HID, 0},
1167 {CMPC_IPML_HID, 0},
1168 {CMPC_KEYS_HID, 0},
1169 {"", 0}
1170 };
1171
1172 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
1173 MODULE_DESCRIPTION("Support for Intel Classmate PC ACPI devices");
1174 MODULE_LICENSE("GPL");
1175