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