diff options
-rw-r--r-- | drivers/platform/x86/asus-laptop.c | 440 |
1 files changed, 223 insertions, 217 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 58a4864096d9..940ce3d63229 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
@@ -58,36 +58,6 @@ | |||
58 | #define ASUS_LAPTOP_FILE KBUILD_MODNAME | 58 | #define ASUS_LAPTOP_FILE KBUILD_MODNAME |
59 | #define ASUS_LAPTOP_PREFIX "\\_SB.ATKD." | 59 | #define ASUS_LAPTOP_PREFIX "\\_SB.ATKD." |
60 | 60 | ||
61 | |||
62 | /* | ||
63 | * Some events we use, same for all Asus | ||
64 | */ | ||
65 | #define ATKD_BR_UP 0x10 | ||
66 | #define ATKD_BR_DOWN 0x20 | ||
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 | MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); | 61 | MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); |
92 | MODULE_DESCRIPTION(ASUS_LAPTOP_NAME); | 62 | MODULE_DESCRIPTION(ASUS_LAPTOP_NAME); |
93 | MODULE_LICENSE("GPL"); | 63 | MODULE_LICENSE("GPL"); |
@@ -119,6 +89,35 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " | |||
119 | "(0 = disabled, 1 = enabled, -1 = don't do anything). " | 89 | "(0 = disabled, 1 = enabled, -1 = don't do anything). " |
120 | "default is 1"); | 90 | "default is 1"); |
121 | 91 | ||
92 | /* | ||
93 | * Some events we use, same for all Asus | ||
94 | */ | ||
95 | #define ATKD_BR_UP 0x10 | ||
96 | #define ATKD_BR_DOWN 0x20 | ||
97 | #define ATKD_LCD_ON 0x33 | ||
98 | #define ATKD_LCD_OFF 0x34 | ||
99 | |||
100 | /* | ||
101 | * Known bits returned by \_SB.ATKD.HWRS | ||
102 | */ | ||
103 | #define WL_HWRS 0x80 | ||
104 | #define BT_HWRS 0x100 | ||
105 | |||
106 | /* | ||
107 | * Flags for hotk status | ||
108 | * WL_ON and BT_ON are also used for wireless_status() | ||
109 | */ | ||
110 | #define WL_ON 0x01 /* internal Wifi */ | ||
111 | #define BT_ON 0x02 /* internal Bluetooth */ | ||
112 | #define MLED_ON 0x04 /* mail LED */ | ||
113 | #define TLED_ON 0x08 /* touchpad LED */ | ||
114 | #define RLED_ON 0x10 /* Record LED */ | ||
115 | #define PLED_ON 0x20 /* Phone LED */ | ||
116 | #define GLED_ON 0x40 /* Gaming LED */ | ||
117 | #define LCD_ON 0x80 /* LCD backlight */ | ||
118 | #define GPS_ON 0x100 /* GPS */ | ||
119 | #define KEY_ON 0x200 /* Keyboard backlight */ | ||
120 | |||
122 | #define ASUS_HANDLE(object, paths...) \ | 121 | #define ASUS_HANDLE(object, paths...) \ |
123 | static acpi_handle object##_handle = NULL; \ | 122 | static acpi_handle object##_handle = NULL; \ |
124 | static char *object##_paths[] = { paths } | 123 | static char *object##_paths[] = { paths } |
@@ -249,36 +248,6 @@ struct asus_laptop { | |||
249 | u16 *keycode_map; | 248 | u16 *keycode_map; |
250 | }; | 249 | }; |
251 | 250 | ||
252 | /* | ||
253 | * The backlight class declaration | ||
254 | */ | ||
255 | static int read_brightness(struct backlight_device *bd); | ||
256 | static int update_bl_status(struct backlight_device *bd); | ||
257 | static struct backlight_ops asusbl_ops = { | ||
258 | .get_brightness = read_brightness, | ||
259 | .update_status = update_bl_status, | ||
260 | }; | ||
261 | |||
262 | #define ASUS_LED(object, ledname, max) \ | ||
263 | static void object##_led_set(struct led_classdev *led_cdev, \ | ||
264 | enum led_brightness value); \ | ||
265 | static enum led_brightness object##_led_get( \ | ||
266 | struct led_classdev *led_cdev); \ | ||
267 | static void object##_led_update(struct work_struct *ignored); \ | ||
268 | static struct led_classdev object##_led = { \ | ||
269 | .name = "asus::" ledname, \ | ||
270 | .brightness_set = object##_led_set, \ | ||
271 | .brightness_get = object##_led_get, \ | ||
272 | .max_brightness = max \ | ||
273 | } | ||
274 | |||
275 | ASUS_LED(mled, "mail", 1); | ||
276 | ASUS_LED(tled, "touchpad", 1); | ||
277 | ASUS_LED(rled, "record", 1); | ||
278 | ASUS_LED(pled, "phone", 1); | ||
279 | ASUS_LED(gled, "gaming", 1); | ||
280 | ASUS_LED(kled, "kbd_backlight", 3); | ||
281 | |||
282 | struct key_entry { | 251 | struct key_entry { |
283 | char type; | 252 | char type; |
284 | u8 code; | 253 | u8 code; |
@@ -427,6 +396,29 @@ static void write_status(struct asus_laptop *asus, acpi_handle handle, | |||
427 | pr_warning(" write failed %x\n", mask); | 396 | pr_warning(" write failed %x\n", mask); |
428 | } | 397 | } |
429 | 398 | ||
399 | /* | ||
400 | * LEDs | ||
401 | */ | ||
402 | #define ASUS_LED(object, ledname, max) \ | ||
403 | static void object##_led_set(struct led_classdev *led_cdev, \ | ||
404 | enum led_brightness value); \ | ||
405 | static enum led_brightness object##_led_get( \ | ||
406 | struct led_classdev *led_cdev); \ | ||
407 | static void object##_led_update(struct work_struct *ignored); \ | ||
408 | static struct led_classdev object##_led = { \ | ||
409 | .name = "asus::" ledname, \ | ||
410 | .brightness_set = object##_led_set, \ | ||
411 | .brightness_get = object##_led_get, \ | ||
412 | .max_brightness = max \ | ||
413 | } | ||
414 | |||
415 | ASUS_LED(mled, "mail", 1); | ||
416 | ASUS_LED(tled, "touchpad", 1); | ||
417 | ASUS_LED(rled, "record", 1); | ||
418 | ASUS_LED(pled, "phone", 1); | ||
419 | ASUS_LED(gled, "gaming", 1); | ||
420 | ASUS_LED(kled, "kbd_backlight", 3); | ||
421 | |||
430 | /* /sys/class/led handlers */ | 422 | /* /sys/class/led handlers */ |
431 | #define ASUS_LED_HANDLER(object, mask) \ | 423 | #define ASUS_LED_HANDLER(object, mask) \ |
432 | static void object##_led_set(struct led_classdev *led_cdev, \ | 424 | static void object##_led_set(struct led_classdev *led_cdev, \ |
@@ -459,7 +451,7 @@ ASUS_LED_HANDLER(tled, TLED_ON); | |||
459 | ASUS_LED_HANDLER(gled, GLED_ON); | 451 | ASUS_LED_HANDLER(gled, GLED_ON); |
460 | 452 | ||
461 | /* | 453 | /* |
462 | * Keyboard backlight | 454 | * Keyboard backlight (also a LED) |
463 | */ | 455 | */ |
464 | static int get_kled_lvl(void) | 456 | static int get_kled_lvl(void) |
465 | { | 457 | { |
@@ -516,6 +508,70 @@ static enum led_brightness kled_led_get(struct led_classdev *led_cdev) | |||
516 | return get_kled_lvl(); | 508 | return get_kled_lvl(); |
517 | } | 509 | } |
518 | 510 | ||
511 | #define ASUS_LED_UNREGISTER(object) \ | ||
512 | if (object##_led.dev) \ | ||
513 | led_classdev_unregister(&object##_led) | ||
514 | |||
515 | static void asus_led_exit(struct asus_laptop *asus) | ||
516 | { | ||
517 | ASUS_LED_UNREGISTER(mled); | ||
518 | ASUS_LED_UNREGISTER(tled); | ||
519 | ASUS_LED_UNREGISTER(pled); | ||
520 | ASUS_LED_UNREGISTER(rled); | ||
521 | ASUS_LED_UNREGISTER(gled); | ||
522 | ASUS_LED_UNREGISTER(kled); | ||
523 | if (asus->leds.workqueue) { | ||
524 | destroy_workqueue(asus->leds.workqueue); | ||
525 | asus->leds.workqueue = NULL; | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /* Ugly macro, need to fix that later */ | ||
530 | #define ASUS_LED_REGISTER(asus, object, _name, max) \ | ||
531 | do { \ | ||
532 | struct led_classdev *ldev = &asus->leds.object; \ | ||
533 | if (!object##_set_handle) \ | ||
534 | break ; \ | ||
535 | \ | ||
536 | INIT_WORK(&asus->leds.object##_work, object##_led_update); \ | ||
537 | ldev->name = "asus::" _name; \ | ||
538 | ldev->brightness_set = object##_led_set; \ | ||
539 | ldev->max_brightness = max; \ | ||
540 | rv = led_classdev_register(&asus->platform_device->dev, ldev); \ | ||
541 | if (rv) \ | ||
542 | goto error; \ | ||
543 | } while (0) | ||
544 | |||
545 | static int asus_led_init(struct asus_laptop *asus) | ||
546 | { | ||
547 | int rv; | ||
548 | |||
549 | /* | ||
550 | * Functions that actually update the LED's are called from a | ||
551 | * workqueue. By doing this as separate work rather than when the LED | ||
552 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | ||
553 | * potentially bad time, such as a timer interrupt. | ||
554 | */ | ||
555 | asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); | ||
556 | if (!asus->leds.workqueue) | ||
557 | return -ENOMEM; | ||
558 | |||
559 | ASUS_LED_REGISTER(asus, mled, "mail", 1); | ||
560 | ASUS_LED_REGISTER(asus, tled, "touchpad", 1); | ||
561 | ASUS_LED_REGISTER(asus, rled, "record", 1); | ||
562 | ASUS_LED_REGISTER(asus, pled, "phone", 1); | ||
563 | ASUS_LED_REGISTER(asus, gled, "gaming", 1); | ||
564 | if (kled_set_handle && kled_get_handle) | ||
565 | ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); | ||
566 | error: | ||
567 | if (rv) | ||
568 | asus_led_exit(asus); | ||
569 | return rv; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * Backlight device | ||
574 | */ | ||
519 | static int get_lcd_state(struct asus_laptop *asus) | 575 | static int get_lcd_state(struct asus_laptop *asus) |
520 | { | 576 | { |
521 | return read_status(asus, LCD_ON); | 577 | return read_status(asus, LCD_ON); |
@@ -588,6 +644,41 @@ static int update_bl_status(struct backlight_device *bd) | |||
588 | return set_lcd_state(asus, value); | 644 | return set_lcd_state(asus, value); |
589 | } | 645 | } |
590 | 646 | ||
647 | static struct backlight_ops asusbl_ops = { | ||
648 | .get_brightness = read_brightness, | ||
649 | .update_status = update_bl_status, | ||
650 | }; | ||
651 | |||
652 | static int asus_backlight_init(struct asus_laptop *asus) | ||
653 | { | ||
654 | struct backlight_device *bd; | ||
655 | struct device *dev = &asus->platform_device->dev; | ||
656 | |||
657 | if (brightness_set_handle && lcd_switch_handle) { | ||
658 | bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, | ||
659 | asus, &asusbl_ops); | ||
660 | if (IS_ERR(bd)) { | ||
661 | pr_err("Could not register asus backlight device\n"); | ||
662 | asus->backlight_device = NULL; | ||
663 | return PTR_ERR(bd); | ||
664 | } | ||
665 | |||
666 | asus->backlight_device = bd; | ||
667 | |||
668 | bd->props.max_brightness = 15; | ||
669 | bd->props.brightness = read_brightness(NULL); | ||
670 | bd->props.power = FB_BLANK_UNBLANK; | ||
671 | backlight_update_status(bd); | ||
672 | } | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static void asus_backlight_exit(struct asus_laptop *asus) | ||
677 | { | ||
678 | if (asus->backlight_device) | ||
679 | backlight_device_unregister(asus->backlight_device); | ||
680 | } | ||
681 | |||
591 | /* | 682 | /* |
592 | * Platform device handlers | 683 | * Platform device handlers |
593 | */ | 684 | */ |
@@ -904,7 +995,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, | |||
904 | } | 995 | } |
905 | 996 | ||
906 | /* | 997 | /* |
907 | * Hotkey functions | 998 | * Input device (i.e. hotkeys) |
908 | */ | 999 | */ |
909 | static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus, | 1000 | static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus, |
910 | int code) | 1001 | int code) |
@@ -965,10 +1056,72 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) | |||
965 | return -EINVAL; | 1056 | return -EINVAL; |
966 | } | 1057 | } |
967 | 1058 | ||
1059 | static void asus_input_notify(struct asus_laptop *asus, int event) | ||
1060 | { | ||
1061 | struct key_entry *key; | ||
1062 | |||
1063 | key = asus_get_entry_by_scancode(asus, event); | ||
1064 | if (!key) | ||
1065 | return ; | ||
1066 | |||
1067 | switch (key->type) { | ||
1068 | case KE_KEY: | ||
1069 | input_report_key(asus->inputdev, key->keycode, 1); | ||
1070 | input_sync(asus->inputdev); | ||
1071 | input_report_key(asus->inputdev, key->keycode, 0); | ||
1072 | input_sync(asus->inputdev); | ||
1073 | break; | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | static int asus_input_init(struct asus_laptop *asus) | ||
1078 | { | ||
1079 | const struct key_entry *key; | ||
1080 | int result; | ||
1081 | |||
1082 | asus->inputdev = input_allocate_device(); | ||
1083 | if (!asus->inputdev) { | ||
1084 | pr_info("Unable to allocate input device\n"); | ||
1085 | return 0; | ||
1086 | } | ||
1087 | asus->inputdev->name = "Asus Laptop extra buttons"; | ||
1088 | asus->inputdev->dev.parent = &asus->platform_device->dev; | ||
1089 | asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; | ||
1090 | asus->inputdev->id.bustype = BUS_HOST; | ||
1091 | asus->inputdev->getkeycode = asus_getkeycode; | ||
1092 | asus->inputdev->setkeycode = asus_setkeycode; | ||
1093 | input_set_drvdata(asus->inputdev, asus); | ||
1094 | |||
1095 | asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), | ||
1096 | GFP_KERNEL); | ||
1097 | for (key = asus->keymap; key->type != KE_END; key++) { | ||
1098 | switch (key->type) { | ||
1099 | case KE_KEY: | ||
1100 | set_bit(EV_KEY, asus->inputdev->evbit); | ||
1101 | set_bit(key->keycode, asus->inputdev->keybit); | ||
1102 | break; | ||
1103 | } | ||
1104 | } | ||
1105 | result = input_register_device(asus->inputdev); | ||
1106 | if (result) { | ||
1107 | pr_info("Unable to register input device\n"); | ||
1108 | input_free_device(asus->inputdev); | ||
1109 | } | ||
1110 | return result; | ||
1111 | } | ||
1112 | |||
1113 | static void asus_input_exit(struct asus_laptop *asus) | ||
1114 | { | ||
1115 | if (asus->inputdev) | ||
1116 | input_unregister_device(asus->inputdev); | ||
1117 | } | ||
1118 | |||
1119 | /* | ||
1120 | * ACPI driver | ||
1121 | */ | ||
968 | static void asus_acpi_notify(struct acpi_device *device, u32 event) | 1122 | static void asus_acpi_notify(struct acpi_device *device, u32 event) |
969 | { | 1123 | { |
970 | struct asus_laptop *asus = acpi_driver_data(device); | 1124 | struct asus_laptop *asus = acpi_driver_data(device); |
971 | static struct key_entry *key; | ||
972 | u16 count; | 1125 | u16 count; |
973 | 1126 | ||
974 | /* | 1127 | /* |
@@ -990,20 +1143,7 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) | |||
990 | dev_name(&asus->device->dev), event, | 1143 | dev_name(&asus->device->dev), event, |
991 | count); | 1144 | count); |
992 | 1145 | ||
993 | if (asus->inputdev) { | 1146 | asus_input_notify(asus, event); |
994 | key = asus_get_entry_by_scancode(asus, event); | ||
995 | if (!key) | ||
996 | return ; | ||
997 | |||
998 | switch (key->type) { | ||
999 | case KE_KEY: | ||
1000 | input_report_key(asus->inputdev, key->keycode, 1); | ||
1001 | input_sync(asus->inputdev); | ||
1002 | input_report_key(asus->inputdev, key->keycode, 0); | ||
1003 | input_sync(asus->inputdev); | ||
1004 | break; | ||
1005 | } | ||
1006 | } | ||
1007 | } | 1147 | } |
1008 | 1148 | ||
1009 | #define ASUS_CREATE_DEVICE_ATTR(_name) \ | 1149 | #define ASUS_CREATE_DEVICE_ATTR(_name) \ |
@@ -1257,142 +1397,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
1257 | return AE_OK; | 1397 | return AE_OK; |
1258 | } | 1398 | } |
1259 | 1399 | ||
1260 | static int asus_input_init(struct asus_laptop *asus) | ||
1261 | { | ||
1262 | const struct key_entry *key; | ||
1263 | int result; | ||
1264 | |||
1265 | asus->inputdev = input_allocate_device(); | ||
1266 | if (!asus->inputdev) { | ||
1267 | pr_info("Unable to allocate input device\n"); | ||
1268 | return 0; | ||
1269 | } | ||
1270 | asus->inputdev->name = "Asus Laptop extra buttons"; | ||
1271 | asus->inputdev->dev.parent = &asus->platform_device->dev; | ||
1272 | asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; | ||
1273 | asus->inputdev->id.bustype = BUS_HOST; | ||
1274 | asus->inputdev->getkeycode = asus_getkeycode; | ||
1275 | asus->inputdev->setkeycode = asus_setkeycode; | ||
1276 | input_set_drvdata(asus->inputdev, asus); | ||
1277 | |||
1278 | asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), | ||
1279 | GFP_KERNEL); | ||
1280 | for (key = asus->keymap; key->type != KE_END; key++) { | ||
1281 | switch (key->type) { | ||
1282 | case KE_KEY: | ||
1283 | set_bit(EV_KEY, asus->inputdev->evbit); | ||
1284 | set_bit(key->keycode, asus->inputdev->keybit); | ||
1285 | break; | ||
1286 | } | ||
1287 | } | ||
1288 | result = input_register_device(asus->inputdev); | ||
1289 | if (result) { | ||
1290 | pr_info("Unable to register input device\n"); | ||
1291 | input_free_device(asus->inputdev); | ||
1292 | } | ||
1293 | return result; | ||
1294 | } | ||
1295 | |||
1296 | static void asus_backlight_exit(struct asus_laptop *asus) | ||
1297 | { | ||
1298 | if (asus->backlight_device) | ||
1299 | backlight_device_unregister(asus->backlight_device); | ||
1300 | } | ||
1301 | |||
1302 | #define ASUS_LED_UNREGISTER(object) \ | ||
1303 | if (object##_led.dev) \ | ||
1304 | led_classdev_unregister(&object##_led) | ||
1305 | |||
1306 | static void asus_led_exit(struct asus_laptop *asus) | ||
1307 | { | ||
1308 | ASUS_LED_UNREGISTER(mled); | ||
1309 | ASUS_LED_UNREGISTER(tled); | ||
1310 | ASUS_LED_UNREGISTER(pled); | ||
1311 | ASUS_LED_UNREGISTER(rled); | ||
1312 | ASUS_LED_UNREGISTER(gled); | ||
1313 | ASUS_LED_UNREGISTER(kled); | ||
1314 | if (asus->leds.workqueue) { | ||
1315 | destroy_workqueue(asus->leds.workqueue); | ||
1316 | asus->leds.workqueue = NULL; | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | static void asus_input_exit(struct asus_laptop *asus) | ||
1321 | { | ||
1322 | if (asus->inputdev) | ||
1323 | input_unregister_device(asus->inputdev); | ||
1324 | } | ||
1325 | |||
1326 | static int asus_backlight_init(struct asus_laptop *asus) | ||
1327 | { | ||
1328 | struct backlight_device *bd; | ||
1329 | struct device *dev = &asus->platform_device->dev; | ||
1330 | |||
1331 | if (brightness_set_handle && lcd_switch_handle) { | ||
1332 | bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, | ||
1333 | asus, &asusbl_ops); | ||
1334 | if (IS_ERR(bd)) { | ||
1335 | pr_err("Could not register asus backlight device\n"); | ||
1336 | asus->backlight_device = NULL; | ||
1337 | return PTR_ERR(bd); | ||
1338 | } | ||
1339 | |||
1340 | asus->backlight_device = bd; | ||
1341 | |||
1342 | bd->props.max_brightness = 15; | ||
1343 | bd->props.brightness = read_brightness(NULL); | ||
1344 | bd->props.power = FB_BLANK_UNBLANK; | ||
1345 | backlight_update_status(bd); | ||
1346 | } | ||
1347 | return 0; | ||
1348 | } | ||
1349 | |||
1350 | /* | ||
1351 | * Ugly macro, need to fix that later | ||
1352 | */ | ||
1353 | #define ASUS_LED_REGISTER(asus, object, _name, max) \ | ||
1354 | do { \ | ||
1355 | struct led_classdev *ldev = &asus->leds.object; \ | ||
1356 | if (!object##_set_handle) \ | ||
1357 | break ; \ | ||
1358 | \ | ||
1359 | INIT_WORK(&asus->leds.object##_work, object##_led_update); \ | ||
1360 | ldev->name = "asus::" _name; \ | ||
1361 | ldev->brightness_set = object##_led_set; \ | ||
1362 | ldev->max_brightness = max; \ | ||
1363 | rv = led_classdev_register(&asus->platform_device->dev, ldev); \ | ||
1364 | if (rv) \ | ||
1365 | goto error; \ | ||
1366 | } while (0) | ||
1367 | |||
1368 | static int asus_led_init(struct asus_laptop *asus) | ||
1369 | { | ||
1370 | int rv; | ||
1371 | |||
1372 | /* | ||
1373 | * Functions that actually update the LED's are called from a | ||
1374 | * workqueue. By doing this as separate work rather than when the LED | ||
1375 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | ||
1376 | * potentially bad time, such as a timer interrupt. | ||
1377 | */ | ||
1378 | asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); | ||
1379 | if (!asus->leds.workqueue) | ||
1380 | return -ENOMEM; | ||
1381 | |||
1382 | ASUS_LED_REGISTER(asus, mled, "mail", 1); | ||
1383 | ASUS_LED_REGISTER(asus, tled, "touchpad", 1); | ||
1384 | ASUS_LED_REGISTER(asus, rled, "record", 1); | ||
1385 | ASUS_LED_REGISTER(asus, pled, "phone", 1); | ||
1386 | ASUS_LED_REGISTER(asus, gled, "gaming", 1); | ||
1387 | if (kled_set_handle && kled_get_handle) | ||
1388 | ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); | ||
1389 | error: | ||
1390 | if (rv) | ||
1391 | asus_led_exit(asus); | ||
1392 | return rv; | ||
1393 | } | ||
1394 | |||
1395 | |||
1396 | static bool asus_device_present; | 1400 | static bool asus_device_present; |
1397 | 1401 | ||
1398 | static int __devinit asus_acpi_init(struct asus_laptop *asus) | 1402 | static int __devinit asus_acpi_init(struct asus_laptop *asus) |
@@ -1414,8 +1418,10 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) | |||
1414 | asus_laptop_add_fs(asus); | 1418 | asus_laptop_add_fs(asus); |
1415 | 1419 | ||
1416 | /* WLED and BLED are on by default */ | 1420 | /* WLED and BLED are on by default */ |
1417 | write_status(asus, bt_switch_handle, 1, BT_ON); | 1421 | if (bluetooth_status >= 0) |
1418 | write_status(asus, wl_switch_handle, 1, WL_ON); | 1422 | write_status(asus, bt_switch_handle, !!bluetooth_status, BT_ON); |
1423 | if (wireless_status >= 0) | ||
1424 | write_status(asus, wl_switch_handle, !!wireless_status, WL_ON); | ||
1419 | 1425 | ||
1420 | /* If the h/w switch is off, we need to check the real status */ | 1426 | /* If the h/w switch is off, we need to check the real status */ |
1421 | write_status(asus, NULL, read_status(asus, BT_ON), BT_ON); | 1427 | write_status(asus, NULL, read_status(asus, BT_ON), BT_ON); |
@@ -1432,8 +1438,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) | |||
1432 | asus->ledd_status = 0xFFF; | 1438 | asus->ledd_status = 0xFFF; |
1433 | 1439 | ||
1434 | /* Set initial values of light sensor and level */ | 1440 | /* Set initial values of light sensor and level */ |
1435 | hotk->light_switch = 0; /* Default to light sensor disabled */ | 1441 | asus->light_switch = 0; /* Default to light sensor disabled */ |
1436 | hotk->light_level = 5; /* level 5 for sensor sensitivity */ | 1442 | asus->light_level = 5; /* level 5 for sensor sensitivity */ |
1437 | 1443 | ||
1438 | if (ls_switch_handle) | 1444 | if (ls_switch_handle) |
1439 | set_light_sens_switch(asus, asus->light_switch); | 1445 | set_light_sens_switch(asus, asus->light_switch); |