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 <acpi/acpi_drivers.h>
25 #include <linux/backlight.h>
26 #include <linux/input.h>
27 #include <linux/rfkill.h>
28 
29 MODULE_LICENSE("GPL");
30 
31 
32 struct cmpc_accel {
33 	int sensitivity;
34 };
35 
36 #define CMPC_ACCEL_SENSITIVITY_DEFAULT		5
37 
38 
39 #define CMPC_ACCEL_HID		"ACCE0000"
40 #define CMPC_TABLET_HID		"TBLT0000"
41 #define CMPC_IPML_HID	"IPML200"
42 #define CMPC_KEYS_HID		"FnBT0000"
43 
44 /*
45  * Generic input device code.
46  */
47 
48 typedef void (*input_device_init)(struct input_dev *dev);
49 
cmpc_add_acpi_notify_device(struct acpi_device * acpi,char * name,input_device_init idev_init)50 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
51 				       input_device_init idev_init)
52 {
53 	struct input_dev *inputdev;
54 	int error;
55 
56 	inputdev = input_allocate_device();
57 	if (!inputdev)
58 		return -ENOMEM;
59 	inputdev->name = name;
60 	inputdev->dev.parent = &acpi->dev;
61 	idev_init(inputdev);
62 	error = input_register_device(inputdev);
63 	if (error) {
64 		input_free_device(inputdev);
65 		return error;
66 	}
67 	dev_set_drvdata(&acpi->dev, inputdev);
68 	return 0;
69 }
70 
cmpc_remove_acpi_notify_device(struct acpi_device * acpi)71 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
72 {
73 	struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
74 	input_unregister_device(inputdev);
75 	return 0;
76 }
77 
78 /*
79  * Accelerometer code.
80  */
cmpc_start_accel(acpi_handle handle)81 static acpi_status cmpc_start_accel(acpi_handle handle)
82 {
83 	union acpi_object param[2];
84 	struct acpi_object_list input;
85 	acpi_status status;
86 
87 	param[0].type = ACPI_TYPE_INTEGER;
88 	param[0].integer.value = 0x3;
89 	param[1].type = ACPI_TYPE_INTEGER;
90 	input.count = 2;
91 	input.pointer = param;
92 	status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
93 	return status;
94 }
95 
cmpc_stop_accel(acpi_handle handle)96 static acpi_status cmpc_stop_accel(acpi_handle handle)
97 {
98 	union acpi_object param[2];
99 	struct acpi_object_list input;
100 	acpi_status status;
101 
102 	param[0].type = ACPI_TYPE_INTEGER;
103 	param[0].integer.value = 0x4;
104 	param[1].type = ACPI_TYPE_INTEGER;
105 	input.count = 2;
106 	input.pointer = param;
107 	status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
108 	return status;
109 }
110 
cmpc_accel_set_sensitivity(acpi_handle handle,int val)111 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
112 {
113 	union acpi_object param[2];
114 	struct acpi_object_list input;
115 
116 	param[0].type = ACPI_TYPE_INTEGER;
117 	param[0].integer.value = 0x02;
118 	param[1].type = ACPI_TYPE_INTEGER;
119 	param[1].integer.value = val;
120 	input.count = 2;
121 	input.pointer = param;
122 	return acpi_evaluate_object(handle, "ACMD", &input, NULL);
123 }
124 
cmpc_get_accel(acpi_handle handle,unsigned char * x,unsigned char * y,unsigned char * z)125 static acpi_status cmpc_get_accel(acpi_handle handle,
126 				  unsigned char *x,
127 				  unsigned char *y,
128 				  unsigned char *z)
129 {
130 	union acpi_object param[2];
131 	struct acpi_object_list input;
132 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
133 	unsigned char *locs;
134 	acpi_status status;
135 
136 	param[0].type = ACPI_TYPE_INTEGER;
137 	param[0].integer.value = 0x01;
138 	param[1].type = ACPI_TYPE_INTEGER;
139 	input.count = 2;
140 	input.pointer = param;
141 	status = acpi_evaluate_object(handle, "ACMD", &input, &output);
142 	if (ACPI_SUCCESS(status)) {
143 		union acpi_object *obj;
144 		obj = output.pointer;
145 		locs = obj->buffer.pointer;
146 		*x = locs[0];
147 		*y = locs[1];
148 		*z = locs[2];
149 		kfree(output.pointer);
150 	}
151 	return status;
152 }
153 
cmpc_accel_handler(struct acpi_device * dev,u32 event)154 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
155 {
156 	if (event == 0x81) {
157 		unsigned char x, y, z;
158 		acpi_status status;
159 
160 		status = cmpc_get_accel(dev->handle, &x, &y, &z);
161 		if (ACPI_SUCCESS(status)) {
162 			struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
163 
164 			input_report_abs(inputdev, ABS_X, x);
165 			input_report_abs(inputdev, ABS_Y, y);
166 			input_report_abs(inputdev, ABS_Z, z);
167 			input_sync(inputdev);
168 		}
169 	}
170 }
171 
cmpc_accel_sensitivity_show(struct device * dev,struct device_attribute * attr,char * buf)172 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
173 					   struct device_attribute *attr,
174 					   char *buf)
175 {
176 	struct acpi_device *acpi;
177 	struct input_dev *inputdev;
178 	struct cmpc_accel *accel;
179 
180 	acpi = to_acpi_device(dev);
181 	inputdev = dev_get_drvdata(&acpi->dev);
182 	accel = dev_get_drvdata(&inputdev->dev);
183 
184 	return sprintf(buf, "%d\n", accel->sensitivity);
185 }
186 
cmpc_accel_sensitivity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)187 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
188 					    struct device_attribute *attr,
189 					    const char *buf, size_t count)
190 {
191 	struct acpi_device *acpi;
192 	struct input_dev *inputdev;
193 	struct cmpc_accel *accel;
194 	unsigned long sensitivity;
195 	int r;
196 
197 	acpi = to_acpi_device(dev);
198 	inputdev = dev_get_drvdata(&acpi->dev);
199 	accel = dev_get_drvdata(&inputdev->dev);
200 
201 	r = strict_strtoul(buf, 0, &sensitivity);
202 	if (r)
203 		return r;
204 
205 	accel->sensitivity = sensitivity;
206 	cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
207 
208 	return strnlen(buf, count);
209 }
210 
211 static struct device_attribute cmpc_accel_sensitivity_attr = {
212 	.attr = { .name = "sensitivity", .mode = 0660 },
213 	.show = cmpc_accel_sensitivity_show,
214 	.store = cmpc_accel_sensitivity_store
215 };
216 
cmpc_accel_open(struct input_dev * input)217 static int cmpc_accel_open(struct input_dev *input)
218 {
219 	struct acpi_device *acpi;
220 
221 	acpi = to_acpi_device(input->dev.parent);
222 	if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
223 		return 0;
224 	return -EIO;
225 }
226 
cmpc_accel_close(struct input_dev * input)227 static void cmpc_accel_close(struct input_dev *input)
228 {
229 	struct acpi_device *acpi;
230 
231 	acpi = to_acpi_device(input->dev.parent);
232 	cmpc_stop_accel(acpi->handle);
233 }
234 
cmpc_accel_idev_init(struct input_dev * inputdev)235 static void cmpc_accel_idev_init(struct input_dev *inputdev)
236 {
237 	set_bit(EV_ABS, inputdev->evbit);
238 	input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
239 	input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
240 	input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
241 	inputdev->open = cmpc_accel_open;
242 	inputdev->close = cmpc_accel_close;
243 }
244 
cmpc_accel_add(struct acpi_device * acpi)245 static int cmpc_accel_add(struct acpi_device *acpi)
246 {
247 	int error;
248 	struct input_dev *inputdev;
249 	struct cmpc_accel *accel;
250 
251 	accel = kmalloc(sizeof(*accel), GFP_KERNEL);
252 	if (!accel)
253 		return -ENOMEM;
254 
255 	accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
256 	cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
257 
258 	error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
259 	if (error)
260 		goto failed_file;
261 
262 	error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
263 					    cmpc_accel_idev_init);
264 	if (error)
265 		goto failed_input;
266 
267 	inputdev = dev_get_drvdata(&acpi->dev);
268 	dev_set_drvdata(&inputdev->dev, accel);
269 
270 	return 0;
271 
272 failed_input:
273 	device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
274 failed_file:
275 	kfree(accel);
276 	return error;
277 }
278 
cmpc_accel_remove(struct acpi_device * acpi,int type)279 static int cmpc_accel_remove(struct acpi_device *acpi, int type)
280 {
281 	struct input_dev *inputdev;
282 	struct cmpc_accel *accel;
283 
284 	inputdev = dev_get_drvdata(&acpi->dev);
285 	accel = dev_get_drvdata(&inputdev->dev);
286 
287 	device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
288 	return cmpc_remove_acpi_notify_device(acpi);
289 }
290 
291 static const struct acpi_device_id cmpc_accel_device_ids[] = {
292 	{CMPC_ACCEL_HID, 0},
293 	{"", 0}
294 };
295 
296 static struct acpi_driver cmpc_accel_acpi_driver = {
297 	.owner = THIS_MODULE,
298 	.name = "cmpc_accel",
299 	.class = "cmpc_accel",
300 	.ids = cmpc_accel_device_ids,
301 	.ops = {
302 		.add = cmpc_accel_add,
303 		.remove = cmpc_accel_remove,
304 		.notify = cmpc_accel_handler,
305 	}
306 };
307 
308 
309 /*
310  * Tablet mode code.
311  */
cmpc_get_tablet(acpi_handle handle,unsigned long long * value)312 static acpi_status cmpc_get_tablet(acpi_handle handle,
313 				   unsigned long long *value)
314 {
315 	union acpi_object param;
316 	struct acpi_object_list input;
317 	unsigned long long output;
318 	acpi_status status;
319 
320 	param.type = ACPI_TYPE_INTEGER;
321 	param.integer.value = 0x01;
322 	input.count = 1;
323 	input.pointer = &param;
324 	status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
325 	if (ACPI_SUCCESS(status))
326 		*value = output;
327 	return status;
328 }
329 
cmpc_tablet_handler(struct acpi_device * dev,u32 event)330 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
331 {
332 	unsigned long long val = 0;
333 	struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
334 
335 	if (event == 0x81) {
336 		if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val)))
337 			input_report_switch(inputdev, SW_TABLET_MODE, !val);
338 	}
339 }
340 
cmpc_tablet_idev_init(struct input_dev * inputdev)341 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
342 {
343 	unsigned long long val = 0;
344 	struct acpi_device *acpi;
345 
346 	set_bit(EV_SW, inputdev->evbit);
347 	set_bit(SW_TABLET_MODE, inputdev->swbit);
348 
349 	acpi = to_acpi_device(inputdev->dev.parent);
350 	if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
351 		input_report_switch(inputdev, SW_TABLET_MODE, !val);
352 }
353 
cmpc_tablet_add(struct acpi_device * acpi)354 static int cmpc_tablet_add(struct acpi_device *acpi)
355 {
356 	return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
357 					   cmpc_tablet_idev_init);
358 }
359 
cmpc_tablet_remove(struct acpi_device * acpi,int type)360 static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
361 {
362 	return cmpc_remove_acpi_notify_device(acpi);
363 }
364 
cmpc_tablet_resume(struct acpi_device * acpi)365 static int cmpc_tablet_resume(struct acpi_device *acpi)
366 {
367 	struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
368 	unsigned long long val = 0;
369 	if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
370 		input_report_switch(inputdev, SW_TABLET_MODE, !val);
371 	return 0;
372 }
373 
374 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
375 	{CMPC_TABLET_HID, 0},
376 	{"", 0}
377 };
378 
379 static struct acpi_driver cmpc_tablet_acpi_driver = {
380 	.owner = THIS_MODULE,
381 	.name = "cmpc_tablet",
382 	.class = "cmpc_tablet",
383 	.ids = cmpc_tablet_device_ids,
384 	.ops = {
385 		.add = cmpc_tablet_add,
386 		.remove = cmpc_tablet_remove,
387 		.resume = cmpc_tablet_resume,
388 		.notify = cmpc_tablet_handler,
389 	}
390 };
391 
392 
393 /*
394  * Backlight code.
395  */
396 
cmpc_get_brightness(acpi_handle handle,unsigned long long * value)397 static acpi_status cmpc_get_brightness(acpi_handle handle,
398 				       unsigned long long *value)
399 {
400 	union acpi_object param;
401 	struct acpi_object_list input;
402 	unsigned long long output;
403 	acpi_status status;
404 
405 	param.type = ACPI_TYPE_INTEGER;
406 	param.integer.value = 0xC0;
407 	input.count = 1;
408 	input.pointer = &param;
409 	status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
410 	if (ACPI_SUCCESS(status))
411 		*value = output;
412 	return status;
413 }
414 
cmpc_set_brightness(acpi_handle handle,unsigned long long value)415 static acpi_status cmpc_set_brightness(acpi_handle handle,
416 				       unsigned long long value)
417 {
418 	union acpi_object param[2];
419 	struct acpi_object_list input;
420 	acpi_status status;
421 	unsigned long long output;
422 
423 	param[0].type = ACPI_TYPE_INTEGER;
424 	param[0].integer.value = 0xC0;
425 	param[1].type = ACPI_TYPE_INTEGER;
426 	param[1].integer.value = value;
427 	input.count = 2;
428 	input.pointer = param;
429 	status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
430 	return status;
431 }
432 
cmpc_bl_get_brightness(struct backlight_device * bd)433 static int cmpc_bl_get_brightness(struct backlight_device *bd)
434 {
435 	acpi_status status;
436 	acpi_handle handle;
437 	unsigned long long brightness;
438 
439 	handle = bl_get_data(bd);
440 	status = cmpc_get_brightness(handle, &brightness);
441 	if (ACPI_SUCCESS(status))
442 		return brightness;
443 	else
444 		return -1;
445 }
446 
cmpc_bl_update_status(struct backlight_device * bd)447 static int cmpc_bl_update_status(struct backlight_device *bd)
448 {
449 	acpi_status status;
450 	acpi_handle handle;
451 
452 	handle = bl_get_data(bd);
453 	status = cmpc_set_brightness(handle, bd->props.brightness);
454 	if (ACPI_SUCCESS(status))
455 		return 0;
456 	else
457 		return -1;
458 }
459 
460 static const struct backlight_ops cmpc_bl_ops = {
461 	.get_brightness = cmpc_bl_get_brightness,
462 	.update_status = cmpc_bl_update_status
463 };
464 
465 /*
466  * RFKILL code.
467  */
468 
cmpc_get_rfkill_wlan(acpi_handle handle,unsigned long long * value)469 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
470 					unsigned long long *value)
471 {
472 	union acpi_object param;
473 	struct acpi_object_list input;
474 	unsigned long long output;
475 	acpi_status status;
476 
477 	param.type = ACPI_TYPE_INTEGER;
478 	param.integer.value = 0xC1;
479 	input.count = 1;
480 	input.pointer = &param;
481 	status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
482 	if (ACPI_SUCCESS(status))
483 		*value = output;
484 	return status;
485 }
486 
cmpc_set_rfkill_wlan(acpi_handle handle,unsigned long long value)487 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
488 					unsigned long long value)
489 {
490 	union acpi_object param[2];
491 	struct acpi_object_list input;
492 	acpi_status status;
493 	unsigned long long output;
494 
495 	param[0].type = ACPI_TYPE_INTEGER;
496 	param[0].integer.value = 0xC1;
497 	param[1].type = ACPI_TYPE_INTEGER;
498 	param[1].integer.value = value;
499 	input.count = 2;
500 	input.pointer = param;
501 	status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
502 	return status;
503 }
504 
cmpc_rfkill_query(struct rfkill * rfkill,void * data)505 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
506 {
507 	acpi_status status;
508 	acpi_handle handle;
509 	unsigned long long state;
510 	bool blocked;
511 
512 	handle = data;
513 	status = cmpc_get_rfkill_wlan(handle, &state);
514 	if (ACPI_SUCCESS(status)) {
515 		blocked = state & 1 ? false : true;
516 		rfkill_set_sw_state(rfkill, blocked);
517 	}
518 }
519 
cmpc_rfkill_block(void * data,bool blocked)520 static int cmpc_rfkill_block(void *data, bool blocked)
521 {
522 	acpi_status status;
523 	acpi_handle handle;
524 	unsigned long long state;
525 	bool is_blocked;
526 
527 	handle = data;
528 	status = cmpc_get_rfkill_wlan(handle, &state);
529 	if (ACPI_FAILURE(status))
530 		return -ENODEV;
531 	/* Check if we really need to call cmpc_set_rfkill_wlan */
532 	is_blocked = state & 1 ? false : true;
533 	if (is_blocked != blocked) {
534 		state = blocked ? 0 : 1;
535 		status = cmpc_set_rfkill_wlan(handle, state);
536 		if (ACPI_FAILURE(status))
537 			return -ENODEV;
538 	}
539 	return 0;
540 }
541 
542 static const struct rfkill_ops cmpc_rfkill_ops = {
543 	.query = cmpc_rfkill_query,
544 	.set_block = cmpc_rfkill_block,
545 };
546 
547 /*
548  * Common backlight and rfkill code.
549  */
550 
551 struct ipml200_dev {
552 	struct backlight_device *bd;
553 	struct rfkill *rf;
554 };
555 
cmpc_ipml_add(struct acpi_device * acpi)556 static int cmpc_ipml_add(struct acpi_device *acpi)
557 {
558 	int retval;
559 	struct ipml200_dev *ipml;
560 	struct backlight_properties props;
561 
562 	ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
563 	if (ipml == NULL)
564 		return -ENOMEM;
565 
566 	memset(&props, 0, sizeof(struct backlight_properties));
567 	props.type = BACKLIGHT_PLATFORM;
568 	props.max_brightness = 7;
569 	ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
570 					     acpi->handle, &cmpc_bl_ops,
571 					     &props);
572 	if (IS_ERR(ipml->bd)) {
573 		retval = PTR_ERR(ipml->bd);
574 		goto out_bd;
575 	}
576 
577 	ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
578 				&cmpc_rfkill_ops, acpi->handle);
579 	/*
580 	 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
581 	 * This is OK, however, since all other uses of the device will not
582 	 * derefence it.
583 	 */
584 	if (ipml->rf) {
585 		retval = rfkill_register(ipml->rf);
586 		if (retval) {
587 			rfkill_destroy(ipml->rf);
588 			ipml->rf = NULL;
589 		}
590 	}
591 
592 	dev_set_drvdata(&acpi->dev, ipml);
593 	return 0;
594 
595 out_bd:
596 	kfree(ipml);
597 	return retval;
598 }
599 
cmpc_ipml_remove(struct acpi_device * acpi,int type)600 static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
601 {
602 	struct ipml200_dev *ipml;
603 
604 	ipml = dev_get_drvdata(&acpi->dev);
605 
606 	backlight_device_unregister(ipml->bd);
607 
608 	if (ipml->rf) {
609 		rfkill_unregister(ipml->rf);
610 		rfkill_destroy(ipml->rf);
611 	}
612 
613 	kfree(ipml);
614 
615 	return 0;
616 }
617 
618 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
619 	{CMPC_IPML_HID, 0},
620 	{"", 0}
621 };
622 
623 static struct acpi_driver cmpc_ipml_acpi_driver = {
624 	.owner = THIS_MODULE,
625 	.name = "cmpc",
626 	.class = "cmpc",
627 	.ids = cmpc_ipml_device_ids,
628 	.ops = {
629 		.add = cmpc_ipml_add,
630 		.remove = cmpc_ipml_remove
631 	}
632 };
633 
634 
635 /*
636  * Extra keys code.
637  */
638 static int cmpc_keys_codes[] = {
639 	KEY_UNKNOWN,
640 	KEY_WLAN,
641 	KEY_SWITCHVIDEOMODE,
642 	KEY_BRIGHTNESSDOWN,
643 	KEY_BRIGHTNESSUP,
644 	KEY_VENDOR,
645 	KEY_UNKNOWN,
646 	KEY_CAMERA,
647 	KEY_BACK,
648 	KEY_FORWARD,
649 	KEY_MAX
650 };
651 
cmpc_keys_handler(struct acpi_device * dev,u32 event)652 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
653 {
654 	struct input_dev *inputdev;
655 	int code = KEY_MAX;
656 
657 	if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
658 		code = cmpc_keys_codes[event & 0x0F];
659 	inputdev = dev_get_drvdata(&dev->dev);
660 	input_report_key(inputdev, code, !(event & 0x10));
661 	input_sync(inputdev);
662 }
663 
cmpc_keys_idev_init(struct input_dev * inputdev)664 static void cmpc_keys_idev_init(struct input_dev *inputdev)
665 {
666 	int i;
667 
668 	set_bit(EV_KEY, inputdev->evbit);
669 	for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
670 		set_bit(cmpc_keys_codes[i], inputdev->keybit);
671 }
672 
cmpc_keys_add(struct acpi_device * acpi)673 static int cmpc_keys_add(struct acpi_device *acpi)
674 {
675 	return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
676 					   cmpc_keys_idev_init);
677 }
678 
cmpc_keys_remove(struct acpi_device * acpi,int type)679 static int cmpc_keys_remove(struct acpi_device *acpi, int type)
680 {
681 	return cmpc_remove_acpi_notify_device(acpi);
682 }
683 
684 static const struct acpi_device_id cmpc_keys_device_ids[] = {
685 	{CMPC_KEYS_HID, 0},
686 	{"", 0}
687 };
688 
689 static struct acpi_driver cmpc_keys_acpi_driver = {
690 	.owner = THIS_MODULE,
691 	.name = "cmpc_keys",
692 	.class = "cmpc_keys",
693 	.ids = cmpc_keys_device_ids,
694 	.ops = {
695 		.add = cmpc_keys_add,
696 		.remove = cmpc_keys_remove,
697 		.notify = cmpc_keys_handler,
698 	}
699 };
700 
701 
702 /*
703  * General init/exit code.
704  */
705 
cmpc_init(void)706 static int cmpc_init(void)
707 {
708 	int r;
709 
710 	r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
711 	if (r)
712 		goto failed_keys;
713 
714 	r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
715 	if (r)
716 		goto failed_bl;
717 
718 	r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
719 	if (r)
720 		goto failed_tablet;
721 
722 	r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
723 	if (r)
724 		goto failed_accel;
725 
726 	return r;
727 
728 failed_accel:
729 	acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
730 
731 failed_tablet:
732 	acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
733 
734 failed_bl:
735 	acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
736 
737 failed_keys:
738 	return r;
739 }
740 
cmpc_exit(void)741 static void cmpc_exit(void)
742 {
743 	acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
744 	acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
745 	acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
746 	acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
747 }
748 
749 module_init(cmpc_init);
750 module_exit(cmpc_exit);
751 
752 static const struct acpi_device_id cmpc_device_ids[] = {
753 	{CMPC_ACCEL_HID, 0},
754 	{CMPC_TABLET_HID, 0},
755 	{CMPC_IPML_HID, 0},
756 	{CMPC_KEYS_HID, 0},
757 	{"", 0}
758 };
759 
760 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
761