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