1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*-*-linux-c-*-*/
3
4 /*
5 Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
6
7 */
8
9 /*
10 * msi-laptop.c - MSI S270 laptop support. This laptop is sold under
11 * various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
12 *
13 * Driver also supports S271, S420 models.
14 *
15 * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
16 *
17 * lcd_level - Screen brightness: contains a single integer in the
18 * range 0..8. (rw)
19 *
20 * auto_brightness - Enable automatic brightness control: contains
21 * either 0 or 1. If set to 1 the hardware adjusts the screen
22 * brightness automatically when the power cord is
23 * plugged/unplugged. (rw)
24 *
25 * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
26 *
27 * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
28 * Please note that this file is constantly 0 if no Bluetooth
29 * hardware is available. (ro)
30 *
31 * In addition to these platform device attributes the driver
32 * registers itself in the Linux backlight control subsystem and is
33 * available to userspace under /sys/class/backlight/msi-laptop-bl/.
34 *
35 * This driver might work on other laptops produced by MSI. If you
36 * want to try it you can pass force=1 as argument to the module which
37 * will force it to load even when the DMI data doesn't identify the
38 * laptop as MSI S270. YMMV.
39 */
40
41 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
42
43 #include <linux/module.h>
44 #include <linux/kernel.h>
45 #include <linux/init.h>
46 #include <linux/acpi.h>
47 #include <linux/dmi.h>
48 #include <linux/backlight.h>
49 #include <linux/platform_device.h>
50 #include <linux/rfkill.h>
51 #include <linux/i8042.h>
52 #include <linux/input.h>
53 #include <linux/input/sparse-keymap.h>
54 #include <acpi/video.h>
55
56 #define MSI_DRIVER_VERSION "0.5"
57
58 #define MSI_LCD_LEVEL_MAX 9
59
60 #define MSI_EC_COMMAND_WIRELESS 0x10
61 #define MSI_EC_COMMAND_LCD_LEVEL 0x11
62
63 #define MSI_STANDARD_EC_COMMAND_ADDRESS 0x2e
64 #define MSI_STANDARD_EC_BLUETOOTH_MASK (1 << 0)
65 #define MSI_STANDARD_EC_WEBCAM_MASK (1 << 1)
66 #define MSI_STANDARD_EC_WLAN_MASK (1 << 3)
67 #define MSI_STANDARD_EC_3G_MASK (1 << 4)
68
69 /* For set SCM load flag to disable BIOS fn key */
70 #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
71 #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
72
73 #define MSI_STANDARD_EC_FUNCTIONS_ADDRESS 0xe4
74 /* Power LED is orange - Turbo mode */
75 #define MSI_STANDARD_EC_TURBO_MASK (1 << 1)
76 /* Power LED is green - ECO mode */
77 #define MSI_STANDARD_EC_ECO_MASK (1 << 3)
78 /* Touchpad is turned on */
79 #define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
80 /* If this bit != bit 1, turbo mode can't be toggled */
81 #define MSI_STANDARD_EC_TURBO_COOLDOWN_MASK (1 << 7)
82
83 #define MSI_STANDARD_EC_FAN_ADDRESS 0x33
84 /* If zero, fan rotates at maximal speed */
85 #define MSI_STANDARD_EC_AUTOFAN_MASK (1 << 0)
86
87 #ifdef CONFIG_PM_SLEEP
88 static int msi_laptop_resume(struct device *device);
89 #endif
90 static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
91
92 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
93
94 static bool force;
95 module_param(force, bool, 0);
96 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
97
98 static int auto_brightness;
99 module_param(auto_brightness, int, 0);
100 MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
101
102 static const struct key_entry msi_laptop_keymap[] = {
103 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */
104 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */
105 {KE_END, 0}
106 };
107
108 static struct input_dev *msi_laptop_input_dev;
109
110 static int wlan_s, bluetooth_s, threeg_s;
111 static int threeg_exists;
112 static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
113
114 /* MSI laptop quirks */
115 struct quirk_entry {
116 bool old_ec_model;
117
118 /* Some MSI 3G netbook only have one fn key to control
119 * Wlan/Bluetooth/3G, those netbook will load the SCM (windows app) to
120 * disable the original Wlan/Bluetooth control by BIOS when user press
121 * fn key, then control Wlan/Bluetooth/3G by SCM (software control by
122 * OS). Without SCM, user cann't on/off 3G module on those 3G netbook.
123 * On Linux, msi-laptop driver will do the same thing to disable the
124 * original BIOS control, then might need use HAL or other userland
125 * application to do the software control that simulate with SCM.
126 * e.g. MSI N034 netbook
127 */
128 bool load_scm_model;
129
130 /* Some MSI laptops need delay before reading from EC */
131 bool ec_delay;
132
133 /* Some MSI Wind netbooks (e.g. MSI Wind U100) need loading SCM to get
134 * some features working (e.g. ECO mode), but we cannot change
135 * Wlan/Bluetooth state in software and we can only read its state.
136 */
137 bool ec_read_only;
138 };
139
140 static struct quirk_entry *quirks;
141
142 /* Hardware access */
143
set_lcd_level(int level)144 static int set_lcd_level(int level)
145 {
146 u8 buf[2];
147
148 if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
149 return -EINVAL;
150
151 buf[0] = 0x80;
152 buf[1] = (u8) (level*31);
153
154 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf),
155 NULL, 0);
156 }
157
get_lcd_level(void)158 static int get_lcd_level(void)
159 {
160 u8 wdata = 0, rdata;
161 int result;
162
163 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
164 &rdata, 1);
165 if (result < 0)
166 return result;
167
168 return (int) rdata / 31;
169 }
170
get_auto_brightness(void)171 static int get_auto_brightness(void)
172 {
173 u8 wdata = 4, rdata;
174 int result;
175
176 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
177 &rdata, 1);
178 if (result < 0)
179 return result;
180
181 return !!(rdata & 8);
182 }
183
set_auto_brightness(int enable)184 static int set_auto_brightness(int enable)
185 {
186 u8 wdata[2], rdata;
187 int result;
188
189 wdata[0] = 4;
190
191 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1,
192 &rdata, 1);
193 if (result < 0)
194 return result;
195
196 wdata[0] = 0x84;
197 wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
198
199 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2,
200 NULL, 0);
201 }
202
set_device_state(const char * buf,size_t count,u8 mask)203 static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
204 {
205 int status;
206 u8 wdata = 0, rdata;
207 int result;
208
209 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
210 return -EINVAL;
211
212 if (quirks->ec_read_only)
213 return 0;
214
215 /* read current device state */
216 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
217 if (result < 0)
218 return result;
219
220 if (!!(rdata & mask) != status) {
221 /* reverse device bit */
222 if (rdata & mask)
223 wdata = rdata & ~mask;
224 else
225 wdata = rdata | mask;
226
227 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
228 if (result < 0)
229 return result;
230 }
231
232 return count;
233 }
234
get_wireless_state(int * wlan,int * bluetooth)235 static int get_wireless_state(int *wlan, int *bluetooth)
236 {
237 u8 wdata = 0, rdata;
238 int result;
239
240 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
241 if (result < 0)
242 return result;
243
244 if (wlan)
245 *wlan = !!(rdata & 8);
246
247 if (bluetooth)
248 *bluetooth = !!(rdata & 128);
249
250 return 0;
251 }
252
get_wireless_state_ec_standard(void)253 static int get_wireless_state_ec_standard(void)
254 {
255 u8 rdata;
256 int result;
257
258 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
259 if (result < 0)
260 return result;
261
262 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
263
264 bluetooth_s = !!(rdata & MSI_STANDARD_EC_BLUETOOTH_MASK);
265
266 threeg_s = !!(rdata & MSI_STANDARD_EC_3G_MASK);
267
268 return 0;
269 }
270
get_threeg_exists(void)271 static int get_threeg_exists(void)
272 {
273 u8 rdata;
274 int result;
275
276 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
277 if (result < 0)
278 return result;
279
280 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
281
282 return 0;
283 }
284
285 /* Backlight device stuff */
286
bl_get_brightness(struct backlight_device * b)287 static int bl_get_brightness(struct backlight_device *b)
288 {
289 return get_lcd_level();
290 }
291
292
bl_update_status(struct backlight_device * b)293 static int bl_update_status(struct backlight_device *b)
294 {
295 return set_lcd_level(b->props.brightness);
296 }
297
298 static const struct backlight_ops msibl_ops = {
299 .get_brightness = bl_get_brightness,
300 .update_status = bl_update_status,
301 };
302
303 static struct backlight_device *msibl_device;
304
305 /* Platform device */
306
show_wlan(struct device * dev,struct device_attribute * attr,char * buf)307 static ssize_t show_wlan(struct device *dev,
308 struct device_attribute *attr, char *buf)
309 {
310
311 int ret, enabled = 0;
312
313 if (quirks->old_ec_model) {
314 ret = get_wireless_state(&enabled, NULL);
315 } else {
316 ret = get_wireless_state_ec_standard();
317 enabled = wlan_s;
318 }
319 if (ret < 0)
320 return ret;
321
322 return sprintf(buf, "%i\n", enabled);
323 }
324
store_wlan(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)325 static ssize_t store_wlan(struct device *dev,
326 struct device_attribute *attr, const char *buf, size_t count)
327 {
328 return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
329 }
330
show_bluetooth(struct device * dev,struct device_attribute * attr,char * buf)331 static ssize_t show_bluetooth(struct device *dev,
332 struct device_attribute *attr, char *buf)
333 {
334
335 int ret, enabled = 0;
336
337 if (quirks->old_ec_model) {
338 ret = get_wireless_state(NULL, &enabled);
339 } else {
340 ret = get_wireless_state_ec_standard();
341 enabled = bluetooth_s;
342 }
343 if (ret < 0)
344 return ret;
345
346 return sprintf(buf, "%i\n", enabled);
347 }
348
store_bluetooth(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)349 static ssize_t store_bluetooth(struct device *dev,
350 struct device_attribute *attr, const char *buf, size_t count)
351 {
352 return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
353 }
354
show_threeg(struct device * dev,struct device_attribute * attr,char * buf)355 static ssize_t show_threeg(struct device *dev,
356 struct device_attribute *attr, char *buf)
357 {
358
359 int ret;
360
361 /* old msi ec not support 3G */
362 if (quirks->old_ec_model)
363 return -ENODEV;
364
365 ret = get_wireless_state_ec_standard();
366 if (ret < 0)
367 return ret;
368
369 return sprintf(buf, "%i\n", threeg_s);
370 }
371
store_threeg(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)372 static ssize_t store_threeg(struct device *dev,
373 struct device_attribute *attr, const char *buf, size_t count)
374 {
375 return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
376 }
377
show_lcd_level(struct device * dev,struct device_attribute * attr,char * buf)378 static ssize_t show_lcd_level(struct device *dev,
379 struct device_attribute *attr, char *buf)
380 {
381
382 int ret;
383
384 ret = get_lcd_level();
385 if (ret < 0)
386 return ret;
387
388 return sprintf(buf, "%i\n", ret);
389 }
390
store_lcd_level(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)391 static ssize_t store_lcd_level(struct device *dev,
392 struct device_attribute *attr, const char *buf, size_t count)
393 {
394
395 int level, ret;
396
397 if (sscanf(buf, "%i", &level) != 1 ||
398 (level < 0 || level >= MSI_LCD_LEVEL_MAX))
399 return -EINVAL;
400
401 ret = set_lcd_level(level);
402 if (ret < 0)
403 return ret;
404
405 return count;
406 }
407
show_auto_brightness(struct device * dev,struct device_attribute * attr,char * buf)408 static ssize_t show_auto_brightness(struct device *dev,
409 struct device_attribute *attr, char *buf)
410 {
411
412 int ret;
413
414 ret = get_auto_brightness();
415 if (ret < 0)
416 return ret;
417
418 return sprintf(buf, "%i\n", ret);
419 }
420
store_auto_brightness(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)421 static ssize_t store_auto_brightness(struct device *dev,
422 struct device_attribute *attr, const char *buf, size_t count)
423 {
424
425 int enable, ret;
426
427 if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
428 return -EINVAL;
429
430 ret = set_auto_brightness(enable);
431 if (ret < 0)
432 return ret;
433
434 return count;
435 }
436
show_touchpad(struct device * dev,struct device_attribute * attr,char * buf)437 static ssize_t show_touchpad(struct device *dev,
438 struct device_attribute *attr, char *buf)
439 {
440
441 u8 rdata;
442 int result;
443
444 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
445 if (result < 0)
446 return result;
447
448 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK));
449 }
450
show_turbo(struct device * dev,struct device_attribute * attr,char * buf)451 static ssize_t show_turbo(struct device *dev,
452 struct device_attribute *attr, char *buf)
453 {
454
455 u8 rdata;
456 int result;
457
458 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
459 if (result < 0)
460 return result;
461
462 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK));
463 }
464
show_eco(struct device * dev,struct device_attribute * attr,char * buf)465 static ssize_t show_eco(struct device *dev,
466 struct device_attribute *attr, char *buf)
467 {
468
469 u8 rdata;
470 int result;
471
472 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
473 if (result < 0)
474 return result;
475
476 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK));
477 }
478
show_turbo_cooldown(struct device * dev,struct device_attribute * attr,char * buf)479 static ssize_t show_turbo_cooldown(struct device *dev,
480 struct device_attribute *attr, char *buf)
481 {
482
483 u8 rdata;
484 int result;
485
486 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
487 if (result < 0)
488 return result;
489
490 return sprintf(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) |
491 (!!(rdata & MSI_STANDARD_EC_TURBO_COOLDOWN_MASK) << 1));
492 }
493
show_auto_fan(struct device * dev,struct device_attribute * attr,char * buf)494 static ssize_t show_auto_fan(struct device *dev,
495 struct device_attribute *attr, char *buf)
496 {
497
498 u8 rdata;
499 int result;
500
501 result = ec_read(MSI_STANDARD_EC_FAN_ADDRESS, &rdata);
502 if (result < 0)
503 return result;
504
505 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK));
506 }
507
store_auto_fan(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)508 static ssize_t store_auto_fan(struct device *dev,
509 struct device_attribute *attr, const char *buf, size_t count)
510 {
511
512 int enable, result;
513
514 if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
515 return -EINVAL;
516
517 result = ec_write(MSI_STANDARD_EC_FAN_ADDRESS, enable);
518 if (result < 0)
519 return result;
520
521 return count;
522 }
523
524 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
525 static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness,
526 store_auto_brightness);
527 static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
528 static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
529 static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
530 static DEVICE_ATTR(touchpad, 0444, show_touchpad, NULL);
531 static DEVICE_ATTR(turbo_mode, 0444, show_turbo, NULL);
532 static DEVICE_ATTR(eco_mode, 0444, show_eco, NULL);
533 static DEVICE_ATTR(turbo_cooldown, 0444, show_turbo_cooldown, NULL);
534 static DEVICE_ATTR(auto_fan, 0644, show_auto_fan, store_auto_fan);
535
536 static struct attribute *msipf_attributes[] = {
537 &dev_attr_bluetooth.attr,
538 &dev_attr_wlan.attr,
539 &dev_attr_touchpad.attr,
540 &dev_attr_turbo_mode.attr,
541 &dev_attr_eco_mode.attr,
542 &dev_attr_turbo_cooldown.attr,
543 &dev_attr_auto_fan.attr,
544 NULL
545 };
546
547 static struct attribute *msipf_old_attributes[] = {
548 &dev_attr_lcd_level.attr,
549 &dev_attr_auto_brightness.attr,
550 NULL
551 };
552
553 static const struct attribute_group msipf_attribute_group = {
554 .attrs = msipf_attributes
555 };
556
557 static const struct attribute_group msipf_old_attribute_group = {
558 .attrs = msipf_old_attributes
559 };
560
561 static struct platform_driver msipf_driver = {
562 .driver = {
563 .name = "msi-laptop-pf",
564 .pm = &msi_laptop_pm,
565 },
566 };
567
568 static struct platform_device *msipf_device;
569
570 /* Initialization */
571
572 static struct quirk_entry quirk_old_ec_model = {
573 .old_ec_model = true,
574 };
575
576 static struct quirk_entry quirk_load_scm_model = {
577 .load_scm_model = true,
578 .ec_delay = true,
579 };
580
581 static struct quirk_entry quirk_load_scm_ro_model = {
582 .load_scm_model = true,
583 .ec_read_only = true,
584 };
585
dmi_check_cb(const struct dmi_system_id * dmi)586 static int dmi_check_cb(const struct dmi_system_id *dmi)
587 {
588 pr_info("Identified laptop model '%s'\n", dmi->ident);
589
590 quirks = dmi->driver_data;
591
592 return 1;
593 }
594
595 static const struct dmi_system_id msi_dmi_table[] __initconst = {
596 {
597 .ident = "MSI S270",
598 .matches = {
599 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"),
600 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
601 DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
602 DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT")
603 },
604 .driver_data = &quirk_old_ec_model,
605 .callback = dmi_check_cb
606 },
607 {
608 .ident = "MSI S271",
609 .matches = {
610 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
611 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"),
612 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
613 DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
614 },
615 .driver_data = &quirk_old_ec_model,
616 .callback = dmi_check_cb
617 },
618 {
619 .ident = "MSI S420",
620 .matches = {
621 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
622 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"),
623 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
624 DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
625 },
626 .driver_data = &quirk_old_ec_model,
627 .callback = dmi_check_cb
628 },
629 {
630 .ident = "Medion MD96100",
631 .matches = {
632 DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
633 DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
634 DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
635 DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT")
636 },
637 .driver_data = &quirk_old_ec_model,
638 .callback = dmi_check_cb
639 },
640 {
641 .ident = "MSI N034",
642 .matches = {
643 DMI_MATCH(DMI_SYS_VENDOR,
644 "MICRO-STAR INTERNATIONAL CO., LTD"),
645 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
646 DMI_MATCH(DMI_CHASSIS_VENDOR,
647 "MICRO-STAR INTERNATIONAL CO., LTD")
648 },
649 .driver_data = &quirk_load_scm_model,
650 .callback = dmi_check_cb
651 },
652 {
653 .ident = "MSI N051",
654 .matches = {
655 DMI_MATCH(DMI_SYS_VENDOR,
656 "MICRO-STAR INTERNATIONAL CO., LTD"),
657 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N051"),
658 DMI_MATCH(DMI_CHASSIS_VENDOR,
659 "MICRO-STAR INTERNATIONAL CO., LTD")
660 },
661 .driver_data = &quirk_load_scm_model,
662 .callback = dmi_check_cb
663 },
664 {
665 .ident = "MSI N014",
666 .matches = {
667 DMI_MATCH(DMI_SYS_VENDOR,
668 "MICRO-STAR INTERNATIONAL CO., LTD"),
669 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
670 },
671 .driver_data = &quirk_load_scm_model,
672 .callback = dmi_check_cb
673 },
674 {
675 .ident = "MSI CR620",
676 .matches = {
677 DMI_MATCH(DMI_SYS_VENDOR,
678 "Micro-Star International"),
679 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
680 },
681 .driver_data = &quirk_load_scm_model,
682 .callback = dmi_check_cb
683 },
684 {
685 .ident = "MSI U270",
686 .matches = {
687 DMI_MATCH(DMI_SYS_VENDOR,
688 "Micro-Star International Co., Ltd."),
689 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
690 },
691 .driver_data = &quirk_load_scm_model,
692 .callback = dmi_check_cb
693 },
694 {
695 .ident = "MSI U90/U100",
696 .matches = {
697 DMI_MATCH(DMI_SYS_VENDOR,
698 "MICRO-STAR INTERNATIONAL CO., LTD"),
699 DMI_MATCH(DMI_PRODUCT_NAME, "U90/U100"),
700 },
701 .driver_data = &quirk_load_scm_ro_model,
702 .callback = dmi_check_cb
703 },
704 { }
705 };
706
rfkill_bluetooth_set(void * data,bool blocked)707 static int rfkill_bluetooth_set(void *data, bool blocked)
708 {
709 /* Do something with blocked...*/
710 /*
711 * blocked == false is on
712 * blocked == true is off
713 */
714 int result = set_device_state(blocked ? "0" : "1", 0,
715 MSI_STANDARD_EC_BLUETOOTH_MASK);
716
717 return min(result, 0);
718 }
719
rfkill_wlan_set(void * data,bool blocked)720 static int rfkill_wlan_set(void *data, bool blocked)
721 {
722 int result = set_device_state(blocked ? "0" : "1", 0,
723 MSI_STANDARD_EC_WLAN_MASK);
724
725 return min(result, 0);
726 }
727
rfkill_threeg_set(void * data,bool blocked)728 static int rfkill_threeg_set(void *data, bool blocked)
729 {
730 int result = set_device_state(blocked ? "0" : "1", 0,
731 MSI_STANDARD_EC_3G_MASK);
732
733 return min(result, 0);
734 }
735
736 static const struct rfkill_ops rfkill_bluetooth_ops = {
737 .set_block = rfkill_bluetooth_set
738 };
739
740 static const struct rfkill_ops rfkill_wlan_ops = {
741 .set_block = rfkill_wlan_set
742 };
743
744 static const struct rfkill_ops rfkill_threeg_ops = {
745 .set_block = rfkill_threeg_set
746 };
747
rfkill_cleanup(void)748 static void rfkill_cleanup(void)
749 {
750 if (rfk_bluetooth) {
751 rfkill_unregister(rfk_bluetooth);
752 rfkill_destroy(rfk_bluetooth);
753 }
754
755 if (rfk_threeg) {
756 rfkill_unregister(rfk_threeg);
757 rfkill_destroy(rfk_threeg);
758 }
759
760 if (rfk_wlan) {
761 rfkill_unregister(rfk_wlan);
762 rfkill_destroy(rfk_wlan);
763 }
764 }
765
msi_rfkill_set_state(struct rfkill * rfkill,bool blocked)766 static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked)
767 {
768 if (quirks->ec_read_only)
769 return rfkill_set_hw_state(rfkill, blocked);
770 else
771 return rfkill_set_sw_state(rfkill, blocked);
772 }
773
msi_update_rfkill(struct work_struct * ignored)774 static void msi_update_rfkill(struct work_struct *ignored)
775 {
776 get_wireless_state_ec_standard();
777
778 if (rfk_wlan)
779 msi_rfkill_set_state(rfk_wlan, !wlan_s);
780 if (rfk_bluetooth)
781 msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
782 if (rfk_threeg)
783 msi_rfkill_set_state(rfk_threeg, !threeg_s);
784 }
785 static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
786 static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
787
msi_send_touchpad_key(struct work_struct * ignored)788 static void msi_send_touchpad_key(struct work_struct *ignored)
789 {
790 u8 rdata;
791 int result;
792
793 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
794 if (result < 0)
795 return;
796
797 sparse_keymap_report_event(msi_laptop_input_dev,
798 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
799 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
800 }
801 static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
802 static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
803
msi_laptop_i8042_filter(unsigned char data,unsigned char str,struct serio * port)804 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
805 struct serio *port)
806 {
807 static bool extended;
808
809 if (str & I8042_STR_AUXDATA)
810 return false;
811
812 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
813 if (unlikely(data == 0xe0)) {
814 extended = true;
815 return false;
816 } else if (unlikely(extended)) {
817 extended = false;
818 switch (data) {
819 case 0xE4:
820 if (quirks->ec_delay) {
821 schedule_delayed_work(&msi_touchpad_dwork,
822 round_jiffies_relative(0.5 * HZ));
823 } else
824 schedule_work(&msi_touchpad_work);
825 break;
826 case 0x54:
827 case 0x62:
828 case 0x76:
829 if (quirks->ec_delay) {
830 schedule_delayed_work(&msi_rfkill_dwork,
831 round_jiffies_relative(0.5 * HZ));
832 } else
833 schedule_work(&msi_rfkill_work);
834 break;
835 }
836 }
837
838 return false;
839 }
840
msi_init_rfkill(struct work_struct * ignored)841 static void msi_init_rfkill(struct work_struct *ignored)
842 {
843 if (rfk_wlan) {
844 msi_rfkill_set_state(rfk_wlan, !wlan_s);
845 rfkill_wlan_set(NULL, !wlan_s);
846 }
847 if (rfk_bluetooth) {
848 msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
849 rfkill_bluetooth_set(NULL, !bluetooth_s);
850 }
851 if (rfk_threeg) {
852 msi_rfkill_set_state(rfk_threeg, !threeg_s);
853 rfkill_threeg_set(NULL, !threeg_s);
854 }
855 }
856 static DECLARE_DELAYED_WORK(msi_rfkill_init, msi_init_rfkill);
857
rfkill_init(struct platform_device * sdev)858 static int rfkill_init(struct platform_device *sdev)
859 {
860 /* add rfkill */
861 int retval;
862
863 /* keep the hardware wireless state */
864 get_wireless_state_ec_standard();
865
866 rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
867 RFKILL_TYPE_BLUETOOTH,
868 &rfkill_bluetooth_ops, NULL);
869 if (!rfk_bluetooth) {
870 retval = -ENOMEM;
871 goto err_bluetooth;
872 }
873 retval = rfkill_register(rfk_bluetooth);
874 if (retval)
875 goto err_bluetooth;
876
877 rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
878 &rfkill_wlan_ops, NULL);
879 if (!rfk_wlan) {
880 retval = -ENOMEM;
881 goto err_wlan;
882 }
883 retval = rfkill_register(rfk_wlan);
884 if (retval)
885 goto err_wlan;
886
887 if (threeg_exists) {
888 rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
889 RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
890 if (!rfk_threeg) {
891 retval = -ENOMEM;
892 goto err_threeg;
893 }
894 retval = rfkill_register(rfk_threeg);
895 if (retval)
896 goto err_threeg;
897 }
898
899 /* schedule to run rfkill state initial */
900 if (quirks->ec_delay) {
901 schedule_delayed_work(&msi_rfkill_init,
902 round_jiffies_relative(1 * HZ));
903 } else
904 schedule_work(&msi_rfkill_work);
905
906 return 0;
907
908 err_threeg:
909 rfkill_destroy(rfk_threeg);
910 if (rfk_wlan)
911 rfkill_unregister(rfk_wlan);
912 err_wlan:
913 rfkill_destroy(rfk_wlan);
914 if (rfk_bluetooth)
915 rfkill_unregister(rfk_bluetooth);
916 err_bluetooth:
917 rfkill_destroy(rfk_bluetooth);
918
919 return retval;
920 }
921
922 #ifdef CONFIG_PM_SLEEP
msi_laptop_resume(struct device * device)923 static int msi_laptop_resume(struct device *device)
924 {
925 u8 data;
926 int result;
927
928 if (!quirks->load_scm_model)
929 return 0;
930
931 /* set load SCM to disable hardware control by fn key */
932 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
933 if (result < 0)
934 return result;
935
936 result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
937 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
938 if (result < 0)
939 return result;
940
941 return 0;
942 }
943 #endif
944
msi_laptop_input_setup(void)945 static int __init msi_laptop_input_setup(void)
946 {
947 int err;
948
949 msi_laptop_input_dev = input_allocate_device();
950 if (!msi_laptop_input_dev)
951 return -ENOMEM;
952
953 msi_laptop_input_dev->name = "MSI Laptop hotkeys";
954 msi_laptop_input_dev->phys = "msi-laptop/input0";
955 msi_laptop_input_dev->id.bustype = BUS_HOST;
956
957 err = sparse_keymap_setup(msi_laptop_input_dev,
958 msi_laptop_keymap, NULL);
959 if (err)
960 goto err_free_dev;
961
962 err = input_register_device(msi_laptop_input_dev);
963 if (err)
964 goto err_free_dev;
965
966 return 0;
967
968 err_free_dev:
969 input_free_device(msi_laptop_input_dev);
970 return err;
971 }
972
load_scm_model_init(struct platform_device * sdev)973 static int __init load_scm_model_init(struct platform_device *sdev)
974 {
975 u8 data;
976 int result;
977
978 if (!quirks->ec_read_only) {
979 /* allow userland write sysfs file */
980 dev_attr_bluetooth.store = store_bluetooth;
981 dev_attr_wlan.store = store_wlan;
982 dev_attr_threeg.store = store_threeg;
983 dev_attr_bluetooth.attr.mode |= S_IWUSR;
984 dev_attr_wlan.attr.mode |= S_IWUSR;
985 dev_attr_threeg.attr.mode |= S_IWUSR;
986 }
987
988 /* disable hardware control by fn key */
989 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
990 if (result < 0)
991 return result;
992
993 result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
994 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
995 if (result < 0)
996 return result;
997
998 /* initial rfkill */
999 result = rfkill_init(sdev);
1000 if (result < 0)
1001 goto fail_rfkill;
1002
1003 /* setup input device */
1004 result = msi_laptop_input_setup();
1005 if (result)
1006 goto fail_input;
1007
1008 result = i8042_install_filter(msi_laptop_i8042_filter);
1009 if (result) {
1010 pr_err("Unable to install key filter\n");
1011 goto fail_filter;
1012 }
1013
1014 return 0;
1015
1016 fail_filter:
1017 input_unregister_device(msi_laptop_input_dev);
1018
1019 fail_input:
1020 rfkill_cleanup();
1021
1022 fail_rfkill:
1023
1024 return result;
1025
1026 }
1027
msi_init(void)1028 static int __init msi_init(void)
1029 {
1030 int ret;
1031
1032 if (acpi_disabled)
1033 return -ENODEV;
1034
1035 dmi_check_system(msi_dmi_table);
1036 if (!quirks)
1037 /* quirks may be NULL if no match in DMI table */
1038 quirks = &quirk_load_scm_model;
1039 if (force)
1040 quirks = &quirk_old_ec_model;
1041
1042 if (!quirks->old_ec_model)
1043 get_threeg_exists();
1044
1045 if (auto_brightness < 0 || auto_brightness > 2)
1046 return -EINVAL;
1047
1048 /* Register backlight stuff */
1049 if (quirks->old_ec_model &&
1050 acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1051 struct backlight_properties props;
1052 memset(&props, 0, sizeof(struct backlight_properties));
1053 props.type = BACKLIGHT_PLATFORM;
1054 props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
1055 msibl_device = backlight_device_register("msi-laptop-bl", NULL,
1056 NULL, &msibl_ops,
1057 &props);
1058 if (IS_ERR(msibl_device))
1059 return PTR_ERR(msibl_device);
1060 }
1061
1062 ret = platform_driver_register(&msipf_driver);
1063 if (ret)
1064 goto fail_backlight;
1065
1066 /* Register platform stuff */
1067
1068 msipf_device = platform_device_alloc("msi-laptop-pf", -1);
1069 if (!msipf_device) {
1070 ret = -ENOMEM;
1071 goto fail_platform_driver;
1072 }
1073
1074 ret = platform_device_add(msipf_device);
1075 if (ret)
1076 goto fail_device_add;
1077
1078 if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
1079 ret = -EINVAL;
1080 goto fail_scm_model_init;
1081 }
1082
1083 ret = sysfs_create_group(&msipf_device->dev.kobj,
1084 &msipf_attribute_group);
1085 if (ret)
1086 goto fail_create_group;
1087
1088 if (!quirks->old_ec_model) {
1089 if (threeg_exists)
1090 ret = device_create_file(&msipf_device->dev,
1091 &dev_attr_threeg);
1092 if (ret)
1093 goto fail_create_attr;
1094 } else {
1095 ret = sysfs_create_group(&msipf_device->dev.kobj,
1096 &msipf_old_attribute_group);
1097 if (ret)
1098 goto fail_create_attr;
1099
1100 /* Disable automatic brightness control by default because
1101 * this module was probably loaded to do brightness control in
1102 * software. */
1103
1104 if (auto_brightness != 2)
1105 set_auto_brightness(auto_brightness);
1106 }
1107
1108 pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
1109
1110 return 0;
1111
1112 fail_create_attr:
1113 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
1114 fail_create_group:
1115 if (quirks->load_scm_model) {
1116 i8042_remove_filter(msi_laptop_i8042_filter);
1117 cancel_delayed_work_sync(&msi_touchpad_dwork);
1118 input_unregister_device(msi_laptop_input_dev);
1119 cancel_delayed_work_sync(&msi_rfkill_dwork);
1120 cancel_work_sync(&msi_rfkill_work);
1121 rfkill_cleanup();
1122 }
1123 fail_scm_model_init:
1124 platform_device_del(msipf_device);
1125 fail_device_add:
1126 platform_device_put(msipf_device);
1127 fail_platform_driver:
1128 platform_driver_unregister(&msipf_driver);
1129 fail_backlight:
1130 backlight_device_unregister(msibl_device);
1131
1132 return ret;
1133 }
1134
msi_cleanup(void)1135 static void __exit msi_cleanup(void)
1136 {
1137 if (quirks->load_scm_model) {
1138 i8042_remove_filter(msi_laptop_i8042_filter);
1139 cancel_delayed_work_sync(&msi_touchpad_dwork);
1140 input_unregister_device(msi_laptop_input_dev);
1141 cancel_delayed_work_sync(&msi_rfkill_dwork);
1142 cancel_work_sync(&msi_rfkill_work);
1143 rfkill_cleanup();
1144 }
1145
1146 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
1147 if (!quirks->old_ec_model && threeg_exists)
1148 device_remove_file(&msipf_device->dev, &dev_attr_threeg);
1149 platform_device_unregister(msipf_device);
1150 platform_driver_unregister(&msipf_driver);
1151 backlight_device_unregister(msibl_device);
1152
1153 if (quirks->old_ec_model) {
1154 /* Enable automatic brightness control again */
1155 if (auto_brightness != 2)
1156 set_auto_brightness(1);
1157 }
1158
1159 pr_info("driver unloaded\n");
1160 }
1161
1162 module_init(msi_init);
1163 module_exit(msi_cleanup);
1164
1165 MODULE_AUTHOR("Lennart Poettering");
1166 MODULE_DESCRIPTION("MSI Laptop Support");
1167 MODULE_VERSION(MSI_DRIVER_VERSION);
1168 MODULE_LICENSE("GPL");
1169
1170 MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
1171 MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
1172 MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
1173 MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
1174 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
1175 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");
1176 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
1177 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
1178 MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*");
1179 MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnU90/U100:*");
1180