aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2010-02-25 15:20:54 -0500
committerMatthew Garrett <mjg@redhat.com>2010-02-25 15:20:54 -0500
commit6335e4d56681f6f08f24f4b812a72d402793d393 (patch)
treea81a85ad4a8b695c721c47d33fbff003954db859 /drivers/platform
parentcaeacf59af3d114a3121bb04f8057109bbf289ea (diff)
toshiba_acpi: Add full hotkey support
Calling the ENAB method on Toshiba laptops results in notifications being sent when laptop hotkeys are pressed. This patch simply calls that method and sets up an input device if it's successful. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/toshiba_acpi.c206
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};
117MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 119MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
118 120
121struct key_entry {
122 char type;
123 u16 code;
124 u16 keycode;
125};
126
127enum {KE_KEY, KE_END};
128
129static 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)
251struct toshiba_acpi_dev { 283struct 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
748static 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
759static 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
770static 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
783static 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
805static 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
842static 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
714static void toshiba_acpi_exit(void) 896static 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",