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", |
