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