Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 70d72dd220da84827ec57c3758a2a754578b812c)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision d5abaf4b55ff0acd80899bb825da600c8de24c59)
@@ -163,13 +163,37 @@
 	    ohci_batch->ed->td_tail, ohci_batch->ed->next);
 
-	size_t i = 0;
-	for (; i < ohci_batch->td_count; ++i) {
+	if (!ed_inactive(ohci_batch->ed) && ed_transfer_pending(ohci_batch->ed))
+		return false;
+
+	/* Now we may be sure that either the ED is inactive because of errors
+	 * or all transfer descriptors completed successfully */
+
+	/* Assume all data got through */
+	ohci_batch->usb_batch->transfered_size =
+	    ohci_batch->usb_batch->buffer_size;
+	/* Assume we will leave the last td behind */
+	ohci_batch->leave_td = ohci_batch->td_count;
+
+	/* Check all TDs */
+	for (size_t i = 0; i < ohci_batch->td_count; ++i) {
 		assert(ohci_batch->tds[i] != NULL);
 		usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.\n", i,
 		    ohci_batch->tds[i]->status, ohci_batch->tds[i]->cbp,
 		    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
-		if (!td_is_finished(ohci_batch->tds[i])) {
-			return false;
-		}
+
+		/* If the TD got all its data through, it will report 0 bytes
+		 * remain, the sole exception is INPUT with data rounding flag
+		 * (short), i.e. every INPUT. Nice thing is that short packets
+		 * will correctly report remaining data, thus making
+		 * this computation correct (short packets need to be produced
+		 * by the last TD)
+		 * NOTE: This also works for CONTROL transfer as
+		 * the first TD will return 0 remain.
+		 * NOTE: Short packets don't break the assumption that
+		 * we leave the very last(unused) TD behind.
+		 */
+		ohci_batch->usb_batch->transfered_size
+		    -= td_remain_size(ohci_batch->tds[i]);
+
 		ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
 		if (ohci_batch->usb_batch->error != EOK) {
@@ -177,19 +201,38 @@
 			    ohci_batch->usb_batch, i,
 			    ohci_batch->tds[i]->status);
-			/* Make sure TD queue is empty (one TD),
-			 * ED should be marked as halted */
-			ohci_batch->ed->td_tail =
-			    (ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK);
-			++i;
+
+			/* ED should be stopped because of errors */
+			assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0);
+
+			/* Now we have a problem: we don't know what TD
+			 * the head pointer points to, the retiring rules
+			 * described in specs say it should be the one after
+			 * the failed one so set the tail pointer accordingly.
+			 * It will be the one TD we leave behind.
+			 */
+			ohci_batch->leave_td = i + 1;
+
+			/* Check TD assumption */
+			const uint32_t pa = addr_to_phys(
+			    ohci_batch->tds[ohci_batch->leave_td]);
+			assert((ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK)
+			    == pa);
+
+			ed_set_tail_td(ohci_batch->ed,
+			    ohci_batch->tds[ohci_batch->leave_td]);
+
+			/* Clear possible ED HALT */
+			ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
 			break;
 		}
 	}
-
-	assert(i <= ohci_batch->td_count);
-	ohci_batch->leave_td = i;
-
+	assert(ohci_batch->usb_batch->transfered_size <=
+	    ohci_batch->usb_batch->buffer_size);
+
+	/* Store the remaining TD */
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
 	assert(ohci_ep);
 	ohci_ep->td = ohci_batch->tds[ohci_batch->leave_td];
+#if 0
 	assert(i > 0);
 	ohci_batch->usb_batch->transfered_size =
@@ -199,8 +242,6 @@
 		    -= td_remain_size(ohci_batch->tds[i]);
 	}
-
-	/* Clear possible ED HALT */
-	ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
-	/* just make sure that we are leaving the right TD behind */
+#endif
+	/* Just make sure that we are leaving the right TD behind */
 	const uint32_t pa = addr_to_phys(ohci_ep->td);
 	assert(pa == (ohci_batch->ed->td_head & ED_TDHEAD_PTR_MASK));
