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