0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0042
0043 #include <linux/module.h>
0044 #include <linux/kernel.h>
0045 #include <linux/init.h>
0046 #include <linux/acpi.h>
0047 #include <linux/dmi.h>
0048 #include <linux/backlight.h>
0049 #include <linux/platform_device.h>
0050 #include <linux/rfkill.h>
0051 #include <linux/i8042.h>
0052 #include <linux/input.h>
0053 #include <linux/input/sparse-keymap.h>
0054 #include <acpi/video.h>
0055
0056 #define MSI_DRIVER_VERSION "0.5"
0057
0058 #define MSI_LCD_LEVEL_MAX 9
0059
0060 #define MSI_EC_COMMAND_WIRELESS 0x10
0061 #define MSI_EC_COMMAND_LCD_LEVEL 0x11
0062
0063 #define MSI_STANDARD_EC_COMMAND_ADDRESS 0x2e
0064 #define MSI_STANDARD_EC_BLUETOOTH_MASK (1 << 0)
0065 #define MSI_STANDARD_EC_WEBCAM_MASK (1 << 1)
0066 #define MSI_STANDARD_EC_WLAN_MASK (1 << 3)
0067 #define MSI_STANDARD_EC_3G_MASK (1 << 4)
0068
0069
0070 #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
0071 #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
0072
0073 #define MSI_STANDARD_EC_FUNCTIONS_ADDRESS 0xe4
0074
0075 #define MSI_STANDARD_EC_TURBO_MASK (1 << 1)
0076
0077 #define MSI_STANDARD_EC_ECO_MASK (1 << 3)
0078
0079 #define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
0080
0081 #define MSI_STANDARD_EC_TURBO_COOLDOWN_MASK (1 << 7)
0082
0083 #define MSI_STANDARD_EC_FAN_ADDRESS 0x33
0084
0085 #define MSI_STANDARD_EC_AUTOFAN_MASK (1 << 0)
0086
0087 #ifdef CONFIG_PM_SLEEP
0088 static int msi_laptop_resume(struct device *device);
0089 #endif
0090 static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
0091
0092 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
0093
0094 static bool force;
0095 module_param(force, bool, 0);
0096 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
0097
0098 static int auto_brightness;
0099 module_param(auto_brightness, int, 0);
0100 MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
0101
0102 static const struct key_entry msi_laptop_keymap[] = {
0103 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
0104 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
0105 {KE_END, 0}
0106 };
0107
0108 static struct input_dev *msi_laptop_input_dev;
0109
0110 static int wlan_s, bluetooth_s, threeg_s;
0111 static int threeg_exists;
0112 static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
0113
0114
0115 struct quirk_entry {
0116 bool old_ec_model;
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128 bool load_scm_model;
0129
0130
0131 bool ec_delay;
0132
0133
0134
0135
0136
0137 bool ec_read_only;
0138 };
0139
0140 static struct quirk_entry *quirks;
0141
0142
0143
0144 static int set_lcd_level(int level)
0145 {
0146 u8 buf[2];
0147
0148 if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
0149 return -EINVAL;
0150
0151 buf[0] = 0x80;
0152 buf[1] = (u8) (level*31);
0153
0154 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf),
0155 NULL, 0);
0156 }
0157
0158 static int get_lcd_level(void)
0159 {
0160 u8 wdata = 0, rdata;
0161 int result;
0162
0163 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
0164 &rdata, 1);
0165 if (result < 0)
0166 return result;
0167
0168 return (int) rdata / 31;
0169 }
0170
0171 static int get_auto_brightness(void)
0172 {
0173 u8 wdata = 4, rdata;
0174 int result;
0175
0176 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
0177 &rdata, 1);
0178 if (result < 0)
0179 return result;
0180
0181 return !!(rdata & 8);
0182 }
0183
0184 static int set_auto_brightness(int enable)
0185 {
0186 u8 wdata[2], rdata;
0187 int result;
0188
0189 wdata[0] = 4;
0190
0191 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1,
0192 &rdata, 1);
0193 if (result < 0)
0194 return result;
0195
0196 wdata[0] = 0x84;
0197 wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
0198
0199 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2,
0200 NULL, 0);
0201 }
0202
0203 static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
0204 {
0205 int status;
0206 u8 wdata = 0, rdata;
0207 int result;
0208
0209 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
0210 return -EINVAL;
0211
0212 if (quirks->ec_read_only)
0213 return -EOPNOTSUPP;
0214
0215
0216 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
0217 if (result < 0)
0218 return result;
0219
0220 if (!!(rdata & mask) != status) {
0221
0222 if (rdata & mask)
0223 wdata = rdata & ~mask;
0224 else
0225 wdata = rdata | mask;
0226
0227 result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
0228 if (result < 0)
0229 return result;
0230 }
0231
0232 return count;
0233 }
0234
0235 static int get_wireless_state(int *wlan, int *bluetooth)
0236 {
0237 u8 wdata = 0, rdata;
0238 int result;
0239
0240 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
0241 if (result < 0)
0242 return result;
0243
0244 if (wlan)
0245 *wlan = !!(rdata & 8);
0246
0247 if (bluetooth)
0248 *bluetooth = !!(rdata & 128);
0249
0250 return 0;
0251 }
0252
0253 static int get_wireless_state_ec_standard(void)
0254 {
0255 u8 rdata;
0256 int result;
0257
0258 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
0259 if (result < 0)
0260 return result;
0261
0262 wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
0263
0264 bluetooth_s = !!(rdata & MSI_STANDARD_EC_BLUETOOTH_MASK);
0265
0266 threeg_s = !!(rdata & MSI_STANDARD_EC_3G_MASK);
0267
0268 return 0;
0269 }
0270
0271 static int get_threeg_exists(void)
0272 {
0273 u8 rdata;
0274 int result;
0275
0276 result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
0277 if (result < 0)
0278 return result;
0279
0280 threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
0281
0282 return 0;
0283 }
0284
0285
0286
0287 static int bl_get_brightness(struct backlight_device *b)
0288 {
0289 return get_lcd_level();
0290 }
0291
0292
0293 static int bl_update_status(struct backlight_device *b)
0294 {
0295 return set_lcd_level(b->props.brightness);
0296 }
0297
0298 static const struct backlight_ops msibl_ops = {
0299 .get_brightness = bl_get_brightness,
0300 .update_status = bl_update_status,
0301 };
0302
0303 static struct backlight_device *msibl_device;
0304
0305
0306
0307 static ssize_t show_wlan(struct device *dev,
0308 struct device_attribute *attr, char *buf)
0309 {
0310
0311 int ret, enabled = 0;
0312
0313 if (quirks->old_ec_model) {
0314 ret = get_wireless_state(&enabled, NULL);
0315 } else {
0316 ret = get_wireless_state_ec_standard();
0317 enabled = wlan_s;
0318 }
0319 if (ret < 0)
0320 return ret;
0321
0322 return sprintf(buf, "%i\n", enabled);
0323 }
0324
0325 static ssize_t store_wlan(struct device *dev,
0326 struct device_attribute *attr, const char *buf, size_t count)
0327 {
0328 return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
0329 }
0330
0331 static ssize_t show_bluetooth(struct device *dev,
0332 struct device_attribute *attr, char *buf)
0333 {
0334
0335 int ret, enabled = 0;
0336
0337 if (quirks->old_ec_model) {
0338 ret = get_wireless_state(NULL, &enabled);
0339 } else {
0340 ret = get_wireless_state_ec_standard();
0341 enabled = bluetooth_s;
0342 }
0343 if (ret < 0)
0344 return ret;
0345
0346 return sprintf(buf, "%i\n", enabled);
0347 }
0348
0349 static ssize_t store_bluetooth(struct device *dev,
0350 struct device_attribute *attr, const char *buf, size_t count)
0351 {
0352 return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
0353 }
0354
0355 static ssize_t show_threeg(struct device *dev,
0356 struct device_attribute *attr, char *buf)
0357 {
0358
0359 int ret;
0360
0361
0362 if (quirks->old_ec_model)
0363 return -ENODEV;
0364
0365 ret = get_wireless_state_ec_standard();
0366 if (ret < 0)
0367 return ret;
0368
0369 return sprintf(buf, "%i\n", threeg_s);
0370 }
0371
0372 static ssize_t store_threeg(struct device *dev,
0373 struct device_attribute *attr, const char *buf, size_t count)
0374 {
0375 return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
0376 }
0377
0378 static ssize_t show_lcd_level(struct device *dev,
0379 struct device_attribute *attr, char *buf)
0380 {
0381
0382 int ret;
0383
0384 ret = get_lcd_level();
0385 if (ret < 0)
0386 return ret;
0387
0388 return sprintf(buf, "%i\n", ret);
0389 }
0390
0391 static ssize_t store_lcd_level(struct device *dev,
0392 struct device_attribute *attr, const char *buf, size_t count)
0393 {
0394
0395 int level, ret;
0396
0397 if (sscanf(buf, "%i", &level) != 1 ||
0398 (level < 0 || level >= MSI_LCD_LEVEL_MAX))
0399 return -EINVAL;
0400
0401 ret = set_lcd_level(level);
0402 if (ret < 0)
0403 return ret;
0404
0405 return count;
0406 }
0407
0408 static ssize_t show_auto_brightness(struct device *dev,
0409 struct device_attribute *attr, char *buf)
0410 {
0411
0412 int ret;
0413
0414 ret = get_auto_brightness();
0415 if (ret < 0)
0416 return ret;
0417
0418 return sprintf(buf, "%i\n", ret);
0419 }
0420
0421 static ssize_t store_auto_brightness(struct device *dev,
0422 struct device_attribute *attr, const char *buf, size_t count)
0423 {
0424
0425 int enable, ret;
0426
0427 if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
0428 return -EINVAL;
0429
0430 ret = set_auto_brightness(enable);
0431 if (ret < 0)
0432 return ret;
0433
0434 return count;
0435 }
0436
0437 static ssize_t show_touchpad(struct device *dev,
0438 struct device_attribute *attr, char *buf)
0439 {
0440
0441 u8 rdata;
0442 int result;
0443
0444 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
0445 if (result < 0)
0446 return result;
0447
0448 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK));
0449 }
0450
0451 static ssize_t show_turbo(struct device *dev,
0452 struct device_attribute *attr, char *buf)
0453 {
0454
0455 u8 rdata;
0456 int result;
0457
0458 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
0459 if (result < 0)
0460 return result;
0461
0462 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_TURBO_MASK));
0463 }
0464
0465 static ssize_t show_eco(struct device *dev,
0466 struct device_attribute *attr, char *buf)
0467 {
0468
0469 u8 rdata;
0470 int result;
0471
0472 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
0473 if (result < 0)
0474 return result;
0475
0476 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_ECO_MASK));
0477 }
0478
0479 static ssize_t show_turbo_cooldown(struct device *dev,
0480 struct device_attribute *attr, char *buf)
0481 {
0482
0483 u8 rdata;
0484 int result;
0485
0486 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
0487 if (result < 0)
0488 return result;
0489
0490 return sprintf(buf, "%i\n", (!!(rdata & MSI_STANDARD_EC_TURBO_MASK)) |
0491 (!!(rdata & MSI_STANDARD_EC_TURBO_COOLDOWN_MASK) << 1));
0492 }
0493
0494 static ssize_t show_auto_fan(struct device *dev,
0495 struct device_attribute *attr, char *buf)
0496 {
0497
0498 u8 rdata;
0499 int result;
0500
0501 result = ec_read(MSI_STANDARD_EC_FAN_ADDRESS, &rdata);
0502 if (result < 0)
0503 return result;
0504
0505 return sprintf(buf, "%i\n", !!(rdata & MSI_STANDARD_EC_AUTOFAN_MASK));
0506 }
0507
0508 static ssize_t store_auto_fan(struct device *dev,
0509 struct device_attribute *attr, const char *buf, size_t count)
0510 {
0511
0512 int enable, result;
0513
0514 if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
0515 return -EINVAL;
0516
0517 result = ec_write(MSI_STANDARD_EC_FAN_ADDRESS, enable);
0518 if (result < 0)
0519 return result;
0520
0521 return count;
0522 }
0523
0524 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
0525 static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness,
0526 store_auto_brightness);
0527 static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
0528 static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
0529 static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
0530 static DEVICE_ATTR(touchpad, 0444, show_touchpad, NULL);
0531 static DEVICE_ATTR(turbo_mode, 0444, show_turbo, NULL);
0532 static DEVICE_ATTR(eco_mode, 0444, show_eco, NULL);
0533 static DEVICE_ATTR(turbo_cooldown, 0444, show_turbo_cooldown, NULL);
0534 static DEVICE_ATTR(auto_fan, 0644, show_auto_fan, store_auto_fan);
0535
0536 static struct attribute *msipf_attributes[] = {
0537 &dev_attr_bluetooth.attr,
0538 &dev_attr_wlan.attr,
0539 &dev_attr_touchpad.attr,
0540 &dev_attr_turbo_mode.attr,
0541 &dev_attr_eco_mode.attr,
0542 &dev_attr_turbo_cooldown.attr,
0543 &dev_attr_auto_fan.attr,
0544 NULL
0545 };
0546
0547 static struct attribute *msipf_old_attributes[] = {
0548 &dev_attr_lcd_level.attr,
0549 &dev_attr_auto_brightness.attr,
0550 NULL
0551 };
0552
0553 static const struct attribute_group msipf_attribute_group = {
0554 .attrs = msipf_attributes
0555 };
0556
0557 static const struct attribute_group msipf_old_attribute_group = {
0558 .attrs = msipf_old_attributes
0559 };
0560
0561 static struct platform_driver msipf_driver = {
0562 .driver = {
0563 .name = "msi-laptop-pf",
0564 .pm = &msi_laptop_pm,
0565 },
0566 };
0567
0568 static struct platform_device *msipf_device;
0569
0570
0571
0572 static struct quirk_entry quirk_old_ec_model = {
0573 .old_ec_model = true,
0574 };
0575
0576 static struct quirk_entry quirk_load_scm_model = {
0577 .load_scm_model = true,
0578 .ec_delay = true,
0579 };
0580
0581 static struct quirk_entry quirk_load_scm_ro_model = {
0582 .load_scm_model = true,
0583 .ec_read_only = true,
0584 };
0585
0586 static int dmi_check_cb(const struct dmi_system_id *dmi)
0587 {
0588 pr_info("Identified laptop model '%s'\n", dmi->ident);
0589
0590 quirks = dmi->driver_data;
0591
0592 return 1;
0593 }
0594
0595 static const struct dmi_system_id msi_dmi_table[] __initconst = {
0596 {
0597 .ident = "MSI S270",
0598 .matches = {
0599 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
0600 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
0601 DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
0602 DMI_MATCH(DMI_CHASSIS_VENDOR,
0603 "MICRO-STAR INT'L CO.,LTD")
0604 },
0605 .driver_data = &quirk_old_ec_model,
0606 .callback = dmi_check_cb
0607 },
0608 {
0609 .ident = "MSI S271",
0610 .matches = {
0611 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
0612 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"),
0613 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
0614 DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
0615 },
0616 .driver_data = &quirk_old_ec_model,
0617 .callback = dmi_check_cb
0618 },
0619 {
0620 .ident = "MSI S420",
0621 .matches = {
0622 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
0623 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"),
0624 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
0625 DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
0626 },
0627 .driver_data = &quirk_old_ec_model,
0628 .callback = dmi_check_cb
0629 },
0630 {
0631 .ident = "Medion MD96100",
0632 .matches = {
0633 DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
0634 DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
0635 DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
0636 DMI_MATCH(DMI_CHASSIS_VENDOR,
0637 "MICRO-STAR INT'L CO.,LTD")
0638 },
0639 .driver_data = &quirk_old_ec_model,
0640 .callback = dmi_check_cb
0641 },
0642 {
0643 .ident = "MSI N034",
0644 .matches = {
0645 DMI_MATCH(DMI_SYS_VENDOR,
0646 "MICRO-STAR INTERNATIONAL CO., LTD"),
0647 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
0648 DMI_MATCH(DMI_CHASSIS_VENDOR,
0649 "MICRO-STAR INTERNATIONAL CO., LTD")
0650 },
0651 .driver_data = &quirk_load_scm_model,
0652 .callback = dmi_check_cb
0653 },
0654 {
0655 .ident = "MSI N051",
0656 .matches = {
0657 DMI_MATCH(DMI_SYS_VENDOR,
0658 "MICRO-STAR INTERNATIONAL CO., LTD"),
0659 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N051"),
0660 DMI_MATCH(DMI_CHASSIS_VENDOR,
0661 "MICRO-STAR INTERNATIONAL CO., LTD")
0662 },
0663 .driver_data = &quirk_load_scm_model,
0664 .callback = dmi_check_cb
0665 },
0666 {
0667 .ident = "MSI N014",
0668 .matches = {
0669 DMI_MATCH(DMI_SYS_VENDOR,
0670 "MICRO-STAR INTERNATIONAL CO., LTD"),
0671 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
0672 },
0673 .driver_data = &quirk_load_scm_model,
0674 .callback = dmi_check_cb
0675 },
0676 {
0677 .ident = "MSI CR620",
0678 .matches = {
0679 DMI_MATCH(DMI_SYS_VENDOR,
0680 "Micro-Star International"),
0681 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
0682 },
0683 .driver_data = &quirk_load_scm_model,
0684 .callback = dmi_check_cb
0685 },
0686 {
0687 .ident = "MSI U270",
0688 .matches = {
0689 DMI_MATCH(DMI_SYS_VENDOR,
0690 "Micro-Star International Co., Ltd."),
0691 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
0692 },
0693 .driver_data = &quirk_load_scm_model,
0694 .callback = dmi_check_cb
0695 },
0696 {
0697 .ident = "MSI U90/U100",
0698 .matches = {
0699 DMI_MATCH(DMI_SYS_VENDOR,
0700 "MICRO-STAR INTERNATIONAL CO., LTD"),
0701 DMI_MATCH(DMI_PRODUCT_NAME, "U90/U100"),
0702 },
0703 .driver_data = &quirk_load_scm_ro_model,
0704 .callback = dmi_check_cb
0705 },
0706 { }
0707 };
0708
0709 static int rfkill_bluetooth_set(void *data, bool blocked)
0710 {
0711
0712
0713
0714
0715
0716 int result = set_device_state(blocked ? "0" : "1", 0,
0717 MSI_STANDARD_EC_BLUETOOTH_MASK);
0718
0719 return min(result, 0);
0720 }
0721
0722 static int rfkill_wlan_set(void *data, bool blocked)
0723 {
0724 int result = set_device_state(blocked ? "0" : "1", 0,
0725 MSI_STANDARD_EC_WLAN_MASK);
0726
0727 return min(result, 0);
0728 }
0729
0730 static int rfkill_threeg_set(void *data, bool blocked)
0731 {
0732 int result = set_device_state(blocked ? "0" : "1", 0,
0733 MSI_STANDARD_EC_3G_MASK);
0734
0735 return min(result, 0);
0736 }
0737
0738 static const struct rfkill_ops rfkill_bluetooth_ops = {
0739 .set_block = rfkill_bluetooth_set
0740 };
0741
0742 static const struct rfkill_ops rfkill_wlan_ops = {
0743 .set_block = rfkill_wlan_set
0744 };
0745
0746 static const struct rfkill_ops rfkill_threeg_ops = {
0747 .set_block = rfkill_threeg_set
0748 };
0749
0750 static void rfkill_cleanup(void)
0751 {
0752 if (rfk_bluetooth) {
0753 rfkill_unregister(rfk_bluetooth);
0754 rfkill_destroy(rfk_bluetooth);
0755 }
0756
0757 if (rfk_threeg) {
0758 rfkill_unregister(rfk_threeg);
0759 rfkill_destroy(rfk_threeg);
0760 }
0761
0762 if (rfk_wlan) {
0763 rfkill_unregister(rfk_wlan);
0764 rfkill_destroy(rfk_wlan);
0765 }
0766 }
0767
0768 static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked)
0769 {
0770 if (quirks->ec_read_only)
0771 return rfkill_set_hw_state(rfkill, blocked);
0772 else
0773 return rfkill_set_sw_state(rfkill, blocked);
0774 }
0775
0776 static void msi_update_rfkill(struct work_struct *ignored)
0777 {
0778 get_wireless_state_ec_standard();
0779
0780 if (rfk_wlan)
0781 msi_rfkill_set_state(rfk_wlan, !wlan_s);
0782 if (rfk_bluetooth)
0783 msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
0784 if (rfk_threeg)
0785 msi_rfkill_set_state(rfk_threeg, !threeg_s);
0786 }
0787 static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
0788 static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
0789
0790 static void msi_send_touchpad_key(struct work_struct *ignored)
0791 {
0792 u8 rdata;
0793 int result;
0794
0795 result = ec_read(MSI_STANDARD_EC_FUNCTIONS_ADDRESS, &rdata);
0796 if (result < 0)
0797 return;
0798
0799 sparse_keymap_report_event(msi_laptop_input_dev,
0800 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
0801 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
0802 }
0803 static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
0804 static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
0805
0806 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
0807 struct serio *port)
0808 {
0809 static bool extended;
0810
0811 if (str & I8042_STR_AUXDATA)
0812 return false;
0813
0814
0815 if (unlikely(data == 0xe0)) {
0816 extended = true;
0817 return false;
0818 } else if (unlikely(extended)) {
0819 extended = false;
0820 switch (data) {
0821 case 0xE4:
0822 if (quirks->ec_delay) {
0823 schedule_delayed_work(&msi_touchpad_dwork,
0824 round_jiffies_relative(0.5 * HZ));
0825 } else
0826 schedule_work(&msi_touchpad_work);
0827 break;
0828 case 0x54:
0829 case 0x62:
0830 case 0x76:
0831 if (quirks->ec_delay) {
0832 schedule_delayed_work(&msi_rfkill_dwork,
0833 round_jiffies_relative(0.5 * HZ));
0834 } else
0835 schedule_work(&msi_rfkill_work);
0836 break;
0837 }
0838 }
0839
0840 return false;
0841 }
0842
0843 static void msi_init_rfkill(struct work_struct *ignored)
0844 {
0845 if (rfk_wlan) {
0846 rfkill_set_sw_state(rfk_wlan, !wlan_s);
0847 rfkill_wlan_set(NULL, !wlan_s);
0848 }
0849 if (rfk_bluetooth) {
0850 rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s);
0851 rfkill_bluetooth_set(NULL, !bluetooth_s);
0852 }
0853 if (rfk_threeg) {
0854 rfkill_set_sw_state(rfk_threeg, !threeg_s);
0855 rfkill_threeg_set(NULL, !threeg_s);
0856 }
0857 }
0858 static DECLARE_DELAYED_WORK(msi_rfkill_init, msi_init_rfkill);
0859
0860 static int rfkill_init(struct platform_device *sdev)
0861 {
0862
0863 int retval;
0864
0865
0866 get_wireless_state_ec_standard();
0867
0868 rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
0869 RFKILL_TYPE_BLUETOOTH,
0870 &rfkill_bluetooth_ops, NULL);
0871 if (!rfk_bluetooth) {
0872 retval = -ENOMEM;
0873 goto err_bluetooth;
0874 }
0875 retval = rfkill_register(rfk_bluetooth);
0876 if (retval)
0877 goto err_bluetooth;
0878
0879 rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
0880 &rfkill_wlan_ops, NULL);
0881 if (!rfk_wlan) {
0882 retval = -ENOMEM;
0883 goto err_wlan;
0884 }
0885 retval = rfkill_register(rfk_wlan);
0886 if (retval)
0887 goto err_wlan;
0888
0889 if (threeg_exists) {
0890 rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
0891 RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
0892 if (!rfk_threeg) {
0893 retval = -ENOMEM;
0894 goto err_threeg;
0895 }
0896 retval = rfkill_register(rfk_threeg);
0897 if (retval)
0898 goto err_threeg;
0899 }
0900
0901
0902 if (quirks->ec_delay) {
0903 schedule_delayed_work(&msi_rfkill_init,
0904 round_jiffies_relative(1 * HZ));
0905 } else
0906 schedule_work(&msi_rfkill_work);
0907
0908 return 0;
0909
0910 err_threeg:
0911 rfkill_destroy(rfk_threeg);
0912 if (rfk_wlan)
0913 rfkill_unregister(rfk_wlan);
0914 err_wlan:
0915 rfkill_destroy(rfk_wlan);
0916 if (rfk_bluetooth)
0917 rfkill_unregister(rfk_bluetooth);
0918 err_bluetooth:
0919 rfkill_destroy(rfk_bluetooth);
0920
0921 return retval;
0922 }
0923
0924 #ifdef CONFIG_PM_SLEEP
0925 static int msi_laptop_resume(struct device *device)
0926 {
0927 u8 data;
0928 int result;
0929
0930 if (!quirks->load_scm_model)
0931 return 0;
0932
0933
0934 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
0935 if (result < 0)
0936 return result;
0937
0938 result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
0939 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
0940 if (result < 0)
0941 return result;
0942
0943 return 0;
0944 }
0945 #endif
0946
0947 static int __init msi_laptop_input_setup(void)
0948 {
0949 int err;
0950
0951 msi_laptop_input_dev = input_allocate_device();
0952 if (!msi_laptop_input_dev)
0953 return -ENOMEM;
0954
0955 msi_laptop_input_dev->name = "MSI Laptop hotkeys";
0956 msi_laptop_input_dev->phys = "msi-laptop/input0";
0957 msi_laptop_input_dev->id.bustype = BUS_HOST;
0958
0959 err = sparse_keymap_setup(msi_laptop_input_dev,
0960 msi_laptop_keymap, NULL);
0961 if (err)
0962 goto err_free_dev;
0963
0964 err = input_register_device(msi_laptop_input_dev);
0965 if (err)
0966 goto err_free_dev;
0967
0968 return 0;
0969
0970 err_free_dev:
0971 input_free_device(msi_laptop_input_dev);
0972 return err;
0973 }
0974
0975 static int __init load_scm_model_init(struct platform_device *sdev)
0976 {
0977 u8 data;
0978 int result;
0979
0980 if (!quirks->ec_read_only) {
0981
0982 dev_attr_bluetooth.store = store_bluetooth;
0983 dev_attr_wlan.store = store_wlan;
0984 dev_attr_threeg.store = store_threeg;
0985 dev_attr_bluetooth.attr.mode |= S_IWUSR;
0986 dev_attr_wlan.attr.mode |= S_IWUSR;
0987 dev_attr_threeg.attr.mode |= S_IWUSR;
0988 }
0989
0990
0991 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
0992 if (result < 0)
0993 return result;
0994
0995 result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
0996 data | MSI_STANDARD_EC_SCM_LOAD_MASK);
0997 if (result < 0)
0998 return result;
0999
1000
1001 result = rfkill_init(sdev);
1002 if (result < 0)
1003 goto fail_rfkill;
1004
1005
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
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
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
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
1104
1105
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
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:*");