aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2009-09-19 01:55:27 -0400
committerLen Brown <len.brown@intel.com>2009-09-19 01:55:27 -0400
commitb4549a24b6194201077d0295207ec204f785fab1 (patch)
treed290a7868f12a1b62aba0449f6c693dd0ff91130 /drivers/platform
parent3bb29ec14ce5f448ab37a5da16c3d720ae5af9cf (diff)
parent52cc96bd5b61775db2792780c610979fc02313eb (diff)
Merge branch 'asus' into release
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/asus-laptop.c227
-rw-r--r--drivers/platform/x86/eeepc-laptop.c340
2 files changed, 378 insertions, 189 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index db657bbeec90..b39d2bb3e75b 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -77,15 +77,16 @@
77 * Flags for hotk status 77 * Flags for hotk status
78 * WL_ON and BT_ON are also used for wireless_status() 78 * WL_ON and BT_ON are also used for wireless_status()
79 */ 79 */
80#define WL_ON 0x01 //internal Wifi 80#define WL_ON 0x01 /* internal Wifi */
81#define BT_ON 0x02 //internal Bluetooth 81#define BT_ON 0x02 /* internal Bluetooth */
82#define MLED_ON 0x04 //mail LED 82#define MLED_ON 0x04 /* mail LED */
83#define TLED_ON 0x08 //touchpad LED 83#define TLED_ON 0x08 /* touchpad LED */
84#define RLED_ON 0x10 //Record LED 84#define RLED_ON 0x10 /* Record LED */
85#define PLED_ON 0x20 //Phone LED 85#define PLED_ON 0x20 /* Phone LED */
86#define GLED_ON 0x40 //Gaming LED 86#define GLED_ON 0x40 /* Gaming LED */
87#define LCD_ON 0x80 //LCD backlight 87#define LCD_ON 0x80 /* LCD backlight */
88#define GPS_ON 0x100 //GPS 88#define GPS_ON 0x100 /* GPS */
89#define KEY_ON 0x200 /* Keyboard backlight */
89 90
90#define ASUS_LOG ASUS_HOTK_FILE ": " 91#define ASUS_LOG ASUS_HOTK_FILE ": "
91#define ASUS_ERR KERN_ERR ASUS_LOG 92#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -98,7 +99,8 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
98MODULE_DESCRIPTION(ASUS_HOTK_NAME); 99MODULE_DESCRIPTION(ASUS_HOTK_NAME);
99MODULE_LICENSE("GPL"); 100MODULE_LICENSE("GPL");
100 101
101/* WAPF defines the behavior of the Fn+Fx wlan key 102/*
103 * WAPF defines the behavior of the Fn+Fx wlan key
102 * The significance of values is yet to be found, but 104 * The significance of values is yet to be found, but
103 * most of the time: 105 * most of the time:
104 * 0x0 will do nothing 106 * 0x0 will do nothing
@@ -125,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
125/* LEDD */ 127/* LEDD */
126ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); 128ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
127 129
128/* Bluetooth and WLAN 130/*
131 * Bluetooth and WLAN
129 * WLED and BLED are not handled like other XLED, because in some dsdt 132 * WLED and BLED are not handled like other XLED, because in some dsdt
130 * they also control the WLAN/Bluetooth device. 133 * they also control the WLAN/Bluetooth device.
131 */ 134 */
@@ -149,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
149 152
150/* Display */ 153/* Display */
151ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); 154ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
152ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G 155ASUS_HANDLE(display_get,
153 M6A M6V VX-1 V6J V6V W3Z */ 156 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
154 "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V 157 "\\_SB.PCI0.P0P1.VGA.GETD",
155 S5A M5A z33A W1Jc W2V G1 */ 158 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
156 "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ 159 "\\_SB.PCI0.P0P2.VGA.GETD",
157 "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ 160 /* A6V A6Q */
158 "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ 161 "\\_SB.PCI0.P0P3.VGA.GETD",
159 "\\_SB.PCI0.VGA.GETD", /* Z96F */ 162 /* A6T, A6M */
160 "\\ACTD", /* A2D */ 163 "\\_SB.PCI0.P0PA.VGA.GETD",
161 "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ 164 /* L3C */
162 "\\DNXT", /* P30 */ 165 "\\_SB.PCI0.PCI1.VGAC.NMAP",
163 "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ 166 /* Z96F */
164 "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ 167 "\\_SB.PCI0.VGA.GETD",
165 168 /* A2D */
166ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ 169 "\\ACTD",
167ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ 170 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
171 "\\ADVG",
172 /* P30 */
173 "\\DNXT",
174 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
175 "\\INFB",
176 /* A3F A6F A3N A3L M6N W3N W6A */
177 "\\SSTE");
178
179ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
180ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
168 181
169/* GPS */ 182/* GPS */
170/* R2H use different handle for GPS on/off */ 183/* R2H use different handle for GPS on/off */
@@ -172,19 +185,23 @@ ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */
172ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ 185ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
173ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); 186ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
174 187
188/* Keyboard light */
189ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB");
190ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
191
175/* 192/*
176 * This is the main structure, we can use it to store anything interesting 193 * This is the main structure, we can use it to store anything interesting
177 * about the hotk device 194 * about the hotk device
178 */ 195 */
179struct asus_hotk { 196struct asus_hotk {
180 char *name; //laptop name 197 char *name; /* laptop name */
181 struct acpi_device *device; //the device we are in 198 struct acpi_device *device; /* the device we are in */
182 acpi_handle handle; //the handle of the hotk device 199 acpi_handle handle; /* the handle of the hotk device */
183 char status; //status of the hotk, for LEDs, ... 200 char status; /* status of the hotk, for LEDs, ... */
184 u32 ledd_status; //status of the LED display 201 u32 ledd_status; /* status of the LED display */
185 u8 light_level; //light sensor level 202 u8 light_level; /* light sensor level */
186 u8 light_switch; //light sensor switch value 203 u8 light_switch; /* light sensor switch value */
187 u16 event_count[128]; //count for each event TODO make this better 204 u16 event_count[128]; /* count for each event TODO make this better */
188 struct input_dev *inputdev; 205 struct input_dev *inputdev;
189 u16 *keycode_map; 206 u16 *keycode_map;
190}; 207};
@@ -237,28 +254,35 @@ static struct backlight_ops asusbl_ops = {
237 .update_status = update_bl_status, 254 .update_status = update_bl_status,
238}; 255};
239 256
240/* These functions actually update the LED's, and are called from a 257/*
258 * These functions actually update the LED's, and are called from a
241 * workqueue. By doing this as separate work rather than when the LED 259 * workqueue. By doing this as separate work rather than when the LED
242 * subsystem asks, we avoid messing with the Asus ACPI stuff during a 260 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
243 * potentially bad time, such as a timer interrupt. */ 261 * potentially bad time, such as a timer interrupt.
262 */
244static struct workqueue_struct *led_workqueue; 263static struct workqueue_struct *led_workqueue;
245 264
246#define ASUS_LED(object, ledname) \ 265#define ASUS_LED(object, ledname, max) \
247 static void object##_led_set(struct led_classdev *led_cdev, \ 266 static void object##_led_set(struct led_classdev *led_cdev, \
248 enum led_brightness value); \ 267 enum led_brightness value); \
268 static enum led_brightness object##_led_get( \
269 struct led_classdev *led_cdev); \
249 static void object##_led_update(struct work_struct *ignored); \ 270 static void object##_led_update(struct work_struct *ignored); \
250 static int object##_led_wk; \ 271 static int object##_led_wk; \
251 static DECLARE_WORK(object##_led_work, object##_led_update); \ 272 static DECLARE_WORK(object##_led_work, object##_led_update); \
252 static struct led_classdev object##_led = { \ 273 static struct led_classdev object##_led = { \
253 .name = "asus::" ledname, \ 274 .name = "asus::" ledname, \
254 .brightness_set = object##_led_set, \ 275 .brightness_set = object##_led_set, \
276 .brightness_get = object##_led_get, \
277 .max_brightness = max \
255 } 278 }
256 279
257ASUS_LED(mled, "mail"); 280ASUS_LED(mled, "mail", 1);
258ASUS_LED(tled, "touchpad"); 281ASUS_LED(tled, "touchpad", 1);
259ASUS_LED(rled, "record"); 282ASUS_LED(rled, "record", 1);
260ASUS_LED(pled, "phone"); 283ASUS_LED(pled, "phone", 1);
261ASUS_LED(gled, "gaming"); 284ASUS_LED(gled, "gaming", 1);
285ASUS_LED(kled, "kbd_backlight", 3);
262 286
263struct key_entry { 287struct key_entry {
264 char type; 288 char type;
@@ -278,16 +302,23 @@ static struct key_entry asus_keymap[] = {
278 {KE_KEY, 0x41, KEY_NEXTSONG}, 302 {KE_KEY, 0x41, KEY_NEXTSONG},
279 {KE_KEY, 0x43, KEY_STOPCD}, 303 {KE_KEY, 0x43, KEY_STOPCD},
280 {KE_KEY, 0x45, KEY_PLAYPAUSE}, 304 {KE_KEY, 0x45, KEY_PLAYPAUSE},
305 {KE_KEY, 0x4c, KEY_MEDIA},
281 {KE_KEY, 0x50, KEY_EMAIL}, 306 {KE_KEY, 0x50, KEY_EMAIL},
282 {KE_KEY, 0x51, KEY_WWW}, 307 {KE_KEY, 0x51, KEY_WWW},
308 {KE_KEY, 0x55, KEY_CALC},
283 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ 309 {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */
284 {KE_KEY, 0x5D, KEY_WLAN}, 310 {KE_KEY, 0x5D, KEY_WLAN},
311 {KE_KEY, 0x5E, KEY_WLAN},
312 {KE_KEY, 0x5F, KEY_WLAN},
313 {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
285 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, 314 {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
286 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ 315 {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
287 {KE_KEY, 0x82, KEY_CAMERA}, 316 {KE_KEY, 0x82, KEY_CAMERA},
288 {KE_KEY, 0x8A, KEY_PROG1}, 317 {KE_KEY, 0x8A, KEY_PROG1},
289 {KE_KEY, 0x95, KEY_MEDIA}, 318 {KE_KEY, 0x95, KEY_MEDIA},
290 {KE_KEY, 0x99, KEY_PHONE}, 319 {KE_KEY, 0x99, KEY_PHONE},
320 {KE_KEY, 0xc4, KEY_KBDILLUMUP},
321 {KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
291 {KE_END, 0}, 322 {KE_END, 0},
292}; 323};
293 324
@@ -301,8 +332,8 @@ static struct key_entry asus_keymap[] = {
301static int write_acpi_int(acpi_handle handle, const char *method, int val, 332static int write_acpi_int(acpi_handle handle, const char *method, int val,
302 struct acpi_buffer *output) 333 struct acpi_buffer *output)
303{ 334{
304 struct acpi_object_list params; //list of input parameters (an int here) 335 struct acpi_object_list params; /* list of input parameters (an int) */
305 union acpi_object in_obj; //the only param we use 336 union acpi_object in_obj; /* the only param we use */
306 acpi_status status; 337 acpi_status status;
307 338
308 if (!handle) 339 if (!handle)
@@ -399,6 +430,11 @@ static void write_status(acpi_handle handle, int out, int mask)
399 { \ 430 { \
400 int value = object##_led_wk; \ 431 int value = object##_led_wk; \
401 write_status(object##_set_handle, value, (mask)); \ 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; \
402 } 438 }
403 439
404ASUS_LED_HANDLER(mled, MLED_ON); 440ASUS_LED_HANDLER(mled, MLED_ON);
@@ -407,6 +443,60 @@ ASUS_LED_HANDLER(rled, RLED_ON);
407ASUS_LED_HANDLER(tled, TLED_ON); 443ASUS_LED_HANDLER(tled, TLED_ON);
408ASUS_LED_HANDLER(gled, GLED_ON); 444ASUS_LED_HANDLER(gled, GLED_ON);
409 445
446/*
447 * Keyboard backlight
448 */
449static int get_kled_lvl(void)
450{
451 unsigned long long kblv;
452 struct acpi_object_list params;
453 union acpi_object in_obj;
454 acpi_status rv;
455
456 params.count = 1;
457 params.pointer = &in_obj;
458 in_obj.type = ACPI_TYPE_INTEGER;
459 in_obj.integer.value = 2;
460
461 rv = acpi_evaluate_integer(kled_get_handle, NULL, &params, &kblv);
462 if (ACPI_FAILURE(rv)) {
463 pr_warning("Error reading kled level\n");
464 return 0;
465 }
466 return kblv;
467}
468
469static int set_kled_lvl(int kblv)
470{
471 if (kblv > 0)
472 kblv = (1 << 7) | (kblv & 0x7F);
473 else
474 kblv = 0;
475
476 if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) {
477 pr_warning("Keyboard LED display write failed\n");
478 return -EINVAL;
479 }
480 return 0;
481}
482
483static void kled_led_set(struct led_classdev *led_cdev,
484 enum led_brightness value)
485{
486 kled_led_wk = value;
487 queue_work(led_workqueue, &kled_led_work);
488}
489
490static void kled_led_update(struct work_struct *ignored)
491{
492 set_kled_lvl(kled_led_wk);
493}
494
495static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
496{
497 return get_kled_lvl();
498}
499
410static int get_lcd_state(void) 500static int get_lcd_state(void)
411{ 501{
412 return read_status(LCD_ON); 502 return read_status(LCD_ON);
@@ -498,7 +588,7 @@ static ssize_t show_infos(struct device *dev,
498{ 588{
499 int len = 0; 589 int len = 0;
500 unsigned long long temp; 590 unsigned long long temp;
501 char buf[16]; //enough for all info 591 char buf[16]; /* enough for all info */
502 acpi_status rv = AE_OK; 592 acpi_status rv = AE_OK;
503 593
504 /* 594 /*
@@ -516,7 +606,17 @@ static ssize_t show_infos(struct device *dev,
516 */ 606 */
517 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); 607 rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
518 if (!ACPI_FAILURE(rv)) 608 if (!ACPI_FAILURE(rv))
519 len += sprintf(page + len, "SFUN value : 0x%04x\n", 609 len += sprintf(page + len, "SFUN value : %#x\n",
610 (uint) temp);
611 /*
612 * The HWRS method return informations about the hardware.
613 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
614 * The significance of others is yet to be found.
615 * If we don't find the method, we assume the device are present.
616 */
617 rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp);
618 if (!ACPI_FAILURE(rv))
619 len += sprintf(page + len, "HRWS value : %#x\n",
520 (uint) temp); 620 (uint) temp);
521 /* 621 /*
522 * Another value for userspace: the ASYM method returns 0x02 for 622 * Another value for userspace: the ASYM method returns 0x02 for
@@ -527,7 +627,7 @@ static ssize_t show_infos(struct device *dev,
527 */ 627 */
528 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); 628 rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
529 if (!ACPI_FAILURE(rv)) 629 if (!ACPI_FAILURE(rv))
530 len += sprintf(page + len, "ASYM value : 0x%04x\n", 630 len += sprintf(page + len, "ASYM value : %#x\n",
531 (uint) temp); 631 (uint) temp);
532 if (asus_info) { 632 if (asus_info) {
533 snprintf(buf, 16, "%d", asus_info->length); 633 snprintf(buf, 16, "%d", asus_info->length);
@@ -648,8 +748,10 @@ static int read_display(void)
648 unsigned long long value = 0; 748 unsigned long long value = 0;
649 acpi_status rv = AE_OK; 749 acpi_status rv = AE_OK;
650 750
651 /* In most of the case, we know how to set the display, but sometime 751 /*
652 we can't read it */ 752 * In most of the case, we know how to set the display, but sometime
753 * we can't read it
754 */
653 if (display_get_handle) { 755 if (display_get_handle) {
654 rv = acpi_evaluate_integer(display_get_handle, NULL, 756 rv = acpi_evaluate_integer(display_get_handle, NULL,
655 NULL, &value); 757 NULL, &value);
@@ -1037,6 +1139,9 @@ static int asus_hotk_get_info(void)
1037 1139
1038 ASUS_HANDLE_INIT(ledd_set); 1140 ASUS_HANDLE_INIT(ledd_set);
1039 1141
1142 ASUS_HANDLE_INIT(kled_set);
1143 ASUS_HANDLE_INIT(kled_get);
1144
1040 /* 1145 /*
1041 * The HWRS method return informations about the hardware. 1146 * The HWRS method return informations about the hardware.
1042 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 1147 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
@@ -1063,8 +1168,10 @@ static int asus_hotk_get_info(void)
1063 ASUS_HANDLE_INIT(display_set); 1168 ASUS_HANDLE_INIT(display_set);
1064 ASUS_HANDLE_INIT(display_get); 1169 ASUS_HANDLE_INIT(display_get);
1065 1170
1066 /* There is a lot of models with "ALSL", but a few get 1171 /*
1067 a real light sens, so we need to check it. */ 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 */
1068 if (!ASUS_HANDLE_INIT(ls_switch)) 1175 if (!ASUS_HANDLE_INIT(ls_switch))
1069 ASUS_HANDLE_INIT(ls_level); 1176 ASUS_HANDLE_INIT(ls_level);
1070 1177
@@ -1168,6 +1275,10 @@ static int asus_hotk_add(struct acpi_device *device)
1168 /* LCD Backlight is on by default */ 1275 /* LCD Backlight is on by default */
1169 write_status(NULL, 1, LCD_ON); 1276 write_status(NULL, 1, LCD_ON);
1170 1277
1278 /* Keyboard Backlight is on by default */
1279 if (kled_set_handle)
1280 set_kled_lvl(1);
1281
1171 /* LED display is off by default */ 1282 /* LED display is off by default */
1172 hotk->ledd_status = 0xFFF; 1283 hotk->ledd_status = 0xFFF;
1173 1284
@@ -1222,6 +1333,7 @@ static void asus_led_exit(void)
1222 ASUS_LED_UNREGISTER(pled); 1333 ASUS_LED_UNREGISTER(pled);
1223 ASUS_LED_UNREGISTER(rled); 1334 ASUS_LED_UNREGISTER(rled);
1224 ASUS_LED_UNREGISTER(gled); 1335 ASUS_LED_UNREGISTER(gled);
1336 ASUS_LED_UNREGISTER(kled);
1225} 1337}
1226 1338
1227static void asus_input_exit(void) 1339static void asus_input_exit(void)
@@ -1301,13 +1413,20 @@ static int asus_led_init(struct device *dev)
1301 if (rv) 1413 if (rv)
1302 goto out4; 1414 goto out4;
1303 1415
1416 if (kled_set_handle && kled_get_handle)
1417 rv = ASUS_LED_REGISTER(kled, dev);
1418 if (rv)
1419 goto out5;
1420
1304 led_workqueue = create_singlethread_workqueue("led_workqueue"); 1421 led_workqueue = create_singlethread_workqueue("led_workqueue");
1305 if (!led_workqueue) 1422 if (!led_workqueue)
1306 goto out5; 1423 goto out6;
1307 1424
1308 return 0; 1425 return 0;
1309out5: 1426out6:
1310 rv = -ENOMEM; 1427 rv = -ENOMEM;
1428 ASUS_LED_UNREGISTER(kled);
1429out5:
1311 ASUS_LED_UNREGISTER(gled); 1430 ASUS_LED_UNREGISTER(gled);
1312out4: 1431out4:
1313 ASUS_LED_UNREGISTER(pled); 1432 ASUS_LED_UNREGISTER(pled);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 222ffb892f22..da3c08b3dcc1 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -142,18 +142,28 @@ struct eeepc_hotk {
142 struct rfkill *wlan_rfkill; 142 struct rfkill *wlan_rfkill;
143 struct rfkill *bluetooth_rfkill; 143 struct rfkill *bluetooth_rfkill;
144 struct rfkill *wwan3g_rfkill; 144 struct rfkill *wwan3g_rfkill;
145 struct rfkill *wimax_rfkill;
145 struct hotplug_slot *hotplug_slot; 146 struct hotplug_slot *hotplug_slot;
146 struct work_struct hotplug_work; 147 struct mutex hotplug_lock;
147}; 148};
148 149
149/* The actual device the driver binds to */ 150/* The actual device the driver binds to */
150static struct eeepc_hotk *ehotk; 151static struct eeepc_hotk *ehotk;
151 152
152/* Platform device/driver */ 153/* Platform device/driver */
154static int eeepc_hotk_thaw(struct device *device);
155static int eeepc_hotk_restore(struct device *device);
156
157static struct dev_pm_ops eeepc_pm_ops = {
158 .thaw = eeepc_hotk_thaw,
159 .restore = eeepc_hotk_restore,
160};
161
153static struct platform_driver platform_driver = { 162static struct platform_driver platform_driver = {
154 .driver = { 163 .driver = {
155 .name = EEEPC_HOTK_FILE, 164 .name = EEEPC_HOTK_FILE,
156 .owner = THIS_MODULE, 165 .owner = THIS_MODULE,
166 .pm = &eeepc_pm_ops,
157 } 167 }
158}; 168};
159 169
@@ -192,7 +202,6 @@ static struct key_entry eeepc_keymap[] = {
192 */ 202 */
193static int eeepc_hotk_add(struct acpi_device *device); 203static int eeepc_hotk_add(struct acpi_device *device);
194static int eeepc_hotk_remove(struct acpi_device *device, int type); 204static int eeepc_hotk_remove(struct acpi_device *device, int type);
195static int eeepc_hotk_resume(struct acpi_device *device);
196static void eeepc_hotk_notify(struct acpi_device *device, u32 event); 205static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
197 206
198static const struct acpi_device_id eeepc_device_ids[] = { 207static const struct acpi_device_id eeepc_device_ids[] = {
@@ -209,7 +218,6 @@ static struct acpi_driver eeepc_hotk_driver = {
209 .ops = { 218 .ops = {
210 .add = eeepc_hotk_add, 219 .add = eeepc_hotk_add,
211 .remove = eeepc_hotk_remove, 220 .remove = eeepc_hotk_remove,
212 .resume = eeepc_hotk_resume,
213 .notify = eeepc_hotk_notify, 221 .notify = eeepc_hotk_notify,
214 }, 222 },
215}; 223};
@@ -579,7 +587,6 @@ static void cmsg_quirks(void)
579 587
580static int eeepc_hotk_check(void) 588static int eeepc_hotk_check(void)
581{ 589{
582 const struct key_entry *key;
583 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 590 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
584 int result; 591 int result;
585 592
@@ -604,31 +611,6 @@ static int eeepc_hotk_check(void)
604 pr_info("Get control methods supported: 0x%x\n", 611 pr_info("Get control methods supported: 0x%x\n",
605 ehotk->cm_supported); 612 ehotk->cm_supported);
606 } 613 }
607 ehotk->inputdev = input_allocate_device();
608 if (!ehotk->inputdev) {
609 pr_info("Unable to allocate input device\n");
610 return 0;
611 }
612 ehotk->inputdev->name = "Asus EeePC extra buttons";
613 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
614 ehotk->inputdev->id.bustype = BUS_HOST;
615 ehotk->inputdev->getkeycode = eeepc_getkeycode;
616 ehotk->inputdev->setkeycode = eeepc_setkeycode;
617
618 for (key = eeepc_keymap; key->type != KE_END; key++) {
619 switch (key->type) {
620 case KE_KEY:
621 set_bit(EV_KEY, ehotk->inputdev->evbit);
622 set_bit(key->keycode, ehotk->inputdev->keybit);
623 break;
624 }
625 }
626 result = input_register_device(ehotk->inputdev);
627 if (result) {
628 pr_info("Unable to register input device\n");
629 input_free_device(ehotk->inputdev);
630 return 0;
631 }
632 } else { 614 } else {
633 pr_err("Hotkey device not present, aborting\n"); 615 pr_err("Hotkey device not present, aborting\n");
634 return -EINVAL; 616 return -EINVAL;
@@ -661,40 +643,48 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
661 return 0; 643 return 0;
662} 644}
663 645
664static void eeepc_hotplug_work(struct work_struct *work) 646static void eeepc_rfkill_hotplug(void)
665{ 647{
666 struct pci_dev *dev; 648 struct pci_dev *dev;
667 struct pci_bus *bus = pci_find_bus(0, 1); 649 struct pci_bus *bus;
668 bool blocked; 650 bool blocked = eeepc_wlan_rfkill_blocked();
669 651
670 if (!bus) { 652 if (ehotk->wlan_rfkill)
671 pr_warning("Unable to find PCI bus 1?\n"); 653 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
672 return;
673 }
674 654
675 blocked = eeepc_wlan_rfkill_blocked(); 655 mutex_lock(&ehotk->hotplug_lock);
676 if (!blocked) { 656
677 dev = pci_get_slot(bus, 0); 657 if (ehotk->hotplug_slot) {
678 if (dev) { 658 bus = pci_find_bus(0, 1);
679 /* Device already present */ 659 if (!bus) {
680 pci_dev_put(dev); 660 pr_warning("Unable to find PCI bus 1?\n");
681 return; 661 goto out_unlock;
682 }
683 dev = pci_scan_single_device(bus, 0);
684 if (dev) {
685 pci_bus_assign_resources(bus);
686 if (pci_bus_add_device(dev))
687 pr_err("Unable to hotplug wifi\n");
688 } 662 }
689 } else { 663
690 dev = pci_get_slot(bus, 0); 664 if (!blocked) {
691 if (dev) { 665 dev = pci_get_slot(bus, 0);
692 pci_remove_bus_device(dev); 666 if (dev) {
693 pci_dev_put(dev); 667 /* Device already present */
668 pci_dev_put(dev);
669 goto out_unlock;
670 }
671 dev = pci_scan_single_device(bus, 0);
672 if (dev) {
673 pci_bus_assign_resources(bus);
674 if (pci_bus_add_device(dev))
675 pr_err("Unable to hotplug wifi\n");
676 }
677 } else {
678 dev = pci_get_slot(bus, 0);
679 if (dev) {
680 pci_remove_bus_device(dev);
681 pci_dev_put(dev);
682 }
694 } 683 }
695 } 684 }
696 685
697 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); 686out_unlock:
687 mutex_unlock(&ehotk->hotplug_lock);
698} 688}
699 689
700static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) 690static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
@@ -702,7 +692,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
702 if (event != ACPI_NOTIFY_BUS_CHECK) 692 if (event != ACPI_NOTIFY_BUS_CHECK)
703 return; 693 return;
704 694
705 schedule_work(&ehotk->hotplug_work); 695 eeepc_rfkill_hotplug();
706} 696}
707 697
708static void eeepc_hotk_notify(struct acpi_device *device, u32 event) 698static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@ -839,66 +829,38 @@ error_slot:
839 return ret; 829 return ret;
840} 830}
841 831
842static int eeepc_hotk_add(struct acpi_device *device) 832static int eeepc_hotk_thaw(struct device *device)
843{
844 int result;
845
846 if (!device)
847 return -EINVAL;
848 pr_notice(EEEPC_HOTK_NAME "\n");
849 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
850 if (!ehotk)
851 return -ENOMEM;
852 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
853 ehotk->handle = device->handle;
854 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
855 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
856 device->driver_data = ehotk;
857 ehotk->device = device;
858 result = eeepc_hotk_check();
859 if (result)
860 goto ehotk_fail;
861
862 return 0;
863
864 ehotk_fail:
865 kfree(ehotk);
866 ehotk = NULL;
867
868 return result;
869}
870
871static int eeepc_hotk_remove(struct acpi_device *device, int type)
872{
873 if (!device || !acpi_driver_data(device))
874 return -EINVAL;
875
876 kfree(ehotk);
877 return 0;
878}
879
880static int eeepc_hotk_resume(struct acpi_device *device)
881{ 833{
882 if (ehotk->wlan_rfkill) { 834 if (ehotk->wlan_rfkill) {
883 bool wlan; 835 bool wlan;
884 836
885 /* Workaround - it seems that _PTS disables the wireless 837 /*
886 without notification or changing the value read by WLAN. 838 * Work around bios bug - acpi _PTS turns off the wireless led
887 Normally this is fine because the correct value is restored 839 * during suspend. Normally it restores it on resume, but
888 from the non-volatile storage on resume, but we need to do 840 * we should kick it ourselves in case hibernation is aborted.
889 it ourself if case suspend is aborted, or we lose wireless.
890 */ 841 */
891 wlan = get_acpi(CM_ASL_WLAN); 842 wlan = get_acpi(CM_ASL_WLAN);
892 set_acpi(CM_ASL_WLAN, wlan); 843 set_acpi(CM_ASL_WLAN, wlan);
844 }
893 845
894 rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); 846 return 0;
847}
895 848
896 schedule_work(&ehotk->hotplug_work); 849static int eeepc_hotk_restore(struct device *device)
897 } 850{
851 /* Refresh both wlan rfkill state and pci hotplug */
852 if (ehotk->wlan_rfkill)
853 eeepc_rfkill_hotplug();
898 854
899 if (ehotk->bluetooth_rfkill) 855 if (ehotk->bluetooth_rfkill)
900 rfkill_set_sw_state(ehotk->bluetooth_rfkill, 856 rfkill_set_sw_state(ehotk->bluetooth_rfkill,
901 get_acpi(CM_ASL_BLUETOOTH) != 1); 857 get_acpi(CM_ASL_BLUETOOTH) != 1);
858 if (ehotk->wwan3g_rfkill)
859 rfkill_set_sw_state(ehotk->wwan3g_rfkill,
860 get_acpi(CM_ASL_3G) != 1);
861 if (ehotk->wimax_rfkill)
862 rfkill_set_sw_state(ehotk->wimax_rfkill,
863 get_acpi(CM_ASL_WIMAX) != 1);
902 864
903 return 0; 865 return 0;
904} 866}
@@ -1019,16 +981,37 @@ static void eeepc_backlight_exit(void)
1019 981
1020static void eeepc_rfkill_exit(void) 982static void eeepc_rfkill_exit(void)
1021{ 983{
984 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
1022 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); 985 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
1023 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); 986 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
1024 if (ehotk->wlan_rfkill) 987 if (ehotk->wlan_rfkill) {
1025 rfkill_unregister(ehotk->wlan_rfkill); 988 rfkill_unregister(ehotk->wlan_rfkill);
1026 if (ehotk->bluetooth_rfkill) 989 rfkill_destroy(ehotk->wlan_rfkill);
1027 rfkill_unregister(ehotk->bluetooth_rfkill); 990 ehotk->wlan_rfkill = NULL;
1028 if (ehotk->wwan3g_rfkill) 991 }
1029 rfkill_unregister(ehotk->wwan3g_rfkill); 992 /*
993 * Refresh pci hotplug in case the rfkill state was changed after
994 * eeepc_unregister_rfkill_notifier()
995 */
996 eeepc_rfkill_hotplug();
1030 if (ehotk->hotplug_slot) 997 if (ehotk->hotplug_slot)
1031 pci_hp_deregister(ehotk->hotplug_slot); 998 pci_hp_deregister(ehotk->hotplug_slot);
999
1000 if (ehotk->bluetooth_rfkill) {
1001 rfkill_unregister(ehotk->bluetooth_rfkill);
1002 rfkill_destroy(ehotk->bluetooth_rfkill);
1003 ehotk->bluetooth_rfkill = NULL;
1004 }
1005 if (ehotk->wwan3g_rfkill) {
1006 rfkill_unregister(ehotk->wwan3g_rfkill);
1007 rfkill_destroy(ehotk->wwan3g_rfkill);
1008 ehotk->wwan3g_rfkill = NULL;
1009 }
1010 if (ehotk->wimax_rfkill) {
1011 rfkill_unregister(ehotk->wimax_rfkill);
1012 rfkill_destroy(ehotk->wimax_rfkill);
1013 ehotk->wimax_rfkill = NULL;
1014 }
1032} 1015}
1033 1016
1034static void eeepc_input_exit(void) 1017static void eeepc_input_exit(void)
@@ -1050,19 +1033,6 @@ static void eeepc_hwmon_exit(void)
1050 eeepc_hwmon_device = NULL; 1033 eeepc_hwmon_device = NULL;
1051} 1034}
1052 1035
1053static void __exit eeepc_laptop_exit(void)
1054{
1055 eeepc_backlight_exit();
1056 eeepc_rfkill_exit();
1057 eeepc_input_exit();
1058 eeepc_hwmon_exit();
1059 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1060 sysfs_remove_group(&platform_device->dev.kobj,
1061 &platform_attribute_group);
1062 platform_device_unregister(platform_device);
1063 platform_driver_unregister(&platform_driver);
1064}
1065
1066static int eeepc_new_rfkill(struct rfkill **rfkill, 1036static int eeepc_new_rfkill(struct rfkill **rfkill,
1067 const char *name, struct device *dev, 1037 const char *name, struct device *dev,
1068 enum rfkill_type type, int cm) 1038 enum rfkill_type type, int cm)
@@ -1094,10 +1064,7 @@ static int eeepc_rfkill_init(struct device *dev)
1094{ 1064{
1095 int result = 0; 1065 int result = 0;
1096 1066
1097 INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work); 1067 mutex_init(&ehotk->hotplug_lock);
1098
1099 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1100 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1101 1068
1102 result = eeepc_new_rfkill(&ehotk->wlan_rfkill, 1069 result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
1103 "eeepc-wlan", dev, 1070 "eeepc-wlan", dev,
@@ -1120,6 +1087,13 @@ static int eeepc_rfkill_init(struct device *dev)
1120 if (result && result != -ENODEV) 1087 if (result && result != -ENODEV)
1121 goto exit; 1088 goto exit;
1122 1089
1090 result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
1091 "eeepc-wimax", dev,
1092 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
1093
1094 if (result && result != -ENODEV)
1095 goto exit;
1096
1123 result = eeepc_setup_pci_hotplug(); 1097 result = eeepc_setup_pci_hotplug();
1124 /* 1098 /*
1125 * If we get -EBUSY then something else is handling the PCI hotplug - 1099 * If we get -EBUSY then something else is handling the PCI hotplug -
@@ -1128,6 +1102,15 @@ static int eeepc_rfkill_init(struct device *dev)
1128 if (result == -EBUSY) 1102 if (result == -EBUSY)
1129 result = 0; 1103 result = 0;
1130 1104
1105 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
1106 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1107 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1108 /*
1109 * Refresh pci hotplug in case the rfkill state was changed during
1110 * setup.
1111 */
1112 eeepc_rfkill_hotplug();
1113
1131exit: 1114exit:
1132 if (result && result != -ENODEV) 1115 if (result && result != -ENODEV)
1133 eeepc_rfkill_exit(); 1116 eeepc_rfkill_exit();
@@ -1172,21 +1155,61 @@ static int eeepc_hwmon_init(struct device *dev)
1172 return result; 1155 return result;
1173} 1156}
1174 1157
1175static int __init eeepc_laptop_init(void) 1158static int eeepc_input_init(struct device *dev)
1176{ 1159{
1177 struct device *dev; 1160 const struct key_entry *key;
1178 int result; 1161 int result;
1179 1162
1180 if (acpi_disabled) 1163 ehotk->inputdev = input_allocate_device();
1181 return -ENODEV; 1164 if (!ehotk->inputdev) {
1182 result = acpi_bus_register_driver(&eeepc_hotk_driver); 1165 pr_info("Unable to allocate input device\n");
1183 if (result < 0) 1166 return -ENOMEM;
1167 }
1168 ehotk->inputdev->name = "Asus EeePC extra buttons";
1169 ehotk->inputdev->dev.parent = dev;
1170 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
1171 ehotk->inputdev->id.bustype = BUS_HOST;
1172 ehotk->inputdev->getkeycode = eeepc_getkeycode;
1173 ehotk->inputdev->setkeycode = eeepc_setkeycode;
1174
1175 for (key = eeepc_keymap; key->type != KE_END; key++) {
1176 switch (key->type) {
1177 case KE_KEY:
1178 set_bit(EV_KEY, ehotk->inputdev->evbit);
1179 set_bit(key->keycode, ehotk->inputdev->keybit);
1180 break;
1181 }
1182 }
1183 result = input_register_device(ehotk->inputdev);
1184 if (result) {
1185 pr_info("Unable to register input device\n");
1186 input_free_device(ehotk->inputdev);
1184 return result; 1187 return result;
1185 if (!ehotk) {
1186 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1187 return -ENODEV;
1188 } 1188 }
1189 return 0;
1190}
1191
1192static int eeepc_hotk_add(struct acpi_device *device)
1193{
1194 struct device *dev;
1195 int result;
1189 1196
1197 if (!device)
1198 return -EINVAL;
1199 pr_notice(EEEPC_HOTK_NAME "\n");
1200 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
1201 if (!ehotk)
1202 return -ENOMEM;
1203 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1204 ehotk->handle = device->handle;
1205 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
1206 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
1207 device->driver_data = ehotk;
1208 ehotk->device = device;
1209
1210 result = eeepc_hotk_check();
1211 if (result)
1212 goto fail_platform_driver;
1190 eeepc_enable_camera(); 1213 eeepc_enable_camera();
1191 1214
1192 /* Register platform stuff */ 1215 /* Register platform stuff */
@@ -1216,6 +1239,10 @@ static int __init eeepc_laptop_init(void)
1216 pr_info("Backlight controlled by ACPI video " 1239 pr_info("Backlight controlled by ACPI video "
1217 "driver\n"); 1240 "driver\n");
1218 1241
1242 result = eeepc_input_init(dev);
1243 if (result)
1244 goto fail_input;
1245
1219 result = eeepc_hwmon_init(dev); 1246 result = eeepc_hwmon_init(dev);
1220 if (result) 1247 if (result)
1221 goto fail_hwmon; 1248 goto fail_hwmon;
@@ -1225,9 +1252,12 @@ static int __init eeepc_laptop_init(void)
1225 goto fail_rfkill; 1252 goto fail_rfkill;
1226 1253
1227 return 0; 1254 return 0;
1255
1228fail_rfkill: 1256fail_rfkill:
1229 eeepc_hwmon_exit(); 1257 eeepc_hwmon_exit();
1230fail_hwmon: 1258fail_hwmon:
1259 eeepc_input_exit();
1260fail_input:
1231 eeepc_backlight_exit(); 1261 eeepc_backlight_exit();
1232fail_backlight: 1262fail_backlight:
1233 sysfs_remove_group(&platform_device->dev.kobj, 1263 sysfs_remove_group(&platform_device->dev.kobj,
@@ -1239,9 +1269,49 @@ fail_platform_device2:
1239fail_platform_device1: 1269fail_platform_device1:
1240 platform_driver_unregister(&platform_driver); 1270 platform_driver_unregister(&platform_driver);
1241fail_platform_driver: 1271fail_platform_driver:
1242 eeepc_input_exit(); 1272 kfree(ehotk);
1273
1243 return result; 1274 return result;
1244} 1275}
1245 1276
1277static int eeepc_hotk_remove(struct acpi_device *device, int type)
1278{
1279 if (!device || !acpi_driver_data(device))
1280 return -EINVAL;
1281
1282 eeepc_backlight_exit();
1283 eeepc_rfkill_exit();
1284 eeepc_input_exit();
1285 eeepc_hwmon_exit();
1286 sysfs_remove_group(&platform_device->dev.kobj,
1287 &platform_attribute_group);
1288 platform_device_unregister(platform_device);
1289 platform_driver_unregister(&platform_driver);
1290
1291 kfree(ehotk);
1292 return 0;
1293}
1294
1295static int __init eeepc_laptop_init(void)
1296{
1297 int result;
1298
1299 if (acpi_disabled)
1300 return -ENODEV;
1301 result = acpi_bus_register_driver(&eeepc_hotk_driver);
1302 if (result < 0)
1303 return result;
1304 if (!ehotk) {
1305 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1306 return -ENODEV;
1307 }
1308 return 0;
1309}
1310
1311static void __exit eeepc_laptop_exit(void)
1312{
1313 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1314}
1315
1246module_init(eeepc_laptop_init); 1316module_init(eeepc_laptop_init);
1247module_exit(eeepc_laptop_exit); 1317module_exit(eeepc_laptop_exit);