aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/msi-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/msi-laptop.c')
-rw-r--r--drivers/platform/x86/msi-laptop.c111
1 files changed, 94 insertions, 17 deletions
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 7e9bb6df9d39..3ff629df9f01 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -51,6 +51,8 @@
51 * laptop as MSI S270. YMMV. 51 * laptop as MSI S270. YMMV.
52 */ 52 */
53 53
54#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
55
54#include <linux/module.h> 56#include <linux/module.h>
55#include <linux/kernel.h> 57#include <linux/kernel.h>
56#include <linux/init.h> 58#include <linux/init.h>
@@ -60,6 +62,8 @@
60#include <linux/platform_device.h> 62#include <linux/platform_device.h>
61#include <linux/rfkill.h> 63#include <linux/rfkill.h>
62#include <linux/i8042.h> 64#include <linux/i8042.h>
65#include <linux/input.h>
66#include <linux/input/sparse-keymap.h>
63 67
64#define MSI_DRIVER_VERSION "0.5" 68#define MSI_DRIVER_VERSION "0.5"
65 69
@@ -78,6 +82,9 @@
78#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 82#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
79#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 83#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
80 84
85#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
86#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
87
81static int msi_laptop_resume(struct platform_device *device); 88static int msi_laptop_resume(struct platform_device *device);
82 89
83#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f 90#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -90,6 +97,14 @@ static int auto_brightness;
90module_param(auto_brightness, int, 0); 97module_param(auto_brightness, int, 0);
91MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); 98MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
92 99
100static 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
106static struct input_dev *msi_laptop_input_dev;
107
93static bool old_ec_model; 108static bool old_ec_model;
94static int wlan_s, bluetooth_s, threeg_s; 109static int wlan_s, bluetooth_s, threeg_s;
95static int threeg_exists; 110static int threeg_exists;
@@ -120,7 +135,7 @@ static int set_lcd_level(int level)
120 buf[1] = (u8) (level*31); 135 buf[1] = (u8) (level*31);
121 136
122 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), 137 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf),
123 NULL, 0, 1); 138 NULL, 0);
124} 139}
125 140
126static int get_lcd_level(void) 141static int get_lcd_level(void)
@@ -129,7 +144,7 @@ static int get_lcd_level(void)
129 int result; 144 int result;
130 145
131 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, 146 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
132 &rdata, 1, 1); 147 &rdata, 1);
133 if (result < 0) 148 if (result < 0)
134 return result; 149 return result;
135 150
@@ -142,7 +157,7 @@ static int get_auto_brightness(void)
142 int result; 157 int result;
143 158
144 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, 159 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1,
145 &rdata, 1, 1); 160 &rdata, 1);
146 if (result < 0) 161 if (result < 0)
147 return result; 162 return result;
148 163
@@ -157,7 +172,7 @@ static int set_auto_brightness(int enable)
157 wdata[0] = 4; 172 wdata[0] = 4;
158 173
159 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, 174 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1,
160 &rdata, 1, 1); 175 &rdata, 1);
161 if (result < 0) 176 if (result < 0)
162 return result; 177 return result;
163 178
@@ -165,7 +180,7 @@ static int set_auto_brightness(int enable)
165 wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); 180 wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
166 181
167 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, 182 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2,
168 NULL, 0, 1); 183 NULL, 0);
169} 184}
170 185
171static ssize_t set_device_state(const char *buf, size_t count, u8 mask) 186static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
@@ -202,7 +217,7 @@ static int get_wireless_state(int *wlan, int *bluetooth)
202 u8 wdata = 0, rdata; 217 u8 wdata = 0, rdata;
203 int result; 218 int result;
204 219
205 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1); 220 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
206 if (result < 0) 221 if (result < 0)
207 return -1; 222 return -1;
208 223
@@ -432,8 +447,7 @@ static struct platform_device *msipf_device;
432 447
433static int dmi_check_cb(const struct dmi_system_id *id) 448static int dmi_check_cb(const struct dmi_system_id *id)
434{ 449{
435 printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", 450 pr_info("Identified laptop model '%s'\n", id->ident);
436 id->ident);
437 return 1; 451 return 1;
438} 452}
439 453
@@ -605,6 +619,21 @@ static void msi_update_rfkill(struct work_struct *ignored)
605} 619}
606static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 620static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
607 621
622static void msi_send_touchpad_key(struct work_struct *ignored)
623{
624 u8 rdata;
625 int result;
626
627 result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata);
628 if (result < 0)
629 return;
630
631 sparse_keymap_report_event(msi_laptop_input_dev,
632 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
633 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
634}
635static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key);
636
608static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 637static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
609 struct serio *port) 638 struct serio *port)
610{ 639{
@@ -613,12 +642,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
613 if (str & 0x20) 642 if (str & 0x20)
614 return false; 643 return false;
615 644
616 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ 645 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
617 if (unlikely(data == 0xe0)) { 646 if (unlikely(data == 0xe0)) {
618 extended = true; 647 extended = true;
619 return false; 648 return false;
620 } else if (unlikely(extended)) { 649 } else if (unlikely(extended)) {
650 extended = false;
621 switch (data) { 651 switch (data) {
652 case 0xE4:
653 schedule_delayed_work(&msi_touchpad_work,
654 round_jiffies_relative(0.5 * HZ));
655 break;
622 case 0x54: 656 case 0x54:
623 case 0x62: 657 case 0x62:
624 case 0x76: 658 case 0x76:
@@ -626,7 +660,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
626 round_jiffies_relative(0.5 * HZ)); 660 round_jiffies_relative(0.5 * HZ));
627 break; 661 break;
628 } 662 }
629 extended = false;
630 } 663 }
631 664
632 return false; 665 return false;
@@ -731,7 +764,43 @@ static int msi_laptop_resume(struct platform_device *device)
731 return 0; 764 return 0;
732} 765}
733 766
734static int load_scm_model_init(struct platform_device *sdev) 767static int __init msi_laptop_input_setup(void)
768{
769 int err;
770
771 msi_laptop_input_dev = input_allocate_device();
772 if (!msi_laptop_input_dev)
773 return -ENOMEM;
774
775 msi_laptop_input_dev->name = "MSI Laptop hotkeys";
776 msi_laptop_input_dev->phys = "msi-laptop/input0";
777 msi_laptop_input_dev->id.bustype = BUS_HOST;
778
779 err = sparse_keymap_setup(msi_laptop_input_dev,
780 msi_laptop_keymap, NULL);
781 if (err)
782 goto err_free_dev;
783
784 err = input_register_device(msi_laptop_input_dev);
785 if (err)
786 goto err_free_keymap;
787
788 return 0;
789
790err_free_keymap:
791 sparse_keymap_free(msi_laptop_input_dev);
792err_free_dev:
793 input_free_device(msi_laptop_input_dev);
794 return err;
795}
796
797static void msi_laptop_input_destroy(void)
798{
799 sparse_keymap_free(msi_laptop_input_dev);
800 input_unregister_device(msi_laptop_input_dev);
801}
802
803static int __init load_scm_model_init(struct platform_device *sdev)
735{ 804{
736 u8 data; 805 u8 data;
737 int result; 806 int result;
@@ -759,16 +828,23 @@ static int load_scm_model_init(struct platform_device *sdev)
759 if (result < 0) 828 if (result < 0)
760 goto fail_rfkill; 829 goto fail_rfkill;
761 830
831 /* setup input device */
832 result = msi_laptop_input_setup();
833 if (result)
834 goto fail_input;
835
762 result = i8042_install_filter(msi_laptop_i8042_filter); 836 result = i8042_install_filter(msi_laptop_i8042_filter);
763 if (result) { 837 if (result) {
764 printk(KERN_ERR 838 pr_err("Unable to install key filter\n");
765 "msi-laptop: Unable to install key filter\n");
766 goto fail_filter; 839 goto fail_filter;
767 } 840 }
768 841
769 return 0; 842 return 0;
770 843
771fail_filter: 844fail_filter:
845 msi_laptop_input_destroy();
846
847fail_input:
772 rfkill_cleanup(); 848 rfkill_cleanup();
773 849
774fail_rfkill: 850fail_rfkill:
@@ -799,11 +875,11 @@ static int __init msi_init(void)
799 /* Register backlight stuff */ 875 /* Register backlight stuff */
800 876
801 if (acpi_video_backlight_support()) { 877 if (acpi_video_backlight_support()) {
802 printk(KERN_INFO "MSI: Brightness ignored, must be controlled " 878 pr_info("Brightness ignored, must be controlled by ACPI video driver\n");
803 "by ACPI video driver\n");
804 } else { 879 } else {
805 struct backlight_properties props; 880 struct backlight_properties props;
806 memset(&props, 0, sizeof(struct backlight_properties)); 881 memset(&props, 0, sizeof(struct backlight_properties));
882 props.type = BACKLIGHT_PLATFORM;
807 props.max_brightness = MSI_LCD_LEVEL_MAX - 1; 883 props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
808 msibl_device = backlight_device_register("msi-laptop-bl", NULL, 884 msibl_device = backlight_device_register("msi-laptop-bl", NULL,
809 NULL, &msibl_ops, 885 NULL, &msibl_ops,
@@ -853,7 +929,7 @@ static int __init msi_init(void)
853 if (auto_brightness != 2) 929 if (auto_brightness != 2)
854 set_auto_brightness(auto_brightness); 930 set_auto_brightness(auto_brightness);
855 931
856 printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); 932 pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
857 933
858 return 0; 934 return 0;
859 935
@@ -885,6 +961,7 @@ static void __exit msi_cleanup(void)
885{ 961{
886 if (load_scm_model) { 962 if (load_scm_model) {
887 i8042_remove_filter(msi_laptop_i8042_filter); 963 i8042_remove_filter(msi_laptop_i8042_filter);
964 msi_laptop_input_destroy();
888 cancel_delayed_work_sync(&msi_rfkill_work); 965 cancel_delayed_work_sync(&msi_rfkill_work);
889 rfkill_cleanup(); 966 rfkill_cleanup();
890 } 967 }
@@ -900,7 +977,7 @@ static void __exit msi_cleanup(void)
900 if (auto_brightness != 2) 977 if (auto_brightness != 2)
901 set_auto_brightness(1); 978 set_auto_brightness(1);
902 979
903 printk(KERN_INFO "msi-laptop: driver unloaded.\n"); 980 pr_info("driver unloaded\n");
904} 981}
905 982
906module_init(msi_init); 983module_init(msi_init);