Index: uspace/drv/bus/usb/ehci/ehci_batch.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_batch.c	(revision 6602e97a7ebe60de7d5763ff25ddd5637d6bc950)
+++ uspace/drv/bus/usb/ehci/ehci_batch.c	(revision a752c78c2ca75b7422b28b6d13994d567d4cfdb1)
@@ -206,5 +206,5 @@
 		    ehci_batch->tds[i]->status, ehci_batch->tds[i]->next,
 		    ehci_batch->tds[i]->alternate);
-#if 0
+
 		ehci_batch->usb_batch->error = td_error(ehci_batch->tds[i]);
 		if (ehci_batch->usb_batch->error == EOK) {
@@ -227,43 +227,16 @@
 			    ehci_batch->usb_batch, i,
 			    ehci_batch->tds[i]->status);
-
-			/* ED should be stopped because of errors */
-			assert((ehci_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.
-			 */
-			leave_td = i + 1;
-
-			/* Check TD assumption */
-			assert(ed_head_td(ehci_batch->ed) ==
-			    addr_to_phys(ehci_batch->tds[leave_td]));
-
-			/* Set tail to the same TD */
-			ed_set_tail_td(ehci_batch->ed,
-			    ehci_batch->tds[leave_td]);
-
 			/* Clear possible ED HALT */
-			ed_clear_halt(ehci_batch->ed);
+			qh_clear_halt(ehci_batch->qh);
 			break;
 		}
-#endif
 	}
 
 	assert(ehci_batch->usb_batch->transfered_size <=
 	    ehci_batch->usb_batch->buffer_size);
-#if 0
-	/* Store the remaining TD */
-	ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ehci_batch->usb_batch->ep);
-	assert(ehci_ep);
-	ehci_ep->td = ehci_batch->tds[leave_td];
-
-	/* Make sure that we are leaving the right TD behind */
-	assert(addr_to_phys(ehci_ep->td) == ed_head_td(ehci_batch->ed));
-	assert(addr_to_phys(ehci_ep->td) == ed_tail_td(ehci_batch->ed));
-#endif
+	/* Clear TD pointers */
+	ehci_batch->qh->next = LINK_POINTER_TERM;
+	ehci_batch->qh->current = LINK_POINTER_TERM;
+
 	return true;
 }
Index: uspace/drv/bus/usb/ehci/hw_struct/queue_head.h
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/queue_head.h	(revision 6602e97a7ebe60de7d5763ff25ddd5637d6bc950)
+++ uspace/drv/bus/usb/ehci/hw_struct/queue_head.h	(revision a752c78c2ca75b7422b28b6d13994d567d4cfdb1)
@@ -184,8 +184,8 @@
 }
 
-static inline void qh_halt(qh_t *qh)
-{
-	assert(qh);
-	EHCI_MEM32_SET(qh->status, QH_STATUS_HALTED_FLAG);
+static inline void qh_clear_halt(qh_t *qh)
+{
+	assert(qh);
+	EHCI_MEM32_CLR(qh->status, QH_STATUS_HALTED_FLAG);
 }
 
Index: uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c	(revision 6602e97a7ebe60de7d5763ff25ddd5637d6bc950)
+++ uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c	(revision a752c78c2ca75b7422b28b6d13994d567d4cfdb1)
@@ -34,4 +34,5 @@
 
 #include <assert.h>
+#include <errno.h>
 #include <macros.h>
 #include <mem.h>
@@ -40,7 +41,25 @@
 
 #include "../utils/malloc32.h"
-//#include "completion_codes.h"
 #include "mem_access.h"
 #include "transfer_descriptor.h"
+
+
+int td_error(const td_t *td)
+{
+	assert(td);
+	const uint32_t status = EHCI_MEM32_RD(td->status);
+	if (status & TD_STATUS_HALTED_FLAG) {
+		if (status & TD_STATUS_TRANS_ERR_FLAG)
+			return EIO;
+		if (status & TD_STATUS_BABBLE_FLAG)
+			return EIO;
+		if (status & TD_STATUS_BUFF_ERROR_FLAG)
+			return EOVERFLOW;
+		return ESTALL;
+	}
+	if (status & TD_STATUS_ACTIVE_FLAG)
+		return EINPROGRESS;
+	return EOK;
+}
 
 /** USB direction to EHCI TD values translation table */
Index: uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h	(revision 6602e97a7ebe60de7d5763ff25ddd5637d6bc950)
+++ uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h	(revision a752c78c2ca75b7422b28b6d13994d567d4cfdb1)
@@ -73,4 +73,19 @@
 } td_t;
 
+static inline bool td_active(const td_t *td)
+{
+	assert(td);
+	return (EHCI_MEM32_RD(td->status) & TD_STATUS_HALTED_FLAG) != 0;
+}
+
+static inline size_t td_remain_size(const td_t *td)
+{
+	assert(td);
+	return (EHCI_MEM32_RD(td->status) >> TD_STATUS_TOTAL_SHIFT) &
+	    TD_STATUS_TOTAL_MASK;
+}
+
+int td_error(const td_t *td);
+
 void td_init(td_t *td, const td_t *next, usb_direction_t dir, const void * buf,
     size_t buf_size, int toggle);
