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