Commit a5ce8f5b authored by Simon Wood's avatar Simon Wood Committed by Jiri Kosina

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: default avatarSimon Wood <simon@mungewell.org>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 2f239858
...@@ -40,9 +40,11 @@ MODULE_PARM_DESC(disable_tap_to_click, ...@@ -40,9 +40,11 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define REPORT_ID_HIDPP_SHORT 0x10 #define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11 #define REPORT_ID_HIDPP_LONG 0x11
#define REPORT_ID_HIDPP_VERY_LONG 0x12
#define HIDPP_REPORT_SHORT_LENGTH 7 #define HIDPP_REPORT_SHORT_LENGTH 7
#define HIDPP_REPORT_LONG_LENGTH 20 #define HIDPP_REPORT_LONG_LENGTH 20
#define HIDPP_REPORT_VERY_LONG_LENGTH 64
#define HIDPP_QUIRK_CLASS_WTP BIT(0) #define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1) #define HIDPP_QUIRK_CLASS_M560 BIT(1)
...@@ -81,13 +83,13 @@ MODULE_PARM_DESC(disable_tap_to_click, ...@@ -81,13 +83,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
struct fap { struct fap {
u8 feature_index; u8 feature_index;
u8 funcindex_clientid; u8 funcindex_clientid;
u8 params[HIDPP_REPORT_LONG_LENGTH - 4U]; u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
}; };
struct rap { struct rap {
u8 sub_id; u8 sub_id;
u8 reg_address; u8 reg_address;
u8 params[HIDPP_REPORT_LONG_LENGTH - 4U]; u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
}; };
struct hidpp_report { struct hidpp_report {
...@@ -153,6 +155,9 @@ static int __hidpp_send_report(struct hid_device *hdev, ...@@ -153,6 +155,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
case REPORT_ID_HIDPP_LONG: case REPORT_ID_HIDPP_LONG:
fields_count = HIDPP_REPORT_LONG_LENGTH; fields_count = HIDPP_REPORT_LONG_LENGTH;
break; break;
case REPORT_ID_HIDPP_VERY_LONG:
fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
break;
default: default:
return -ENODEV; return -ENODEV;
} }
...@@ -217,8 +222,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, ...@@ -217,8 +222,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
goto exit; goto exit;
} }
if (response->report_id == REPORT_ID_HIDPP_LONG && if ((response->report_id == REPORT_ID_HIDPP_LONG ||
response->fap.feature_index == HIDPP20_ERROR) { response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1]; ret = response->fap.params[1];
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit; goto exit;
...@@ -243,7 +249,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, ...@@ -243,7 +249,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
if (!message) if (!message)
return -ENOMEM; return -ENOMEM;
message->report_id = REPORT_ID_HIDPP_LONG;
if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
message->report_id = REPORT_ID_HIDPP_VERY_LONG;
else
message->report_id = REPORT_ID_HIDPP_LONG;
message->fap.feature_index = feat_index; message->fap.feature_index = feat_index;
message->fap.funcindex_clientid = funcindex_clientid; message->fap.funcindex_clientid = funcindex_clientid;
memcpy(&message->fap.params, params, param_count); memcpy(&message->fap.params, params, param_count);
...@@ -258,13 +268,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev, ...@@ -258,13 +268,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
struct hidpp_report *response) struct hidpp_report *response)
{ {
struct hidpp_report *message; struct hidpp_report *message;
int ret; int ret, max_count;
if ((report_id != REPORT_ID_HIDPP_SHORT) && switch (report_id) {
(report_id != REPORT_ID_HIDPP_LONG)) case REPORT_ID_HIDPP_SHORT:
max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
break;
case REPORT_ID_HIDPP_LONG:
max_count = HIDPP_REPORT_LONG_LENGTH - 4;
break;
case REPORT_ID_HIDPP_VERY_LONG:
max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
break;
default:
return -EINVAL; return -EINVAL;
}
if (param_count > sizeof(message->rap.params)) if (param_count > max_count)
return -EINVAL; return -EINVAL;
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
...@@ -508,10 +528,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp, ...@@ -508,10 +528,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
if (ret) if (ret)
return ret; return ret;
if (response.report_id == REPORT_ID_HIDPP_LONG) switch (response.report_id) {
case REPORT_ID_HIDPP_VERY_LONG:
count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
break;
case REPORT_ID_HIDPP_LONG:
count = HIDPP_REPORT_LONG_LENGTH - 4; count = HIDPP_REPORT_LONG_LENGTH - 4;
else break;
case REPORT_ID_HIDPP_SHORT:
count = HIDPP_REPORT_SHORT_LENGTH - 4; count = HIDPP_REPORT_SHORT_LENGTH - 4;
break;
default:
return -EPROTO;
}
if (len_buf < count) if (len_buf < count)
count = len_buf; count = len_buf;
...@@ -1347,6 +1376,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -1347,6 +1376,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
/* Generic HID++ processing. */ /* Generic HID++ processing. */
switch (data[0]) { switch (data[0]) {
case REPORT_ID_HIDPP_VERY_LONG:
if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)",
size);
return 1;
}
ret = hidpp_raw_hidpp_event(hidpp, data, size);
break;
case REPORT_ID_HIDPP_LONG: case REPORT_ID_HIDPP_LONG:
if (size != HIDPP_REPORT_LONG_LENGTH) { if (size != HIDPP_REPORT_LONG_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)", hid_err(hdev, "received hid++ report of bad size (%d)",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment