__releases(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) {
case 0:
level = 4;
);
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);
}
break;
}
+ usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
+
qh->is_ready = 0;
__musb_giveback(musb, urb, status);
qh->is_ready = ready;
static int musb_urb_enqueue(
struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
unsigned long flags;
struct musb *musb = hcd_to_musb(hcd);
+ struct usb_host_endpoint *hep = urb->ep;
struct musb_qh *qh = hep->hcpriv;
struct usb_endpoint_descriptor *epd = &hep->desc;
- int status;
+ int ret;
unsigned type_reg;
unsigned interval;
if (!is_host_active(musb) || !musb->is_active)
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
* hep->urb_list ... so there's little to do unless hep wasn't
* yet scheduled onto a live qh.
* for bugs in other kernel code to break this driver...
*/
qh = kzalloc(sizeof *qh, mem_flags);
- if (!qh)
+ if (!qh) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
return -ENOMEM;
+ }
qh->hep = hep;
qh->dev = urb->dev;
/* no high bandwidth support yet */
if (qh->maxpacket & ~0x7ff) {
- status = -EMSGSIZE;
+ ret = -EMSGSIZE;
goto done;
}
* odd, rare, error prone, but legal.
*/
kfree(qh);
- status = 0;
+ ret = 0;
} else
- status = musb_schedule(musb, qh,
+ ret = musb_schedule(musb, qh,
epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
- if (status == 0) {
+ if (ret == 0) {
urb->hcpriv = qh;
/* FIXME set urb->start_frame for iso/intr, it's tested in
* musb_start_urb(), but otherwise only konicawc cares ...
spin_unlock_irqrestore(&musb->lock, flags);
done:
- if (status != 0)
+ if (ret != 0) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
kfree(qh);
- return status;
+ }
+ return ret;
}
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_qh *qh;
struct list_head *sched;
- struct urb *tmp;
unsigned long flags;
- int status = -ENOENT;
+ int ret;
DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
usb_pipedevice(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out");
spin_lock_irqsave(&musb->lock, flags);
-
- /* make sure the urb is still queued and not completed */
- 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;
+ ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (ret)
goto done;
- }
- /* still queued but not found on the list */
- if (status)
+ qh = urb->hcpriv;
+ if (!qh)
goto done;
/* Any URB not actively programmed into endpoint hardware can be
* OK to hold off until after some IRQ, though.
*/
if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
- status = -EINPROGRESS;
+ ret = -EINPROGRESS;
else {
switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL:
}
/* 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;
- status = 0;
+ ret = 0;
qh->is_ready = 0;
__musb_giveback(musb, urb, 0);
qh->is_ready = ready;
} else
- status = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+ ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
done:
spin_unlock_irqrestore(&musb->lock, flags);
- return status;
+ return ret;
}
/* disable an endpoint */
urb = next_urb(qh);
/* make software (then hardware) stop ASAP */
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
+ if (!urb->unlinked)
urb->status = -ESHUTDOWN;
- spin_unlock(&urb->lock);
/* cleanup */
musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);