aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wood <simon@mungewell.org>2015-11-19 18:42:11 -0500
committerJiri Kosina <jkosina@suse.cz>2015-11-20 04:29:57 -0500
commita5ce8f5b12966d34623d6c20278b5b4da7a53675 (patch)
tree6d899e575b439446c8df8e5def2820d676d74fdc
parent2f23985879c2fb2967e8bca77b1014b437a9b9ff (diff)
HID: hid-logitech-hidpp: Add support for very long packets
Patch add support for the 'very long' HID++ packets, which are 64 bytes in length. Signed-off-by: Simon Wood <simon@mungewell.org> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-logitech-hidpp.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 5fd97860aec4..0f53dc8c79b1 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -40,9 +40,11 @@ MODULE_PARM_DESC(disable_tap_to_click,
40 40
41#define REPORT_ID_HIDPP_SHORT 0x10 41#define REPORT_ID_HIDPP_SHORT 0x10
42#define REPORT_ID_HIDPP_LONG 0x11 42#define REPORT_ID_HIDPP_LONG 0x11
43#define REPORT_ID_HIDPP_VERY_LONG 0x12
43 44
44#define HIDPP_REPORT_SHORT_LENGTH 7 45#define HIDPP_REPORT_SHORT_LENGTH 7
45#define HIDPP_REPORT_LONG_LENGTH 20 46#define HIDPP_REPORT_LONG_LENGTH 20
47#define HIDPP_REPORT_VERY_LONG_LENGTH 64
46 48
47#define HIDPP_QUIRK_CLASS_WTP BIT(0) 49#define HIDPP_QUIRK_CLASS_WTP BIT(0)
48#define HIDPP_QUIRK_CLASS_M560 BIT(1) 50#define HIDPP_QUIRK_CLASS_M560 BIT(1)
@@ -81,13 +83,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
81struct fap { 83struct fap {
82 u8 feature_index; 84 u8 feature_index;
83 u8 funcindex_clientid; 85 u8 funcindex_clientid;
84 u8 params[HIDPP_REPORT_LONG_LENGTH - 4U]; 86 u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
85}; 87};
86 88
87struct rap { 89struct rap {
88 u8 sub_id; 90 u8 sub_id;
89 u8 reg_address; 91 u8 reg_address;
90 u8 params[HIDPP_REPORT_LONG_LENGTH - 4U]; 92 u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
91}; 93};
92 94
93struct hidpp_report { 95struct hidpp_report {
@@ -153,6 +155,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
153 case REPORT_ID_HIDPP_LONG: 155 case REPORT_ID_HIDPP_LONG:
154 fields_count = HIDPP_REPORT_LONG_LENGTH; 156 fields_count = HIDPP_REPORT_LONG_LENGTH;
155 break; 157 break;
158 case REPORT_ID_HIDPP_VERY_LONG:
159 fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
160 break;
156 default: 161 default:
157 return -ENODEV; 162 return -ENODEV;
158 } 163 }
@@ -217,8 +222,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
217 goto exit; 222 goto exit;
218 } 223 }
219 224
220 if (response->report_id == REPORT_ID_HIDPP_LONG && 225 if ((response->report_id == REPORT_ID_HIDPP_LONG ||
221 response->fap.feature_index == HIDPP20_ERROR) { 226 response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
227 response->fap.feature_index == HIDPP20_ERROR) {
222 ret = response->fap.params[1]; 228 ret = response->fap.params[1];
223 dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); 229 dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
224 goto exit; 230 goto exit;
@@ -243,7 +249,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
243 message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); 249 message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
244 if (!message) 250 if (!message)
245 return -ENOMEM; 251 return -ENOMEM;
246 message->report_id = REPORT_ID_HIDPP_LONG; 252
253 if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
254 message->report_id = REPORT_ID_HIDPP_VERY_LONG;
255 else
256 message->report_id = REPORT_ID_HIDPP_LONG;
247 message->fap.feature_index = feat_index; 257 message->fap.feature_index = feat_index;
248 message->fap.funcindex_clientid = funcindex_clientid; 258 message->fap.funcindex_clientid = funcindex_clientid;
249 memcpy(&message->fap.params, params, param_count); 259 memcpy(&message->fap.params, params, param_count);
@@ -258,13 +268,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
258 struct hidpp_report *response) 268 struct hidpp_report *response)
259{ 269{
260 struct hidpp_report *message; 270 struct hidpp_report *message;
261 int ret; 271 int ret, max_count;
262 272
263 if ((report_id != REPORT_ID_HIDPP_SHORT) && 273 switch (report_id) {
264 (report_id != REPORT_ID_HIDPP_LONG)) 274 case REPORT_ID_HIDPP_SHORT:
275 max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
276 break;
277 case REPORT_ID_HIDPP_LONG:
278 max_count = HIDPP_REPORT_LONG_LENGTH - 4;
279 break;
280 case REPORT_ID_HIDPP_VERY_LONG:
281 max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
282 break;
283 default:
265 return -EINVAL; 284 return -EINVAL;
285 }
266 286
267 if (param_count > sizeof(message->rap.params)) 287 if (param_count > max_count)
268 return -EINVAL; 288 return -EINVAL;
269 289
270 message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); 290 message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
@@ -508,10 +528,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
508 if (ret) 528 if (ret)
509 return ret; 529 return ret;
510 530
511 if (response.report_id == REPORT_ID_HIDPP_LONG) 531 switch (response.report_id) {
532 case REPORT_ID_HIDPP_VERY_LONG:
533 count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
534 break;
535 case REPORT_ID_HIDPP_LONG:
512 count = HIDPP_REPORT_LONG_LENGTH - 4; 536 count = HIDPP_REPORT_LONG_LENGTH - 4;
513 else 537 break;
538 case REPORT_ID_HIDPP_SHORT:
514 count = HIDPP_REPORT_SHORT_LENGTH - 4; 539 count = HIDPP_REPORT_SHORT_LENGTH - 4;
540 break;
541 default:
542 return -EPROTO;
543 }
515 544
516 if (len_buf < count) 545 if (len_buf < count)
517 count = len_buf; 546 count = len_buf;
@@ -1347,6 +1376,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
1347 1376
1348 /* Generic HID++ processing. */ 1377 /* Generic HID++ processing. */
1349 switch (data[0]) { 1378 switch (data[0]) {
1379 case REPORT_ID_HIDPP_VERY_LONG:
1380 if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
1381 hid_err(hdev, "received hid++ report of bad size (%d)",
1382 size);
1383 return 1;
1384 }
1385 ret = hidpp_raw_hidpp_event(hidpp, data, size);
1386 break;
1350 case REPORT_ID_HIDPP_LONG: 1387 case REPORT_ID_HIDPP_LONG:
1351 if (size != HIDPP_REPORT_LONG_LENGTH) { 1388 if (size != HIDPP_REPORT_LONG_LENGTH) {
1352 hid_err(hdev, "received hid++ report of bad size (%d)", 1389 hid_err(hdev, "received hid++ report of bad size (%d)",