aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/core/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/usb.c')
-rw-r--r--drivers/usb/core/usb.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index f026991d0bd..55b8d3a22d2 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -184,11 +184,16 @@ EXPORT_SYMBOL_GPL(usb_find_interface);
static void usb_release_dev(struct device *dev)
{
struct usb_device *udev;
+ struct usb_hcd *hcd;
udev = to_usb_device(dev);
+ hcd = bus_to_hcd(udev->bus);
usb_destroy_configuration(udev);
- usb_put_hcd(bus_to_hcd(udev->bus));
+ /* Root hubs aren't real devices, so don't free HCD resources */
+ if (hcd->driver->free_dev && udev->parent)
+ hcd->driver->free_dev(hcd, udev);
+ usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
kfree(udev->serial);
@@ -348,6 +353,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
kfree(dev);
return NULL;
}
+ /* Root hubs aren't true devices, so don't allocate HCD resources */
+ if (usb_hcd->driver->alloc_dev && parent &&
+ !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
+ usb_put_hcd(bus_to_hcd(bus));
+ kfree(dev);
+ return NULL;
+ }
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;