aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/msi-laptop.c
diff options
context:
space:
mode:
authorLee, Chun-Yi <joeyli.kernel@gmail.com>2011-03-07 02:46:28 -0500
committerMatthew Garrett <mjg@redhat.com>2011-03-28 06:07:26 -0400
commit143a4c0284dc2378b3ce78866b3548d90121d843 (patch)
tree2c22036049bd6aa36ed7f6c0c632d324a617b0b3 /drivers/platform/x86/msi-laptop.c
parent8941178efad900e48e44000208513a6426c74368 (diff)
msi-laptop: send out touchpad on/off key
MSI BIOS's raw behavior is send out KEY_TOUCHPAD_TOGGLE key when user pressed touchpad hotkey. Actually, we can capture the real touchpad status by read 0xE4 EC address on MSI netbook/notebook. So, add msi-laptop input device for send out KEY_TOUCHPAD_ON or KEY_TOUCHPAD_OFF key when user pressed Fn+F3 touchpad hotkey. It leave userland applications to know the real touchpad status. Tested on MSI netbook U-100, U-115, U160(N051), U160DX, N014, N034 Tested on MSI notebook CR620 Cc: Carlos Corbacho <carlos@strangeworlds.co.uk> Cc: Matthew Garrett <mjg@redhat.com> Cc: Dmitry Torokhov <dtor@mail.ru> Cc: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Lee, Chun-Yi <jlee@novell.com> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/msi-laptop.c')
-rw-r--r--drivers/platform/x86/msi-laptop.c81
1 files changed, 79 insertions, 2 deletions
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 142d38579314..fb4da28f5906 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -60,6 +60,8 @@
60#include <linux/platform_device.h> 60#include <linux/platform_device.h>
61#include <linux/rfkill.h> 61#include <linux/rfkill.h>
62#include <linux/i8042.h> 62#include <linux/i8042.h>
63#include <linux/input.h>
64#include <linux/input/sparse-keymap.h>
63 65
64#define MSI_DRIVER_VERSION "0.5" 66#define MSI_DRIVER_VERSION "0.5"
65 67
@@ -78,6 +80,9 @@
78#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 80#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
79#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 81#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
80 82
83#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
84#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
85
81static int msi_laptop_resume(struct platform_device *device); 86static int msi_laptop_resume(struct platform_device *device);
82 87
83#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f 88#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -90,6 +95,14 @@ static int auto_brightness;
90module_param(auto_brightness, int, 0); 95module_param(auto_brightness, int, 0);
91MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); 96MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
92 97
98static const struct key_entry msi_laptop_keymap[] = {
99 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */
100 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */
101 {KE_END, 0}
102};
103
104static struct input_dev *msi_laptop_input_dev;
105
93static bool old_ec_model; 106static bool old_ec_model;
94static int wlan_s, bluetooth_s, threeg_s; 107static int wlan_s, bluetooth_s, threeg_s;
95static int threeg_exists; 108static int threeg_exists;
@@ -605,6 +618,21 @@ static void msi_update_rfkill(struct work_struct *ignored)
605} 618}
606static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 619static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
607 620
621static void msi_send_touchpad_key(struct work_struct *ignored)
622{
623 u8 rdata;
624 int result;
625
626 result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata);
627 if (result < 0)
628 return;
629
630 sparse_keymap_report_event(msi_laptop_input_dev,
631 (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
632 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
633}
634static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key);
635
608static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 636static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
609 struct serio *port) 637 struct serio *port)
610{ 638{
@@ -613,12 +641,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
613 if (str & 0x20) 641 if (str & 0x20)
614 return false; 642 return false;
615 643
616 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ 644 /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
617 if (unlikely(data == 0xe0)) { 645 if (unlikely(data == 0xe0)) {
618 extended = true; 646 extended = true;
619 return false; 647 return false;
620 } else if (unlikely(extended)) { 648 } else if (unlikely(extended)) {
649 extended = false;
621 switch (data) { 650 switch (data) {
651 case 0xE4:
652 schedule_delayed_work(&msi_touchpad_work,
653 round_jiffies_relative(0.5 * HZ));
654 break;
622 case 0x54: 655 case 0x54:
623 case 0x62: 656 case 0x62:
624 case 0x76: 657 case 0x76:
@@ -626,7 +659,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
626 round_jiffies_relative(0.5 * HZ)); 659 round_jiffies_relative(0.5 * HZ));
627 break; 660 break;
628 } 661 }
629 extended = false;
630 } 662 }
631 663
632 return false; 664 return false;
@@ -731,6 +763,42 @@ static int msi_laptop_resume(struct platform_device *device)
731 return 0; 763 return 0;
732} 764}
733 765
766static int __init msi_laptop_input_setup(void)
767{
768 int err;
769
770 msi_laptop_input_dev = input_allocate_device();
771 if (!msi_laptop_input_dev)
772 return -ENOMEM;
773
774 msi_laptop_input_dev->name = "MSI Laptop hotkeys";
775 msi_laptop_input_dev->phys = "msi-laptop/input0";
776 msi_laptop_input_dev->id.bustype = BUS_HOST;
777
778 err = sparse_keymap_setup(msi_laptop_input_dev,
779 msi_laptop_keymap, NULL);
780 if (err)
781 goto err_free_dev;
782
783 err = input_register_device(msi_laptop_input_dev);
784 if (err)
785 goto err_free_keymap;
786
787 return 0;
788
789err_free_keymap:
790 sparse_keymap_free(msi_laptop_input_dev);
791err_free_dev:
792 input_free_device(msi_laptop_input_dev);
793 return err;
794}
795
796static void msi_laptop_input_destroy(void)
797{
798 sparse_keymap_free(msi_laptop_input_dev);
799 input_unregister_device(msi_laptop_input_dev);
800}
801
734static int load_scm_model_init(struct platform_device *sdev) 802static int load_scm_model_init(struct platform_device *sdev)
735{ 803{
736 u8 data; 804 u8 data;
@@ -759,6 +827,11 @@ static int load_scm_model_init(struct platform_device *sdev)
759 if (result < 0) 827 if (result < 0)
760 goto fail_rfkill; 828 goto fail_rfkill;
761 829
830 /* setup input device */
831 result = msi_laptop_input_setup();
832 if (result)
833 goto fail_input;
834
762 result = i8042_install_filter(msi_laptop_i8042_filter); 835 result = i8042_install_filter(msi_laptop_i8042_filter);
763 if (result) { 836 if (result) {
764 printk(KERN_ERR 837 printk(KERN_ERR
@@ -769,6 +842,9 @@ static int load_scm_model_init(struct platform_device *sdev)
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:
@@ -886,6 +962,7 @@ static void __exit msi_cleanup(void)
886{ 962{
887 if (load_scm_model) { 963 if (load_scm_model) {
888 i8042_remove_filter(msi_laptop_i8042_filter); 964 i8042_remove_filter(msi_laptop_i8042_filter);
965 msi_laptop_input_destroy();
889 cancel_delayed_work_sync(&msi_rfkill_work); 966 cancel_delayed_work_sync(&msi_rfkill_work);
890 rfkill_cleanup(); 967 rfkill_cleanup();
891 } 968 }