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