root/drivers/platform/x86/msi-laptop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_lcd_level
  2. get_lcd_level
  3. get_auto_brightness
  4. set_auto_brightness
  5. set_device_state
  6. get_wireless_state
  7. get_wireless_state_ec_standard
  8. get_threeg_exists
  9. bl_get_brightness
  10. bl_update_status
  11. show_wlan
  12. store_wlan
  13. show_bluetooth
  14. store_bluetooth
  15. show_threeg
  16. store_threeg
  17. show_lcd_level
  18. store_lcd_level
  19. show_auto_brightness
  20. store_auto_brightness
  21. show_touchpad
  22. show_turbo
  23. show_eco
  24. show_turbo_cooldown
  25. show_auto_fan
  26. store_auto_fan
  27. dmi_check_cb
  28. rfkill_bluetooth_set
  29. rfkill_wlan_set
  30. rfkill_threeg_set
  31. rfkill_cleanup
  32. msi_rfkill_set_state
  33. msi_update_rfkill
  34. msi_send_touchpad_key
  35. msi_laptop_i8042_filter
  36. msi_init_rfkill
  37. rfkill_init
  38. msi_laptop_resume
  39. msi_laptop_input_setup
  40. load_scm_model_init
  41. msi_init
  42. msi_cleanup

   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 
 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 
 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 
 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 
 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 
 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 -EOPNOTSUPP;
 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 
 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 
 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 
 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 
 287 static int bl_get_brightness(struct backlight_device *b)
 288 {
 289         return get_lcd_level();
 290 }
 291 
 292 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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'L CO.,LTD"),
 600                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
 601                         DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
 602                         DMI_MATCH(DMI_CHASSIS_VENDOR,
 603                                   "MICRO-STAR INT'L CO.,LTD")
 604                 },
 605                 .driver_data = &quirk_old_ec_model,
 606                 .callback = dmi_check_cb
 607         },
 608         {
 609                 .ident = "MSI S271",
 610                 .matches = {
 611                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
 612                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"),
 613                         DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
 614                         DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
 615                 },
 616                 .driver_data = &quirk_old_ec_model,
 617                 .callback = dmi_check_cb
 618         },
 619         {
 620                 .ident = "MSI S420",
 621                 .matches = {
 622                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
 623                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"),
 624                         DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
 625                         DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
 626                 },
 627                 .driver_data = &quirk_old_ec_model,
 628                 .callback = dmi_check_cb
 629         },
 630         {
 631                 .ident = "Medion MD96100",
 632                 .matches = {
 633                         DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
 634                         DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
 635                         DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
 636                         DMI_MATCH(DMI_CHASSIS_VENDOR,
 637                                   "MICRO-STAR INT'L CO.,LTD")
 638                 },
 639                 .driver_data = &quirk_old_ec_model,
 640                 .callback = dmi_check_cb
 641         },
 642         {
 643                 .ident = "MSI N034",
 644                 .matches = {
 645                         DMI_MATCH(DMI_SYS_VENDOR,
 646                                 "MICRO-STAR INTERNATIONAL CO., LTD"),
 647                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
 648                         DMI_MATCH(DMI_CHASSIS_VENDOR,
 649                         "MICRO-STAR INTERNATIONAL CO., LTD")
 650                 },
 651                 .driver_data = &quirk_load_scm_model,
 652                 .callback = dmi_check_cb
 653         },
 654         {
 655                 .ident = "MSI N051",
 656                 .matches = {
 657                         DMI_MATCH(DMI_SYS_VENDOR,
 658                                 "MICRO-STAR INTERNATIONAL CO., LTD"),
 659                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-N051"),
 660                         DMI_MATCH(DMI_CHASSIS_VENDOR,
 661                         "MICRO-STAR INTERNATIONAL CO., LTD")
 662                 },
 663                 .driver_data = &quirk_load_scm_model,
 664                 .callback = dmi_check_cb
 665         },
 666         {
 667                 .ident = "MSI N014",
 668                 .matches = {
 669                         DMI_MATCH(DMI_SYS_VENDOR,
 670                                 "MICRO-STAR INTERNATIONAL CO., LTD"),
 671                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
 672                 },
 673                 .driver_data = &quirk_load_scm_model,
 674                 .callback = dmi_check_cb
 675         },
 676         {
 677                 .ident = "MSI CR620",
 678                 .matches = {
 679                         DMI_MATCH(DMI_SYS_VENDOR,
 680                                 "Micro-Star International"),
 681                         DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
 682                 },
 683                 .driver_data = &quirk_load_scm_model,
 684                 .callback = dmi_check_cb
 685         },
 686         {
 687                 .ident = "MSI U270",
 688                 .matches = {
 689                         DMI_MATCH(DMI_SYS_VENDOR,
 690                                 "Micro-Star International Co., Ltd."),
 691                         DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
 692                 },
 693                 .driver_data = &quirk_load_scm_model,
 694                 .callback = dmi_check_cb
 695         },
 696         {
 697                 .ident = "MSI U90/U100",
 698                 .matches = {
 699                         DMI_MATCH(DMI_SYS_VENDOR,
 700                                 "MICRO-STAR INTERNATIONAL CO., LTD"),
 701                         DMI_MATCH(DMI_PRODUCT_NAME, "U90/U100"),
 702                 },
 703                 .driver_data = &quirk_load_scm_ro_model,
 704                 .callback = dmi_check_cb
 705         },
 706         { }
 707 };
 708 
 709 static int rfkill_bluetooth_set(void *data, bool blocked)
 710 {
 711         /* Do something with blocked...*/
 712         /*
 713          * blocked == false is on
 714          * blocked == true is off
 715          */
 716         int result = set_device_state(blocked ? "0" : "1", 0,
 717                         MSI_STANDARD_EC_BLUETOOTH_MASK);
 718 
 719         return min(result, 0);
 720 }
 721 
 722 static int rfkill_wlan_set(void *data, bool blocked)
 723 {
 724         int result = set_device_state(blocked ? "0" : "1", 0,
 725                         MSI_STANDARD_EC_WLAN_MASK);
 726 
 727         return min(result, 0);
 728 }
 729 
 730 static int rfkill_threeg_set(void *data, bool blocked)
 731 {
 732         int result = set_device_state(blocked ? "0" : "1", 0,
 733                         MSI_STANDARD_EC_3G_MASK);
 734 
 735         return min(result, 0);
 736 }
 737 
 738 static const struct rfkill_ops rfkill_bluetooth_ops = {
 739         .set_block = rfkill_bluetooth_set
 740 };
 741 
 742 static const struct rfkill_ops rfkill_wlan_ops = {
 743         .set_block = rfkill_wlan_set
 744 };
 745 
 746 static const struct rfkill_ops rfkill_threeg_ops = {
 747         .set_block = rfkill_threeg_set
 748 };
 749 
 750 static void rfkill_cleanup(void)
 751 {
 752         if (rfk_bluetooth) {
 753                 rfkill_unregister(rfk_bluetooth);
 754                 rfkill_destroy(rfk_bluetooth);
 755         }
 756 
 757         if (rfk_threeg) {
 758                 rfkill_unregister(rfk_threeg);
 759                 rfkill_destroy(rfk_threeg);
 760         }
 761 
 762         if (rfk_wlan) {
 763                 rfkill_unregister(rfk_wlan);
 764                 rfkill_destroy(rfk_wlan);
 765         }
 766 }
 767 
 768 static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked)
 769 {
 770         if (quirks->ec_read_only)
 771                 return rfkill_set_hw_state(rfkill, blocked);
 772         else
 773                 return rfkill_set_sw_state(rfkill, blocked);
 774 }
 775 
 776 static void msi_update_rfkill(struct work_struct *ignored)
 777 {
 778         get_wireless_state_ec_standard();
 779 
 780         if (rfk_wlan)
 781                 msi_rfkill_set_state(rfk_wlan, !wlan_s);
 782         if (rfk_bluetooth)
 783                 msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
 784         if (rfk_threeg)
 785                 msi_rfkill_set_state(rfk_threeg, !threeg_s);
 786 }
 787 static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
 788 static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
 789 
 790 static void msi_send_touchpad_key(struct work_struct *ignored)
 791 {
 792         u8 rdata;
 793         int result;
 794 
 795         result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
 796         if (result < 0)
 797                 return;
 798 
 799         sparse_keymap_report_event(msi_laptop_input_dev,
 800                 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
 801                 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
 802 }
 803 static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
 804 static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
 805 
 806 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
 807                                 struct serio *port)
 808 {
 809         static bool extended;
 810 
 811         if (str & I8042_STR_AUXDATA)
 812                 return false;
 813 
 814         /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
 815         if (unlikely(data == 0xe0)) {
 816                 extended = true;
 817                 return false;
 818         } else if (unlikely(extended)) {
 819                 extended = false;
 820                 switch (data) {
 821                 case 0xE4:
 822                         if (quirks->ec_delay) {
 823                                 schedule_delayed_work(&msi_touchpad_dwork,
 824                                         round_jiffies_relative(0.5 * HZ));
 825                         } else
 826                                 schedule_work(&msi_touchpad_work);
 827                         break;
 828                 case 0x54:
 829                 case 0x62:
 830                 case 0x76:
 831                         if (quirks->ec_delay) {
 832                                 schedule_delayed_work(&msi_rfkill_dwork,
 833                                         round_jiffies_relative(0.5 * HZ));
 834                         } else
 835                                 schedule_work(&msi_rfkill_work);
 836                         break;
 837                 }
 838         }
 839 
 840         return false;
 841 }
 842 
 843 static void msi_init_rfkill(struct work_struct *ignored)
 844 {
 845         if (rfk_wlan) {
 846                 rfkill_set_sw_state(rfk_wlan, !wlan_s);
 847                 rfkill_wlan_set(NULL, !wlan_s);
 848         }
 849         if (rfk_bluetooth) {
 850                 rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s);
 851                 rfkill_bluetooth_set(NULL, !bluetooth_s);
 852         }
 853         if (rfk_threeg) {
 854                 rfkill_set_sw_state(rfk_threeg, !threeg_s);
 855                 rfkill_threeg_set(NULL, !threeg_s);
 856         }
 857 }
 858 static DECLARE_DELAYED_WORK(msi_rfkill_init, msi_init_rfkill);
 859 
 860 static int rfkill_init(struct platform_device *sdev)
 861 {
 862         /* add rfkill */
 863         int retval;
 864 
 865         /* keep the hardware wireless state */
 866         get_wireless_state_ec_standard();
 867 
 868         rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
 869                                 RFKILL_TYPE_BLUETOOTH,
 870                                 &rfkill_bluetooth_ops, NULL);
 871         if (!rfk_bluetooth) {
 872                 retval = -ENOMEM;
 873                 goto err_bluetooth;
 874         }
 875         retval = rfkill_register(rfk_bluetooth);
 876         if (retval)
 877                 goto err_bluetooth;
 878 
 879         rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
 880                                 &rfkill_wlan_ops, NULL);
 881         if (!rfk_wlan) {
 882                 retval = -ENOMEM;
 883                 goto err_wlan;
 884         }
 885         retval = rfkill_register(rfk_wlan);
 886         if (retval)
 887                 goto err_wlan;
 888 
 889         if (threeg_exists) {
 890                 rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
 891                                 RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
 892                 if (!rfk_threeg) {
 893                         retval = -ENOMEM;
 894                         goto err_threeg;
 895                 }
 896                 retval = rfkill_register(rfk_threeg);
 897                 if (retval)
 898                         goto err_threeg;
 899         }
 900 
 901         /* schedule to run rfkill state initial */
 902         if (quirks->ec_delay) {
 903                 schedule_delayed_work(&msi_rfkill_init,
 904                         round_jiffies_relative(1 * HZ));
 905         } else
 906                 schedule_work(&msi_rfkill_work);
 907 
 908         return 0;
 909 
 910 err_threeg:
 911         rfkill_destroy(rfk_threeg);
 912         if (rfk_wlan)
 913                 rfkill_unregister(rfk_wlan);
 914 err_wlan:
 915         rfkill_destroy(rfk_wlan);
 916         if (rfk_bluetooth)
 917                 rfkill_unregister(rfk_bluetooth);
 918 err_bluetooth:
 919         rfkill_destroy(rfk_bluetooth);
 920 
 921         return retval;
 922 }
 923 
 924 #ifdef CONFIG_PM_SLEEP
 925 static int msi_laptop_resume(struct device *device)
 926 {
 927         u8 data;
 928         int result;
 929 
 930         if (!quirks->load_scm_model)
 931                 return 0;
 932 
 933         /* set load SCM to disable hardware control by fn key */
 934         result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
 935         if (result < 0)
 936                 return result;
 937 
 938         result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
 939                 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
 940         if (result < 0)
 941                 return result;
 942 
 943         return 0;
 944 }
 945 #endif
 946 
 947 static int __init msi_laptop_input_setup(void)
 948 {
 949         int err;
 950 
 951         msi_laptop_input_dev = input_allocate_device();
 952         if (!msi_laptop_input_dev)
 953                 return -ENOMEM;
 954 
 955         msi_laptop_input_dev->name = "MSI Laptop hotkeys";
 956         msi_laptop_input_dev->phys = "msi-laptop/input0";
 957         msi_laptop_input_dev->id.bustype = BUS_HOST;
 958 
 959         err = sparse_keymap_setup(msi_laptop_input_dev,
 960                 msi_laptop_keymap, NULL);
 961         if (err)
 962                 goto err_free_dev;
 963 
 964         err = input_register_device(msi_laptop_input_dev);
 965         if (err)
 966                 goto err_free_dev;
 967 
 968         return 0;
 969 
 970 err_free_dev:
 971         input_free_device(msi_laptop_input_dev);
 972         return err;
 973 }
 974 
 975 static int __init load_scm_model_init(struct platform_device *sdev)
 976 {
 977         u8 data;
 978         int result;
 979 
 980         if (!quirks->ec_read_only) {
 981                 /* allow userland write sysfs file  */
 982                 dev_attr_bluetooth.store = store_bluetooth;
 983                 dev_attr_wlan.store = store_wlan;
 984                 dev_attr_threeg.store = store_threeg;
 985                 dev_attr_bluetooth.attr.mode |= S_IWUSR;
 986                 dev_attr_wlan.attr.mode |= S_IWUSR;
 987                 dev_attr_threeg.attr.mode |= S_IWUSR;
 988         }
 989 
 990         /* disable hardware control by fn key */
 991         result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
 992         if (result < 0)
 993                 return result;
 994 
 995         result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
 996                 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
 997         if (result < 0)
 998                 return result;
 999 
1000         /* initial rfkill */
1001         result = rfkill_init(sdev);
1002         if (result < 0)
1003                 goto fail_rfkill;
1004 
1005         /* setup input device */
1006         result = msi_laptop_input_setup();
1007         if (result)
1008                 goto fail_input;
1009 
1010         result = i8042_install_filter(msi_laptop_i8042_filter);
1011         if (result) {
1012                 pr_err("Unable to install key filter\n");
1013                 goto fail_filter;
1014         }
1015 
1016         return 0;
1017 
1018 fail_filter:
1019         input_unregister_device(msi_laptop_input_dev);
1020 
1021 fail_input:
1022         rfkill_cleanup();
1023 
1024 fail_rfkill:
1025 
1026         return result;
1027 
1028 }
1029 
1030 static int __init msi_init(void)
1031 {
1032         int ret;
1033 
1034         if (acpi_disabled)
1035                 return -ENODEV;
1036 
1037         dmi_check_system(msi_dmi_table);
1038         if (!quirks)
1039                 /* quirks may be NULL if no match in DMI table */
1040                 quirks = &quirk_load_scm_model;
1041         if (force)
1042                 quirks = &quirk_old_ec_model;
1043 
1044         if (!quirks->old_ec_model)
1045                 get_threeg_exists();
1046 
1047         if (auto_brightness < 0 || auto_brightness > 2)
1048                 return -EINVAL;
1049 
1050         /* Register backlight stuff */
1051 
1052         if (quirks->old_ec_model ||
1053             acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1054                 struct backlight_properties props;
1055                 memset(&props, 0, sizeof(struct backlight_properties));
1056                 props.type = BACKLIGHT_PLATFORM;
1057                 props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
1058                 msibl_device = backlight_device_register("msi-laptop-bl", NULL,
1059                                                          NULL, &msibl_ops,
1060                                                          &props);
1061                 if (IS_ERR(msibl_device))
1062                         return PTR_ERR(msibl_device);
1063         }
1064 
1065         ret = platform_driver_register(&msipf_driver);
1066         if (ret)
1067                 goto fail_backlight;
1068 
1069         /* Register platform stuff */
1070 
1071         msipf_device = platform_device_alloc("msi-laptop-pf", -1);
1072         if (!msipf_device) {
1073                 ret = -ENOMEM;
1074                 goto fail_platform_driver;
1075         }
1076 
1077         ret = platform_device_add(msipf_device);
1078         if (ret)
1079                 goto fail_device_add;
1080 
1081         if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
1082                 ret = -EINVAL;
1083                 goto fail_scm_model_init;
1084         }
1085 
1086         ret = sysfs_create_group(&msipf_device->dev.kobj,
1087                                  &msipf_attribute_group);
1088         if (ret)
1089                 goto fail_create_group;
1090 
1091         if (!quirks->old_ec_model) {
1092                 if (threeg_exists)
1093                         ret = device_create_file(&msipf_device->dev,
1094                                                 &dev_attr_threeg);
1095                 if (ret)
1096                         goto fail_create_attr;
1097         } else {
1098                 ret = sysfs_create_group(&msipf_device->dev.kobj,
1099                                          &msipf_old_attribute_group);
1100                 if (ret)
1101                         goto fail_create_attr;
1102 
1103                 /* Disable automatic brightness control by default because
1104                  * this module was probably loaded to do brightness control in
1105                  * software. */
1106 
1107                 if (auto_brightness != 2)
1108                         set_auto_brightness(auto_brightness);
1109         }
1110 
1111         pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
1112 
1113         return 0;
1114 
1115 fail_create_attr:
1116         sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
1117 fail_create_group:
1118         if (quirks->load_scm_model) {
1119                 i8042_remove_filter(msi_laptop_i8042_filter);
1120                 cancel_delayed_work_sync(&msi_rfkill_dwork);
1121                 cancel_work_sync(&msi_rfkill_work);
1122                 rfkill_cleanup();
1123         }
1124 fail_scm_model_init:
1125         platform_device_del(msipf_device);
1126 fail_device_add:
1127         platform_device_put(msipf_device);
1128 fail_platform_driver:
1129         platform_driver_unregister(&msipf_driver);
1130 fail_backlight:
1131         backlight_device_unregister(msibl_device);
1132 
1133         return ret;
1134 }
1135 
1136 static void __exit msi_cleanup(void)
1137 {
1138         if (quirks->load_scm_model) {
1139                 i8042_remove_filter(msi_laptop_i8042_filter);
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:*");

/* [<][>][^][v][top][bottom][index][help] */