diff options
Diffstat (limited to 'drivers/usb/core/usb.c')
-rw-r--r-- | drivers/usb/core/usb.c | 14 |
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); | |||
184 | static void usb_release_dev(struct device *dev) | 184 | static void usb_release_dev(struct device *dev) |
185 | { | 185 | { |
186 | struct usb_device *udev; | 186 | struct usb_device *udev; |
187 | struct usb_hcd *hcd; | ||
187 | 188 | ||
188 | udev = to_usb_device(dev); | 189 | udev = to_usb_device(dev); |
190 | hcd = bus_to_hcd(udev->bus); | ||
189 | 191 | ||
190 | usb_destroy_configuration(udev); | 192 | usb_destroy_configuration(udev); |
191 | usb_put_hcd(bus_to_hcd(udev->bus)); | 193 | /* Root hubs aren't real devices, so don't free HCD resources */ |
194 | if (hcd->driver->free_dev && udev->parent) | ||
195 | hcd->driver->free_dev(hcd, udev); | ||
196 | usb_put_hcd(hcd); | ||
192 | kfree(udev->product); | 197 | kfree(udev->product); |
193 | kfree(udev->manufacturer); | 198 | kfree(udev->manufacturer); |
194 | kfree(udev->serial); | 199 | kfree(udev->serial); |
@@ -348,6 +353,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, | |||
348 | kfree(dev); | 353 | kfree(dev); |
349 | return NULL; | 354 | return NULL; |
350 | } | 355 | } |
356 | /* Root hubs aren't true devices, so don't allocate HCD resources */ | ||
357 | if (usb_hcd->driver->alloc_dev && parent && | ||
358 | !usb_hcd->driver->alloc_dev(usb_hcd, dev)) { | ||
359 | usb_put_hcd(bus_to_hcd(bus)); | ||
360 | kfree(dev); | ||
361 | return NULL; | ||
362 | } | ||
351 | 363 | ||
352 | device_initialize(&dev->dev); | 364 | device_initialize(&dev->dev); |
353 | dev->dev.bus = &usb_bus_type; | 365 | dev->dev.bus = &usb_bus_type; |