Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us