aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/asus-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/asus-laptop.c')
-rw-r--r--drivers/platform/x86/asus-laptop.c1741
1 files changed, 906 insertions, 835 deletions
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);