]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/misc/eeepc-laptop.c
ACPI: catch calls of acpi_driver_data on pointer of wrong type
[mirror_ubuntu-artful-kernel.git] / drivers / misc / eeepc-laptop.c
CommitLineData
e59f8796
EC
1/*
2 * eepc-laptop.c - Asus Eee PC extras
3 *
4 * Based on asus_acpi.c as patched for the Eee PC by Asus:
5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
6 * Based on eee.c from eeepc-linux
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/types.h>
23#include <linux/platform_device.h>
a5fa429b
CC
24#include <linux/backlight.h>
25#include <linux/fb.h>
e1faa9da
CC
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
e59f8796
EC
28#include <acpi/acpi_drivers.h>
29#include <acpi/acpi_bus.h>
30#include <linux/uaccess.h>
31
32#define EEEPC_LAPTOP_VERSION "0.1"
33
34#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
35#define EEEPC_HOTK_FILE "eeepc"
36#define EEEPC_HOTK_CLASS "hotkey"
37#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
38#define EEEPC_HOTK_HID "ASUS010"
39
40#define EEEPC_LOG EEEPC_HOTK_FILE ": "
41#define EEEPC_ERR KERN_ERR EEEPC_LOG
42#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
43#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
44#define EEEPC_INFO KERN_INFO EEEPC_LOG
45
46/*
47 * Definitions for Asus EeePC
48 */
49#define NOTIFY_WLAN_ON 0x10
a5fa429b
CC
50#define NOTIFY_BRN_MIN 0x20
51#define NOTIFY_BRN_MAX 0x2f
e59f8796
EC
52
53enum {
54 DISABLE_ASL_WLAN = 0x0001,
55 DISABLE_ASL_BLUETOOTH = 0x0002,
56 DISABLE_ASL_IRDA = 0x0004,
57 DISABLE_ASL_CAMERA = 0x0008,
58 DISABLE_ASL_TV = 0x0010,
59 DISABLE_ASL_GPS = 0x0020,
60 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
61 DISABLE_ASL_MODEM = 0x0080,
62 DISABLE_ASL_CARDREADER = 0x0100
63};
64
65enum {
66 CM_ASL_WLAN = 0,
67 CM_ASL_BLUETOOTH,
68 CM_ASL_IRDA,
69 CM_ASL_1394,
70 CM_ASL_CAMERA,
71 CM_ASL_TV,
72 CM_ASL_GPS,
73 CM_ASL_DVDROM,
74 CM_ASL_DISPLAYSWITCH,
75 CM_ASL_PANELBRIGHT,
76 CM_ASL_BIOSFLASH,
77 CM_ASL_ACPIFLASH,
78 CM_ASL_CPUFV,
79 CM_ASL_CPUTEMPERATURE,
80 CM_ASL_FANCPU,
81 CM_ASL_FANCHASSIS,
82 CM_ASL_USBPORT1,
83 CM_ASL_USBPORT2,
84 CM_ASL_USBPORT3,
85 CM_ASL_MODEM,
86 CM_ASL_CARDREADER,
87 CM_ASL_LID
88};
89
14109461 90static const char *cm_getv[] = {
e59f8796
EC
91 "WLDG", NULL, NULL, NULL,
92 "CAMG", NULL, NULL, NULL,
93 NULL, "PBLG", NULL, NULL,
94 "CFVG", NULL, NULL, NULL,
95 "USBG", NULL, NULL, "MODG",
96 "CRDG", "LIDG"
97};
98
14109461 99static const char *cm_setv[] = {
e59f8796
EC
100 "WLDS", NULL, NULL, NULL,
101 "CAMS", NULL, NULL, NULL,
102 "SDSP", "PBLS", "HDPS", NULL,
103 "CFVS", NULL, NULL, NULL,
104 "USBG", NULL, NULL, "MODS",
105 "CRDS", NULL
106};
107
e1faa9da
CC
108#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
109
110#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
111#define EEEPC_EC_SC02 0x63
112#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
113#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
114#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
115#define EEEPC_EC_SFB3 0xD3
116
e59f8796
EC
117/*
118 * This is the main structure, we can use it to store useful information
119 * about the hotk device
120 */
121struct eeepc_hotk {
122 struct acpi_device *device; /* the device we are in */
123 acpi_handle handle; /* the handle of the hotk device */
124 u32 cm_supported; /* the control methods supported
125 by this BIOS */
126 uint init_flag; /* Init flags */
127 u16 event_count[128]; /* count for each event */
128};
129
130/* The actual device the driver binds to */
131static struct eeepc_hotk *ehotk;
132
133/* Platform device/driver */
134static struct platform_driver platform_driver = {
135 .driver = {
136 .name = EEEPC_HOTK_FILE,
137 .owner = THIS_MODULE,
138 }
139};
140
141static struct platform_device *platform_device;
142
143/*
144 * The hotkey driver declaration
145 */
146static int eeepc_hotk_add(struct acpi_device *device);
147static int eeepc_hotk_remove(struct acpi_device *device, int type);
148
149static const struct acpi_device_id eeepc_device_ids[] = {
150 {EEEPC_HOTK_HID, 0},
151 {"", 0},
152};
153MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
154
155static struct acpi_driver eeepc_hotk_driver = {
156 .name = EEEPC_HOTK_NAME,
157 .class = EEEPC_HOTK_CLASS,
158 .ids = eeepc_device_ids,
159 .ops = {
160 .add = eeepc_hotk_add,
161 .remove = eeepc_hotk_remove,
162 },
163};
164
a5fa429b
CC
165/* The backlight device /sys/class/backlight */
166static struct backlight_device *eeepc_backlight_device;
167
e1faa9da
CC
168/* The hwmon device */
169static struct device *eeepc_hwmon_device;
170
a5fa429b
CC
171/*
172 * The backlight class declaration
173 */
174static int read_brightness(struct backlight_device *bd);
175static int update_bl_status(struct backlight_device *bd);
176static struct backlight_ops eeepcbl_ops = {
177 .get_brightness = read_brightness,
178 .update_status = update_bl_status,
179};
180
e59f8796
EC
181MODULE_AUTHOR("Corentin Chary, Eric Cooper");
182MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
183MODULE_LICENSE("GPL");
184
185/*
186 * ACPI Helpers
187 */
188static int write_acpi_int(acpi_handle handle, const char *method, int val,
189 struct acpi_buffer *output)
190{
191 struct acpi_object_list params;
192 union acpi_object in_obj;
193 acpi_status status;
194
195 params.count = 1;
196 params.pointer = &in_obj;
197 in_obj.type = ACPI_TYPE_INTEGER;
198 in_obj.integer.value = val;
199
200 status = acpi_evaluate_object(handle, (char *)method, &params, output);
201 return (status == AE_OK ? 0 : -1);
202}
203
204static int read_acpi_int(acpi_handle handle, const char *method, int *val)
205{
206 acpi_status status;
207 ulong result;
208
209 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
210 if (ACPI_FAILURE(status)) {
211 *val = -1;
212 return -1;
213 } else {
214 *val = result;
215 return 0;
216 }
217}
218
219static int set_acpi(int cm, int value)
220{
221 if (ehotk->cm_supported & (0x1 << cm)) {
222 const char *method = cm_setv[cm];
223 if (method == NULL)
224 return -ENODEV;
225 if (write_acpi_int(ehotk->handle, method, value, NULL))
226 printk(EEEPC_WARNING "Error writing %s\n", method);
227 }
228 return 0;
229}
230
231static int get_acpi(int cm)
232{
233 int value = -1;
234 if ((ehotk->cm_supported & (0x1 << cm))) {
235 const char *method = cm_getv[cm];
236 if (method == NULL)
237 return -ENODEV;
238 if (read_acpi_int(ehotk->handle, method, &value))
239 printk(EEEPC_WARNING "Error reading %s\n", method);
240 }
241 return value;
242}
243
a5fa429b
CC
244/*
245 * Backlight
246 */
247static int read_brightness(struct backlight_device *bd)
248{
249 return get_acpi(CM_ASL_PANELBRIGHT);
250}
251
252static int set_brightness(struct backlight_device *bd, int value)
253{
254 value = max(0, min(15, value));
255 return set_acpi(CM_ASL_PANELBRIGHT, value);
256}
257
258static int update_bl_status(struct backlight_device *bd)
259{
260 return set_brightness(bd, bd->props.brightness);
261}
262
e59f8796
EC
263/*
264 * Sys helpers
265 */
266static int parse_arg(const char *buf, unsigned long count, int *val)
267{
268 if (!count)
269 return 0;
270 if (sscanf(buf, "%i", val) != 1)
271 return -EINVAL;
272 return count;
273}
274
275static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
276{
277 int rv, value;
278
279 rv = parse_arg(buf, count, &value);
280 if (rv > 0)
281 set_acpi(cm, value);
282 return rv;
283}
284
285static ssize_t show_sys_acpi(int cm, char *buf)
286{
287 return sprintf(buf, "%d\n", get_acpi(cm));
288}
289
290#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
291 static ssize_t show_##_name(struct device *dev, \
292 struct device_attribute *attr, \
293 char *buf) \
294 { \
295 return show_sys_acpi(_cm, buf); \
296 } \
297 static ssize_t store_##_name(struct device *dev, \
298 struct device_attribute *attr, \
299 const char *buf, size_t count) \
300 { \
301 return store_sys_acpi(_cm, buf, count); \
302 } \
303 static struct device_attribute dev_attr_##_name = { \
304 .attr = { \
305 .name = __stringify(_name), \
306 .mode = 0644 }, \
307 .show = show_##_name, \
308 .store = store_##_name, \
309 }
310
311EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
312EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
313EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
314EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
315
316static struct attribute *platform_attributes[] = {
317 &dev_attr_camera.attr,
318 &dev_attr_cardr.attr,
319 &dev_attr_disp.attr,
320 &dev_attr_wlan.attr,
321 NULL
322};
323
324static struct attribute_group platform_attribute_group = {
325 .attrs = platform_attributes
326};
327
328/*
329 * Hotkey functions
330 */
331static int eeepc_hotk_check(void)
332{
333 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
334 int result;
335
336 result = acpi_bus_get_status(ehotk->device);
337 if (result)
338 return result;
339 if (ehotk->device->status.present) {
340 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
341 &buffer)) {
342 printk(EEEPC_ERR "Hotkey initialization failed\n");
343 return -ENODEV;
344 } else {
345 printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
346 ehotk->init_flag);
347 }
348 /* get control methods supported */
349 if (read_acpi_int(ehotk->handle, "CMSG"
350 , &ehotk->cm_supported)) {
351 printk(EEEPC_ERR
352 "Get control methods supported failed\n");
353 return -ENODEV;
354 } else {
355 printk(EEEPC_INFO
356 "Get control methods supported: 0x%x\n",
357 ehotk->cm_supported);
358 }
359 } else {
360 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
361 return -EINVAL;
362 }
363 return 0;
364}
365
366static void notify_wlan(u32 *event)
367{
368 /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
369 will always be 0x10 */
370 if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
371 const char *method = cm_getv[CM_ASL_WLAN];
372 int value;
373 if (read_acpi_int(ehotk->handle, method, &value))
374 printk(EEEPC_WARNING "Error reading %s\n",
375 method);
376 else if (value == 1)
377 *event = 0x11;
378 }
379}
380
a5fa429b
CC
381static void notify_brn(void)
382{
383 struct backlight_device *bd = eeepc_backlight_device;
384 bd->props.brightness = read_brightness(bd);
385}
386
e59f8796
EC
387static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
388{
389 if (!ehotk)
390 return;
391 if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
392 notify_wlan(&event);
a5fa429b
CC
393 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
394 notify_brn();
e59f8796
EC
395 acpi_bus_generate_proc_event(ehotk->device, event,
396 ehotk->event_count[event % 128]++);
397}
398
399static int eeepc_hotk_add(struct acpi_device *device)
400{
401 acpi_status status = AE_OK;
402 int result;
403
404 if (!device)
405 return -EINVAL;
406 printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
407 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
408 if (!ehotk)
409 return -ENOMEM;
410 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
411 ehotk->handle = device->handle;
412 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
413 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
db89b4f0 414 device->driver_data = ehotk;
e59f8796
EC
415 ehotk->device = device;
416 result = eeepc_hotk_check();
417 if (result)
418 goto end;
419 status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
420 eeepc_hotk_notify, ehotk);
421 if (ACPI_FAILURE(status))
422 printk(EEEPC_ERR "Error installing notify handler\n");
423 end:
424 if (result) {
425 kfree(ehotk);
426 ehotk = NULL;
427 }
428 return result;
429}
430
431static int eeepc_hotk_remove(struct acpi_device *device, int type)
432{
433 acpi_status status = 0;
434
435 if (!device || !acpi_driver_data(device))
436 return -EINVAL;
437 status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
438 eeepc_hotk_notify);
439 if (ACPI_FAILURE(status))
440 printk(EEEPC_ERR "Error removing notify handler\n");
441 kfree(ehotk);
442 return 0;
443}
444
e1faa9da
CC
445/*
446 * Hwmon
447 */
448static int eeepc_get_fan_pwm(void)
449{
450 int value = 0;
451
452 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
04dcd84b 453 value = value * 255 / 100;
e1faa9da
CC
454 return (value);
455}
456
457static void eeepc_set_fan_pwm(int value)
458{
04dcd84b
CC
459 value = SENSORS_LIMIT(value, 0, 255);
460 value = value * 100 / 255;
e1faa9da
CC
461 ec_write(EEEPC_EC_SC02, value);
462}
463
464static int eeepc_get_fan_rpm(void)
465{
466 int high = 0;
467 int low = 0;
468
469 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
470 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
471 return (high << 8 | low);
472}
473
474static int eeepc_get_fan_ctrl(void)
475{
476 int value = 0;
477
478 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
479 return ((value & 0x02 ? 1 : 0));
480}
481
482static void eeepc_set_fan_ctrl(int manual)
483{
484 int value = 0;
485
486 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
487 if (manual)
488 value |= 0x02;
489 else
490 value &= ~0x02;
491 ec_write(EEEPC_EC_SFB3, value);
492}
493
494static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
495{
496 int rv, value;
497
498 rv = parse_arg(buf, count, &value);
499 if (rv > 0)
500 set(value);
501 return rv;
502}
503
504static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
505{
506 return sprintf(buf, "%d\n", get());
507}
508
509#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
510 static ssize_t show_##_name(struct device *dev, \
511 struct device_attribute *attr, \
512 char *buf) \
513 { \
514 return show_sys_hwmon(_set, buf); \
515 } \
516 static ssize_t store_##_name(struct device *dev, \
517 struct device_attribute *attr, \
518 const char *buf, size_t count) \
519 { \
520 return store_sys_hwmon(_get, buf, count); \
521 } \
522 static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
523
524EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
04dcd84b 525EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
e1faa9da
CC
526 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
527EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
528 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
529
04dcd84b
CC
530static ssize_t
531show_name(struct device *dev, struct device_attribute *attr, char *buf)
532{
533 return sprintf(buf, "eeepc\n");
534}
535static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
536
e1faa9da 537static struct attribute *hwmon_attributes[] = {
04dcd84b 538 &sensor_dev_attr_pwm1.dev_attr.attr,
e1faa9da
CC
539 &sensor_dev_attr_fan1_input.dev_attr.attr,
540 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
04dcd84b 541 &sensor_dev_attr_name.dev_attr.attr,
e1faa9da
CC
542 NULL
543};
544
545static struct attribute_group hwmon_attribute_group = {
546 .attrs = hwmon_attributes
547};
548
e59f8796
EC
549/*
550 * exit/init
551 */
a5fa429b
CC
552static void eeepc_backlight_exit(void)
553{
554 if (eeepc_backlight_device)
555 backlight_device_unregister(eeepc_backlight_device);
556 eeepc_backlight_device = NULL;
557}
558
e1faa9da
CC
559static void eeepc_hwmon_exit(void)
560{
561 struct device *hwmon;
562
563 hwmon = eeepc_hwmon_device;
564 if (!hwmon)
565 return ;
e1faa9da
CC
566 sysfs_remove_group(&hwmon->kobj,
567 &hwmon_attribute_group);
f1441318 568 hwmon_device_unregister(hwmon);
e1faa9da
CC
569 eeepc_hwmon_device = NULL;
570}
571
e59f8796
EC
572static void __exit eeepc_laptop_exit(void)
573{
a5fa429b 574 eeepc_backlight_exit();
e1faa9da 575 eeepc_hwmon_exit();
e59f8796
EC
576 acpi_bus_unregister_driver(&eeepc_hotk_driver);
577 sysfs_remove_group(&platform_device->dev.kobj,
578 &platform_attribute_group);
579 platform_device_unregister(platform_device);
580 platform_driver_unregister(&platform_driver);
581}
582
a5fa429b
CC
583static int eeepc_backlight_init(struct device *dev)
584{
585 struct backlight_device *bd;
586
587 bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
588 NULL, &eeepcbl_ops);
589 if (IS_ERR(bd)) {
590 printk(EEEPC_ERR
591 "Could not register eeepc backlight device\n");
592 eeepc_backlight_device = NULL;
593 return PTR_ERR(bd);
594 }
595 eeepc_backlight_device = bd;
596 bd->props.max_brightness = 15;
597 bd->props.brightness = read_brightness(NULL);
598 bd->props.power = FB_BLANK_UNBLANK;
599 backlight_update_status(bd);
600 return 0;
601}
602
e1faa9da
CC
603static int eeepc_hwmon_init(struct device *dev)
604{
605 struct device *hwmon;
606 int result;
607
608 hwmon = hwmon_device_register(dev);
609 if (IS_ERR(hwmon)) {
610 printk(EEEPC_ERR
611 "Could not register eeepc hwmon device\n");
612 eeepc_hwmon_device = NULL;
613 return PTR_ERR(hwmon);
614 }
615 eeepc_hwmon_device = hwmon;
616 result = sysfs_create_group(&hwmon->kobj,
617 &hwmon_attribute_group);
618 if (result)
619 eeepc_hwmon_exit();
620 return result;
621}
622
e59f8796
EC
623static int __init eeepc_laptop_init(void)
624{
625 struct device *dev;
626 int result;
627
628 if (acpi_disabled)
629 return -ENODEV;
630 result = acpi_bus_register_driver(&eeepc_hotk_driver);
631 if (result < 0)
632 return result;
633 if (!ehotk) {
634 acpi_bus_unregister_driver(&eeepc_hotk_driver);
635 return -ENODEV;
636 }
637 dev = acpi_get_physical_device(ehotk->device->handle);
a5fa429b
CC
638 result = eeepc_backlight_init(dev);
639 if (result)
640 goto fail_backlight;
e1faa9da
CC
641 result = eeepc_hwmon_init(dev);
642 if (result)
643 goto fail_hwmon;
e59f8796
EC
644 /* Register platform stuff */
645 result = platform_driver_register(&platform_driver);
646 if (result)
647 goto fail_platform_driver;
648 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
649 if (!platform_device) {
650 result = -ENOMEM;
651 goto fail_platform_device1;
652 }
653 result = platform_device_add(platform_device);
654 if (result)
655 goto fail_platform_device2;
656 result = sysfs_create_group(&platform_device->dev.kobj,
657 &platform_attribute_group);
658 if (result)
659 goto fail_sysfs;
660 return 0;
661fail_sysfs:
662 platform_device_del(platform_device);
663fail_platform_device2:
664 platform_device_put(platform_device);
665fail_platform_device1:
666 platform_driver_unregister(&platform_driver);
667fail_platform_driver:
e1faa9da
CC
668 eeepc_hwmon_exit();
669fail_hwmon:
a5fa429b
CC
670 eeepc_backlight_exit();
671fail_backlight:
e59f8796
EC
672 return result;
673}
674
675module_init(eeepc_laptop_init);
676module_exit(eeepc_laptop_exit);