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