aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee, Chun-Yi <jlee@suse.com>2012-12-15 12:31:27 -0500
committerMatthew Garrett <matthew.garrett@nebula.com>2013-02-24 17:49:53 -0500
commit0816392b97d45b779c6ab2cfac4e1561d3ef7242 (patch)
treec0a05c2ce359b40eefc7df6399226199055ade2a
parent1b6517a0a99b3a950d708d31de1a015843039066 (diff)
msi-laptop: merge quirk tables to one
This patch introduced a quirk_entry struct, then we merged all quirk tables to msi_dmi_table. Then we can more easily to set different quirk attributes for different machine. Signed-off-by: Lee, Chun-Yi <jlee@suse.com> Changed this patch so that it could be applied before MSI Wind U100 support patch. Changed rfkill logic for ec_read_only quirk support. Removed delays if ec_delay = false. Signed-off-by: Maxim Mikityanskiy <maxtram95@gmail.com> Acked-by: Lee, Chun-Yi <jlee@suse.com> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
-rw-r--r--drivers/platform/x86/msi-laptop.c196
1 files changed, 127 insertions, 69 deletions
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 7ba107ae1d09..0bf94b5c2744 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -108,23 +108,38 @@ static const struct key_entry msi_laptop_keymap[] = {
108 108
109static struct input_dev *msi_laptop_input_dev; 109static struct input_dev *msi_laptop_input_dev;
110 110
111static bool old_ec_model;
112static int wlan_s, bluetooth_s, threeg_s; 111static int wlan_s, bluetooth_s, threeg_s;
113static int threeg_exists; 112static int threeg_exists;
114
115/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
116 * those netbook will load the SCM (windows app) to disable the original
117 * Wlan/Bluetooth control by BIOS when user press fn key, then control
118 * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
119 * cann't on/off 3G module on those 3G netbook.
120 * On Linux, msi-laptop driver will do the same thing to disable the
121 * original BIOS control, then might need use HAL or other userland
122 * application to do the software control that simulate with SCM.
123 * e.g. MSI N034 netbook
124 */
125static bool load_scm_model;
126static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg; 113static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
127 114
115/* MSI laptop quirks */
116struct quirk_entry {
117 bool old_ec_model;
118
119 /* Some MSI 3G netbook only have one fn key to control
120 * Wlan/Bluetooth/3G, those netbook will load the SCM (windows app) to
121 * disable the original Wlan/Bluetooth control by BIOS when user press
122 * fn key, then control Wlan/Bluetooth/3G by SCM (software control by
123 * OS). Without SCM, user cann't on/off 3G module on those 3G netbook.
124 * On Linux, msi-laptop driver will do the same thing to disable the
125 * original BIOS control, then might need use HAL or other userland
126 * application to do the software control that simulate with SCM.
127 * e.g. MSI N034 netbook
128 */
129 bool load_scm_model;
130
131 /* Some MSI laptops need delay before reading from EC */
132 bool ec_delay;
133
134 /* Some MSI Wind netbooks (e.g. MSI Wind U100) need loading SCM to get
135 * some features working (e.g. ECO mode), but we cannot change
136 * Wlan/Bluetooth state in software and we can only read its state.
137 */
138 bool ec_read_only;
139};
140
141static struct quirk_entry *quirks;
142
128/* Hardware access */ 143/* Hardware access */
129 144
130static int set_lcd_level(int level) 145static int set_lcd_level(int level)
@@ -195,6 +210,9 @@ static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
195 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1)) 210 if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
196 return -EINVAL; 211 return -EINVAL;
197 212
213 if (quirks->ec_read_only)
214 return -EOPNOTSUPP;
215
198 /* read current device state */ 216 /* read current device state */
199 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata); 217 result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
200 if (result < 0) 218 if (result < 0)
@@ -293,7 +311,7 @@ static ssize_t show_wlan(struct device *dev,
293 311
294 int ret, enabled = 0; 312 int ret, enabled = 0;
295 313
296 if (old_ec_model) { 314 if (quirks->old_ec_model) {
297 ret = get_wireless_state(&enabled, NULL); 315 ret = get_wireless_state(&enabled, NULL);
298 } else { 316 } else {
299 ret = get_wireless_state_ec_standard(); 317 ret = get_wireless_state_ec_standard();
@@ -317,7 +335,7 @@ static ssize_t show_bluetooth(struct device *dev,
317 335
318 int ret, enabled = 0; 336 int ret, enabled = 0;
319 337
320 if (old_ec_model) { 338 if (quirks->old_ec_model) {
321 ret = get_wireless_state(NULL, &enabled); 339 ret = get_wireless_state(NULL, &enabled);
322 } else { 340 } else {
323 ret = get_wireless_state_ec_standard(); 341 ret = get_wireless_state_ec_standard();
@@ -342,7 +360,7 @@ static ssize_t show_threeg(struct device *dev,
342 int ret; 360 int ret;
343 361
344 /* old msi ec not support 3G */ 362 /* old msi ec not support 3G */
345 if (old_ec_model) 363 if (quirks->old_ec_model)
346 return -ENODEV; 364 return -ENODEV;
347 365
348 ret = get_wireless_state_ec_standard(); 366 ret = get_wireless_state_ec_standard();
@@ -448,9 +466,26 @@ static struct platform_device *msipf_device;
448 466
449/* Initialization */ 467/* Initialization */
450 468
451static int dmi_check_cb(const struct dmi_system_id *id) 469static struct quirk_entry quirk_old_ec_model = {
470 .old_ec_model = true,
471};
472
473static struct quirk_entry quirk_load_scm_model = {
474 .load_scm_model = true,
475 .ec_delay = true,
476};
477
478static struct quirk_entry quirk_load_scm_ro_model = {
479 .load_scm_model = true,
480 .ec_read_only = true,
481};
482
483static int dmi_check_cb(const struct dmi_system_id *dmi)
452{ 484{
453 pr_info("Identified laptop model '%s'\n", id->ident); 485 pr_info("Identified laptop model '%s'\n", dmi->ident);
486
487 quirks = dmi->driver_data;
488
454 return 1; 489 return 1;
455} 490}
456 491
@@ -464,6 +499,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
464 DMI_MATCH(DMI_CHASSIS_VENDOR, 499 DMI_MATCH(DMI_CHASSIS_VENDOR,
465 "MICRO-STAR INT'L CO.,LTD") 500 "MICRO-STAR INT'L CO.,LTD")
466 }, 501 },
502 .driver_data = &quirk_old_ec_model,
467 .callback = dmi_check_cb 503 .callback = dmi_check_cb
468 }, 504 },
469 { 505 {
@@ -474,6 +510,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
474 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"), 510 DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
475 DMI_MATCH(DMI_BOARD_NAME, "MS-1058") 511 DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
476 }, 512 },
513 .driver_data = &quirk_old_ec_model,
477 .callback = dmi_check_cb 514 .callback = dmi_check_cb
478 }, 515 },
479 { 516 {
@@ -484,6 +521,7 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
484 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), 521 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
485 DMI_MATCH(DMI_BOARD_NAME, "MS-1412") 522 DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
486 }, 523 },
524 .driver_data = &quirk_old_ec_model,
487 .callback = dmi_check_cb 525 .callback = dmi_check_cb
488 }, 526 },
489 { 527 {
@@ -495,12 +533,9 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
495 DMI_MATCH(DMI_CHASSIS_VENDOR, 533 DMI_MATCH(DMI_CHASSIS_VENDOR,
496 "MICRO-STAR INT'L CO.,LTD") 534 "MICRO-STAR INT'L CO.,LTD")
497 }, 535 },
536 .driver_data = &quirk_old_ec_model,
498 .callback = dmi_check_cb 537 .callback = dmi_check_cb
499 }, 538 },
500 { }
501};
502
503static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
504 { 539 {
505 .ident = "MSI N034", 540 .ident = "MSI N034",
506 .matches = { 541 .matches = {
@@ -510,6 +545,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
510 DMI_MATCH(DMI_CHASSIS_VENDOR, 545 DMI_MATCH(DMI_CHASSIS_VENDOR,
511 "MICRO-STAR INTERNATIONAL CO., LTD") 546 "MICRO-STAR INTERNATIONAL CO., LTD")
512 }, 547 },
548 .driver_data = &quirk_load_scm_model,
513 .callback = dmi_check_cb 549 .callback = dmi_check_cb
514 }, 550 },
515 { 551 {
@@ -521,6 +557,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
521 DMI_MATCH(DMI_CHASSIS_VENDOR, 557 DMI_MATCH(DMI_CHASSIS_VENDOR,
522 "MICRO-STAR INTERNATIONAL CO., LTD") 558 "MICRO-STAR INTERNATIONAL CO., LTD")
523 }, 559 },
560 .driver_data = &quirk_load_scm_model,
524 .callback = dmi_check_cb 561 .callback = dmi_check_cb
525 }, 562 },
526 { 563 {
@@ -530,6 +567,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
530 "MICRO-STAR INTERNATIONAL CO., LTD"), 567 "MICRO-STAR INTERNATIONAL CO., LTD"),
531 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"), 568 DMI_MATCH(DMI_PRODUCT_NAME, "MS-N014"),
532 }, 569 },
570 .driver_data = &quirk_load_scm_model,
533 .callback = dmi_check_cb 571 .callback = dmi_check_cb
534 }, 572 },
535 { 573 {
@@ -539,6 +577,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
539 "Micro-Star International"), 577 "Micro-Star International"),
540 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"), 578 DMI_MATCH(DMI_PRODUCT_NAME, "CR620"),
541 }, 579 },
580 .driver_data = &quirk_load_scm_model,
542 .callback = dmi_check_cb 581 .callback = dmi_check_cb
543 }, 582 },
544 { 583 {
@@ -548,6 +587,7 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
548 "Micro-Star International Co., Ltd."), 587 "Micro-Star International Co., Ltd."),
549 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), 588 DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
550 }, 589 },
590 .driver_data = &quirk_load_scm_model,
551 .callback = dmi_check_cb 591 .callback = dmi_check_cb
552 }, 592 },
553 { } 593 { }
@@ -560,32 +600,26 @@ static int rfkill_bluetooth_set(void *data, bool blocked)
560 * blocked == false is on 600 * blocked == false is on
561 * blocked == true is off 601 * blocked == true is off
562 */ 602 */
563 if (blocked) 603 int result = set_device_state(blocked ? "0" : "1", 0,
564 set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK); 604 MSI_STANDARD_EC_BLUETOOTH_MASK);
565 else
566 set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
567 605
568 return 0; 606 return min(result, 0);
569} 607}
570 608
571static int rfkill_wlan_set(void *data, bool blocked) 609static int rfkill_wlan_set(void *data, bool blocked)
572{ 610{
573 if (blocked) 611 int result = set_device_state(blocked ? "0" : "1", 0,
574 set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK); 612 MSI_STANDARD_EC_WLAN_MASK);
575 else
576 set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
577 613
578 return 0; 614 return min(result, 0);
579} 615}
580 616
581static int rfkill_threeg_set(void *data, bool blocked) 617static int rfkill_threeg_set(void *data, bool blocked)
582{ 618{
583 if (blocked) 619 int result = set_device_state(blocked ? "0" : "1", 0,
584 set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK); 620 MSI_STANDARD_EC_3G_MASK);
585 else
586 set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
587 621
588 return 0; 622 return min(result, 0);
589} 623}
590 624
591static const struct rfkill_ops rfkill_bluetooth_ops = { 625static const struct rfkill_ops rfkill_bluetooth_ops = {
@@ -618,18 +652,27 @@ static void rfkill_cleanup(void)
618 } 652 }
619} 653}
620 654
655static bool msi_rfkill_set_state(struct rfkill *rfkill, bool blocked)
656{
657 if (quirks->ec_read_only)
658 return rfkill_set_hw_state(rfkill, blocked);
659 else
660 return rfkill_set_sw_state(rfkill, blocked);
661}
662
621static void msi_update_rfkill(struct work_struct *ignored) 663static void msi_update_rfkill(struct work_struct *ignored)
622{ 664{
623 get_wireless_state_ec_standard(); 665 get_wireless_state_ec_standard();
624 666
625 if (rfk_wlan) 667 if (rfk_wlan)
626 rfkill_set_sw_state(rfk_wlan, !wlan_s); 668 msi_rfkill_set_state(rfk_wlan, !wlan_s);
627 if (rfk_bluetooth) 669 if (rfk_bluetooth)
628 rfkill_set_sw_state(rfk_bluetooth, !bluetooth_s); 670 msi_rfkill_set_state(rfk_bluetooth, !bluetooth_s);
629 if (rfk_threeg) 671 if (rfk_threeg)
630 rfkill_set_sw_state(rfk_threeg, !threeg_s); 672 msi_rfkill_set_state(rfk_threeg, !threeg_s);
631} 673}
632static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 674static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
675static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
633 676
634static void msi_send_touchpad_key(struct work_struct *ignored) 677static void msi_send_touchpad_key(struct work_struct *ignored)
635{ 678{
@@ -644,7 +687,8 @@ static void msi_send_touchpad_key(struct work_struct *ignored)
644 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? 687 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
645 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); 688 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
646} 689}
647static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); 690static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
691static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
648 692
649static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 693static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
650 struct serio *port) 694 struct serio *port)
@@ -662,14 +706,20 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
662 extended = false; 706 extended = false;
663 switch (data) { 707 switch (data) {
664 case 0xE4: 708 case 0xE4:
665 schedule_delayed_work(&msi_touchpad_work, 709 if (quirks->ec_delay) {
666 round_jiffies_relative(0.5 * HZ)); 710 schedule_delayed_work(&msi_touchpad_dwork,
711 round_jiffies_relative(0.5 * HZ));
712 } else
713 schedule_work(&msi_touchpad_work);
667 break; 714 break;
668 case 0x54: 715 case 0x54:
669 case 0x62: 716 case 0x62:
670 case 0x76: 717 case 0x76:
671 schedule_delayed_work(&msi_rfkill_work, 718 if (quirks->ec_delay) {
672 round_jiffies_relative(0.5 * HZ)); 719 schedule_delayed_work(&msi_rfkill_dwork,
720 round_jiffies_relative(0.5 * HZ));
721 } else
722 schedule_work(&msi_rfkill_work);
673 break; 723 break;
674 } 724 }
675 } 725 }
@@ -736,8 +786,11 @@ static int rfkill_init(struct platform_device *sdev)
736 } 786 }
737 787
738 /* schedule to run rfkill state initial */ 788 /* schedule to run rfkill state initial */
739 schedule_delayed_work(&msi_rfkill_init, 789 if (quirks->ec_delay) {
740 round_jiffies_relative(1 * HZ)); 790 schedule_delayed_work(&msi_rfkill_init,
791 round_jiffies_relative(1 * HZ));
792 } else
793 schedule_work(&msi_rfkill_work);
741 794
742 return 0; 795 return 0;
743 796
@@ -761,7 +814,7 @@ static int msi_laptop_resume(struct device *device)
761 u8 data; 814 u8 data;
762 int result; 815 int result;
763 816
764 if (!load_scm_model) 817 if (!quirks->load_scm_model)
765 return 0; 818 return 0;
766 819
767 /* set load SCM to disable hardware control by fn key */ 820 /* set load SCM to disable hardware control by fn key */
@@ -819,13 +872,15 @@ static int __init load_scm_model_init(struct platform_device *sdev)
819 u8 data; 872 u8 data;
820 int result; 873 int result;
821 874
822 /* allow userland write sysfs file */ 875 if (!quirks->ec_read_only) {
823 dev_attr_bluetooth.store = store_bluetooth; 876 /* allow userland write sysfs file */
824 dev_attr_wlan.store = store_wlan; 877 dev_attr_bluetooth.store = store_bluetooth;
825 dev_attr_threeg.store = store_threeg; 878 dev_attr_wlan.store = store_wlan;
826 dev_attr_bluetooth.attr.mode |= S_IWUSR; 879 dev_attr_threeg.store = store_threeg;
827 dev_attr_wlan.attr.mode |= S_IWUSR; 880 dev_attr_bluetooth.attr.mode |= S_IWUSR;
828 dev_attr_threeg.attr.mode |= S_IWUSR; 881 dev_attr_wlan.attr.mode |= S_IWUSR;
882 dev_attr_threeg.attr.mode |= S_IWUSR;
883 }
829 884
830 /* disable hardware control by fn key */ 885 /* disable hardware control by fn key */
831 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data); 886 result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
@@ -874,15 +929,16 @@ static int __init msi_init(void)
874 if (acpi_disabled) 929 if (acpi_disabled)
875 return -ENODEV; 930 return -ENODEV;
876 931
877 if (force || dmi_check_system(msi_dmi_table)) 932 dmi_check_system(msi_dmi_table);
878 old_ec_model = 1; 933 if (!quirks)
934 /* quirks may be NULL if no match in DMI table */
935 quirks = &quirk_load_scm_model;
936 if (force)
937 quirks = &quirk_old_ec_model;
879 938
880 if (!old_ec_model) 939 if (!quirks->old_ec_model)
881 get_threeg_exists(); 940 get_threeg_exists();
882 941
883 if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
884 load_scm_model = 1;
885
886 if (auto_brightness < 0 || auto_brightness > 2) 942 if (auto_brightness < 0 || auto_brightness > 2)
887 return -EINVAL; 943 return -EINVAL;
888 944
@@ -918,7 +974,7 @@ static int __init msi_init(void)
918 if (ret) 974 if (ret)
919 goto fail_platform_device1; 975 goto fail_platform_device1;
920 976
921 if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) { 977 if (quirks->load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
922 ret = -EINVAL; 978 ret = -EINVAL;
923 goto fail_platform_device1; 979 goto fail_platform_device1;
924 } 980 }
@@ -928,7 +984,7 @@ static int __init msi_init(void)
928 if (ret) 984 if (ret)
929 goto fail_platform_device2; 985 goto fail_platform_device2;
930 986
931 if (!old_ec_model) { 987 if (!quirks->old_ec_model) {
932 if (threeg_exists) 988 if (threeg_exists)
933 ret = device_create_file(&msipf_device->dev, 989 ret = device_create_file(&msipf_device->dev,
934 &dev_attr_threeg); 990 &dev_attr_threeg);
@@ -949,9 +1005,10 @@ static int __init msi_init(void)
949 1005
950fail_platform_device2: 1006fail_platform_device2:
951 1007
952 if (load_scm_model) { 1008 if (quirks->load_scm_model) {
953 i8042_remove_filter(msi_laptop_i8042_filter); 1009 i8042_remove_filter(msi_laptop_i8042_filter);
954 cancel_delayed_work_sync(&msi_rfkill_work); 1010 cancel_delayed_work_sync(&msi_rfkill_dwork);
1011 cancel_work_sync(&msi_rfkill_work);
955 rfkill_cleanup(); 1012 rfkill_cleanup();
956 } 1013 }
957 platform_device_del(msipf_device); 1014 platform_device_del(msipf_device);
@@ -973,15 +1030,16 @@ fail_backlight:
973 1030
974static void __exit msi_cleanup(void) 1031static void __exit msi_cleanup(void)
975{ 1032{
976 if (load_scm_model) { 1033 if (quirks->load_scm_model) {
977 i8042_remove_filter(msi_laptop_i8042_filter); 1034 i8042_remove_filter(msi_laptop_i8042_filter);
978 msi_laptop_input_destroy(); 1035 msi_laptop_input_destroy();
979 cancel_delayed_work_sync(&msi_rfkill_work); 1036 cancel_delayed_work_sync(&msi_rfkill_dwork);
1037 cancel_work_sync(&msi_rfkill_work);
980 rfkill_cleanup(); 1038 rfkill_cleanup();
981 } 1039 }
982 1040
983 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); 1041 sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
984 if (!old_ec_model && threeg_exists) 1042 if (!quirks->old_ec_model && threeg_exists)
985 device_remove_file(&msipf_device->dev, &dev_attr_threeg); 1043 device_remove_file(&msipf_device->dev, &dev_attr_threeg);
986 platform_device_unregister(msipf_device); 1044 platform_device_unregister(msipf_device);
987 platform_driver_unregister(&msipf_driver); 1045 platform_driver_unregister(&msipf_driver);