diff options
-rw-r--r-- | drivers/leds/Kconfig | 24 | ||||
-rw-r--r-- | drivers/leds/Makefile | 1 | ||||
-rw-r--r-- | drivers/leds/leds-clevo-mail.c | 182 |
3 files changed, 207 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index ec568fa1c6cc..cf3a6d4d9475 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -114,6 +114,30 @@ config LEDS_CM_X270 | |||
114 | help | 114 | help |
115 | This option enables support for the CM-X270 LEDs. | 115 | This option enables support for the CM-X270 LEDs. |
116 | 116 | ||
117 | config LEDS_CLEVO_MAIL | ||
118 | tristate "Mail LED on Clevo notebook (EXPERIMENTAL)" | ||
119 | depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL | ||
120 | help | ||
121 | This driver makes the mail LED accessible from userspace | ||
122 | programs through the leds subsystem. This LED have three | ||
123 | known mode: off, blink at 0.5Hz and blink at 1Hz. | ||
124 | |||
125 | As this LED cannot change it's brightness it blinks instead. | ||
126 | The brightness value 0 means off, 1..127 means blink at 0.5Hz | ||
127 | and 128..255 means blink at 1Hz. | ||
128 | |||
129 | This module can drive the mail LED for the following notebooks: | ||
130 | |||
131 | Clevo D410J | ||
132 | Clevo D410V | ||
133 | Clevo D400V/D470V (not tested, but might work) | ||
134 | Clevo M540N | ||
135 | Clevo M5x0N (not tested, but might work) | ||
136 | Positivo Mobile (Clevo M5x0V) | ||
137 | |||
138 | To compile this driver as a module, choose M here: the | ||
139 | module will be called leds-clevo-mail. | ||
140 | |||
117 | comment "LED Triggers" | 141 | comment "LED Triggers" |
118 | 142 | ||
119 | config LEDS_TRIGGERS | 143 | config LEDS_TRIGGERS |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index a60de1b46c2c..e433e2f4e52b 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o | |||
19 | obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o | 19 | obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o |
20 | obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o | 20 | obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o |
21 | obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o | 21 | obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o |
22 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o | ||
22 | 23 | ||
23 | # LED Triggers | 24 | # LED Triggers |
24 | obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o | 25 | obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o |
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c new file mode 100644 index 000000000000..50aaa0b33810 --- /dev/null +++ b/drivers/leds/leds-clevo-mail.c | |||
@@ -0,0 +1,182 @@ | |||
1 | |||
2 | #include <linux/module.h> | ||
3 | |||
4 | #include <linux/platform_device.h> | ||
5 | #include <linux/err.h> | ||
6 | #include <linux/leds.h> | ||
7 | |||
8 | #include <linux/io.h> | ||
9 | #include <linux/dmi.h> | ||
10 | |||
11 | #include <linux/i8042.h> | ||
12 | |||
13 | #define CLEVO_MAIL_LED_OFF 0x0084 | ||
14 | #define CLEVO_MAIL_LED_BLINK_1HZ 0x008A | ||
15 | #define CLEVO_MAIL_LED_BLINK_0_5HZ 0x0083 | ||
16 | |||
17 | MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>"); | ||
18 | MODULE_DESCRIPTION("Clevo mail LED driver"); | ||
19 | MODULE_LICENSE("GPL"); | ||
20 | |||
21 | static unsigned int __initdata nodetect; | ||
22 | module_param_named(nodetect, nodetect, bool, 0); | ||
23 | MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection"); | ||
24 | |||
25 | static struct platform_device *pdev; | ||
26 | |||
27 | static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id) | ||
28 | { | ||
29 | printk(KERN_INFO KBUILD_MODNAME ": '%s' found\n", id->ident); | ||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * struct mail_led_whitelist - List of known good models | ||
35 | * | ||
36 | * Contains the known good models this driver is compatible with. | ||
37 | * When adding a new model try to be as strict as possible. This | ||
38 | * makes it possible to keep the false positives (the model is | ||
39 | * detected as working, but in reality it is not) as low as | ||
40 | * possible. | ||
41 | */ | ||
42 | static struct dmi_system_id __initdata mail_led_whitelist[] = { | ||
43 | { | ||
44 | .callback = clevo_mail_led_dmi_callback, | ||
45 | .ident = "Clevo D410J", | ||
46 | .matches = { | ||
47 | DMI_MATCH(DMI_SYS_VENDOR, "VIA"), | ||
48 | DMI_MATCH(DMI_PRODUCT_NAME, "K8N800"), | ||
49 | DMI_MATCH(DMI_PRODUCT_VERSION, "VT8204B") | ||
50 | } | ||
51 | }, | ||
52 | { | ||
53 | .callback = clevo_mail_led_dmi_callback, | ||
54 | .ident = "Clevo M5x0N", | ||
55 | .matches = { | ||
56 | DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."), | ||
57 | DMI_MATCH(DMI_PRODUCT_NAME, "M5x0N") | ||
58 | } | ||
59 | }, | ||
60 | { | ||
61 | .callback = clevo_mail_led_dmi_callback, | ||
62 | .ident = "Positivo Mobile", | ||
63 | .matches = { | ||
64 | DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "), | ||
65 | DMI_MATCH(DMI_BOARD_NAME, "M5X0V "), | ||
66 | DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"), | ||
67 | DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198") | ||
68 | } | ||
69 | }, | ||
70 | { | ||
71 | .callback = clevo_mail_led_dmi_callback, | ||
72 | .ident = "Clevo D410V", | ||
73 | .matches = { | ||
74 | DMI_MATCH(DMI_BOARD_VENDOR, "Clevo, Co."), | ||
75 | DMI_MATCH(DMI_BOARD_NAME, "D400V/D470V"), | ||
76 | DMI_MATCH(DMI_BOARD_VERSION, "SS78B"), | ||
77 | DMI_MATCH(DMI_PRODUCT_VERSION, "Rev. A1") | ||
78 | } | ||
79 | }, | ||
80 | { } | ||
81 | }; | ||
82 | |||
83 | static void clevo_mail_led_set(struct led_classdev *led_cdev, | ||
84 | enum led_brightness value) | ||
85 | { | ||
86 | if (value == LED_OFF) | ||
87 | i8042_command(NULL, CLEVO_MAIL_LED_OFF); | ||
88 | else if (value <= LED_HALF) | ||
89 | i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ); | ||
90 | else | ||
91 | i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ); | ||
92 | |||
93 | } | ||
94 | |||
95 | static struct led_classdev clevo_mail_led = { | ||
96 | .name = "clevo", | ||
97 | .brightness_set = clevo_mail_led_set, | ||
98 | }; | ||
99 | |||
100 | static int __init clevo_mail_led_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | return led_classdev_register(&pdev->dev, &clevo_mail_led); | ||
103 | } | ||
104 | |||
105 | static int clevo_mail_led_remove(struct platform_device *pdev) | ||
106 | { | ||
107 | led_classdev_unregister(&clevo_mail_led); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | #ifdef CONFIG_PM | ||
112 | static int clevo_mail_led_suspend(struct platform_device *dev, | ||
113 | pm_message_t state) | ||
114 | { | ||
115 | led_classdev_suspend(&clevo_mail_led); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int clevo_mail_led_resume(struct platform_device *dev) | ||
120 | { | ||
121 | led_classdev_resume(&clevo_mail_led); | ||
122 | return 0; | ||
123 | } | ||
124 | #else | ||
125 | #define clevo_mail_led_suspend NULL | ||
126 | #define clevo_mail_led_resume NULL | ||
127 | #endif | ||
128 | |||
129 | static struct platform_driver clevo_mail_led_driver = { | ||
130 | .probe = clevo_mail_led_probe, | ||
131 | .remove = clevo_mail_led_remove, | ||
132 | .suspend = clevo_mail_led_suspend, | ||
133 | .resume = clevo_mail_led_resume, | ||
134 | .driver = { | ||
135 | .name = KBUILD_MODNAME, | ||
136 | }, | ||
137 | }; | ||
138 | |||
139 | static int __init clevo_mail_led_init(void) | ||
140 | { | ||
141 | int error = 0; | ||
142 | int count = 0; | ||
143 | |||
144 | /* Check with the help of DMI if we are running on supported hardware */ | ||
145 | if (!nodetect) { | ||
146 | count = dmi_check_system(mail_led_whitelist); | ||
147 | } else { | ||
148 | count = 1; | ||
149 | printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. " | ||
150 | "If the driver works on your hardware please " | ||
151 | "report model and the output of dmidecode in tracker " | ||
152 | "at http://sourceforge.net/projects/clevo-mailled/\n"); | ||
153 | } | ||
154 | |||
155 | if (!count) | ||
156 | return -ENODEV; | ||
157 | |||
158 | pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); | ||
159 | if (!IS_ERR(pdev)) { | ||
160 | error = platform_driver_probe(&clevo_mail_led_driver, | ||
161 | clevo_mail_led_probe); | ||
162 | if (error) { | ||
163 | printk(KERN_ERR KBUILD_MODNAME | ||
164 | ": Can't probe platform driver\n"); | ||
165 | platform_device_unregister(pdev); | ||
166 | } | ||
167 | } else | ||
168 | error = PTR_ERR(pdev); | ||
169 | |||
170 | return error; | ||
171 | } | ||
172 | |||
173 | static void __exit clevo_mail_led_exit(void) | ||
174 | { | ||
175 | platform_device_unregister(pdev); | ||
176 | platform_driver_unregister(&clevo_mail_led_driver); | ||
177 | |||
178 | clevo_mail_led_set(NULL, LED_OFF); | ||
179 | } | ||
180 | |||
181 | module_init(clevo_mail_led_init); | ||
182 | module_exit(clevo_mail_led_exit); | ||