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