summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorXenia Ragiadakou <burzalodowa@gmail.com>2013-08-29 21:45:48 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-30 12:02:08 -0700
commite3376d6c87eea09bd65ece6073f6e5d47aa560a3 (patch)
tree0d44a8f7a1f48d61534fec9cdaa0d4b3bbe29cd0 /drivers/usb
parenteb5ea7300d48c52b028966a6e59f9244faa930d0 (diff)
downloadblackbird-op-linux-e3376d6c87eea09bd65ece6073f6e5d47aa560a3.tar.gz
blackbird-op-linux-e3376d6c87eea09bd65ece6073f6e5d47aa560a3.zip
usbcore: compare and release one bos descriptor in usb_reset_and_verify_device()
In usb_reset_and_verify_device(), hub_port_init() allocates a new bos descriptor to hold the value read by the device. The new bos descriptor has to be compared with the old one in order to figure out if device 's firmware has changed in which case the device has to be reenumerated. In the original code, none of the two descriptors was deallocated leading to memory leaks. This patch compares the old bos descriptor with the new one to detect change in firmware and releases the newly allocated bos descriptor to prevent memory leak. Signed-off-by: Xenia Ragiadakou <burzalodowa@gmail.com> Reported-by: Martin MOKREJS <mmokrejs@gmail.com> Tested-by: Martin MOKREJS <mmokrejs@gmail.com> Suggested-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/hub.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5d859fc07610..3b7ca181cd72 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4944,7 +4944,8 @@ void usb_hub_cleanup(void)
} /* usb_hub_cleanup() */
static int descriptors_changed(struct usb_device *udev,
- struct usb_device_descriptor *old_device_descriptor)
+ struct usb_device_descriptor *old_device_descriptor,
+ struct usb_host_bos *old_bos)
{
int changed = 0;
unsigned index;
@@ -4958,6 +4959,16 @@ static int descriptors_changed(struct usb_device *udev,
sizeof(*old_device_descriptor)) != 0)
return 1;
+ if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
+ return 1;
+ if (udev->bos) {
+ len = udev->bos->desc->wTotalLength;
+ if (len != old_bos->desc->wTotalLength)
+ return 1;
+ if (memcmp(udev->bos->desc, old_bos->desc, le16_to_cpu(len)))
+ return 1;
+ }
+
/* Since the idVendor, idProduct, and bcdDevice values in the
* device descriptor haven't changed, we will assume the
* Manufacturer and Product strings haven't changed either.
@@ -5054,6 +5065,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
struct usb_hub *parent_hub;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct usb_device_descriptor descriptor = udev->descriptor;
+ struct usb_host_bos *bos;
int i, ret = 0;
int port1 = udev->portnum;
@@ -5071,6 +5083,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
}
parent_hub = usb_hub_to_struct_hub(parent_hdev);
+ bos = udev->bos;
+ udev->bos = NULL;
+
/* Disable LPM and LTM while we reset the device and reinstall the alt
* settings. Device-initiated LPM settings, and system exit latency
* settings are cleared when the device is reset, so we have to set
@@ -5104,7 +5119,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
goto re_enumerate;
/* Device might have changed firmware (DFU or similar) */
- if (descriptors_changed(udev, &descriptor)) {
+ if (descriptors_changed(udev, &descriptor, bos)) {
dev_info(&udev->dev, "device firmware changed\n");
udev->descriptor = descriptor; /* for disconnect() calls */
goto re_enumerate;
@@ -5177,11 +5192,15 @@ done:
/* Now that the alt settings are re-installed, enable LTM and LPM. */
usb_unlocked_enable_lpm(udev);
usb_enable_ltm(udev);
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
return 0;
re_enumerate:
/* LPM state doesn't matter when we're about to destroy the device. */
hub_port_logical_disconnect(parent_hub, port1);
+ usb_release_bos_descriptor(udev);
+ udev->bos = bos;
return -ENODEV;
}
OpenPOWER on IntegriCloud