aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorSimon Haggett <simon.haggett@realvnc.com>2012-04-03 11:04:15 -0400
committerJiri Kosina <jkosina@suse.cz>2012-04-03 18:07:58 -0400
commitdc3c78e43469063c5bf4b744214508f94c4129f9 (patch)
tree78fbb32e78761be2fa477f703c3c940017feb6e5 /drivers/hid
parent72f1367b5e15b80275d3805c9afc961549a12a1e (diff)
HID: usbhid: Check HID report descriptor contents after device reset
When a USB device reset occurs, usbcore will refetch the device and configuration descriptors and compare them with those retrieved before the reset to ensure that they have not changed. For USB HID devices, this implicitly includes the HID class descriptor (as this is fetched with the configuration descriptor). However, the HID report descriptor is not checked again. Whilst a change in the size of the HID report descriptor will be detected (as this is held in the class descriptor), content changes to the report descriptor which do not result in a change in its size will be missed. If a firmware update were applied to a USB HID device which resulted in such a change to the report descriptor after device reset, then this would not be picked up by usbhid. This patch fixes this issue by allowing usbhid to check the contents of the report descriptor after the device reset, and trigger a rebind of the device if there is a mismatch. Reviewed-by: Toby Gray <toby.gray@realvnc.com> Signed-off-by: Simon Haggett <simon.haggett@realvnc.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/usbhid/hid-core.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index c1a1dd54601c..aa1c503a9526 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -28,6 +28,7 @@
28#include <linux/input.h> 28#include <linux/input.h>
29#include <linux/wait.h> 29#include <linux/wait.h>
30#include <linux/workqueue.h> 30#include <linux/workqueue.h>
31#include <linux/string.h>
31 32
32#include <linux/usb.h> 33#include <linux/usb.h>
33 34
@@ -1364,7 +1365,34 @@ static int hid_post_reset(struct usb_interface *intf)
1364 struct usb_device *dev = interface_to_usbdev (intf); 1365 struct usb_device *dev = interface_to_usbdev (intf);
1365 struct hid_device *hid = usb_get_intfdata(intf); 1366 struct hid_device *hid = usb_get_intfdata(intf);
1366 struct usbhid_device *usbhid = hid->driver_data; 1367 struct usbhid_device *usbhid = hid->driver_data;
1368 struct usb_host_interface *interface = intf->cur_altsetting;
1367 int status; 1369 int status;
1370 char *rdesc;
1371
1372 /* Fetch and examine the HID report descriptor. If this
1373 * has changed, then rebind. Since usbcore's check of the
1374 * configuration descriptors passed, we already know that
1375 * the size of the HID report descriptor has not changed.
1376 */
1377 rdesc = kmalloc(hid->rsize, GFP_KERNEL);
1378 if (!rdesc) {
1379 dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
1380 return 1;
1381 }
1382 status = hid_get_class_descriptor(dev,
1383 interface->desc.bInterfaceNumber,
1384 HID_DT_REPORT, rdesc, hid->rsize);
1385 if (status < 0) {
1386 dbg_hid("reading report descriptor failed (post_reset)\n");
1387 kfree(rdesc);
1388 return 1;
1389 }
1390 status = memcmp(rdesc, hid->rdesc, hid->rsize);
1391 kfree(rdesc);
1392 if (status != 0) {
1393 dbg_hid("report descriptor changed\n");
1394 return 1;
1395 }
1368 1396
1369 spin_lock_irq(&usbhid->lock); 1397 spin_lock_irq(&usbhid->lock);
1370 clear_bit(HID_RESET_PENDING, &usbhid->iofl); 1398 clear_bit(HID_RESET_PENDING, &usbhid->iofl);