From b918a0c6f694a58b54a7de949d0c720bc6671bd9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 11 Jan 2015 20:34:52 +0100 Subject: [PATCH] musb-new: Properly remove a transfer from the schedule on timeout If a transfer / urb times-out, properly remove it from the schedule, rather then letting it sit on the ep head. This stops the musb code from getting confused and refusing to queue further transfers after a timeout. Tested by unplugging a usb-keyboard, replugging it and doing a usb-reset, before this commit the keyboard would not work after the usb-reset. Signed-off-by: Hans de Goede --- drivers/usb/musb-new/musb_host.c | 12 +++++++++--- drivers/usb/musb-new/musb_host.h | 1 + drivers/usb/musb-new/musb_uboot.c | 3 +++ drivers/usb/musb-new/usb-compat.h | 1 + 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c index bbcee88241..437309ceb4 100644 --- a/drivers/usb/musb-new/musb_host.c +++ b/drivers/usb/musb-new/musb_host.c @@ -2130,8 +2130,6 @@ done: return ret; } - -#ifndef __UBOOT__ /* * abort a transfer that's at the head of a hardware queue. * called with controller locked, irqs blocked @@ -2195,7 +2193,14 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) return status; } -static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +#ifndef __UBOOT__ +static int musb_urb_dequeue( +#else +int musb_urb_dequeue( +#endif + struct usb_hcd *hcd, + struct urb *urb, + int status) { struct musb *musb = hcd_to_musb(hcd); struct musb_qh *qh; @@ -2253,6 +2258,7 @@ done: return ret; } +#ifndef __UBOOT__ /* disable an endpoint */ static void musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) diff --git a/drivers/usb/musb-new/musb_host.h b/drivers/usb/musb-new/musb_host.h index ebebe0c02a..546b4a2715 100644 --- a/drivers/usb/musb-new/musb_host.h +++ b/drivers/usb/musb-new/musb_host.h @@ -110,5 +110,6 @@ static inline struct urb *next_urb(struct musb_qh *qh) #ifdef __UBOOT__ int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); +int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); #endif #endif /* _MUSB_HOST_H */ diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index dab6f9b213..e823ad1a74 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -77,6 +77,9 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb) } while (urb->status == -EINPROGRESS && get_timer(0) < timeout); + if (urb->status == -EINPROGRESS) + musb_urb_dequeue(hcd, urb, -ETIME); + return urb->status; } diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h index 27f656f0ce..50bad378c5 100644 --- a/drivers/usb/musb-new/usb-compat.h +++ b/drivers/usb/musb-new/usb-compat.h @@ -48,6 +48,7 @@ struct urb { list_add_tail(&urb->urb_list, &urb->ep->urb_list); \ ret; }) #define usb_hcd_unlink_urb_from_ep(hcd, urb) list_del_init(&urb->urb_list) +#define usb_hcd_check_unlink_urb(hdc, urb, status) 0 static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, -- 2.39.5