aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-05 16:32:02 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:10 -0400
commit2775562ad2af2fc131ef7987166db6e42217528f (patch)
tree87c0ba46d8daa8d4b9af6f54b34b21b52c3fa57e /drivers/usb/host/uhci-q.c
parent4de7d2c231a8624a47417977be0768c5b5257c4f (diff)
[PATCH] USB: UHCI: fix obscure bug in enqueue()
This patch (as676) fixes a small bug in uhci-hcd's enqueue routine. When an URB is unlinked or gets an error and the completion handler queues another URB for the same endpoint, the queue shouldn't be allowed to start up again until the handler returns. Not even if the new URB is the only one on its queue. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 8639e9035931..693e92c1bd9e 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1148,8 +1148,9 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
1148 1148
1149 /* If the new URB is the first and only one on this QH then either 1149 /* If the new URB is the first and only one on this QH then either
1150 * the QH is new and idle or else it's unlinked and waiting to 1150 * the QH is new and idle or else it's unlinked and waiting to
1151 * become idle, so we can activate it right away. */ 1151 * become idle, so we can activate it right away. But only if the
1152 if (qh->queue.next == &urbp->node) 1152 * queue isn't stopped. */
1153 if (qh->queue.next == &urbp->node && !qh->is_stopped)
1153 uhci_activate_qh(uhci, qh); 1154 uhci_activate_qh(uhci, qh);
1154 goto done; 1155 goto done;
1155 1156
@@ -1293,27 +1294,32 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
1293 if (urb->status == -EINPROGRESS) /* Not dequeued */ 1294 if (urb->status == -EINPROGRESS) /* Not dequeued */
1294 urb->status = status; 1295 urb->status = status;
1295 else 1296 else
1296 status = -ECONNRESET; 1297 status = ECONNRESET; /* Not -ECONNRESET */
1297 spin_unlock(&urb->lock); 1298 spin_unlock(&urb->lock);
1298 1299
1299 /* Dequeued but completed URBs can't be given back unless 1300 /* Dequeued but completed URBs can't be given back unless
1300 * the QH is stopped or has finished unlinking. */ 1301 * the QH is stopped or has finished unlinking. */
1301 if (status == -ECONNRESET && 1302 if (status == ECONNRESET) {
1302 !(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) 1303 if (QH_FINISHED_UNLINKING(qh))
1303 return; 1304 qh->is_stopped = 1;
1305 else if (!qh->is_stopped)
1306 return;
1307 }
1304 1308
1305 uhci_giveback_urb(uhci, qh, urb, regs); 1309 uhci_giveback_urb(uhci, qh, urb, regs);
1306 if (qh->is_stopped) 1310 if (status < 0)
1307 break; 1311 break;
1308 } 1312 }
1309 1313
1310 /* If the QH is neither stopped nor finished unlinking (normal case), 1314 /* If the QH is neither stopped nor finished unlinking (normal case),
1311 * our work here is done. */ 1315 * our work here is done. */
1312 restart: 1316 if (QH_FINISHED_UNLINKING(qh))
1313 if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) 1317 qh->is_stopped = 1;
1318 else if (!qh->is_stopped)
1314 return; 1319 return;
1315 1320
1316 /* Otherwise give back each of the dequeued URBs */ 1321 /* Otherwise give back each of the dequeued URBs */
1322restart:
1317 list_for_each_entry(urbp, &qh->queue, node) { 1323 list_for_each_entry(urbp, &qh->queue, node) {
1318 urb = urbp->urb; 1324 urb = urbp->urb;
1319 if (urb->status != -EINPROGRESS) { 1325 if (urb->status != -EINPROGRESS) {