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