aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-logitech-hidpp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-logitech-hidpp.c')
-rw-r--r--drivers/hid/hid-logitech-hidpp.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index a93cefe0e522..e77658cd037c 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -89,6 +89,7 @@ struct hidpp_device {
89 struct hid_device *hid_dev; 89 struct hid_device *hid_dev;
90 struct mutex send_mutex; 90 struct mutex send_mutex;
91 void *send_receive_buf; 91 void *send_receive_buf;
92 char *name; /* will never be NULL and should not be freed */
92 wait_queue_head_t wait; 93 wait_queue_head_t wait;
93 bool answer_available; 94 bool answer_available;
94 u8 protocol_major; 95 u8 protocol_major;
@@ -105,6 +106,7 @@ struct hidpp_device {
105}; 106};
106 107
107 108
109/* HID++ 1.0 error codes */
108#define HIDPP_ERROR 0x8f 110#define HIDPP_ERROR 0x8f
109#define HIDPP_ERROR_SUCCESS 0x00 111#define HIDPP_ERROR_SUCCESS 0x00
110#define HIDPP_ERROR_INVALID_SUBID 0x01 112#define HIDPP_ERROR_INVALID_SUBID 0x01
@@ -119,6 +121,8 @@ struct hidpp_device {
119#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a 121#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a
120#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b 122#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
121#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c 123#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
124/* HID++ 2.0 error codes */
125#define HIDPP20_ERROR 0xff
122 126
123static void hidpp_connect_event(struct hidpp_device *hidpp_dev); 127static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
124 128
@@ -192,9 +196,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
192 } 196 }
193 197
194 if (response->report_id == REPORT_ID_HIDPP_SHORT && 198 if (response->report_id == REPORT_ID_HIDPP_SHORT &&
195 response->fap.feature_index == HIDPP_ERROR) { 199 response->rap.sub_id == HIDPP_ERROR) {
200 ret = response->rap.params[1];
201 dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
202 goto exit;
203 }
204
205 if (response->report_id == REPORT_ID_HIDPP_LONG &&
206 response->fap.feature_index == HIDPP20_ERROR) {
196 ret = response->fap.params[1]; 207 ret = response->fap.params[1];
197 dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret); 208 dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
198 goto exit; 209 goto exit;
199 } 210 }
200 211
@@ -271,7 +282,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question,
271static inline bool hidpp_match_error(struct hidpp_report *question, 282static inline bool hidpp_match_error(struct hidpp_report *question,
272 struct hidpp_report *answer) 283 struct hidpp_report *answer)
273{ 284{
274 return (answer->fap.feature_index == HIDPP_ERROR) && 285 return ((answer->rap.sub_id == HIDPP_ERROR) ||
286 (answer->fap.feature_index == HIDPP20_ERROR)) &&
275 (answer->fap.funcindex_clientid == question->fap.feature_index) && 287 (answer->fap.funcindex_clientid == question->fap.feature_index) &&
276 (answer->fap.params[0] == question->fap.funcindex_clientid); 288 (answer->fap.params[0] == question->fap.funcindex_clientid);
277} 289}
@@ -903,24 +915,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id)
903 return 0; 915 return 0;
904}; 916};
905 917
906static void wtp_connect(struct hid_device *hdev, bool connected) 918static int wtp_connect(struct hid_device *hdev, bool connected)
907{ 919{
908 struct hidpp_device *hidpp = hid_get_drvdata(hdev); 920 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
909 struct wtp_data *wd = hidpp->private_data; 921 struct wtp_data *wd = hidpp->private_data;
910 int ret; 922 int ret;
911 923
912 if (!connected) 924 if (!connected)
913 return; 925 return 0;
914 926
915 if (!wd->x_size) { 927 if (!wd->x_size) {
916 ret = wtp_get_config(hidpp); 928 ret = wtp_get_config(hidpp);
917 if (ret) { 929 if (ret) {
918 hid_err(hdev, "Can not get wtp config: %d\n", ret); 930 hid_err(hdev, "Can not get wtp config: %d\n", ret);
919 return; 931 return ret;
920 } 932 }
921 } 933 }
922 934
923 hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, 935 return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index,
924 true, true); 936 true, true);
925} 937}
926 938
@@ -965,7 +977,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
965 977
966 /* 978 /*
967 * If the mutex is locked then we have a pending answer from a 979 * If the mutex is locked then we have a pending answer from a
968 * previoulsly sent command 980 * previously sent command.
969 */ 981 */
970 if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { 982 if (unlikely(mutex_is_locked(&hidpp->send_mutex))) {
971 /* 983 /*
@@ -996,9 +1008,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
996 return 1; 1008 return 1;
997 } 1009 }
998 1010
999 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
1000 return wtp_raw_event(hidpp->hid_dev, data, size);
1001
1002 return 0; 1011 return 0;
1003} 1012}
1004 1013
@@ -1006,7 +1015,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
1006 u8 *data, int size) 1015 u8 *data, int size)
1007{ 1016{
1008 struct hidpp_device *hidpp = hid_get_drvdata(hdev); 1017 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
1018 int ret = 0;
1009 1019
1020 /* Generic HID++ processing. */
1010 switch (data[0]) { 1021 switch (data[0]) {
1011 case REPORT_ID_HIDPP_LONG: 1022 case REPORT_ID_HIDPP_LONG:
1012 if (size != HIDPP_REPORT_LONG_LENGTH) { 1023 if (size != HIDPP_REPORT_LONG_LENGTH) {
@@ -1014,16 +1025,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
1014 size); 1025 size);
1015 return 1; 1026 return 1;
1016 } 1027 }
1017 return hidpp_raw_hidpp_event(hidpp, data, size); 1028 ret = hidpp_raw_hidpp_event(hidpp, data, size);
1029 break;
1018 case REPORT_ID_HIDPP_SHORT: 1030 case REPORT_ID_HIDPP_SHORT:
1019 if (size != HIDPP_REPORT_SHORT_LENGTH) { 1031 if (size != HIDPP_REPORT_SHORT_LENGTH) {
1020 hid_err(hdev, "received hid++ report of bad size (%d)", 1032 hid_err(hdev, "received hid++ report of bad size (%d)",
1021 size); 1033 size);
1022 return 1; 1034 return 1;
1023 } 1035 }
1024 return hidpp_raw_hidpp_event(hidpp, data, size); 1036 ret = hidpp_raw_hidpp_event(hidpp, data, size);
1037 break;
1025 } 1038 }
1026 1039
1040 /* If no report is available for further processing, skip calling
1041 * raw_event of subclasses. */
1042 if (ret != 0)
1043 return ret;
1044
1027 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) 1045 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
1028 return wtp_raw_event(hdev, data, size); 1046 return wtp_raw_event(hdev, data, size);
1029 1047
@@ -1070,6 +1088,7 @@ static void hidpp_input_close(struct input_dev *dev)
1070static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) 1088static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
1071{ 1089{
1072 struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev); 1090 struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev);
1091 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
1073 1092
1074 if (!input_dev) 1093 if (!input_dev)
1075 return NULL; 1094 return NULL;
@@ -1078,7 +1097,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
1078 input_dev->open = hidpp_input_open; 1097 input_dev->open = hidpp_input_open;
1079 input_dev->close = hidpp_input_close; 1098 input_dev->close = hidpp_input_close;
1080 1099
1081 input_dev->name = hdev->name; 1100 input_dev->name = hidpp->name;
1082 input_dev->phys = hdev->phys; 1101 input_dev->phys = hdev->phys;
1083 input_dev->uniq = hdev->uniq; 1102 input_dev->uniq = hdev->uniq;
1084 input_dev->id.bustype = hdev->bus; 1103 input_dev->id.bustype = hdev->bus;
@@ -1098,8 +1117,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
1098 struct input_dev *input; 1117 struct input_dev *input;
1099 char *name, *devm_name; 1118 char *name, *devm_name;
1100 1119
1101 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) 1120 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
1102 wtp_connect(hdev, connected); 1121 ret = wtp_connect(hdev, connected);
1122 if (ret)
1123 return;
1124 }
1103 1125
1104 if (!connected || hidpp->delayed_input) 1126 if (!connected || hidpp->delayed_input)
1105 return; 1127 return;
@@ -1117,22 +1139,28 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
1117 hid_info(hdev, "HID++ %u.%u device connected.\n", 1139 hid_info(hdev, "HID++ %u.%u device connected.\n",
1118 hidpp->protocol_major, hidpp->protocol_minor); 1140 hidpp->protocol_major, hidpp->protocol_minor);
1119 1141
1142 if (!hidpp->name || hidpp->name == hdev->name) {
1143 name = hidpp_get_device_name(hidpp);
1144 if (!name) {
1145 hid_err(hdev,
1146 "unable to retrieve the name of the device");
1147 return;
1148 }
1149
1150 devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name);
1151 kfree(name);
1152 if (!devm_name)
1153 return;
1154
1155 hidpp->name = devm_name;
1156 }
1157
1120 input = hidpp_allocate_input(hdev); 1158 input = hidpp_allocate_input(hdev);
1121 if (!input) { 1159 if (!input) {
1122 hid_err(hdev, "cannot allocate new input device: %d\n", ret); 1160 hid_err(hdev, "cannot allocate new input device: %d\n", ret);
1123 return; 1161 return;
1124 } 1162 }
1125 1163
1126 name = hidpp_get_device_name(hidpp);
1127 if (!name) {
1128 hid_err(hdev, "unable to retrieve the name of the device");
1129 } else {
1130 devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name);
1131 if (devm_name)
1132 input->name = devm_name;
1133 kfree(name);
1134 }
1135
1136 hidpp_populate_input(hidpp, input, false); 1164 hidpp_populate_input(hidpp, input, false);
1137 1165
1138 ret = input_register_device(input); 1166 ret = input_register_device(input);
@@ -1155,6 +1183,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1155 return -ENOMEM; 1183 return -ENOMEM;
1156 1184
1157 hidpp->hid_dev = hdev; 1185 hidpp->hid_dev = hdev;
1186 hidpp->name = hdev->name;
1158 hid_set_drvdata(hdev, hidpp); 1187 hid_set_drvdata(hdev, hidpp);
1159 1188
1160 hidpp->quirks = id->driver_data; 1189 hidpp->quirks = id->driver_data;