| From 4f57cace81438cc873a96f9f13f08298815c9b51 Mon Sep 17 00:00:00 2001 |
| From: Grant Likely <grant.likely@secretlab.ca> |
| Date: Fri, 10 Jul 2020 16:19:39 +0100 |
| Subject: HID: input: Fix devices that return multiple bytes in battery report |
| |
| From: Grant Likely <grant.likely@secretlab.ca> |
| |
| commit 4f57cace81438cc873a96f9f13f08298815c9b51 upstream. |
| |
| Some devices, particularly the 3DConnexion Spacemouse wireless 3D |
| controllers, return more than just the battery capacity in the battery |
| report. The Spacemouse devices return an additional byte with a device |
| specific field. However, hidinput_query_battery_capacity() only |
| requests a 2 byte transfer. |
| |
| When a spacemouse is connected via USB (direct wire, no wireless dongle) |
| and it returns a 3 byte report instead of the assumed 2 byte battery |
| report the larger transfer confuses and frightens the USB subsystem |
| which chooses to ignore the transfer. Then after 2 seconds assume the |
| device has stopped responding and reset it. This can be reproduced |
| easily by using a wired connection with a wireless spacemouse. The |
| Spacemouse will enter a loop of resetting every 2 seconds which can be |
| observed in dmesg. |
| |
| This patch solves the problem by increasing the transfer request to 4 |
| bytes instead of 2. The fix isn't particularly elegant, but it is simple |
| and safe to backport to stable kernels. A further patch will follow to |
| more elegantly handle battery reports that contain additional data. |
| |
| Signed-off-by: Grant Likely <grant.likely@secretlab.ca> |
| Cc: Darren Hart <darren@dvhart.com> |
| Cc: Jiri Kosina <jikos@kernel.org> |
| Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com> |
| Cc: stable@vger.kernel.org |
| Tested-by: Darren Hart <dvhart@infradead.org> |
| Signed-off-by: Jiri Kosina <jkosina@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/hid/hid-input.c | 6 +++--- |
| 1 file changed, 3 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/hid/hid-input.c |
| +++ b/drivers/hid/hid-input.c |
| @@ -350,13 +350,13 @@ static int hidinput_query_battery_capaci |
| u8 *buf; |
| int ret; |
| |
| - buf = kmalloc(2, GFP_KERNEL); |
| + buf = kmalloc(4, GFP_KERNEL); |
| if (!buf) |
| return -ENOMEM; |
| |
| - ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2, |
| + ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4, |
| dev->battery_report_type, HID_REQ_GET_REPORT); |
| - if (ret != 2) { |
| + if (ret < 2) { |
| kfree(buf); |
| return -ENODATA; |
| } |