diff options
| -rw-r--r-- | drivers/usb/musb/musb_host.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index e32323938e98..c74ebadd4b9d 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c | |||
| @@ -2103,15 +2103,16 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) | |||
| 2103 | unsigned long flags; | 2103 | unsigned long flags; |
| 2104 | struct musb *musb = hcd_to_musb(hcd); | 2104 | struct musb *musb = hcd_to_musb(hcd); |
| 2105 | u8 is_in = epnum & USB_DIR_IN; | 2105 | u8 is_in = epnum & USB_DIR_IN; |
| 2106 | struct musb_qh *qh = hep->hcpriv; | 2106 | struct musb_qh *qh; |
| 2107 | struct urb *urb, *tmp; | 2107 | struct urb *urb; |
| 2108 | struct list_head *sched; | 2108 | struct list_head *sched; |
| 2109 | 2109 | ||
| 2110 | if (!qh) | ||
| 2111 | return; | ||
| 2112 | |||
| 2113 | spin_lock_irqsave(&musb->lock, flags); | 2110 | spin_lock_irqsave(&musb->lock, flags); |
| 2114 | 2111 | ||
| 2112 | qh = hep->hcpriv; | ||
| 2113 | if (qh == NULL) | ||
| 2114 | goto exit; | ||
| 2115 | |||
| 2115 | switch (qh->type) { | 2116 | switch (qh->type) { |
| 2116 | case USB_ENDPOINT_XFER_CONTROL: | 2117 | case USB_ENDPOINT_XFER_CONTROL: |
| 2117 | sched = &musb->control; | 2118 | sched = &musb->control; |
| @@ -2145,13 +2146,28 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) | |||
| 2145 | 2146 | ||
| 2146 | /* cleanup */ | 2147 | /* cleanup */ |
| 2147 | musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); | 2148 | musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); |
| 2148 | } else | ||
| 2149 | urb = NULL; | ||
| 2150 | 2149 | ||
| 2151 | /* then just nuke all the others */ | 2150 | /* Then nuke all the others ... and advance the |
| 2152 | list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list) | 2151 | * queue on hw_ep (e.g. bulk ring) when we're done. |
| 2153 | musb_giveback(qh, urb, -ESHUTDOWN); | 2152 | */ |
| 2153 | while (!list_empty(&hep->urb_list)) { | ||
| 2154 | urb = next_urb(qh); | ||
| 2155 | urb->status = -ESHUTDOWN; | ||
| 2156 | musb_advance_schedule(musb, urb, qh->hw_ep, is_in); | ||
| 2157 | } | ||
| 2158 | } else { | ||
| 2159 | /* Just empty the queue; the hardware is busy with | ||
| 2160 | * other transfers, and since !qh->is_ready nothing | ||
| 2161 | * will activate any of these as it advances. | ||
| 2162 | */ | ||
| 2163 | while (!list_empty(&hep->urb_list)) | ||
| 2164 | __musb_giveback(musb, next_urb(qh), -ESHUTDOWN); | ||
| 2154 | 2165 | ||
| 2166 | hep->hcpriv = NULL; | ||
| 2167 | list_del(&qh->ring); | ||
| 2168 | kfree(qh); | ||
| 2169 | } | ||
| 2170 | exit: | ||
| 2155 | spin_unlock_irqrestore(&musb->lock, flags); | 2171 | spin_unlock_irqrestore(&musb->lock, flags); |
| 2156 | } | 2172 | } |
| 2157 | 2173 | ||
