summaryrefslogtreecommitdiff
path: root/drivers/usb/usbip/vhci_hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/usbip/vhci_hcd.c')
-rw-r--r--drivers/usb/usbip/vhci_hcd.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 4ba6bcdaa8e9..b07b2925ff78 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -455,8 +455,14 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
vhci_hcd->port_status[rhport] &= ~(1 << USB_PORT_FEAT_RESET);
vhci_hcd->re_timeout = 0;
+ /*
+ * A few drivers do usb reset during probe when
+ * the device could be in VDEV_ST_USED state
+ */
if (vhci_hcd->vdev[rhport].ud.status ==
- VDEV_ST_NOTASSIGNED) {
+ VDEV_ST_NOTASSIGNED ||
+ vhci_hcd->vdev[rhport].ud.status ==
+ VDEV_ST_USED) {
usbip_dbg_vhci_rh(
" enable rhport %d (status %u)\n",
rhport,
@@ -957,8 +963,32 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
spin_lock(&vdev->priv_lock);
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+ struct urb *urb;
+
+ /* give back urb of unsent unlink request */
pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
+
+ urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+ if (!urb) {
+ list_del(&unlink->list);
+ kfree(unlink);
+ continue;
+ }
+
+ urb->status = -ENODEV;
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
list_del(&unlink->list);
+
+ spin_unlock(&vdev->priv_lock);
+ spin_unlock_irqrestore(&vhci->lock, flags);
+
+ usb_hcd_giveback_urb(hcd, urb, urb->status);
+
+ spin_lock_irqsave(&vhci->lock, flags);
+ spin_lock(&vdev->priv_lock);
+
kfree(unlink);
}