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