diff options
-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 | } |