diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/uhci-q.c | 24 |
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 */ |
1322 | restart: | ||
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) { |