asus-laptop: add Lenovo SL hotkey support
[safe/jmp/linux-2.6] / drivers / platform / x86 / asus-laptop.c
1 /*
2  *  asus-laptop.c - Asus Laptop Support
3  *
4  *
5  *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
6  *  Copyright (C) 2006-2007 Corentin Chary
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  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  *
23  *  The development page for this driver is located at
24  *  http://sourceforge.net/projects/acpi4asus/
25  *
26  *  Credits:
27  *  Pontus Fuchs   - Helper functions, cleanup
28  *  Johann Wiesner - Small compile fixes
29  *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
30  *  Eric Burghard  - LED display support for W1N
31  *  Josh Green     - Light Sens support
32  *  Thomas Tuttle  - His first patch for led support was very helpfull
33  *  Sam Lin        - GPS support
34  */
35
36 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
37
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/init.h>
41 #include <linux/types.h>
42 #include <linux/err.h>
43 #include <linux/proc_fs.h>
44 #include <linux/backlight.h>
45 #include <linux/fb.h>
46 #include <linux/leds.h>
47 #include <linux/platform_device.h>
48 #include <acpi/acpi_drivers.h>
49 #include <acpi/acpi_bus.h>
50 #include <asm/uaccess.h>
51 #include <linux/input.h>
52
53 #define ASUS_LAPTOP_VERSION "0.42"
54
55 #define ASUS_HOTK_NAME          "Asus Laptop Support"
56 #define ASUS_HOTK_CLASS         "hotkey"
57 #define ASUS_HOTK_DEVICE_NAME   "Hotkey"
58 #define ASUS_HOTK_FILE          KBUILD_MODNAME
59 #define ASUS_HOTK_PREFIX        "\\_SB.ATKD."
60
61
62 /*
63  * Some events we use, same for all Asus
64  */
65 #define ATKD_BR_UP       0x10
66 #define ATKD_BR_DOWN     0x20
67 #define ATKD_LCD_ON      0x33
68 #define ATKD_LCD_OFF     0x34
69
70 /*
71  * Known bits returned by \_SB.ATKD.HWRS
72  */
73 #define WL_HWRS     0x80
74 #define BT_HWRS     0x100
75
76 /*
77  * Flags for hotk status
78  * WL_ON and BT_ON are also used for wireless_status()
79  */
80 #define WL_ON       0x01        /* internal Wifi */
81 #define BT_ON       0x02        /* internal Bluetooth */
82 #define MLED_ON     0x04        /* mail LED */
83 #define TLED_ON     0x08        /* touchpad LED */
84 #define RLED_ON     0x10        /* Record LED */
85 #define PLED_ON     0x20        /* Phone LED */
86 #define GLED_ON     0x40        /* Gaming LED */
87 #define LCD_ON      0x80        /* LCD backlight */
88 #define GPS_ON      0x100       /* GPS */
89 #define KEY_ON      0x200       /* Keyboard backlight */
90
91 #define ASUS_LOG    ASUS_HOTK_FILE ": "
92 #define ASUS_ERR    KERN_ERR    ASUS_LOG
93 #define ASUS_WARNING    KERN_WARNING    ASUS_LOG
94 #define ASUS_NOTICE KERN_NOTICE ASUS_LOG
95 #define ASUS_INFO   KERN_INFO   ASUS_LOG
96 #define ASUS_DEBUG  KERN_DEBUG  ASUS_LOG
97
98 MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
99 MODULE_DESCRIPTION(ASUS_HOTK_NAME);
100 MODULE_LICENSE("GPL");
101
102 /*
103  * WAPF defines the behavior of the Fn+Fx wlan key
104  * The significance of values is yet to be found, but
105  * most of the time:
106  * 0x0 will do nothing
107  * 0x1 will allow to control the device with Fn+Fx key.
108  * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
109  * 0x5 like 0x1 or 0x4
110  * So, if something doesn't work as you want, just try other values =)
111  */
112 static uint wapf = 1;
113 module_param(wapf, uint, 0644);
114 MODULE_PARM_DESC(wapf, "WAPF value");
115
116 #define ASUS_HANDLE(object, paths...)                                   \
117         static acpi_handle  object##_handle = NULL;                     \
118         static char *object##_paths[] = { paths }
119
120 /* LED */
121 ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
122 ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
123 ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
124 ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
125 ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
126
127 /* LEDD */
128 ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
129
130 /*
131  * Bluetooth and WLAN
132  * WLED and BLED are not handled like other XLED, because in some dsdt
133  * they also control the WLAN/Bluetooth device.
134  */
135 ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
136 ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
137 ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS");  /* All new models */
138
139 /* Brightness */
140 ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
141 ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");
142
143 /* Backlight */
144 ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10",     /* All new models */
145             "\\_SB.PCI0.ISA.EC0._Q10",  /* A1x */
146             "\\_SB.PCI0.PX40.ECD0._Q10",        /* L3C */
147             "\\_SB.PCI0.PX40.EC0.Q10",  /* M1A */
148             "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
149             "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
150             "\\_SB.PCI0.PX40.Q10",      /* S1x */
151             "\\Q10");           /* A2x, L2D, L3D, M2E */
152
153 /* Display */
154 ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
155 ASUS_HANDLE(display_get,
156             /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
157             "\\_SB.PCI0.P0P1.VGA.GETD",
158             /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
159             "\\_SB.PCI0.P0P2.VGA.GETD",
160             /* A6V A6Q */
161             "\\_SB.PCI0.P0P3.VGA.GETD",
162             /* A6T, A6M */
163             "\\_SB.PCI0.P0PA.VGA.GETD",
164             /* L3C */
165             "\\_SB.PCI0.PCI1.VGAC.NMAP",
166             /* Z96F */
167             "\\_SB.PCI0.VGA.GETD",
168             /* A2D */
169             "\\ACTD",
170             /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
171             "\\ADVG",
172             /* P30 */
173             "\\DNXT",
174             /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
175             "\\INFB",
176             /* A3F A6F A3N A3L M6N W3N W6A */
177             "\\SSTE");
178
179 ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
180 ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL");  /* Z71A Z71V */
181
182 /* GPS */
183 /* R2H use different handle for GPS on/off */
184 ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON");   /* R2H */
185 ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF");  /* R2H */
186 ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
187
188 /* Keyboard light */
189 ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB");
190 ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
191
192 /*
193  * This is the main structure, we can use it to store anything interesting
194  * about the hotk device
195  */
196 struct asus_hotk {
197         char *name;             /* laptop name */
198         struct acpi_device *device;     /* the device we are in */
199         acpi_handle handle;     /* the handle of the hotk device */
200         char status;            /* status of the hotk, for LEDs, ... */
201         u32 ledd_status;        /* status of the LED display */
202         u8 light_level;         /* light sensor level */
203         u8 light_switch;        /* light sensor switch value */
204         u16 event_count[128];   /* count for each event TODO make this better */
205         struct input_dev *inputdev;
206         u16 *keycode_map;
207 };
208
209 /*
210  * This header is made available to allow proper configuration given model,
211  * revision number , ... this info cannot go in struct asus_hotk because it is
212  * available before the hotk
213  */
214 static struct acpi_table_header *asus_info;
215
216 /* The actual device the driver binds to */
217 static struct asus_hotk *hotk;
218
219 /*
220  * The hotkey driver declaration
221  */
222 static const struct acpi_device_id asus_device_ids[] = {
223         {"ATK0100", 0},
224         {"ATK0101", 0},
225         {"", 0},
226 };
227 MODULE_DEVICE_TABLE(acpi, asus_device_ids);
228
229 static int asus_hotk_add(struct acpi_device *device);
230 static int asus_hotk_remove(struct acpi_device *device, int type);
231 static void asus_hotk_notify(struct acpi_device *device, u32 event);
232
233 static struct acpi_driver asus_hotk_driver = {
234         .name = ASUS_HOTK_NAME,
235         .class = ASUS_HOTK_CLASS,
236         .owner = THIS_MODULE,
237         .ids = asus_device_ids,
238         .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
239         .ops = {
240                 .add = asus_hotk_add,
241                 .remove = asus_hotk_remove,
242                 .notify = asus_hotk_notify,
243                 },
244 };
245
246 /* The backlight device /sys/class/backlight */
247 static struct backlight_device *asus_backlight_device;
248
249 /*
250  * The backlight class declaration
251  */
252 static int read_brightness(struct backlight_device *bd);
253 static int update_bl_status(struct backlight_device *bd);
254 static struct backlight_ops asusbl_ops = {
255         .get_brightness = read_brightness,
256         .update_status = update_bl_status,
257 };
258
259 /*
260  * These functions actually update the LED's, and are called from a
261  * workqueue. By doing this as separate work rather than when the LED
262  * subsystem asks, we avoid messing with the Asus ACPI stuff during a
263  * potentially bad time, such as a timer interrupt.
264  */
265 static struct workqueue_struct *led_workqueue;
266
267 #define ASUS_LED(object, ledname, max)                                  \
268         static void object##_led_set(struct led_classdev *led_cdev,     \
269                                      enum led_brightness value);        \
270         static enum led_brightness object##_led_get(                    \
271                 struct led_classdev *led_cdev);                         \
272         static void object##_led_update(struct work_struct *ignored);   \
273         static int object##_led_wk;                                     \
274         static DECLARE_WORK(object##_led_work, object##_led_update);    \
275         static struct led_classdev object##_led = {                     \
276                 .name           = "asus::" ledname,                     \
277                 .brightness_set = object##_led_set,                     \
278                 .brightness_get = object##_led_get,                     \
279                 .max_brightness = max                                   \
280         }
281
282 ASUS_LED(mled, "mail", 1);
283 ASUS_LED(tled, "touchpad", 1);
284 ASUS_LED(rled, "record", 1);
285 ASUS_LED(pled, "phone", 1);
286 ASUS_LED(gled, "gaming", 1);
287 ASUS_LED(kled, "kbd_backlight", 3);
288
289 struct key_entry {
290         char type;
291         u8 code;
292         u16 keycode;
293 };
294
295 enum { KE_KEY, KE_END };
296
297 static struct key_entry asus_keymap[] = {
298         {KE_KEY, 0x02, KEY_SCREENLOCK},
299         {KE_KEY, 0x05, KEY_WLAN},
300         {KE_KEY, 0x08, KEY_F13},
301         {KE_KEY, 0x17, KEY_ZOOM},
302         {KE_KEY, 0x1f, KEY_BATTERY},
303         {KE_KEY, 0x30, KEY_VOLUMEUP},
304         {KE_KEY, 0x31, KEY_VOLUMEDOWN},
305         {KE_KEY, 0x32, KEY_MUTE},
306         {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE},
307         {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE},
308         {KE_KEY, 0x40, KEY_PREVIOUSSONG},
309         {KE_KEY, 0x41, KEY_NEXTSONG},
310         {KE_KEY, 0x43, KEY_STOPCD},
311         {KE_KEY, 0x45, KEY_PLAYPAUSE},
312         {KE_KEY, 0x4c, KEY_MEDIA},
313         {KE_KEY, 0x50, KEY_EMAIL},
314         {KE_KEY, 0x51, KEY_WWW},
315         {KE_KEY, 0x55, KEY_CALC},
316         {KE_KEY, 0x5C, KEY_SCREENLOCK},  /* Screenlock */
317         {KE_KEY, 0x5D, KEY_WLAN},
318         {KE_KEY, 0x5E, KEY_WLAN},
319         {KE_KEY, 0x5F, KEY_WLAN},
320         {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
321         {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
322         {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE},
323         {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE},
324         {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */
325         {KE_KEY, 0x82, KEY_CAMERA},
326         {KE_KEY, 0x8A, KEY_PROG1},
327         {KE_KEY, 0x95, KEY_MEDIA},
328         {KE_KEY, 0x99, KEY_PHONE},
329         {KE_KEY, 0xc4, KEY_KBDILLUMUP},
330         {KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
331         {KE_END, 0},
332 };
333
334 /*
335  * This function evaluates an ACPI method, given an int as parameter, the
336  * method is searched within the scope of the handle, can be NULL. The output
337  * of the method is written is output, which can also be NULL
338  *
339  * returns 0 if write is successful, -1 else.
340  */
341 static int write_acpi_int(acpi_handle handle, const char *method, int val,
342                           struct acpi_buffer *output)
343 {
344         struct acpi_object_list params; /* list of input parameters (an int) */
345         union acpi_object in_obj;       /* the only param we use */
346         acpi_status status;
347
348         if (!handle)
349                 return 0;
350
351         params.count = 1;
352         params.pointer = &in_obj;
353         in_obj.type = ACPI_TYPE_INTEGER;
354         in_obj.integer.value = val;
355
356         status = acpi_evaluate_object(handle, (char *)method, &params, output);
357         if (status == AE_OK)
358                 return 0;
359         else
360                 return -1;
361 }
362
363 static int read_wireless_status(int mask)
364 {
365         unsigned long long status;
366         acpi_status rv = AE_OK;
367
368         if (!wireless_status_handle)
369                 return (hotk->status & mask) ? 1 : 0;
370
371         rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
372         if (ACPI_FAILURE(rv))
373                 pr_warning("Error reading Wireless status\n");
374         else
375                 return (status & mask) ? 1 : 0;
376
377         return (hotk->status & mask) ? 1 : 0;
378 }
379
380 static int read_gps_status(void)
381 {
382         unsigned long long status;
383         acpi_status rv = AE_OK;
384
385         rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
386         if (ACPI_FAILURE(rv))
387                 pr_warning("Error reading GPS status\n");
388         else
389                 return status ? 1 : 0;
390
391         return (hotk->status & GPS_ON) ? 1 : 0;
392 }
393
394 /* Generic LED functions */
395 static int read_status(int mask)
396 {
397         /* There is a special method for both wireless devices */
398         if (mask == BT_ON || mask == WL_ON)
399                 return read_wireless_status(mask);
400         else if (mask == GPS_ON)
401                 return read_gps_status();
402
403         return (hotk->status & mask) ? 1 : 0;
404 }
405
406 static void write_status(acpi_handle handle, int out, int mask)
407 {
408         hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
409
410         switch (mask) {
411         case MLED_ON:
412                 out = !(out & 0x1);
413                 break;
414         case GLED_ON:
415                 out = (out & 0x1) + 1;
416                 break;
417         case GPS_ON:
418                 handle = (out) ? gps_on_handle : gps_off_handle;
419                 out = 0x02;
420                 break;
421         default:
422                 out &= 0x1;
423                 break;
424         }
425
426         if (write_acpi_int(handle, NULL, out, NULL))
427                 pr_warning(" write failed %x\n", mask);
428 }
429
430 /* /sys/class/led handlers */
431 #define ASUS_LED_HANDLER(object, mask)                                  \
432         static void object##_led_set(struct led_classdev *led_cdev,     \
433                                      enum led_brightness value)         \
434         {                                                               \
435                 object##_led_wk = (value > 0) ? 1 : 0;                  \
436                 queue_work(led_workqueue, &object##_led_work);          \
437         }                                                               \
438         static void object##_led_update(struct work_struct *ignored)    \
439         {                                                               \
440                 int value = object##_led_wk;                            \
441                 write_status(object##_set_handle, value, (mask));       \
442         }                                                               \
443         static enum led_brightness object##_led_get(                    \
444                 struct led_classdev *led_cdev)                          \
445         {                                                               \
446                 return led_cdev->brightness;                            \
447         }
448
449 ASUS_LED_HANDLER(mled, MLED_ON);
450 ASUS_LED_HANDLER(pled, PLED_ON);
451 ASUS_LED_HANDLER(rled, RLED_ON);
452 ASUS_LED_HANDLER(tled, TLED_ON);
453 ASUS_LED_HANDLER(gled, GLED_ON);
454
455 /*
456  * Keyboard backlight
457  */
458 static int get_kled_lvl(void)
459 {
460         unsigned long long kblv;
461         struct acpi_object_list params;
462         union acpi_object in_obj;
463         acpi_status rv;
464
465         params.count = 1;
466         params.pointer = &in_obj;
467         in_obj.type = ACPI_TYPE_INTEGER;
468         in_obj.integer.value = 2;
469
470         rv = acpi_evaluate_integer(kled_get_handle, NULL, &params, &kblv);
471         if (ACPI_FAILURE(rv)) {
472                 pr_warning("Error reading kled level\n");
473                 return 0;
474         }
475         return kblv;
476 }
477
478 static int set_kled_lvl(int kblv)
479 {
480         if (kblv > 0)
481                 kblv = (1 << 7) | (kblv & 0x7F);
482         else
483                 kblv = 0;
484
485         if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) {
486                 pr_warning("Keyboard LED display write failed\n");
487                 return -EINVAL;
488         }
489         return 0;
490 }
491
492 static void kled_led_set(struct led_classdev *led_cdev,
493                          enum led_brightness value)
494 {
495         kled_led_wk = value;
496         queue_work(led_workqueue, &kled_led_work);
497 }
498
499 static void kled_led_update(struct work_struct *ignored)
500 {
501         set_kled_lvl(kled_led_wk);
502 }
503
504 static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
505 {
506         return get_kled_lvl();
507 }
508
509 static int get_lcd_state(void)
510 {
511         return read_status(LCD_ON);
512 }
513
514 static int set_lcd_state(int value)
515 {
516         int lcd = 0;
517         acpi_status status = 0;
518
519         lcd = value ? 1 : 0;
520
521         if (lcd == get_lcd_state())
522                 return 0;
523
524         if (lcd_switch_handle) {
525                 status = acpi_evaluate_object(lcd_switch_handle,
526                                               NULL, NULL, NULL);
527
528                 if (ACPI_FAILURE(status))
529                         pr_warning("Error switching LCD\n");
530         }
531
532         write_status(NULL, lcd, LCD_ON);
533         return 0;
534 }
535
536 static void lcd_blank(int blank)
537 {
538         struct backlight_device *bd = asus_backlight_device;
539
540         if (bd) {
541                 bd->props.power = blank;
542                 backlight_update_status(bd);
543         }
544 }
545
546 static int read_brightness(struct backlight_device *bd)
547 {
548         unsigned long long value;
549         acpi_status rv = AE_OK;
550
551         rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
552         if (ACPI_FAILURE(rv))
553                 pr_warning("Error reading brightness\n");
554
555         return value;
556 }
557
558 static int set_brightness(struct backlight_device *bd, int value)
559 {
560         int ret = 0;
561
562         value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
563         /* 0 <= value <= 15 */
564
565         if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
566                 pr_warning("Error changing brightness\n");
567                 ret = -EIO;
568         }
569
570         return ret;
571 }
572
573 static int update_bl_status(struct backlight_device *bd)
574 {
575         int rv;
576         int value = bd->props.brightness;
577
578         rv = set_brightness(bd, value);
579         if (rv)
580                 return rv;
581
582         value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
583         return set_lcd_state(value);
584 }
585
586 /*
587  * Platform device handlers
588  */
589
590 /*
591  * We write our info in page, we begin at offset off and cannot write more
592  * than count bytes. We set eof to 1 if we handle those 2 values. We return the
593  * number of bytes written in page
594  */
595 static ssize_t show_infos(struct device *dev,
596                           struct device_attribute *attr, char *page)
597 {
598         int len = 0;
599         unsigned long long temp;
600         char buf[16];           /* enough for all info */
601         acpi_status rv = AE_OK;
602
603         /*
604          * We use the easy way, we don't care of off and count, so we don't set eof
605          * to 1
606          */
607
608         len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n");
609         len += sprintf(page + len, "Model reference    : %s\n", hotk->name);
610         /*
611          * The SFUN method probably allows the original driver to get the list
612          * of features supported by a given model. For now, 0x0100 or 0x0800
613          * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
614          * The significance of others is yet to be found.
615          */
616         rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
617         if (!ACPI_FAILURE(rv))
618                 len += sprintf(page + len, "SFUN value         : %#x\n",
619                                (uint) temp);
620         /*
621          * The HWRS method return informations about the hardware.
622          * 0x80 bit is for WLAN, 0x100 for Bluetooth.
623          * The significance of others is yet to be found.
624          * If we don't find the method, we assume the device are present.
625          */
626         rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp);
627         if (!ACPI_FAILURE(rv))
628                 len += sprintf(page + len, "HRWS value         : %#x\n",
629                                (uint) temp);
630         /*
631          * Another value for userspace: the ASYM method returns 0x02 for
632          * battery low and 0x04 for battery critical, its readings tend to be
633          * more accurate than those provided by _BST.
634          * Note: since not all the laptops provide this method, errors are
635          * silently ignored.
636          */
637         rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
638         if (!ACPI_FAILURE(rv))
639                 len += sprintf(page + len, "ASYM value         : %#x\n",
640                                (uint) temp);
641         if (asus_info) {
642                 snprintf(buf, 16, "%d", asus_info->length);
643                 len += sprintf(page + len, "DSDT length        : %s\n", buf);
644                 snprintf(buf, 16, "%d", asus_info->checksum);
645                 len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
646                 snprintf(buf, 16, "%d", asus_info->revision);
647                 len += sprintf(page + len, "DSDT revision      : %s\n", buf);
648                 snprintf(buf, 7, "%s", asus_info->oem_id);
649                 len += sprintf(page + len, "OEM id             : %s\n", buf);
650                 snprintf(buf, 9, "%s", asus_info->oem_table_id);
651                 len += sprintf(page + len, "OEM table id       : %s\n", buf);
652                 snprintf(buf, 16, "%x", asus_info->oem_revision);
653                 len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
654                 snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
655                 len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
656                 snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
657                 len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
658         }
659
660         return len;
661 }
662
663 static int parse_arg(const char *buf, unsigned long count, int *val)
664 {
665         if (!count)
666                 return 0;
667         if (count > 31)
668                 return -EINVAL;
669         if (sscanf(buf, "%i", val) != 1)
670                 return -EINVAL;
671         return count;
672 }
673
674 static ssize_t store_status(const char *buf, size_t count,
675                             acpi_handle handle, int mask)
676 {
677         int rv, value;
678         int out = 0;
679
680         rv = parse_arg(buf, count, &value);
681         if (rv > 0)
682                 out = value ? 1 : 0;
683
684         write_status(handle, out, mask);
685
686         return rv;
687 }
688
689 /*
690  * LEDD display
691  */
692 static ssize_t show_ledd(struct device *dev,
693                          struct device_attribute *attr, char *buf)
694 {
695         return sprintf(buf, "0x%08x\n", hotk->ledd_status);
696 }
697
698 static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
699                           const char *buf, size_t count)
700 {
701         int rv, value;
702
703         rv = parse_arg(buf, count, &value);
704         if (rv > 0) {
705                 if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
706                         pr_warning("LED display write failed\n");
707                 else
708                         hotk->ledd_status = (u32) value;
709         }
710         return rv;
711 }
712
713 /*
714  * WLAN
715  */
716 static ssize_t show_wlan(struct device *dev,
717                          struct device_attribute *attr, char *buf)
718 {
719         return sprintf(buf, "%d\n", read_status(WL_ON));
720 }
721
722 static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
723                           const char *buf, size_t count)
724 {
725         return store_status(buf, count, wl_switch_handle, WL_ON);
726 }
727
728 /*
729  * Bluetooth
730  */
731 static ssize_t show_bluetooth(struct device *dev,
732                               struct device_attribute *attr, char *buf)
733 {
734         return sprintf(buf, "%d\n", read_status(BT_ON));
735 }
736
737 static ssize_t store_bluetooth(struct device *dev,
738                                struct device_attribute *attr, const char *buf,
739                                size_t count)
740 {
741         return store_status(buf, count, bt_switch_handle, BT_ON);
742 }
743
744 /*
745  * Display
746  */
747 static void set_display(int value)
748 {
749         /* no sanity check needed for now */
750         if (write_acpi_int(display_set_handle, NULL, value, NULL))
751                 pr_warning("Error setting display\n");
752         return;
753 }
754
755 static int read_display(void)
756 {
757         unsigned long long value = 0;
758         acpi_status rv = AE_OK;
759
760         /*
761          * In most of the case, we know how to set the display, but sometime
762          * we can't read it
763          */
764         if (display_get_handle) {
765                 rv = acpi_evaluate_integer(display_get_handle, NULL,
766                                            NULL, &value);
767                 if (ACPI_FAILURE(rv))
768                         pr_warning("Error reading display status\n");
769         }
770
771         value &= 0x0F;          /* needed for some models, shouldn't hurt others */
772
773         return value;
774 }
775
776 /*
777  * Now, *this* one could be more user-friendly, but so far, no-one has
778  * complained. The significance of bits is the same as in store_disp()
779  */
780 static ssize_t show_disp(struct device *dev,
781                          struct device_attribute *attr, char *buf)
782 {
783         return sprintf(buf, "%d\n", read_display());
784 }
785
786 /*
787  * Experimental support for display switching. As of now: 1 should activate
788  * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
789  * Any combination (bitwise) of these will suffice. I never actually tested 4
790  * displays hooked up simultaneously, so be warned. See the acpi4asus README
791  * for more info.
792  */
793 static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
794                           const char *buf, size_t count)
795 {
796         int rv, value;
797
798         rv = parse_arg(buf, count, &value);
799         if (rv > 0)
800                 set_display(value);
801         return rv;
802 }
803
804 /*
805  * Light Sens
806  */
807 static void set_light_sens_switch(int value)
808 {
809         if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
810                 pr_warning("Error setting light sensor switch\n");
811         hotk->light_switch = value;
812 }
813
814 static ssize_t show_lssw(struct device *dev,
815                          struct device_attribute *attr, char *buf)
816 {
817         return sprintf(buf, "%d\n", hotk->light_switch);
818 }
819
820 static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
821                           const char *buf, size_t count)
822 {
823         int rv, value;
824
825         rv = parse_arg(buf, count, &value);
826         if (rv > 0)
827                 set_light_sens_switch(value ? 1 : 0);
828
829         return rv;
830 }
831
832 static void set_light_sens_level(int value)
833 {
834         if (write_acpi_int(ls_level_handle, NULL, value, NULL))
835                 pr_warning("Error setting light sensor level\n");
836         hotk->light_level = value;
837 }
838
839 static ssize_t show_lslvl(struct device *dev,
840                           struct device_attribute *attr, char *buf)
841 {
842         return sprintf(buf, "%d\n", hotk->light_level);
843 }
844
845 static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
846                            const char *buf, size_t count)
847 {
848         int rv, value;
849
850         rv = parse_arg(buf, count, &value);
851         if (rv > 0) {
852                 value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
853                 /* 0 <= value <= 15 */
854                 set_light_sens_level(value);
855         }
856
857         return rv;
858 }
859
860 /*
861  * GPS
862  */
863 static ssize_t show_gps(struct device *dev,
864                         struct device_attribute *attr, char *buf)
865 {
866         return sprintf(buf, "%d\n", read_status(GPS_ON));
867 }
868
869 static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
870                          const char *buf, size_t count)
871 {
872         return store_status(buf, count, NULL, GPS_ON);
873 }
874
875 /*
876  * Hotkey functions
877  */
878 static struct key_entry *asus_get_entry_by_scancode(int code)
879 {
880         struct key_entry *key;
881
882         for (key = asus_keymap; key->type != KE_END; key++)
883                 if (code == key->code)
884                         return key;
885
886         return NULL;
887 }
888
889 static struct key_entry *asus_get_entry_by_keycode(int code)
890 {
891         struct key_entry *key;
892
893         for (key = asus_keymap; key->type != KE_END; key++)
894                 if (code == key->keycode && key->type == KE_KEY)
895                         return key;
896
897         return NULL;
898 }
899
900 static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
901 {
902         struct key_entry *key = asus_get_entry_by_scancode(scancode);
903
904         if (key && key->type == KE_KEY) {
905                 *keycode = key->keycode;
906                 return 0;
907         }
908
909         return -EINVAL;
910 }
911
912 static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
913 {
914         struct key_entry *key;
915         int old_keycode;
916
917         if (keycode < 0 || keycode > KEY_MAX)
918                 return -EINVAL;
919
920         key = asus_get_entry_by_scancode(scancode);
921         if (key && key->type == KE_KEY) {
922                 old_keycode = key->keycode;
923                 key->keycode = keycode;
924                 set_bit(keycode, dev->keybit);
925                 if (!asus_get_entry_by_keycode(old_keycode))
926                         clear_bit(old_keycode, dev->keybit);
927                 return 0;
928         }
929
930         return -EINVAL;
931 }
932
933 static void asus_hotk_notify(struct acpi_device *device, u32 event)
934 {
935         static struct key_entry *key;
936         u16 count;
937
938         /* TODO Find a better way to handle events count. */
939         if (!hotk)
940                 return;
941
942         /*
943          * We need to tell the backlight device when the backlight power is
944          * switched
945          */
946         if (event == ATKD_LCD_ON) {
947                 write_status(NULL, 1, LCD_ON);
948                 lcd_blank(FB_BLANK_UNBLANK);
949         } else if (event == ATKD_LCD_OFF) {
950                 write_status(NULL, 0, LCD_ON);
951                 lcd_blank(FB_BLANK_POWERDOWN);
952         }
953
954         count = hotk->event_count[event % 128]++;
955         acpi_bus_generate_proc_event(hotk->device, event, count);
956         acpi_bus_generate_netlink_event(hotk->device->pnp.device_class,
957                                         dev_name(&hotk->device->dev), event,
958                                         count);
959
960         if (hotk->inputdev) {
961                 key = asus_get_entry_by_scancode(event);
962                 if (!key)
963                         return ;
964
965                 switch (key->type) {
966                 case KE_KEY:
967                         input_report_key(hotk->inputdev, key->keycode, 1);
968                         input_sync(hotk->inputdev);
969                         input_report_key(hotk->inputdev, key->keycode, 0);
970                         input_sync(hotk->inputdev);
971                         break;
972                 }
973         }
974 }
975
976 #define ASUS_CREATE_DEVICE_ATTR(_name)                                  \
977         struct device_attribute dev_attr_##_name = {                    \
978                 .attr = {                                               \
979                         .name = __stringify(_name),                     \
980                         .mode = 0 },                                    \
981                 .show   = NULL,                                         \
982                 .store  = NULL,                                         \
983         }
984
985 #define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store)               \
986         do {                                                            \
987                 dev_attr_##_name.attr.mode = _mode;                     \
988                 dev_attr_##_name.show = _show;                          \
989                 dev_attr_##_name.store = _store;                        \
990         } while(0)
991
992 static ASUS_CREATE_DEVICE_ATTR(infos);
993 static ASUS_CREATE_DEVICE_ATTR(wlan);
994 static ASUS_CREATE_DEVICE_ATTR(bluetooth);
995 static ASUS_CREATE_DEVICE_ATTR(display);
996 static ASUS_CREATE_DEVICE_ATTR(ledd);
997 static ASUS_CREATE_DEVICE_ATTR(ls_switch);
998 static ASUS_CREATE_DEVICE_ATTR(ls_level);
999 static ASUS_CREATE_DEVICE_ATTR(gps);
1000
1001 static struct attribute *asuspf_attributes[] = {
1002         &dev_attr_infos.attr,
1003         &dev_attr_wlan.attr,
1004         &dev_attr_bluetooth.attr,
1005         &dev_attr_display.attr,
1006         &dev_attr_ledd.attr,
1007         &dev_attr_ls_switch.attr,
1008         &dev_attr_ls_level.attr,
1009         &dev_attr_gps.attr,
1010         NULL
1011 };
1012
1013 static struct attribute_group asuspf_attribute_group = {
1014         .attrs = asuspf_attributes
1015 };
1016
1017 static struct platform_driver asuspf_driver = {
1018         .driver = {
1019                    .name = ASUS_HOTK_FILE,
1020                    .owner = THIS_MODULE,
1021                    }
1022 };
1023
1024 static struct platform_device *asuspf_device;
1025
1026 static void asus_hotk_add_fs(void)
1027 {
1028         ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
1029
1030         if (wl_switch_handle)
1031                 ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
1032
1033         if (bt_switch_handle)
1034                 ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
1035                                      show_bluetooth, store_bluetooth);
1036
1037         if (display_set_handle && display_get_handle)
1038                 ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp);
1039         else if (display_set_handle)
1040                 ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp);
1041
1042         if (ledd_set_handle)
1043                 ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
1044
1045         if (ls_switch_handle && ls_level_handle) {
1046                 ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
1047                 ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
1048         }
1049
1050         if (gps_status_handle && gps_on_handle && gps_off_handle)
1051                 ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps);
1052 }
1053
1054 static int asus_handle_init(char *name, acpi_handle * handle,
1055                             char **paths, int num_paths)
1056 {
1057         int i;
1058         acpi_status status;
1059
1060         for (i = 0; i < num_paths; i++) {
1061                 status = acpi_get_handle(NULL, paths[i], handle);
1062                 if (ACPI_SUCCESS(status))
1063                         return 0;
1064         }
1065
1066         *handle = NULL;
1067         return -ENODEV;
1068 }
1069
1070 #define ASUS_HANDLE_INIT(object)                                        \
1071         asus_handle_init(#object, &object##_handle, object##_paths,     \
1072                          ARRAY_SIZE(object##_paths))
1073
1074 /*
1075  * This function is used to initialize the hotk with right values. In this
1076  * method, we can make all the detection we want, and modify the hotk struct
1077  */
1078 static int asus_hotk_get_info(void)
1079 {
1080         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1081         union acpi_object *model = NULL;
1082         unsigned long long bsts_result, hwrs_result;
1083         char *string = NULL;
1084         acpi_status status;
1085
1086         /*
1087          * Get DSDT headers early enough to allow for differentiating between
1088          * models, but late enough to allow acpi_bus_register_driver() to fail
1089          * before doing anything ACPI-specific. Should we encounter a machine,
1090          * which needs special handling (i.e. its hotkey device has a different
1091          * HID), this bit will be moved. A global variable asus_info contains
1092          * the DSDT header.
1093          */
1094         status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
1095         if (ACPI_FAILURE(status))
1096                 pr_warning("Couldn't get the DSDT table header\n");
1097
1098         /* We have to write 0 on init this far for all ASUS models */
1099         if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
1100                 pr_err("Hotkey initialization failed\n");
1101                 return -ENODEV;
1102         }
1103
1104         /* This needs to be called for some laptops to init properly */
1105         status =
1106             acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
1107         if (ACPI_FAILURE(status))
1108                 pr_warning("Error calling BSTS\n");
1109         else if (bsts_result)
1110                 pr_notice("BSTS called, 0x%02x returned\n",
1111                        (uint) bsts_result);
1112
1113         /* This too ... */
1114         write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
1115
1116         /*
1117          * Try to match the object returned by INIT to the specific model.
1118          * Handle every possible object (or the lack of thereof) the DSDT
1119          * writers might throw at us. When in trouble, we pass NULL to
1120          * asus_model_match() and try something completely different.
1121          */
1122         if (buffer.pointer) {
1123                 model = buffer.pointer;
1124                 switch (model->type) {
1125                 case ACPI_TYPE_STRING:
1126                         string = model->string.pointer;
1127                         break;
1128                 case ACPI_TYPE_BUFFER:
1129                         string = model->buffer.pointer;
1130                         break;
1131                 default:
1132                         string = "";
1133                         break;
1134                 }
1135         }
1136         hotk->name = kstrdup(string, GFP_KERNEL);
1137         if (!hotk->name)
1138                 return -ENOMEM;
1139
1140         if (*string)
1141                 pr_notice("  %s model detected\n", string);
1142
1143         ASUS_HANDLE_INIT(mled_set);
1144         ASUS_HANDLE_INIT(tled_set);
1145         ASUS_HANDLE_INIT(rled_set);
1146         ASUS_HANDLE_INIT(pled_set);
1147         ASUS_HANDLE_INIT(gled_set);
1148
1149         ASUS_HANDLE_INIT(ledd_set);
1150
1151         ASUS_HANDLE_INIT(kled_set);
1152         ASUS_HANDLE_INIT(kled_get);
1153
1154         /*
1155          * The HWRS method return informations about the hardware.
1156          * 0x80 bit is for WLAN, 0x100 for Bluetooth.
1157          * The significance of others is yet to be found.
1158          * If we don't find the method, we assume the device are present.
1159          */
1160         status =
1161             acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
1162         if (ACPI_FAILURE(status))
1163                 hwrs_result = WL_HWRS | BT_HWRS;
1164
1165         if (hwrs_result & WL_HWRS)
1166                 ASUS_HANDLE_INIT(wl_switch);
1167         if (hwrs_result & BT_HWRS)
1168                 ASUS_HANDLE_INIT(bt_switch);
1169
1170         ASUS_HANDLE_INIT(wireless_status);
1171
1172         ASUS_HANDLE_INIT(brightness_set);
1173         ASUS_HANDLE_INIT(brightness_get);
1174
1175         ASUS_HANDLE_INIT(lcd_switch);
1176
1177         ASUS_HANDLE_INIT(display_set);
1178         ASUS_HANDLE_INIT(display_get);
1179
1180         /*
1181          * There is a lot of models with "ALSL", but a few get
1182          * a real light sens, so we need to check it.
1183          */
1184         if (!ASUS_HANDLE_INIT(ls_switch))
1185                 ASUS_HANDLE_INIT(ls_level);
1186
1187         ASUS_HANDLE_INIT(gps_on);
1188         ASUS_HANDLE_INIT(gps_off);
1189         ASUS_HANDLE_INIT(gps_status);
1190
1191         kfree(model);
1192
1193         return AE_OK;
1194 }
1195
1196 static int asus_input_init(void)
1197 {
1198         const struct key_entry *key;
1199         int result;
1200
1201         hotk->inputdev = input_allocate_device();
1202         if (!hotk->inputdev) {
1203                 pr_info("Unable to allocate input device\n");
1204                 return 0;
1205         }
1206         hotk->inputdev->name = "Asus Laptop extra buttons";
1207         hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
1208         hotk->inputdev->id.bustype = BUS_HOST;
1209         hotk->inputdev->getkeycode = asus_getkeycode;
1210         hotk->inputdev->setkeycode = asus_setkeycode;
1211
1212         for (key = asus_keymap; key->type != KE_END; key++) {
1213                 switch (key->type) {
1214                 case KE_KEY:
1215                         set_bit(EV_KEY, hotk->inputdev->evbit);
1216                         set_bit(key->keycode, hotk->inputdev->keybit);
1217                         break;
1218                 }
1219         }
1220         result = input_register_device(hotk->inputdev);
1221         if (result) {
1222                 pr_info("Unable to register input device\n");
1223                 input_free_device(hotk->inputdev);
1224         }
1225         return result;
1226 }
1227
1228 static int asus_hotk_check(void)
1229 {
1230         int result = 0;
1231
1232         result = acpi_bus_get_status(hotk->device);
1233         if (result)
1234                 return result;
1235
1236         if (hotk->device->status.present) {
1237                 result = asus_hotk_get_info();
1238         } else {
1239                 pr_err("Hotkey device not present, aborting\n");
1240                 return -EINVAL;
1241         }
1242
1243         return result;
1244 }
1245
1246 static int asus_hotk_found;
1247
1248 static int asus_hotk_add(struct acpi_device *device)
1249 {
1250         int result;
1251
1252         pr_notice("Asus Laptop Support version %s\n",
1253                ASUS_LAPTOP_VERSION);
1254
1255         hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
1256         if (!hotk)
1257                 return -ENOMEM;
1258
1259         hotk->handle = device->handle;
1260         strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
1261         strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
1262         device->driver_data = hotk;
1263         hotk->device = device;
1264
1265         result = asus_hotk_check();
1266         if (result)
1267                 goto end;
1268
1269         asus_hotk_add_fs();
1270
1271         asus_hotk_found = 1;
1272
1273         /* WLED and BLED are on by default */
1274         write_status(bt_switch_handle, 1, BT_ON);
1275         write_status(wl_switch_handle, 1, WL_ON);
1276
1277         /* If the h/w switch is off, we need to check the real status */
1278         write_status(NULL, read_status(BT_ON), BT_ON);
1279         write_status(NULL, read_status(WL_ON), WL_ON);
1280
1281         /* LCD Backlight is on by default */
1282         write_status(NULL, 1, LCD_ON);
1283
1284         /* Keyboard Backlight is on by default */
1285         if (kled_set_handle)
1286                 set_kled_lvl(1);
1287
1288         /* LED display is off by default */
1289         hotk->ledd_status = 0xFFF;
1290
1291         /* Set initial values of light sensor and level */
1292         hotk->light_switch = 1; /* Default to light sensor disabled */
1293         hotk->light_level = 0;  /* level 5 for sensor sensitivity */
1294
1295         if (ls_switch_handle)
1296                 set_light_sens_switch(hotk->light_switch);
1297
1298         if (ls_level_handle)
1299                 set_light_sens_level(hotk->light_level);
1300
1301         /* GPS is on by default */
1302         write_status(NULL, 1, GPS_ON);
1303
1304 end:
1305         if (result) {
1306                 kfree(hotk->name);
1307                 kfree(hotk);
1308         }
1309
1310         return result;
1311 }
1312
1313 static int asus_hotk_remove(struct acpi_device *device, int type)
1314 {
1315         kfree(hotk->name);
1316         kfree(hotk);
1317
1318         return 0;
1319 }
1320
1321 static void asus_backlight_exit(void)
1322 {
1323         if (asus_backlight_device)
1324                 backlight_device_unregister(asus_backlight_device);
1325 }
1326
1327 #define  ASUS_LED_UNREGISTER(object)                            \
1328         if (object##_led.dev)                                   \
1329                 led_classdev_unregister(&object##_led)
1330
1331 static void asus_led_exit(void)
1332 {
1333         destroy_workqueue(led_workqueue);
1334         ASUS_LED_UNREGISTER(mled);
1335         ASUS_LED_UNREGISTER(tled);
1336         ASUS_LED_UNREGISTER(pled);
1337         ASUS_LED_UNREGISTER(rled);
1338         ASUS_LED_UNREGISTER(gled);
1339         ASUS_LED_UNREGISTER(kled);
1340 }
1341
1342 static void asus_input_exit(void)
1343 {
1344         if (hotk->inputdev)
1345                 input_unregister_device(hotk->inputdev);
1346 }
1347
1348 static void __exit asus_laptop_exit(void)
1349 {
1350         asus_backlight_exit();
1351         asus_led_exit();
1352         asus_input_exit();
1353
1354         acpi_bus_unregister_driver(&asus_hotk_driver);
1355         sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
1356         platform_device_unregister(asuspf_device);
1357         platform_driver_unregister(&asuspf_driver);
1358 }
1359
1360 static int asus_backlight_init(struct device *dev)
1361 {
1362         struct backlight_device *bd;
1363
1364         if (brightness_set_handle && lcd_switch_handle) {
1365                 bd = backlight_device_register(ASUS_HOTK_FILE, dev,
1366                                                NULL, &asusbl_ops);
1367                 if (IS_ERR(bd)) {
1368                         pr_err("Could not register asus backlight device\n");
1369                         asus_backlight_device = NULL;
1370                         return PTR_ERR(bd);
1371                 }
1372
1373                 asus_backlight_device = bd;
1374
1375                 bd->props.max_brightness = 15;
1376                 bd->props.brightness = read_brightness(NULL);
1377                 bd->props.power = FB_BLANK_UNBLANK;
1378                 backlight_update_status(bd);
1379         }
1380         return 0;
1381 }
1382
1383 static int asus_led_register(acpi_handle handle,
1384                              struct led_classdev *ldev, struct device *dev)
1385 {
1386         if (!handle)
1387                 return 0;
1388
1389         return led_classdev_register(dev, ldev);
1390 }
1391
1392 #define ASUS_LED_REGISTER(object, device)                               \
1393         asus_led_register(object##_set_handle, &object##_led, device)
1394
1395 static int asus_led_init(struct device *dev)
1396 {
1397         int rv;
1398
1399         rv = ASUS_LED_REGISTER(mled, dev);
1400         if (rv)
1401                 goto out;
1402
1403         rv = ASUS_LED_REGISTER(tled, dev);
1404         if (rv)
1405                 goto out1;
1406
1407         rv = ASUS_LED_REGISTER(rled, dev);
1408         if (rv)
1409                 goto out2;
1410
1411         rv = ASUS_LED_REGISTER(pled, dev);
1412         if (rv)
1413                 goto out3;
1414
1415         rv = ASUS_LED_REGISTER(gled, dev);
1416         if (rv)
1417                 goto out4;
1418
1419         if (kled_set_handle && kled_get_handle)
1420                 rv = ASUS_LED_REGISTER(kled, dev);
1421         if (rv)
1422                 goto out5;
1423
1424         led_workqueue = create_singlethread_workqueue("led_workqueue");
1425         if (!led_workqueue)
1426                 goto out6;
1427
1428         return 0;
1429 out6:
1430         rv = -ENOMEM;
1431         ASUS_LED_UNREGISTER(kled);
1432 out5:
1433         ASUS_LED_UNREGISTER(gled);
1434 out4:
1435         ASUS_LED_UNREGISTER(pled);
1436 out3:
1437         ASUS_LED_UNREGISTER(rled);
1438 out2:
1439         ASUS_LED_UNREGISTER(tled);
1440 out1:
1441         ASUS_LED_UNREGISTER(mled);
1442 out:
1443         return rv;
1444 }
1445
1446 static int __init asus_laptop_init(void)
1447 {
1448         int result;
1449
1450         result = acpi_bus_register_driver(&asus_hotk_driver);
1451         if (result < 0)
1452                 return result;
1453
1454         /*
1455          * This is a bit of a kludge.  We only want this module loaded
1456          * for ASUS systems, but there's currently no way to probe the
1457          * ACPI namespace for ASUS HIDs.  So we just return failure if
1458          * we didn't find one, which will cause the module to be
1459          * unloaded.
1460          */
1461         if (!asus_hotk_found) {
1462                 acpi_bus_unregister_driver(&asus_hotk_driver);
1463                 return -ENODEV;
1464         }
1465
1466         result = asus_input_init();
1467         if (result)
1468                 goto fail_input;
1469
1470         /* Register platform stuff */
1471         result = platform_driver_register(&asuspf_driver);
1472         if (result)
1473                 goto fail_platform_driver;
1474
1475         asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
1476         if (!asuspf_device) {
1477                 result = -ENOMEM;
1478                 goto fail_platform_device1;
1479         }
1480
1481         result = platform_device_add(asuspf_device);
1482         if (result)
1483                 goto fail_platform_device2;
1484
1485         result = sysfs_create_group(&asuspf_device->dev.kobj,
1486                                     &asuspf_attribute_group);
1487         if (result)
1488                 goto fail_sysfs;
1489
1490         result = asus_led_init(&asuspf_device->dev);
1491         if (result)
1492                 goto fail_led;
1493
1494         if (!acpi_video_backlight_support()) {
1495                 result = asus_backlight_init(&asuspf_device->dev);
1496                 if (result)
1497                         goto fail_backlight;
1498         } else
1499                 pr_info("Brightness ignored, must be controlled by "
1500                        "ACPI video driver\n");
1501
1502         return 0;
1503
1504 fail_backlight:
1505        asus_led_exit();
1506
1507 fail_led:
1508        sysfs_remove_group(&asuspf_device->dev.kobj,
1509                           &asuspf_attribute_group);
1510
1511 fail_sysfs:
1512         platform_device_del(asuspf_device);
1513
1514 fail_platform_device2:
1515         platform_device_put(asuspf_device);
1516
1517 fail_platform_device1:
1518         platform_driver_unregister(&asuspf_driver);
1519
1520 fail_platform_driver:
1521         asus_input_exit();
1522
1523 fail_input:
1524
1525         return result;
1526 }
1527
1528 module_init(asus_laptop_init);
1529 module_exit(asus_laptop_exit);