aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSeth Forshee <seth.forshee@canonical.com>2012-01-18 14:44:09 -0500
committerMatthew Garrett <mjg@redhat.com>2012-03-22 09:31:51 -0400
commit29cd293f9f8cd76444657622980010b9364b1de6 (patch)
treef39a927d66951f13d031dfa45f3558a689ac0575 /drivers
parent3e2abc5a35d25442821e1733687b7abbc83b5072 (diff)
toshiba_acpi: Support alternate hotkey interfaces
There are two types of problems that prevent hotkeys from working on many of the machines supported by toshiba_acpi. The first of these is the lack of a functioning SCI for hotkey events. For these machines it is possible to filter the Fn keypresses from the keyboard and generate a notification by executing the ACPI NTFY method. The second problem is a lack of support for HCI_SYSTEM_EVENT, which is used for reading the hotkey scancodes. On these machines the scancodes can be read by executing the ACPI NTFY method. This patch fixes both problems by installing an i8042 filter when the NTFY method is present to generate notifications and by detecting which of INFO or HCI_SYSTEM_EVENT is supported for reading scancodes. If neither method of reading scancodes is supported, the hotkey input device is not registered. Signed-off-by: Azael Avalos <coproscefalo@gmail.com> Signed-off-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/toshiba_acpi.c231
1 files changed, 195 insertions, 36 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index eab5e11fb41f..42d73b0f530a 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -52,6 +52,8 @@
52#include <linux/input/sparse-keymap.h> 52#include <linux/input/sparse-keymap.h>
53#include <linux/leds.h> 53#include <linux/leds.h>
54#include <linux/slab.h> 54#include <linux/slab.h>
55#include <linux/workqueue.h>
56#include <linux/i8042.h>
55 57
56#include <asm/uaccess.h> 58#include <asm/uaccess.h>
57 59
@@ -61,6 +63,9 @@ MODULE_AUTHOR("John Belmonte");
61MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 63MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
62MODULE_LICENSE("GPL"); 64MODULE_LICENSE("GPL");
63 65
66/* Scan code for Fn key on TOS1900 models */
67#define TOS1900_FN_SCAN 0x6e
68
64/* Toshiba ACPI method paths */ 69/* Toshiba ACPI method paths */
65#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 70#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
66 71
@@ -95,6 +100,8 @@ MODULE_LICENSE("GPL");
95#define HCI_WIRELESS 0x0056 100#define HCI_WIRELESS 0x0056
96 101
97/* field definitions */ 102/* field definitions */
103#define HCI_HOTKEY_DISABLE 0x0b
104#define HCI_HOTKEY_ENABLE 0x09
98#define HCI_LCD_BRIGHTNESS_BITS 3 105#define HCI_LCD_BRIGHTNESS_BITS 3
99#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 106#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
100#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 107#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
@@ -111,6 +118,7 @@ struct toshiba_acpi_dev {
111 const char *method_hci; 118 const char *method_hci;
112 struct rfkill *bt_rfk; 119 struct rfkill *bt_rfk;
113 struct input_dev *hotkey_dev; 120 struct input_dev *hotkey_dev;
121 struct work_struct hotkey_work;
114 struct backlight_device *backlight_dev; 122 struct backlight_device *backlight_dev;
115 struct led_classdev led_dev; 123 struct led_classdev led_dev;
116 124
@@ -122,10 +130,14 @@ struct toshiba_acpi_dev {
122 unsigned int video_supported:1; 130 unsigned int video_supported:1;
123 unsigned int fan_supported:1; 131 unsigned int fan_supported:1;
124 unsigned int system_event_supported:1; 132 unsigned int system_event_supported:1;
133 unsigned int ntfy_supported:1;
134 unsigned int info_supported:1;
125 135
126 struct mutex mutex; 136 struct mutex mutex;
127}; 137};
128 138
139static struct toshiba_acpi_dev *toshiba_acpi;
140
129static const struct acpi_device_id toshiba_device_ids[] = { 141static const struct acpi_device_id toshiba_device_ids[] = {
130 {"TOS6200", 0}, 142 {"TOS6200", 0},
131 {"TOS6208", 0}, 143 {"TOS6208", 0},
@@ -847,10 +859,78 @@ static const struct backlight_ops toshiba_backlight_data = {
847 .update_status = set_lcd_status, 859 .update_status = set_lcd_status,
848}; 860};
849 861
862static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
863 struct serio *port)
864{
865 if (str & 0x20)
866 return false;
867
868 if (unlikely(data == 0xe0))
869 return false;
870
871 if ((data & 0x7f) == TOS1900_FN_SCAN) {
872 schedule_work(&toshiba_acpi->hotkey_work);
873 return true;
874 }
875
876 return false;
877}
878
879static void toshiba_acpi_hotkey_work(struct work_struct *work)
880{
881 acpi_handle ec_handle = ec_get_handle();
882 acpi_status status;
883
884 if (!ec_handle)
885 return;
886
887 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
888 if (ACPI_FAILURE(status))
889 pr_err("ACPI NTFY method execution failed\n");
890}
891
892/*
893 * Returns hotkey scancode, or < 0 on failure.
894 */
895static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
896{
897 struct acpi_buffer buf;
898 union acpi_object out_obj;
899 acpi_status status;
900
901 buf.pointer = &out_obj;
902 buf.length = sizeof(out_obj);
903
904 status = acpi_evaluate_object(dev->acpi_dev->handle, "INFO",
905 NULL, &buf);
906 if (ACPI_FAILURE(status) || out_obj.type != ACPI_TYPE_INTEGER) {
907 pr_err("ACPI INFO method execution failed\n");
908 return -EIO;
909 }
910
911 return out_obj.integer.value;
912}
913
914static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
915 int scancode)
916{
917 if (scancode == 0x100)
918 return;
919
920 /* act on key press; ignore key release */
921 if (scancode & 0x80)
922 return;
923
924 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
925 pr_info("Unknown key %x\n", scancode);
926}
927
850static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 928static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
851{ 929{
852 acpi_status status; 930 acpi_status status;
931 acpi_handle ec_handle, handle;
853 int error; 932 int error;
933 u32 hci_result;
854 934
855 dev->hotkey_dev = input_allocate_device(); 935 dev->hotkey_dev = input_allocate_device();
856 if (!dev->hotkey_dev) { 936 if (!dev->hotkey_dev) {
@@ -866,21 +946,67 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
866 if (error) 946 if (error)
867 goto err_free_dev; 947 goto err_free_dev;
868 948
949 /*
950 * For some machines the SCI responsible for providing hotkey
951 * notification doesn't fire. We can trigger the notification
952 * whenever the Fn key is pressed using the NTFY method, if
953 * supported, so if it's present set up an i8042 key filter
954 * for this purpose.
955 */
956 status = AE_ERROR;
957 ec_handle = ec_get_handle();
958 if (ec_handle)
959 status = acpi_get_handle(ec_handle, "NTFY", &handle);
960
961 if (ACPI_SUCCESS(status)) {
962 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
963
964 error = i8042_install_filter(toshiba_acpi_i8042_filter);
965 if (error) {
966 pr_err("Error installing key filter\n");
967 goto err_free_keymap;
968 }
969
970 dev->ntfy_supported = 1;
971 }
972
973 /*
974 * Determine hotkey query interface. Prefer using the INFO
975 * method when it is available.
976 */
977 status = acpi_get_handle(dev->acpi_dev->handle, "INFO", &handle);
978 if (ACPI_SUCCESS(status)) {
979 dev->info_supported = 1;
980 } else {
981 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
982 if (hci_result == HCI_SUCCESS)
983 dev->system_event_supported = 1;
984 }
985
986 if (!dev->info_supported && !dev->system_event_supported) {
987 pr_warn("No hotkey query interface found\n");
988 goto err_remove_filter;
989 }
990
869 status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL); 991 status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
870 if (ACPI_FAILURE(status)) { 992 if (ACPI_FAILURE(status)) {
871 pr_info("Unable to enable hotkeys\n"); 993 pr_info("Unable to enable hotkeys\n");
872 error = -ENODEV; 994 error = -ENODEV;
873 goto err_free_keymap; 995 goto err_remove_filter;
874 } 996 }
875 997
876 error = input_register_device(dev->hotkey_dev); 998 error = input_register_device(dev->hotkey_dev);
877 if (error) { 999 if (error) {
878 pr_info("Unable to register input device\n"); 1000 pr_info("Unable to register input device\n");
879 goto err_free_keymap; 1001 goto err_remove_filter;
880 } 1002 }
881 1003
1004 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
882 return 0; 1005 return 0;
883 1006
1007 err_remove_filter:
1008 if (dev->ntfy_supported)
1009 i8042_remove_filter(toshiba_acpi_i8042_filter);
884 err_free_keymap: 1010 err_free_keymap:
885 sparse_keymap_free(dev->hotkey_dev); 1011 sparse_keymap_free(dev->hotkey_dev);
886 err_free_dev: 1012 err_free_dev:
@@ -895,6 +1021,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
895 1021
896 remove_toshiba_proc_entries(dev); 1022 remove_toshiba_proc_entries(dev);
897 1023
1024 if (dev->ntfy_supported) {
1025 i8042_remove_filter(toshiba_acpi_i8042_filter);
1026 cancel_work_sync(&dev->hotkey_work);
1027 }
1028
898 if (dev->hotkey_dev) { 1029 if (dev->hotkey_dev) {
899 input_unregister_device(dev->hotkey_dev); 1030 input_unregister_device(dev->hotkey_dev);
900 sparse_keymap_free(dev->hotkey_dev); 1031 sparse_keymap_free(dev->hotkey_dev);
@@ -911,6 +1042,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
911 if (dev->illumination_supported) 1042 if (dev->illumination_supported)
912 led_classdev_unregister(&dev->led_dev); 1043 led_classdev_unregister(&dev->led_dev);
913 1044
1045 if (toshiba_acpi)
1046 toshiba_acpi = NULL;
1047
914 kfree(dev); 1048 kfree(dev);
915 1049
916 return 0; 1050 return 0;
@@ -936,12 +1070,14 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
936{ 1070{
937 struct toshiba_acpi_dev *dev; 1071 struct toshiba_acpi_dev *dev;
938 const char *hci_method; 1072 const char *hci_method;
939 u32 hci_result;
940 u32 dummy; 1073 u32 dummy;
941 bool bt_present; 1074 bool bt_present;
942 int ret = 0; 1075 int ret = 0;
943 struct backlight_properties props; 1076 struct backlight_properties props;
944 1077
1078 if (toshiba_acpi)
1079 return -EBUSY;
1080
945 pr_info("Toshiba Laptop ACPI Extras version %s\n", 1081 pr_info("Toshiba Laptop ACPI Extras version %s\n",
946 TOSHIBA_ACPI_VERSION); 1082 TOSHIBA_ACPI_VERSION);
947 1083
@@ -963,11 +1099,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
963 1099
964 mutex_init(&dev->mutex); 1100 mutex_init(&dev->mutex);
965 1101
966 /* enable event fifo */
967 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
968 if (hci_result == HCI_SUCCESS)
969 dev->system_event_supported = 1;
970
971 props.type = BACKLIGHT_PLATFORM; 1102 props.type = BACKLIGHT_PLATFORM;
972 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 1103 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
973 dev->backlight_dev = backlight_device_register("toshiba", 1104 dev->backlight_dev = backlight_device_register("toshiba",
@@ -1024,6 +1155,8 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
1024 1155
1025 create_toshiba_proc_entries(dev); 1156 create_toshiba_proc_entries(dev);
1026 1157
1158 toshiba_acpi = dev;
1159
1027 return 0; 1160 return 0;
1028 1161
1029error: 1162error:
@@ -1036,40 +1169,64 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
1036 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 1169 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1037 u32 hci_result, value; 1170 u32 hci_result, value;
1038 int retries = 3; 1171 int retries = 3;
1172 int scancode;
1039 1173
1040 if (!dev->system_event_supported || event != 0x80) 1174 if (event != 0x80)
1041 return; 1175 return;
1042 1176
1043 do { 1177 if (dev->info_supported) {
1044 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result); 1178 scancode = toshiba_acpi_query_hotkey(dev);
1045 switch (hci_result) { 1179 if (scancode < 0)
1046 case HCI_SUCCESS: 1180 pr_err("Failed to query hotkey event\n");
1047 if (value == 0x100) 1181 else if (scancode != 0)
1048 continue; 1182 toshiba_acpi_report_hotkey(dev, scancode);
1049 /* act on key press; ignore key release */ 1183 } else if (dev->system_event_supported) {
1050 if (value & 0x80) 1184 do {
1051 continue; 1185 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
1052 1186 switch (hci_result) {
1053 if (!sparse_keymap_report_event(dev->hotkey_dev, 1187 case HCI_SUCCESS:
1054 value, 1, true)) { 1188 toshiba_acpi_report_hotkey(dev, (int)value);
1055 pr_info("Unknown key %x\n", 1189 break;
1056 value); 1190 case HCI_NOT_SUPPORTED:
1191 /*
1192 * This is a workaround for an unresolved
1193 * issue on some machines where system events
1194 * sporadically become disabled.
1195 */
1196 hci_write1(dev, HCI_SYSTEM_EVENT, 1,
1197 &hci_result);
1198 pr_notice("Re-enabled hotkeys\n");
1199 /* fall through */
1200 default:
1201 retries--;
1202 break;
1057 } 1203 }
1058 break; 1204 } while (retries && hci_result != HCI_EMPTY);
1059 case HCI_NOT_SUPPORTED: 1205 }
1060 /* This is a workaround for an unresolved issue on
1061 * some machines where system events sporadically
1062 * become disabled. */
1063 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
1064 pr_notice("Re-enabled hotkeys\n");
1065 /* fall through */
1066 default:
1067 retries--;
1068 break;
1069 }
1070 } while (retries && hci_result != HCI_EMPTY);
1071} 1206}
1072 1207
1208static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
1209 pm_message_t state)
1210{
1211 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1212 u32 result;
1213
1214 if (dev->hotkey_dev)
1215 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
1216
1217 return 0;
1218}
1219
1220static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
1221{
1222 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1223 u32 result;
1224
1225 if (dev->hotkey_dev)
1226 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
1227
1228 return 0;
1229}
1073 1230
1074static struct acpi_driver toshiba_acpi_driver = { 1231static struct acpi_driver toshiba_acpi_driver = {
1075 .name = "Toshiba ACPI driver", 1232 .name = "Toshiba ACPI driver",
@@ -1080,6 +1237,8 @@ static struct acpi_driver toshiba_acpi_driver = {
1080 .add = toshiba_acpi_add, 1237 .add = toshiba_acpi_add,
1081 .remove = toshiba_acpi_remove, 1238 .remove = toshiba_acpi_remove,
1082 .notify = toshiba_acpi_notify, 1239 .notify = toshiba_acpi_notify,
1240 .suspend = toshiba_acpi_suspend,
1241 .resume = toshiba_acpi_resume,
1083 }, 1242 },
1084}; 1243};
1085 1244