From: Dmitry Torokhov dmitry.torokhov@gmail.com
stable inclusion from stable-v5.10.110 commit ab63b24ae632f8b5ff034c7baf8cf583991e02c0 bugzilla: https://gitee.com/openeuler/kernel/issues/I574AL
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit a5e5e03e94764148a01757b2fa4737d3445c13a6 ]
Internally kernel prepends all report buffers, for both numbered and unnumbered reports, with report ID, therefore to properly handle unnumbered reports we should prepend it ourselves.
For the same reason we should skip the first byte of the buffer when calling i2c_hid_set_or_send_report() which then will take care of properly formatting the transfer buffer based on its separate report ID argument along with report payload.
[jkosina@suse.cz: finalize trimmed sentence in changelog as spotted by Benjamin] Fixes: 9b5a9ae88573 ("HID: i2c-hid: implement ll_driver transport-layer callbacks") Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Tested-by: Benjamin Tissoires benjamin.tissoires@redhat.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Yu Liao liaoyu15@huawei.com Reviewed-by: Wei Li liwei391@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/hid/i2c-hid/i2c-hid-core.c | 32 ++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 998aad8a9e60..14811d42a5a9 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -620,6 +620,17 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, if (report_type == HID_OUTPUT_REPORT) return -EINVAL;
+ /* + * In case of unnumbered reports the response from the device will + * not have the report ID that the upper layers expect, so we need + * to stash it the buffer ourselves and adjust the data size. + */ + if (!report_number) { + buf[0] = 0; + buf++; + count--; + } + /* +2 bytes to include the size of the reply in the query buffer */ ask_count = min(count + 2, (size_t)ihid->bufsize);
@@ -641,6 +652,9 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, count = min(count, ret_count - 2); memcpy(buf, ihid->rawbuf + 2, count);
+ if (!report_number) + count++; + return count; }
@@ -657,17 +671,19 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
mutex_lock(&ihid->reset_lock);
- if (report_id) { - buf++; - count--; - } - + /* + * Note that both numbered and unnumbered reports passed here + * are supposed to have report ID stored in the 1st byte of the + * buffer, so we strip it off unconditionally before passing payload + * to i2c_hid_set_or_send_report which takes care of encoding + * everything properly. + */ ret = i2c_hid_set_or_send_report(client, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, - report_id, buf, count, use_data); + report_id, buf + 1, count - 1, use_data);
- if (report_id && ret >= 0) - ret++; /* add report_id to the number of transfered bytes */ + if (ret >= 0) + ret++; /* add report_id to the number of transferred bytes */
mutex_unlock(&ihid->reset_lock);