diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 88e29074ac90..4326f536f849 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -65,9 +65,12 @@ config INPUT_COBALT_BTNS config INPUT_WISTRON_BTNS tristate "x86 Wistron laptop button interface" depends on X86 && !X86_64 + select NEW_LEDS + select LEDS_CLASS help Say Y here for support of Winstron laptop button interface, used on - laptops of various brands, including Acer and Fujitsu-Siemens. + laptops of various brands, including Acer and Fujitsu-Siemens. If + available, mail and wifi leds will be controlable via /sys/class/leds. To compile this driver as a module, choose M here: the module will be called wistron_btns. diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 320262aa4c17..d58ddcab601f 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -31,6 +31,7 @@ #include #include #include +#include /* * Number of attempts to read data from queue per poll; @@ -48,11 +49,12 @@ /* BIOS subsystem IDs */ #define WIFI 0x35 #define BLUETOOTH 0x34 +#define MAIL_LED 0x31 MODULE_AUTHOR("Miloslav Trmac "); MODULE_DESCRIPTION("Wistron laptop button driver"); MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.2"); +MODULE_VERSION("0.3"); static int force; /* = 0; */ module_param(force, bool, 0); @@ -253,6 +255,7 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; static const struct key_entry *keymap; /* = NULL; Current key map */ static int have_wifi; static int have_bluetooth; +static int have_leds; static int __init dmi_matched(struct dmi_system_id *dmi) { @@ -265,6 +268,8 @@ static int __init dmi_matched(struct dmi_system_id *dmi) else if (key->type == KE_BLUETOOTH) have_bluetooth = 1; } + have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED); + return 1; } @@ -1030,6 +1035,83 @@ static void report_switch(unsigned code, int value) input_sync(input_dev); } + + /* led management */ +static void wistron_mail_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0); +} + +/* same as setting up wifi card, but for laptops on which the led is managed */ +static void wistron_wifi_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0); +} + +static struct led_classdev wistron_mail_led = { + .name = "mail:green", + .brightness_set = wistron_mail_led_set, +}; + +static struct led_classdev wistron_wifi_led = { + .name = "wifi:red", + .brightness_set = wistron_wifi_led_set, +}; + +static void __devinit wistron_led_init(struct device *parent) +{ + if (have_leds & FE_WIFI_LED) { + u16 wifi = bios_get_default_setting(WIFI); + if (wifi & 1) { + wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; + if (led_classdev_register(parent, &wistron_wifi_led)) + have_leds &= ~FE_WIFI_LED; + else + bios_set_state(WIFI, wistron_wifi_led.brightness); + + } else + have_leds &= ~FE_WIFI_LED; + } + + if (have_leds & FE_MAIL_LED) { + /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ + wistron_mail_led.brightness = LED_OFF; + if (led_classdev_register(parent, &wistron_mail_led)) + have_leds &= ~FE_MAIL_LED; + else + bios_set_state(MAIL_LED, wistron_mail_led.brightness); + } +} + +static void __devexit wistron_led_remove(void) +{ + if (have_leds & FE_MAIL_LED) + led_classdev_unregister(&wistron_mail_led); + + if (have_leds & FE_WIFI_LED) + led_classdev_unregister(&wistron_wifi_led); +} + +static inline void wistron_led_suspend(void) +{ + if (have_leds & FE_MAIL_LED) + led_classdev_suspend(&wistron_mail_led); + + if (have_leds & FE_WIFI_LED) + led_classdev_suspend(&wistron_wifi_led); +} + +static inline void wistron_led_resume(void) +{ + if (have_leds & FE_MAIL_LED) + led_classdev_resume(&wistron_mail_led); + + if (have_leds & FE_WIFI_LED) + led_classdev_resume(&wistron_wifi_led); +} + /* Driver core */ static int wifi_enabled; @@ -1135,6 +1217,7 @@ static int __devinit wistron_probe(struct platform_device *dev) bios_set_state(BLUETOOTH, bluetooth_enabled); } + wistron_led_init(&dev->dev); poll_bios(1); /* Flush stale event queue and arm timer */ return 0; @@ -1143,6 +1226,7 @@ static int __devinit wistron_probe(struct platform_device *dev) static int __devexit wistron_remove(struct platform_device *dev) { del_timer_sync(&poll_timer); + wistron_led_remove(); input_unregister_device(input_dev); bios_detach(); @@ -1160,6 +1244,7 @@ static int wistron_suspend(struct platform_device *dev, pm_message_t state) if (have_bluetooth) bios_set_state(BLUETOOTH, 0); + wistron_led_suspend(); return 0; } @@ -1171,6 +1256,7 @@ static int wistron_resume(struct platform_device *dev) if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); + wistron_led_resume(); poll_bios(1); return 0;