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