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 <[email protected]>
Cc: Darren Hart <[email protected]>
Cc: Jiri Kosina <[email protected]>
Cc: Benjamin Tissoires <[email protected]>
Cc: [email protected]
---
 drivers/hid/hid-input.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index dea9cc65bf80..e8641ce677e4 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -350,13 +350,13 @@ static int hidinput_query_battery_capacity(struct 
hid_device *dev)
        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;
        }
-- 
2.20.1

Reply via email to