Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/leds/leds-clevo-mail.c
15109 views
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 <[email protected]>");
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 D400P",
73
.matches = {
74
DMI_MATCH(DMI_BOARD_VENDOR, "Clevo"),
75
DMI_MATCH(DMI_BOARD_NAME, "D400P"),
76
DMI_MATCH(DMI_BOARD_VERSION, "Rev.A"),
77
DMI_MATCH(DMI_PRODUCT_VERSION, "0106")
78
}
79
},
80
{
81
.callback = clevo_mail_led_dmi_callback,
82
.ident = "Clevo D410V",
83
.matches = {
84
DMI_MATCH(DMI_BOARD_VENDOR, "Clevo, Co."),
85
DMI_MATCH(DMI_BOARD_NAME, "D400V/D470V"),
86
DMI_MATCH(DMI_BOARD_VERSION, "SS78B"),
87
DMI_MATCH(DMI_PRODUCT_VERSION, "Rev. A1")
88
}
89
},
90
{ }
91
};
92
93
static void clevo_mail_led_set(struct led_classdev *led_cdev,
94
enum led_brightness value)
95
{
96
i8042_lock_chip();
97
98
if (value == LED_OFF)
99
i8042_command(NULL, CLEVO_MAIL_LED_OFF);
100
else if (value <= LED_HALF)
101
i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
102
else
103
i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
104
105
i8042_unlock_chip();
106
107
}
108
109
static int clevo_mail_led_blink(struct led_classdev *led_cdev,
110
unsigned long *delay_on,
111
unsigned long *delay_off)
112
{
113
int status = -EINVAL;
114
115
i8042_lock_chip();
116
117
if (*delay_on == 0 /* ms */ && *delay_off == 0 /* ms */) {
118
/* Special case: the leds subsystem requested us to
119
* chose one user friendly blinking of the LED, and
120
* start it. Let's blink the led slowly (0.5Hz).
121
*/
122
*delay_on = 1000; /* ms */
123
*delay_off = 1000; /* ms */
124
i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
125
status = 0;
126
127
} else if (*delay_on == 500 /* ms */ && *delay_off == 500 /* ms */) {
128
/* blink the led with 1Hz */
129
i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
130
status = 0;
131
132
} else if (*delay_on == 1000 /* ms */ && *delay_off == 1000 /* ms */) {
133
/* blink the led with 0.5Hz */
134
i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
135
status = 0;
136
137
} else {
138
printk(KERN_DEBUG KBUILD_MODNAME
139
": clevo_mail_led_blink(..., %lu, %lu),"
140
" returning -EINVAL (unsupported)\n",
141
*delay_on, *delay_off);
142
}
143
144
i8042_unlock_chip();
145
146
return status;
147
}
148
149
static struct led_classdev clevo_mail_led = {
150
.name = "clevo::mail",
151
.brightness_set = clevo_mail_led_set,
152
.blink_set = clevo_mail_led_blink,
153
.flags = LED_CORE_SUSPENDRESUME,
154
};
155
156
static int __devinit clevo_mail_led_probe(struct platform_device *pdev)
157
{
158
return led_classdev_register(&pdev->dev, &clevo_mail_led);
159
}
160
161
static int clevo_mail_led_remove(struct platform_device *pdev)
162
{
163
led_classdev_unregister(&clevo_mail_led);
164
return 0;
165
}
166
167
static struct platform_driver clevo_mail_led_driver = {
168
.probe = clevo_mail_led_probe,
169
.remove = clevo_mail_led_remove,
170
.driver = {
171
.name = KBUILD_MODNAME,
172
.owner = THIS_MODULE,
173
},
174
};
175
176
static int __init clevo_mail_led_init(void)
177
{
178
int error = 0;
179
int count = 0;
180
181
/* Check with the help of DMI if we are running on supported hardware */
182
if (!nodetect) {
183
count = dmi_check_system(mail_led_whitelist);
184
} else {
185
count = 1;
186
printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
187
"If the driver works on your hardware please "
188
"report model and the output of dmidecode in tracker "
189
"at http://sourceforge.net/projects/clevo-mailled/\n");
190
}
191
192
if (!count)
193
return -ENODEV;
194
195
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
196
if (!IS_ERR(pdev)) {
197
error = platform_driver_probe(&clevo_mail_led_driver,
198
clevo_mail_led_probe);
199
if (error) {
200
printk(KERN_ERR KBUILD_MODNAME
201
": Can't probe platform driver\n");
202
platform_device_unregister(pdev);
203
}
204
} else
205
error = PTR_ERR(pdev);
206
207
return error;
208
}
209
210
static void __exit clevo_mail_led_exit(void)
211
{
212
platform_device_unregister(pdev);
213
platform_driver_unregister(&clevo_mail_led_driver);
214
215
clevo_mail_led_set(NULL, LED_OFF);
216
}
217
218
module_init(clevo_mail_led_init);
219
module_exit(clevo_mail_led_exit);
220
221