diff options
-rw-r--r-- | drivers/platform/x86/asus-laptop.c | 79 |
1 files changed, 77 insertions, 2 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 652902e6f20..0fb4e597151 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -86,6 +86,7 @@ #define GLED_ON 0x40 //Gaming LED #define LCD_ON 0x80 //LCD backlight #define GPS_ON 0x100 //GPS +#define KEY_ON 0x200 //Keyboard backlight #define ASUS_LOG ASUS_HOTK_FILE ": " #define ASUS_ERR KERN_ERR ASUS_LOG @@ -172,6 +173,10 @@ ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); +/* Keyboard light */ +ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB"); +ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); + /* * This is the main structure, we can use it to store anything interesting * about the hotk device @@ -263,6 +268,7 @@ ASUS_LED(tled, "touchpad", 1); ASUS_LED(rled, "record", 1); ASUS_LED(pled, "phone", 1); ASUS_LED(gled, "gaming", 1); +ASUS_LED(kled, "kbd_backlight", 3); struct key_entry { char type; @@ -419,6 +425,60 @@ ASUS_LED_HANDLER(rled, RLED_ON); ASUS_LED_HANDLER(tled, TLED_ON); ASUS_LED_HANDLER(gled, GLED_ON); +/* + * Keyboard backlight + */ +static int get_kled_lvl(void) +{ + unsigned long long kblv; + struct acpi_object_list params; + union acpi_object in_obj; + acpi_status rv; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = 2; + + rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv); + if (ACPI_FAILURE(rv)) { + pr_warning("Error reading kled level\n"); + return 0; + } + return kblv; +} + +static int set_kled_lvl(int kblv) +{ + if (kblv > 0) + kblv = (1 << 7) | (kblv & 0x7F); + else + kblv = 0; + + if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) { + pr_warning("Keyboard LED display write failed\n"); + return -EINVAL; + } + return 0; +} + +static void kled_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + kled_led_wk = value; + queue_work(led_workqueue, &kled_led_work); +} + +static void kled_led_update(struct work_struct *ignored) +{ + set_kled_lvl(kled_led_wk); +} + +static enum led_brightness kled_led_get(struct led_classdev *led_cdev) +{ + return get_kled_lvl(); +} + static int get_lcd_state(void) { return read_status(LCD_ON); @@ -1059,6 +1119,9 @@ static int asus_hotk_get_info(void) ASUS_HANDLE_INIT(ledd_set); + ASUS_HANDLE_INIT(kled_set); + ASUS_HANDLE_INIT(kled_get); + /* * The HWRS method return informations about the hardware. * 0x80 bit is for WLAN, 0x100 for Bluetooth. @@ -1190,6 +1253,10 @@ static int asus_hotk_add(struct acpi_device *device) /* LCD Backlight is on by default */ write_status(NULL, 1, LCD_ON); + /* Keyboard Backlight is on by default */ + if (kled_set_handle) + set_kled_lvl(1); + /* LED display is off by default */ hotk->ledd_status = 0xFFF; @@ -1244,6 +1311,7 @@ static void asus_led_exit(void) ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); ASUS_LED_UNREGISTER(gled); + ASUS_LED_UNREGISTER(kled); } static void asus_input_exit(void) @@ -1323,13 +1391,20 @@ static int asus_led_init(struct device *dev) if (rv) goto out4; + if (kled_set_handle && kled_get_handle) + rv = ASUS_LED_REGISTER(kled, dev); + if (rv) + goto out5; + led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) - goto out5; + goto out6; return 0; -out5: +out6: rv = -ENOMEM; + ASUS_LED_UNREGISTER(kled); +out5: ASUS_LED_UNREGISTER(gled); out4: ASUS_LED_UNREGISTER(pled); |