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