aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c57
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 */
209static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb) 211static 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 }