Commit a0b458b6 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] UHCI: Move code for cleaning up unlinked URBs

This patch (as681) moves some code for cleaning up after unlinked URBs
out of the general completion pathway into the unlinking pathway.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 59e29ed9
...@@ -204,25 +204,49 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -204,25 +204,49 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
} }
/* /*
* When the currently executing URB is dequeued, save its current toggle value * When a queue is stopped and a dequeued URB is given back, adjust
* the previous TD link (if the URB isn't first on the queue) or
* save its toggle value (if it is first and is currently executing).
*/ */
static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb) static void uhci_cleanup_queue(struct uhci_qh *qh,
struct urb *urb)
{ {
struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td; struct uhci_td *td;
/* Isochronous pipes don't use toggles and their TD link pointers
* get adjusted during uhci_urb_dequeue(). */
if (qh->type == USB_ENDPOINT_XFER_ISOC)
return;
/* If the URB isn't first on its queue, adjust the link pointer
* of the last TD in the previous URB. The toggle doesn't need
* to be saved since this URB can't be executing yet. */
if (qh->queue.next != &urbp->node) {
struct urb_priv *purbp;
struct uhci_td *ptd;
purbp = list_entry(urbp->node.prev, struct urb_priv, node);
WARN_ON(list_empty(&purbp->td_list));
ptd = list_entry(purbp->td_list.prev, struct uhci_td,
list);
td = list_entry(urbp->td_list.prev, struct uhci_td,
list);
ptd->link = td->link;
return;
}
/* If the QH element pointer is UHCI_PTR_TERM then then currently /* If the QH element pointer is UHCI_PTR_TERM then then currently
* executing URB has already been unlinked, so this one isn't it. */ * executing URB has already been unlinked, so this one isn't it. */
if (qh_element(qh) == UHCI_PTR_TERM || if (qh_element(qh) == UHCI_PTR_TERM)
qh->queue.next != &urbp->node)
return; return;
qh->element = UHCI_PTR_TERM; qh->element = UHCI_PTR_TERM;
/* Only bulk and interrupt pipes have to worry about toggles */ /* Control pipes have to worry about toggles */
if (!(qh->type == USB_ENDPOINT_XFER_BULK || if (qh->type == USB_ENDPOINT_XFER_CONTROL)
qh->type == USB_ENDPOINT_XFER_INT))
return; return;
/* Save the next toggle value */
WARN_ON(list_empty(&urbp->td_list)); WARN_ON(list_empty(&urbp->td_list));
td = list_entry(urbp->td_list.next, struct uhci_td, list); td = list_entry(urbp->td_list.next, struct uhci_td, list);
qh->needs_fixup = 1; qh->needs_fixup = 1;
...@@ -1121,21 +1145,6 @@ __acquires(uhci->lock) ...@@ -1121,21 +1145,6 @@ __acquires(uhci->lock)
if (qh->type == USB_ENDPOINT_XFER_ISOC) if (qh->type == USB_ENDPOINT_XFER_ISOC)
uhci_unlink_isochronous_tds(uhci, urb); uhci_unlink_isochronous_tds(uhci, urb);
/* If the URB isn't first on its queue, adjust the link pointer
* of the last TD in the previous URB. */
else if (qh->queue.next != &urbp->node) {
struct urb_priv *purbp;
struct uhci_td *ptd, *ltd;
purbp = list_entry(urbp->node.prev, struct urb_priv, node);
WARN_ON(list_empty(&purbp->td_list));
ptd = list_entry(purbp->td_list.prev, struct uhci_td,
list);
ltd = list_entry(urbp->td_list.prev, struct uhci_td,
list);
ptd->link = ltd->link;
}
/* Take the URB off the QH's queue. If the queue is now empty, /* Take the URB off the QH's queue. If the queue is now empty,
* this is a perfect time for a toggle fixup. */ * this is a perfect time for a toggle fixup. */
list_del_init(&urbp->node); list_del_init(&urbp->node);
...@@ -1237,7 +1246,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, ...@@ -1237,7 +1246,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
list_for_each_entry(urbp, &qh->queue, node) { list_for_each_entry(urbp, &qh->queue, node) {
urb = urbp->urb; urb = urbp->urb;
if (urb->status != -EINPROGRESS) { if (urb->status != -EINPROGRESS) {
uhci_save_toggle(qh, urb); uhci_cleanup_queue(qh, urb);
uhci_giveback_urb(uhci, qh, urb, regs); uhci_giveback_urb(uhci, qh, urb, regs);
goto restart; goto restart;
} }
......
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