diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2006-05-12 11:23:19 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 18:04:11 -0400 |
| commit | a0b458b64b2a3a4cb806dd5cd889bbf6c7e9d686 (patch) | |
| tree | 88a5d6e48140f4534e6b9e02352bf4b16cb5ef42 | |
| parent | 59e29ed91cff90b27d393c7a3d3ac9c3fcaea7dd (diff) | |
[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: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/usb/host/uhci-q.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 888938d78230..64b6c74789fd 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
| @@ -204,25 +204,49 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | /* | 206 | /* |
| 207 | * When the currently executing URB is dequeued, save its current toggle value | 207 | * When a queue is stopped and a dequeued URB is given back, adjust |
| 208 | * the previous TD link (if the URB isn't first on the queue) or | ||
| 209 | * save its toggle value (if it is first and is currently executing). | ||
| 208 | */ | 210 | */ |
| 209 | static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb) | 211 | static void uhci_cleanup_queue(struct uhci_qh *qh, |
| 212 | struct urb *urb) | ||
| 210 | { | 213 | { |
| 211 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | 214 | struct urb_priv *urbp = urb->hcpriv; |
| 212 | struct uhci_td *td; | 215 | struct uhci_td *td; |
| 213 | 216 | ||
| 217 | /* Isochronous pipes don't use toggles and their TD link pointers | ||
| 218 | * get adjusted during uhci_urb_dequeue(). */ | ||
| 219 | if (qh->type == USB_ENDPOINT_XFER_ISOC) | ||
| 220 | return; | ||
| 221 | |||
| 222 | /* If the URB isn't first on its queue, adjust the link pointer | ||
| 223 | * of the last TD in the previous URB. The toggle doesn't need | ||
| 224 | * to be saved since this URB can't be executing yet. */ | ||
| 225 | if (qh->queue.next != &urbp->node) { | ||
| 226 | struct urb_priv *purbp; | ||
| 227 | struct uhci_td *ptd; | ||
| 228 | |||
| 229 | purbp = list_entry(urbp->node.prev, struct urb_priv, node); | ||
| 230 | WARN_ON(list_empty(&purbp->td_list)); | ||
| 231 | ptd = list_entry(purbp->td_list.prev, struct uhci_td, | ||
| 232 | list); | ||
| 233 | td = list_entry(urbp->td_list.prev, struct uhci_td, | ||
| 234 | list); | ||
| 235 | ptd->link = td->link; | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 214 | /* If the QH element pointer is UHCI_PTR_TERM then then currently | 239 | /* If the QH element pointer is UHCI_PTR_TERM then then currently |
| 215 | * executing URB has already been unlinked, so this one isn't it. */ | 240 | * executing URB has already been unlinked, so this one isn't it. */ |
| 216 | if (qh_element(qh) == UHCI_PTR_TERM || | 241 | if (qh_element(qh) == UHCI_PTR_TERM) |
| 217 | qh->queue.next != &urbp->node) | ||
| 218 | return; | 242 | return; |
| 219 | qh->element = UHCI_PTR_TERM; | 243 | qh->element = UHCI_PTR_TERM; |
| 220 | 244 | ||
| 221 | /* Only bulk and interrupt pipes have to worry about toggles */ | 245 | /* Control pipes have to worry about toggles */ |
| 222 | if (!(qh->type == USB_ENDPOINT_XFER_BULK || | 246 | if (qh->type == USB_ENDPOINT_XFER_CONTROL) |
| 223 | qh->type == USB_ENDPOINT_XFER_INT)) | ||
| 224 | return; | 247 | return; |
| 225 | 248 | ||
| 249 | /* Save the next toggle value */ | ||
| 226 | WARN_ON(list_empty(&urbp->td_list)); | 250 | WARN_ON(list_empty(&urbp->td_list)); |
| 227 | td = list_entry(urbp->td_list.next, struct uhci_td, list); | 251 | td = list_entry(urbp->td_list.next, struct uhci_td, list); |
| 228 | qh->needs_fixup = 1; | 252 | qh->needs_fixup = 1; |
| @@ -1121,21 +1145,6 @@ __acquires(uhci->lock) | |||
| 1121 | if (qh->type == USB_ENDPOINT_XFER_ISOC) | 1145 | if (qh->type == USB_ENDPOINT_XFER_ISOC) |
| 1122 | uhci_unlink_isochronous_tds(uhci, urb); | 1146 | uhci_unlink_isochronous_tds(uhci, urb); |
| 1123 | 1147 | ||
| 1124 | /* If the URB isn't first on its queue, adjust the link pointer | ||
| 1125 | * of the last TD in the previous URB. */ | ||
| 1126 | else if (qh->queue.next != &urbp->node) { | ||
| 1127 | struct urb_priv *purbp; | ||
| 1128 | struct uhci_td *ptd, *ltd; | ||
| 1129 | |||
| 1130 | purbp = list_entry(urbp->node.prev, struct urb_priv, node); | ||
| 1131 | WARN_ON(list_empty(&purbp->td_list)); | ||
| 1132 | ptd = list_entry(purbp->td_list.prev, struct uhci_td, | ||
| 1133 | list); | ||
| 1134 | ltd = list_entry(urbp->td_list.prev, struct uhci_td, | ||
| 1135 | list); | ||
| 1136 | ptd->link = ltd->link; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | /* Take the URB off the QH's queue. If the queue is now empty, | 1148 | /* Take the URB off the QH's queue. If the queue is now empty, |
| 1140 | * this is a perfect time for a toggle fixup. */ | 1149 | * this is a perfect time for a toggle fixup. */ |
| 1141 | list_del_init(&urbp->node); | 1150 | list_del_init(&urbp->node); |
| @@ -1237,7 +1246,7 @@ restart: | |||
| 1237 | list_for_each_entry(urbp, &qh->queue, node) { | 1246 | list_for_each_entry(urbp, &qh->queue, node) { |
| 1238 | urb = urbp->urb; | 1247 | urb = urbp->urb; |
| 1239 | if (urb->status != -EINPROGRESS) { | 1248 | if (urb->status != -EINPROGRESS) { |
| 1240 | uhci_save_toggle(qh, urb); | 1249 | uhci_cleanup_queue(qh, urb); |
| 1241 | uhci_giveback_urb(uhci, qh, urb, regs); | 1250 | uhci_giveback_urb(uhci, qh, urb, regs); |
| 1242 | goto restart; | 1251 | goto restart; |
| 1243 | } | 1252 | } |
