Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
classmate-laptop.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <[email protected]>
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 {
34  int g_select;
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;
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;
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;
171  int16_t *locs;
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;
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))) {
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);
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 
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 
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 
401 
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 
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;
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;
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;
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;
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 
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;
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  input_sync(inputdev);
731  }
732  }
733 }
734 
735 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
736 {
737  unsigned long long val = 0;
738  struct acpi_device *acpi;
739 
740  set_bit(EV_SW, inputdev->evbit);
741  set_bit(SW_TABLET_MODE, inputdev->swbit);
742 
743  acpi = to_acpi_device(inputdev->dev.parent);
744  if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
745  input_report_switch(inputdev, SW_TABLET_MODE, !val);
746  input_sync(inputdev);
747  }
748 }
749 
750 static int cmpc_tablet_add(struct acpi_device *acpi)
751 {
752  return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
753  cmpc_tablet_idev_init);
754 }
755 
756 static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
757 {
758  return cmpc_remove_acpi_notify_device(acpi);
759 }
760 
761 #ifdef CONFIG_PM_SLEEP
762 static int cmpc_tablet_resume(struct device *dev)
763 {
764  struct input_dev *inputdev = dev_get_drvdata(dev);
765 
766  unsigned long long val = 0;
767  if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
768  input_report_switch(inputdev, SW_TABLET_MODE, !val);
769  input_sync(inputdev);
770  }
771  return 0;
772 }
773 #endif
774 
775 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
776 
777 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
778  {CMPC_TABLET_HID, 0},
779  {"", 0}
780 };
781 
782 static struct acpi_driver cmpc_tablet_acpi_driver = {
783  .owner = THIS_MODULE,
784  .name = "cmpc_tablet",
785  .class = "cmpc_tablet",
786  .ids = cmpc_tablet_device_ids,
787  .ops = {
788  .add = cmpc_tablet_add,
789  .remove = cmpc_tablet_remove,
790  .notify = cmpc_tablet_handler,
791  },
792  .drv.pm = &cmpc_tablet_pm,
793 };
794 
795 
796 /*
797  * Backlight code.
798  */
799 
800 static acpi_status cmpc_get_brightness(acpi_handle handle,
801  unsigned long long *value)
802 {
803  union acpi_object param;
804  struct acpi_object_list input;
805  unsigned long long output;
807 
808  param.type = ACPI_TYPE_INTEGER;
809  param.integer.value = 0xC0;
810  input.count = 1;
811  input.pointer = &param;
812  status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
813  if (ACPI_SUCCESS(status))
814  *value = output;
815  return status;
816 }
817 
818 static acpi_status cmpc_set_brightness(acpi_handle handle,
819  unsigned long long value)
820 {
821  union acpi_object param[2];
822  struct acpi_object_list input;
824  unsigned long long output;
825 
826  param[0].type = ACPI_TYPE_INTEGER;
827  param[0].integer.value = 0xC0;
828  param[1].type = ACPI_TYPE_INTEGER;
829  param[1].integer.value = value;
830  input.count = 2;
831  input.pointer = param;
832  status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
833  return status;
834 }
835 
836 static int cmpc_bl_get_brightness(struct backlight_device *bd)
837 {
840  unsigned long long brightness;
841 
842  handle = bl_get_data(bd);
843  status = cmpc_get_brightness(handle, &brightness);
844  if (ACPI_SUCCESS(status))
845  return brightness;
846  else
847  return -1;
848 }
849 
850 static int cmpc_bl_update_status(struct backlight_device *bd)
851 {
854 
855  handle = bl_get_data(bd);
856  status = cmpc_set_brightness(handle, bd->props.brightness);
857  if (ACPI_SUCCESS(status))
858  return 0;
859  else
860  return -1;
861 }
862 
863 static const struct backlight_ops cmpc_bl_ops = {
864  .get_brightness = cmpc_bl_get_brightness,
865  .update_status = cmpc_bl_update_status
866 };
867 
868 /*
869  * RFKILL code.
870  */
871 
872 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
873  unsigned long long *value)
874 {
875  union acpi_object param;
876  struct acpi_object_list input;
877  unsigned long long output;
879 
880  param.type = ACPI_TYPE_INTEGER;
881  param.integer.value = 0xC1;
882  input.count = 1;
883  input.pointer = &param;
884  status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
885  if (ACPI_SUCCESS(status))
886  *value = output;
887  return status;
888 }
889 
890 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
891  unsigned long long value)
892 {
893  union acpi_object param[2];
894  struct acpi_object_list input;
896  unsigned long long output;
897 
898  param[0].type = ACPI_TYPE_INTEGER;
899  param[0].integer.value = 0xC1;
900  param[1].type = ACPI_TYPE_INTEGER;
901  param[1].integer.value = value;
902  input.count = 2;
903  input.pointer = param;
904  status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
905  return status;
906 }
907 
908 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
909 {
912  unsigned long long state;
913  bool blocked;
914 
915  handle = data;
916  status = cmpc_get_rfkill_wlan(handle, &state);
917  if (ACPI_SUCCESS(status)) {
918  blocked = state & 1 ? false : true;
919  rfkill_set_sw_state(rfkill, blocked);
920  }
921 }
922 
923 static int cmpc_rfkill_block(void *data, bool blocked)
924 {
927  unsigned long long state;
928  bool is_blocked;
929 
930  handle = data;
931  status = cmpc_get_rfkill_wlan(handle, &state);
932  if (ACPI_FAILURE(status))
933  return -ENODEV;
934  /* Check if we really need to call cmpc_set_rfkill_wlan */
935  is_blocked = state & 1 ? false : true;
936  if (is_blocked != blocked) {
937  state = blocked ? 0 : 1;
938  status = cmpc_set_rfkill_wlan(handle, state);
939  if (ACPI_FAILURE(status))
940  return -ENODEV;
941  }
942  return 0;
943 }
944 
945 static const struct rfkill_ops cmpc_rfkill_ops = {
946  .query = cmpc_rfkill_query,
947  .set_block = cmpc_rfkill_block,
948 };
949 
950 /*
951  * Common backlight and rfkill code.
952  */
953 
954 struct ipml200_dev {
956  struct rfkill *rf;
957 };
958 
959 static int cmpc_ipml_add(struct acpi_device *acpi)
960 {
961  int retval;
962  struct ipml200_dev *ipml;
963  struct backlight_properties props;
964 
965  ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
966  if (ipml == NULL)
967  return -ENOMEM;
968 
969  memset(&props, 0, sizeof(struct backlight_properties));
970  props.type = BACKLIGHT_PLATFORM;
971  props.max_brightness = 7;
972  ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
973  acpi->handle, &cmpc_bl_ops,
974  &props);
975  if (IS_ERR(ipml->bd)) {
976  retval = PTR_ERR(ipml->bd);
977  goto out_bd;
978  }
979 
980  ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
981  &cmpc_rfkill_ops, acpi->handle);
982  /*
983  * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
984  * This is OK, however, since all other uses of the device will not
985  * derefence it.
986  */
987  if (ipml->rf) {
988  retval = rfkill_register(ipml->rf);
989  if (retval) {
990  rfkill_destroy(ipml->rf);
991  ipml->rf = NULL;
992  }
993  }
994 
995  dev_set_drvdata(&acpi->dev, ipml);
996  return 0;
997 
998 out_bd:
999  kfree(ipml);
1000  return retval;
1001 }
1002 
1003 static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
1004 {
1005  struct ipml200_dev *ipml;
1006 
1007  ipml = dev_get_drvdata(&acpi->dev);
1008 
1010 
1011  if (ipml->rf) {
1012  rfkill_unregister(ipml->rf);
1013  rfkill_destroy(ipml->rf);
1014  }
1015 
1016  kfree(ipml);
1017 
1018  return 0;
1019 }
1020 
1021 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
1022  {CMPC_IPML_HID, 0},
1023  {"", 0}
1024 };
1025 
1026 static struct acpi_driver cmpc_ipml_acpi_driver = {
1027  .owner = THIS_MODULE,
1028  .name = "cmpc",
1029  .class = "cmpc",
1030  .ids = cmpc_ipml_device_ids,
1031  .ops = {
1032  .add = cmpc_ipml_add,
1033  .remove = cmpc_ipml_remove
1034  }
1035 };
1036 
1037 
1038 /*
1039  * Extra keys code.
1040  */
1041 static int cmpc_keys_codes[] = {
1042  KEY_UNKNOWN,
1043  KEY_WLAN,
1047  KEY_VENDOR,
1048  KEY_UNKNOWN,
1049  KEY_CAMERA,
1050  KEY_BACK,
1051  KEY_FORWARD,
1052  KEY_MAX
1053 };
1054 
1055 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1056 {
1057  struct input_dev *inputdev;
1058  int code = KEY_MAX;
1059 
1060  if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1061  code = cmpc_keys_codes[event & 0x0F];
1062  inputdev = dev_get_drvdata(&dev->dev);
1063  input_report_key(inputdev, code, !(event & 0x10));
1064  input_sync(inputdev);
1065 }
1066 
1067 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1068 {
1069  int i;
1070 
1071  set_bit(EV_KEY, inputdev->evbit);
1072  for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1073  set_bit(cmpc_keys_codes[i], inputdev->keybit);
1074 }
1075 
1076 static int cmpc_keys_add(struct acpi_device *acpi)
1077 {
1078  return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1079  cmpc_keys_idev_init);
1080 }
1081 
1082 static int cmpc_keys_remove(struct acpi_device *acpi, int type)
1083 {
1084  return cmpc_remove_acpi_notify_device(acpi);
1085 }
1086 
1087 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1088  {CMPC_KEYS_HID, 0},
1089  {"", 0}
1090 };
1091 
1092 static struct acpi_driver cmpc_keys_acpi_driver = {
1093  .owner = THIS_MODULE,
1094  .name = "cmpc_keys",
1095  .class = "cmpc_keys",
1096  .ids = cmpc_keys_device_ids,
1097  .ops = {
1098  .add = cmpc_keys_add,
1099  .remove = cmpc_keys_remove,
1100  .notify = cmpc_keys_handler,
1101  }
1102 };
1103 
1104 
1105 /*
1106  * General init/exit code.
1107  */
1108 
1109 static int cmpc_init(void)
1110 {
1111  int r;
1112 
1113  r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1114  if (r)
1115  goto failed_keys;
1116 
1117  r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1118  if (r)
1119  goto failed_bl;
1120 
1121  r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1122  if (r)
1123  goto failed_tablet;
1124 
1125  r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1126  if (r)
1127  goto failed_accel;
1128 
1129  r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1130  if (r)
1131  goto failed_accel_v4;
1132 
1133  return r;
1134 
1135 failed_accel_v4:
1136  acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1137 
1138 failed_accel:
1139  acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1140 
1141 failed_tablet:
1142  acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1143 
1144 failed_bl:
1145  acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1146 
1147 failed_keys:
1148  return r;
1149 }
1150 
1151 static void cmpc_exit(void)
1152 {
1153  acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1154  acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1155  acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1156  acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1157  acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1158 }
1159 
1160 module_init(cmpc_init);
1161 module_exit(cmpc_exit);
1162 
1163 static const struct acpi_device_id cmpc_device_ids[] = {
1164  {CMPC_ACCEL_HID, 0},
1165  {CMPC_ACCEL_HID_V4, 0},
1166  {CMPC_TABLET_HID, 0},
1167  {CMPC_IPML_HID, 0},
1168  {CMPC_KEYS_HID, 0},
1169  {"", 0}
1170 };
1171 
1172 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);