summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/input/misc/Kconfig5
-rw-r--r--drivers/input/misc/wistron_btns.c88
2 files changed, 91 insertions, 2 deletions
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 <linux/timer.h>
#include <linux/types.h>
#include <linux/platform_device.h>
+#include <linux/leds.h>
/*
* 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 <mitr@volny.cz>");
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;