Commit c54864a5 authored by Tony Lindgren's avatar Tony Lindgren

musb_hdrc: Fixes to make host features work again

Fixes to make host features work again
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 548ae8ac
...@@ -268,18 +268,6 @@ __musb_giveback(struct musb *musb, struct urb *urb, int status) ...@@ -268,18 +268,6 @@ __musb_giveback(struct musb *musb, struct urb *urb, int status)
__releases(musb->lock) __releases(musb->lock)
__acquires(musb->lock) __acquires(musb->lock)
{ {
if ((urb->transfer_flags & URB_SHORT_NOT_OK)
&& (urb->actual_length < urb->transfer_buffer_length)
&& status == 0
&& usb_pipein(urb->pipe))
status = -EREMOTEIO;
spin_lock(&urb->lock);
urb->hcpriv = NULL;
if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock(&urb->lock);
DBG(({ int level; switch (urb->status) { DBG(({ int level; switch (urb->status) {
case 0: case 0:
level = 4; level = 4;
...@@ -304,7 +292,7 @@ __acquires(musb->lock) ...@@ -304,7 +292,7 @@ __acquires(musb->lock)
); );
spin_unlock(&musb->lock); spin_unlock(&musb->lock);
usb_hcd_giveback_urb(musb_to_hcd(musb), urb); usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status);
spin_lock(&musb->lock); spin_lock(&musb->lock);
} }
...@@ -365,6 +353,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status) ...@@ -365,6 +353,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
break; break;
} }
usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
qh->is_ready = 0; qh->is_ready = 0;
__musb_giveback(musb, urb, status); __musb_giveback(musb, urb, status);
qh->is_ready = ready; qh->is_ready = ready;
...@@ -1738,15 +1728,15 @@ success: ...@@ -1738,15 +1728,15 @@ success:
static int musb_urb_enqueue( static int musb_urb_enqueue(
struct usb_hcd *hcd, struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb, struct urb *urb,
gfp_t mem_flags) gfp_t mem_flags)
{ {
unsigned long flags; unsigned long flags;
struct musb *musb = hcd_to_musb(hcd); struct musb *musb = hcd_to_musb(hcd);
struct usb_host_endpoint *hep = urb->ep;
struct musb_qh *qh = hep->hcpriv; struct musb_qh *qh = hep->hcpriv;
struct usb_endpoint_descriptor *epd = &hep->desc; struct usb_endpoint_descriptor *epd = &hep->desc;
int status; int ret;
unsigned type_reg; unsigned type_reg;
unsigned interval; unsigned interval;
...@@ -1754,6 +1744,10 @@ static int musb_urb_enqueue( ...@@ -1754,6 +1744,10 @@ static int musb_urb_enqueue(
if (!is_host_active(musb) || !musb->is_active) if (!is_host_active(musb) || !musb->is_active)
return -ENODEV; return -ENODEV;
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret)
return ret;
/* DMA mapping was already done, if needed, and this urb is on /* DMA mapping was already done, if needed, and this urb is on
* hep->urb_list ... so there's little to do unless hep wasn't * hep->urb_list ... so there's little to do unless hep wasn't
* yet scheduled onto a live qh. * yet scheduled onto a live qh.
...@@ -1774,8 +1768,10 @@ static int musb_urb_enqueue( ...@@ -1774,8 +1768,10 @@ static int musb_urb_enqueue(
* for bugs in other kernel code to break this driver... * for bugs in other kernel code to break this driver...
*/ */
qh = kzalloc(sizeof *qh, mem_flags); qh = kzalloc(sizeof *qh, mem_flags);
if (!qh) if (!qh) {
usb_hcd_unlink_urb_from_ep(hcd, urb);
return -ENOMEM; return -ENOMEM;
}
qh->hep = hep; qh->hep = hep;
qh->dev = urb->dev; qh->dev = urb->dev;
...@@ -1786,7 +1782,7 @@ static int musb_urb_enqueue( ...@@ -1786,7 +1782,7 @@ static int musb_urb_enqueue(
/* no high bandwidth support yet */ /* no high bandwidth support yet */
if (qh->maxpacket & ~0x7ff) { if (qh->maxpacket & ~0x7ff) {
status = -EMSGSIZE; ret = -EMSGSIZE;
goto done; goto done;
} }
...@@ -1870,12 +1866,12 @@ static int musb_urb_enqueue( ...@@ -1870,12 +1866,12 @@ static int musb_urb_enqueue(
* odd, rare, error prone, but legal. * odd, rare, error prone, but legal.
*/ */
kfree(qh); kfree(qh);
status = 0; ret = 0;
} else } else
status = musb_schedule(musb, qh, ret = musb_schedule(musb, qh,
epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK); epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
if (status == 0) { if (ret == 0) {
urb->hcpriv = qh; urb->hcpriv = qh;
/* FIXME set urb->start_frame for iso/intr, it's tested in /* FIXME set urb->start_frame for iso/intr, it's tested in
* musb_start_urb(), but otherwise only konicawc cares ... * musb_start_urb(), but otherwise only konicawc cares ...
...@@ -1884,9 +1880,11 @@ static int musb_urb_enqueue( ...@@ -1884,9 +1880,11 @@ static int musb_urb_enqueue(
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
done: done:
if (status != 0) if (ret != 0) {
usb_hcd_unlink_urb_from_ep(hcd, urb);
kfree(qh); kfree(qh);
return status; }
return ret;
} }
...@@ -1950,14 +1948,13 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in) ...@@ -1950,14 +1948,13 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
return status; return status;
} }
static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{ {
struct musb *musb = hcd_to_musb(hcd); struct musb *musb = hcd_to_musb(hcd);
struct musb_qh *qh; struct musb_qh *qh;
struct list_head *sched; struct list_head *sched;
struct urb *tmp;
unsigned long flags; unsigned long flags;
int status = -ENOENT; int ret;
DBG(4, "urb=%p, dev%d ep%d%s\n", urb, DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
usb_pipedevice(urb->pipe), usb_pipedevice(urb->pipe),
...@@ -1965,31 +1962,12 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1965,31 +1962,12 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
usb_pipein(urb->pipe) ? "in" : "out"); usb_pipein(urb->pipe) ? "in" : "out");
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
/* make sure the urb is still queued and not completed */ if (ret)
spin_lock(&urb->lock);
qh = urb->hcpriv;
if (qh) {
struct usb_host_endpoint *hep;
hep = qh->hep;
list_for_each_entry(tmp, &hep->urb_list, urb_list) {
if (urb == tmp) {
status = 0;
break;
}
}
}
spin_unlock(&urb->lock);
/* already completed */
if (!qh) {
status = 0;
goto done; goto done;
}
/* still queued but not found on the list */ qh = urb->hcpriv;
if (status) if (!qh)
goto done; goto done;
/* Any URB not actively programmed into endpoint hardware can be /* Any URB not actively programmed into endpoint hardware can be
...@@ -2002,7 +1980,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -2002,7 +1980,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
* OK to hold off until after some IRQ, though. * OK to hold off until after some IRQ, though.
*/ */
if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list) if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
status = -EINPROGRESS; ret = -EINPROGRESS;
else { else {
switch (qh->type) { switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_CONTROL:
...@@ -2025,18 +2003,18 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -2025,18 +2003,18 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
} }
/* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
if (status < 0 || (sched && qh != first_qh(sched))) { if (ret < 0 || (sched && qh != first_qh(sched))) {
int ready = qh->is_ready; int ready = qh->is_ready;
status = 0; ret = 0;
qh->is_ready = 0; qh->is_ready = 0;
__musb_giveback(musb, urb, 0); __musb_giveback(musb, urb, 0);
qh->is_ready = ready; qh->is_ready = ready;
} else } else
status = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
done: done:
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
return status; return ret;
} }
/* disable an endpoint */ /* disable an endpoint */
...@@ -2082,10 +2060,8 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) ...@@ -2082,10 +2060,8 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
urb = next_urb(qh); urb = next_urb(qh);
/* make software (then hardware) stop ASAP */ /* make software (then hardware) stop ASAP */
spin_lock(&urb->lock); if (!urb->unlinked)
if (urb->status == -EINPROGRESS)
urb->status = -ESHUTDOWN; urb->status = -ESHUTDOWN;
spin_unlock(&urb->lock);
/* cleanup */ /* cleanup */
musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN); musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment