diff options
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 206 |
1 files changed, 199 insertions, 7 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 77bf5d8f893a..26c211724acf 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/backlight.h> | 46 | #include <linux/backlight.h> |
47 | #include <linux/platform_device.h> | 47 | #include <linux/platform_device.h> |
48 | #include <linux/rfkill.h> | 48 | #include <linux/rfkill.h> |
49 | #include <linux/input.h> | ||
49 | 50 | ||
50 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
51 | 52 | ||
@@ -62,9 +63,10 @@ MODULE_LICENSE("GPL"); | |||
62 | 63 | ||
63 | /* Toshiba ACPI method paths */ | 64 | /* Toshiba ACPI method paths */ |
64 | #define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM" | 65 | #define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM" |
65 | #define METHOD_HCI_1 "\\_SB_.VALD.GHCI" | 66 | #define TOSH_INTERFACE_1 "\\_SB_.VALD" |
66 | #define METHOD_HCI_2 "\\_SB_.VALZ.GHCI" | 67 | #define TOSH_INTERFACE_2 "\\_SB_.VALZ" |
67 | #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" | 68 | #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" |
69 | #define GHCI_METHOD ".GHCI" | ||
68 | 70 | ||
69 | /* Toshiba HCI interface definitions | 71 | /* Toshiba HCI interface definitions |
70 | * | 72 | * |
@@ -116,6 +118,36 @@ static const struct acpi_device_id toshiba_device_ids[] = { | |||
116 | }; | 118 | }; |
117 | MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); | 119 | MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); |
118 | 120 | ||
121 | struct key_entry { | ||
122 | char type; | ||
123 | u16 code; | ||
124 | u16 keycode; | ||
125 | }; | ||
126 | |||
127 | enum {KE_KEY, KE_END}; | ||
128 | |||
129 | static struct key_entry toshiba_acpi_keymap[] = { | ||
130 | {KE_KEY, 0x101, KEY_MUTE}, | ||
131 | {KE_KEY, 0x13b, KEY_COFFEE}, | ||
132 | {KE_KEY, 0x13c, KEY_BATTERY}, | ||
133 | {KE_KEY, 0x13d, KEY_SLEEP}, | ||
134 | {KE_KEY, 0x13e, KEY_SUSPEND}, | ||
135 | {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE}, | ||
136 | {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN}, | ||
137 | {KE_KEY, 0x141, KEY_BRIGHTNESSUP}, | ||
138 | {KE_KEY, 0x142, KEY_WLAN}, | ||
139 | {KE_KEY, 0x143, KEY_PROG1}, | ||
140 | {KE_KEY, 0xb05, KEY_PROG2}, | ||
141 | {KE_KEY, 0xb06, KEY_WWW}, | ||
142 | {KE_KEY, 0xb07, KEY_MAIL}, | ||
143 | {KE_KEY, 0xb30, KEY_STOP}, | ||
144 | {KE_KEY, 0xb31, KEY_PREVIOUSSONG}, | ||
145 | {KE_KEY, 0xb32, KEY_NEXTSONG}, | ||
146 | {KE_KEY, 0xb33, KEY_PLAYPAUSE}, | ||
147 | {KE_KEY, 0xb5a, KEY_MEDIA}, | ||
148 | {KE_END, 0, 0}, | ||
149 | }; | ||
150 | |||
119 | /* utility | 151 | /* utility |
120 | */ | 152 | */ |
121 | 153 | ||
@@ -251,6 +283,8 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) | |||
251 | struct toshiba_acpi_dev { | 283 | struct toshiba_acpi_dev { |
252 | struct platform_device *p_dev; | 284 | struct platform_device *p_dev; |
253 | struct rfkill *bt_rfk; | 285 | struct rfkill *bt_rfk; |
286 | struct input_dev *hotkey_dev; | ||
287 | acpi_handle handle; | ||
254 | 288 | ||
255 | const char *bt_name; | 289 | const char *bt_name; |
256 | 290 | ||
@@ -711,8 +745,159 @@ static struct backlight_ops toshiba_backlight_data = { | |||
711 | .update_status = set_lcd_status, | 745 | .update_status = set_lcd_status, |
712 | }; | 746 | }; |
713 | 747 | ||
748 | static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code) | ||
749 | { | ||
750 | struct key_entry *key; | ||
751 | |||
752 | for (key = toshiba_acpi_keymap; key->type != KE_END; key++) | ||
753 | if (code == key->code) | ||
754 | return key; | ||
755 | |||
756 | return NULL; | ||
757 | } | ||
758 | |||
759 | static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code) | ||
760 | { | ||
761 | struct key_entry *key; | ||
762 | |||
763 | for (key = toshiba_acpi_keymap; key->type != KE_END; key++) | ||
764 | if (code == key->keycode && key->type == KE_KEY) | ||
765 | return key; | ||
766 | |||
767 | return NULL; | ||
768 | } | ||
769 | |||
770 | static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode, | ||
771 | int *keycode) | ||
772 | { | ||
773 | struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode); | ||
774 | |||
775 | if (key && key->type == KE_KEY) { | ||
776 | *keycode = key->keycode; | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | return -EINVAL; | ||
781 | } | ||
782 | |||
783 | static int toshiba_acpi_setkeycode(struct input_dev *dev, int scancode, | ||
784 | int keycode) | ||
785 | { | ||
786 | struct key_entry *key; | ||
787 | int old_keycode; | ||
788 | |||
789 | if (keycode < 0 || keycode > KEY_MAX) | ||
790 | return -EINVAL; | ||
791 | |||
792 | key = toshiba_acpi_get_entry_by_scancode(scancode); | ||
793 | if (key && key->type == KE_KEY) { | ||
794 | old_keycode = key->keycode; | ||
795 | key->keycode = keycode; | ||
796 | set_bit(keycode, dev->keybit); | ||
797 | if (!toshiba_acpi_get_entry_by_keycode(old_keycode)) | ||
798 | clear_bit(old_keycode, dev->keybit); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | return -EINVAL; | ||
803 | } | ||
804 | |||
805 | static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context) | ||
806 | { | ||
807 | u32 hci_result, value; | ||
808 | struct key_entry *key; | ||
809 | |||
810 | if (event != 0x80) | ||
811 | return; | ||
812 | do { | ||
813 | hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result); | ||
814 | if (hci_result == HCI_SUCCESS) { | ||
815 | if (value == 0x100) | ||
816 | continue; | ||
817 | else if (value & 0x80) { | ||
818 | key = toshiba_acpi_get_entry_by_scancode | ||
819 | (value & ~0x80); | ||
820 | if (!key) { | ||
821 | printk(MY_INFO "Unknown key %x\n", | ||
822 | value & ~0x80); | ||
823 | continue; | ||
824 | } | ||
825 | input_report_key(toshiba_acpi.hotkey_dev, | ||
826 | key->keycode, 1); | ||
827 | input_sync(toshiba_acpi.hotkey_dev); | ||
828 | input_report_key(toshiba_acpi.hotkey_dev, | ||
829 | key->keycode, 0); | ||
830 | input_sync(toshiba_acpi.hotkey_dev); | ||
831 | } | ||
832 | } else if (hci_result == HCI_NOT_SUPPORTED) { | ||
833 | /* This is a workaround for an unresolved issue on | ||
834 | * some machines where system events sporadically | ||
835 | * become disabled. */ | ||
836 | hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result); | ||
837 | printk(MY_NOTICE "Re-enabled hotkeys\n"); | ||
838 | } | ||
839 | } while (hci_result != HCI_EMPTY); | ||
840 | } | ||
841 | |||
842 | static int toshiba_acpi_setup_keyboard(char *device) | ||
843 | { | ||
844 | acpi_status status; | ||
845 | acpi_handle handle; | ||
846 | int result; | ||
847 | const struct key_entry *key; | ||
848 | |||
849 | status = acpi_get_handle(NULL, device, &handle); | ||
850 | if (ACPI_FAILURE(status)) { | ||
851 | printk(MY_INFO "Unable to get notification device\n"); | ||
852 | return -ENODEV; | ||
853 | } | ||
854 | |||
855 | toshiba_acpi.handle = handle; | ||
856 | |||
857 | status = acpi_evaluate_object(handle, "ENAB", NULL, NULL); | ||
858 | if (ACPI_FAILURE(status)) { | ||
859 | printk(MY_INFO "Unable to enable hotkeys\n"); | ||
860 | return -ENODEV; | ||
861 | } | ||
862 | |||
863 | status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, | ||
864 | toshiba_acpi_notify, NULL); | ||
865 | if (ACPI_FAILURE(status)) { | ||
866 | printk(MY_INFO "Unable to install hotkey notification\n"); | ||
867 | return -ENODEV; | ||
868 | } | ||
869 | |||
870 | toshiba_acpi.hotkey_dev = input_allocate_device(); | ||
871 | if (!toshiba_acpi.hotkey_dev) { | ||
872 | printk(MY_INFO "Unable to register input device\n"); | ||
873 | return -ENOMEM; | ||
874 | } | ||
875 | |||
876 | toshiba_acpi.hotkey_dev->name = "Toshiba input device"; | ||
877 | toshiba_acpi.hotkey_dev->phys = device; | ||
878 | toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST; | ||
879 | toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode; | ||
880 | toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode; | ||
881 | |||
882 | for (key = toshiba_acpi_keymap; key->type != KE_END; key++) { | ||
883 | set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit); | ||
884 | set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit); | ||
885 | } | ||
886 | |||
887 | result = input_register_device(toshiba_acpi.hotkey_dev); | ||
888 | if (result) { | ||
889 | printk(MY_INFO "Unable to register input device\n"); | ||
890 | return result; | ||
891 | } | ||
892 | |||
893 | return 0; | ||
894 | } | ||
895 | |||
714 | static void toshiba_acpi_exit(void) | 896 | static void toshiba_acpi_exit(void) |
715 | { | 897 | { |
898 | if (toshiba_acpi.hotkey_dev) | ||
899 | input_unregister_device(toshiba_acpi.hotkey_dev); | ||
900 | |||
716 | if (toshiba_acpi.bt_rfk) { | 901 | if (toshiba_acpi.bt_rfk) { |
717 | rfkill_unregister(toshiba_acpi.bt_rfk); | 902 | rfkill_unregister(toshiba_acpi.bt_rfk); |
718 | rfkill_destroy(toshiba_acpi.bt_rfk); | 903 | rfkill_destroy(toshiba_acpi.bt_rfk); |
@@ -726,6 +911,9 @@ static void toshiba_acpi_exit(void) | |||
726 | if (toshiba_proc_dir) | 911 | if (toshiba_proc_dir) |
727 | remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); | 912 | remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); |
728 | 913 | ||
914 | acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY, | ||
915 | toshiba_acpi_notify); | ||
916 | |||
729 | platform_device_unregister(toshiba_acpi.p_dev); | 917 | platform_device_unregister(toshiba_acpi.p_dev); |
730 | 918 | ||
731 | return; | 919 | return; |
@@ -742,11 +930,15 @@ static int __init toshiba_acpi_init(void) | |||
742 | return -ENODEV; | 930 | return -ENODEV; |
743 | 931 | ||
744 | /* simple device detection: look for HCI method */ | 932 | /* simple device detection: look for HCI method */ |
745 | if (is_valid_acpi_path(METHOD_HCI_1)) | 933 | if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) { |
746 | method_hci = METHOD_HCI_1; | 934 | method_hci = TOSH_INTERFACE_1 GHCI_METHOD; |
747 | else if (is_valid_acpi_path(METHOD_HCI_2)) | 935 | if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1)) |
748 | method_hci = METHOD_HCI_2; | 936 | printk(MY_INFO "Unable to activate hotkeys\n"); |
749 | else | 937 | } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) { |
938 | method_hci = TOSH_INTERFACE_2 GHCI_METHOD; | ||
939 | if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2)) | ||
940 | printk(MY_INFO "Unable to activate hotkeys\n"); | ||
941 | } else | ||
750 | return -ENODEV; | 942 | return -ENODEV; |
751 | 943 | ||
752 | printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n", | 944 | printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n", |