diff options
Diffstat (limited to 'drivers/leds/leds-clevo-mail.c')
-rw-r--r-- | drivers/leds/leds-clevo-mail.c | 182 |
1 files changed, 182 insertions, 0 deletions
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); | ||