netfilter: remove unnecessary goto statement for error recovery
[cascardo/linux.git] / drivers / platform / x86 / classmate-laptop.c
1 /*
2  *  Copyright (C) 2009  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/workqueue.h>
24 #include <acpi/acpi_drivers.h>
25 #include <linux/backlight.h>
26 #include <linux/input.h>
27 #include <linux/rfkill.h>
28
29 MODULE_LICENSE("GPL");
30
31
32 struct cmpc_accel {
33         int sensitivity;
34 };
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 static 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 device *dev)
366 {
367         struct input_dev *inputdev = dev_get_drvdata(dev);
368
369         unsigned long long val = 0;
370         if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val)))
371                 input_report_switch(inputdev, SW_TABLET_MODE, !val);
372         return 0;
373 }
374
375 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
376
377 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
378         {CMPC_TABLET_HID, 0},
379         {"", 0}
380 };
381
382 static struct acpi_driver cmpc_tablet_acpi_driver = {
383         .owner = THIS_MODULE,
384         .name = "cmpc_tablet",
385         .class = "cmpc_tablet",
386         .ids = cmpc_tablet_device_ids,
387         .ops = {
388                 .add = cmpc_tablet_add,
389                 .remove = cmpc_tablet_remove,
390                 .notify = cmpc_tablet_handler,
391         },
392         .drv.pm = &cmpc_tablet_pm,
393 };
394
395
396 /*
397  * Backlight code.
398  */
399
400 static acpi_status cmpc_get_brightness(acpi_handle handle,
401                                        unsigned long long *value)
402 {
403         union acpi_object param;
404         struct acpi_object_list input;
405         unsigned long long output;
406         acpi_status status;
407
408         param.type = ACPI_TYPE_INTEGER;
409         param.integer.value = 0xC0;
410         input.count = 1;
411         input.pointer = &param;
412         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
413         if (ACPI_SUCCESS(status))
414                 *value = output;
415         return status;
416 }
417
418 static acpi_status cmpc_set_brightness(acpi_handle handle,
419                                        unsigned long long value)
420 {
421         union acpi_object param[2];
422         struct acpi_object_list input;
423         acpi_status status;
424         unsigned long long output;
425
426         param[0].type = ACPI_TYPE_INTEGER;
427         param[0].integer.value = 0xC0;
428         param[1].type = ACPI_TYPE_INTEGER;
429         param[1].integer.value = value;
430         input.count = 2;
431         input.pointer = param;
432         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
433         return status;
434 }
435
436 static int cmpc_bl_get_brightness(struct backlight_device *bd)
437 {
438         acpi_status status;
439         acpi_handle handle;
440         unsigned long long brightness;
441
442         handle = bl_get_data(bd);
443         status = cmpc_get_brightness(handle, &brightness);
444         if (ACPI_SUCCESS(status))
445                 return brightness;
446         else
447                 return -1;
448 }
449
450 static int cmpc_bl_update_status(struct backlight_device *bd)
451 {
452         acpi_status status;
453         acpi_handle handle;
454
455         handle = bl_get_data(bd);
456         status = cmpc_set_brightness(handle, bd->props.brightness);
457         if (ACPI_SUCCESS(status))
458                 return 0;
459         else
460                 return -1;
461 }
462
463 static const struct backlight_ops cmpc_bl_ops = {
464         .get_brightness = cmpc_bl_get_brightness,
465         .update_status = cmpc_bl_update_status
466 };
467
468 /*
469  * RFKILL code.
470  */
471
472 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
473                                         unsigned long long *value)
474 {
475         union acpi_object param;
476         struct acpi_object_list input;
477         unsigned long long output;
478         acpi_status status;
479
480         param.type = ACPI_TYPE_INTEGER;
481         param.integer.value = 0xC1;
482         input.count = 1;
483         input.pointer = &param;
484         status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
485         if (ACPI_SUCCESS(status))
486                 *value = output;
487         return status;
488 }
489
490 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
491                                         unsigned long long value)
492 {
493         union acpi_object param[2];
494         struct acpi_object_list input;
495         acpi_status status;
496         unsigned long long output;
497
498         param[0].type = ACPI_TYPE_INTEGER;
499         param[0].integer.value = 0xC1;
500         param[1].type = ACPI_TYPE_INTEGER;
501         param[1].integer.value = value;
502         input.count = 2;
503         input.pointer = param;
504         status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
505         return status;
506 }
507
508 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
509 {
510         acpi_status status;
511         acpi_handle handle;
512         unsigned long long state;
513         bool blocked;
514
515         handle = data;
516         status = cmpc_get_rfkill_wlan(handle, &state);
517         if (ACPI_SUCCESS(status)) {
518                 blocked = state & 1 ? false : true;
519                 rfkill_set_sw_state(rfkill, blocked);
520         }
521 }
522
523 static int cmpc_rfkill_block(void *data, bool blocked)
524 {
525         acpi_status status;
526         acpi_handle handle;
527         unsigned long long state;
528         bool is_blocked;
529
530         handle = data;
531         status = cmpc_get_rfkill_wlan(handle, &state);
532         if (ACPI_FAILURE(status))
533                 return -ENODEV;
534         /* Check if we really need to call cmpc_set_rfkill_wlan */
535         is_blocked = state & 1 ? false : true;
536         if (is_blocked != blocked) {
537                 state = blocked ? 0 : 1;
538                 status = cmpc_set_rfkill_wlan(handle, state);
539                 if (ACPI_FAILURE(status))
540                         return -ENODEV;
541         }
542         return 0;
543 }
544
545 static const struct rfkill_ops cmpc_rfkill_ops = {
546         .query = cmpc_rfkill_query,
547         .set_block = cmpc_rfkill_block,
548 };
549
550 /*
551  * Common backlight and rfkill code.
552  */
553
554 struct ipml200_dev {
555         struct backlight_device *bd;
556         struct rfkill *rf;
557 };
558
559 static int cmpc_ipml_add(struct acpi_device *acpi)
560 {
561         int retval;
562         struct ipml200_dev *ipml;
563         struct backlight_properties props;
564
565         ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
566         if (ipml == NULL)
567                 return -ENOMEM;
568
569         memset(&props, 0, sizeof(struct backlight_properties));
570         props.type = BACKLIGHT_PLATFORM;
571         props.max_brightness = 7;
572         ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
573                                              acpi->handle, &cmpc_bl_ops,
574                                              &props);
575         if (IS_ERR(ipml->bd)) {
576                 retval = PTR_ERR(ipml->bd);
577                 goto out_bd;
578         }
579
580         ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
581                                 &cmpc_rfkill_ops, acpi->handle);
582         /*
583          * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
584          * This is OK, however, since all other uses of the device will not
585          * derefence it.
586          */
587         if (ipml->rf) {
588                 retval = rfkill_register(ipml->rf);
589                 if (retval) {
590                         rfkill_destroy(ipml->rf);
591                         ipml->rf = NULL;
592                 }
593         }
594
595         dev_set_drvdata(&acpi->dev, ipml);
596         return 0;
597
598 out_bd:
599         kfree(ipml);
600         return retval;
601 }
602
603 static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
604 {
605         struct ipml200_dev *ipml;
606
607         ipml = dev_get_drvdata(&acpi->dev);
608
609         backlight_device_unregister(ipml->bd);
610
611         if (ipml->rf) {
612                 rfkill_unregister(ipml->rf);
613                 rfkill_destroy(ipml->rf);
614         }
615
616         kfree(ipml);
617
618         return 0;
619 }
620
621 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
622         {CMPC_IPML_HID, 0},
623         {"", 0}
624 };
625
626 static struct acpi_driver cmpc_ipml_acpi_driver = {
627         .owner = THIS_MODULE,
628         .name = "cmpc",
629         .class = "cmpc",
630         .ids = cmpc_ipml_device_ids,
631         .ops = {
632                 .add = cmpc_ipml_add,
633                 .remove = cmpc_ipml_remove
634         }
635 };
636
637
638 /*
639  * Extra keys code.
640  */
641 static int cmpc_keys_codes[] = {
642         KEY_UNKNOWN,
643         KEY_WLAN,
644         KEY_SWITCHVIDEOMODE,
645         KEY_BRIGHTNESSDOWN,
646         KEY_BRIGHTNESSUP,
647         KEY_VENDOR,
648         KEY_UNKNOWN,
649         KEY_CAMERA,
650         KEY_BACK,
651         KEY_FORWARD,
652         KEY_MAX
653 };
654
655 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
656 {
657         struct input_dev *inputdev;
658         int code = KEY_MAX;
659
660         if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
661                 code = cmpc_keys_codes[event & 0x0F];
662         inputdev = dev_get_drvdata(&dev->dev);
663         input_report_key(inputdev, code, !(event & 0x10));
664         input_sync(inputdev);
665 }
666
667 static void cmpc_keys_idev_init(struct input_dev *inputdev)
668 {
669         int i;
670
671         set_bit(EV_KEY, inputdev->evbit);
672         for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
673                 set_bit(cmpc_keys_codes[i], inputdev->keybit);
674 }
675
676 static int cmpc_keys_add(struct acpi_device *acpi)
677 {
678         return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
679                                            cmpc_keys_idev_init);
680 }
681
682 static int cmpc_keys_remove(struct acpi_device *acpi, int type)
683 {
684         return cmpc_remove_acpi_notify_device(acpi);
685 }
686
687 static const struct acpi_device_id cmpc_keys_device_ids[] = {
688         {CMPC_KEYS_HID, 0},
689         {"", 0}
690 };
691
692 static struct acpi_driver cmpc_keys_acpi_driver = {
693         .owner = THIS_MODULE,
694         .name = "cmpc_keys",
695         .class = "cmpc_keys",
696         .ids = cmpc_keys_device_ids,
697         .ops = {
698                 .add = cmpc_keys_add,
699                 .remove = cmpc_keys_remove,
700                 .notify = cmpc_keys_handler,
701         }
702 };
703
704
705 /*
706  * General init/exit code.
707  */
708
709 static int cmpc_init(void)
710 {
711         int r;
712
713         r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
714         if (r)
715                 goto failed_keys;
716
717         r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
718         if (r)
719                 goto failed_bl;
720
721         r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
722         if (r)
723                 goto failed_tablet;
724
725         r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
726         if (r)
727                 goto failed_accel;
728
729         return r;
730
731 failed_accel:
732         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
733
734 failed_tablet:
735         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
736
737 failed_bl:
738         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
739
740 failed_keys:
741         return r;
742 }
743
744 static void cmpc_exit(void)
745 {
746         acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
747         acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
748         acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
749         acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
750 }
751
752 module_init(cmpc_init);
753 module_exit(cmpc_exit);
754
755 static const struct acpi_device_id cmpc_device_ids[] = {
756         {CMPC_ACCEL_HID, 0},
757         {CMPC_TABLET_HID, 0},
758         {CMPC_IPML_HID, 0},
759         {CMPC_KEYS_HID, 0},
760         {"", 0}
761 };
762
763 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);