Index: uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h	(revision 9515f674f1653460bfb4650aefd98bd6c414bd1b)
+++ uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h	(revision 70d72dd220da84827ec57c3758a2a754578b812c)
@@ -109,4 +109,28 @@
 
 /**
+ * Check for SKIP or HALTED flag being set.
+ * @param instance ED
+ * @return true if either SKIP or HALTED flag is set, false otherwise.
+ */
+static inline bool ed_inactive(const ed_t *instance)
+{
+	assert(instance);
+	return (instance->td_head & ED_TDHEAD_HALTED_FLAG)
+	    || (instance->status & ED_STATUS_K_FLAG);
+}
+
+/**
+ * Check whether this ED contains TD to be executed.
+ * @param instance ED
+ * @return true if there are pending TDs, false otherwise.
+ */
+static inline bool ed_transfer_pending(const ed_t *instance)
+{
+	assert(instance);
+	return (instance->td_head & ED_TDHEAD_PTR_MASK)
+	    != (instance->td_tail & ED_TDTAIL_PTR_MASK);
+}
+
+/**
  * Set the last element of TD list
  * @param instance ED
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision 9515f674f1653460bfb4650aefd98bd6c414bd1b)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision 70d72dd220da84827ec57c3758a2a754578b812c)
@@ -35,22 +35,42 @@
 #include "transfer_descriptor.h"
 
-static unsigned dp[3] =
-    { TD_STATUS_DP_IN, TD_STATUS_DP_OUT, TD_STATUS_DP_SETUP };
-static unsigned togg[2] = { TD_STATUS_T_0, TD_STATUS_T_1 };
+/** USB direction to OHCI TD values translation table */
+static const uint32_t dir[] = {
+	[USB_DIRECTION_IN] = TD_STATUS_DP_IN,
+	[USB_DIRECTION_OUT] = TD_STATUS_DP_OUT,
+	[USB_DIRECTION_BOTH] = TD_STATUS_DP_SETUP,
+};
 
-void td_init(td_t *instance,
-    usb_direction_t dir, const void *buffer, size_t size, int toggle)
+/**
+ * Initialize OHCI TD.
+ * @param instance TD structure to initialize.
+ * @param next Next TD in ED list.
+ * @param direction Used to determine PID, BOTH means setup PID.
+ * @param buffer Pointer to the first byte of transferred data.
+ * @param size Size of the buffer.
+ * @param toggle Toggle bit value, use 0/1 to set explicitly,
+ *        any other value means that ED toggle will be used.
+ */
+void td_init(td_t *instance, const td_t *next,
+    usb_direction_t direction, const void *buffer, size_t size, int toggle)
 {
 	assert(instance);
 	bzero(instance, sizeof(td_t));
+	/* Set PID and Error code */
 	instance->status = 0
-	    | ((dp[dir] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
+	    | ((dir[direction] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
 	    | ((CC_NOACCESS2 & TD_STATUS_CC_MASK) << TD_STATUS_CC_SHIFT);
+
 	if (toggle == 0 || toggle == 1) {
-		instance->status |= togg[toggle] << TD_STATUS_T_SHIFT;
+		/* Set explicit toggle bit */
+		instance->status |= TD_STATUS_T_USE_TD_FLAG;
+		instance->status |= toggle ? TD_STATUS_T_FLAG : 0;
 	}
+
+	/* Alow less data on input. */
 	if (dir == USB_DIRECTION_IN) {
 		instance->status |= TD_STATUS_ROUND_FLAG;
 	}
+
 	if (buffer != NULL) {
 		assert(size != 0);
@@ -58,4 +78,7 @@
 		instance->be = addr_to_phys(buffer + size - 1);
 	}
+
+	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
+
 }
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision 9515f674f1653460bfb4650aefd98bd6c414bd1b)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision 70d72dd220da84827ec57c3758a2a754578b812c)
@@ -37,6 +37,6 @@
 #include <bool.h>
 #include <stdint.h>
+
 #include "../utils/malloc32.h"
-
 #include "completion_codes.h"
 
@@ -46,52 +46,64 @@
 #define OHCI_TD_MAX_TRANSFER (4 * 1024)
 
+/**
+ * Transfer Descriptor representation.
+ *
+ * See OHCI spec chapter 4.3.1 General Transfer Descriptor on page 19
+ * (pdf page 33) for details.
+ */
 typedef struct td {
+	/** Status field. Do not touch on active TDs. */
 	volatile uint32_t status;
 #define TD_STATUS_ROUND_FLAG (1 << 18)
-#define TD_STATUS_DP_MASK (0x3) /* direction/PID */
+#define TD_STATUS_DP_MASK (0x3) /* Direction/PID */
 #define TD_STATUS_DP_SHIFT (19)
 #define TD_STATUS_DP_SETUP (0x0)
 #define TD_STATUS_DP_OUT (0x1)
 #define TD_STATUS_DP_IN (0x2)
-#define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */
+#define TD_STATUS_DI_MASK (0x7) /* Delay interrupt, wait n frames before irq */
 #define TD_STATUS_DI_SHIFT (21)
 #define TD_STATUS_DI_NO_INTERRUPT (0x7)
-#define TD_STATUS_T_MASK (0x3)  /* data toggle 1x = use ED toggle carry */
-#define TD_STATUS_T_SHIFT (24)
-#define TD_STATUS_T_0 (0x2)
-#define TD_STATUS_T_1 (0x3)
-#define TD_STATUS_T_ED (0)
-#define TD_STATUS_EC_MASK (0x3) /* error count */
+#define TD_STATUS_T_FLAG (1 << 24) /* Explicit toggle bit value for this TD */
+#define TD_STATUS_T_USE_TD_FLAG (1 << 25) /* 1 = use bit 24 as toggle bit */
+#define TD_STATUS_EC_MASK (0x3) /* Error count */
 #define TD_STATUS_EC_SHIFT (26)
-#define TD_STATUS_CC_MASK (0xf) /* condition code */
+#define TD_STATUS_CC_MASK (0xf) /* Condition code */
 #define TD_STATUS_CC_SHIFT (28)
 
-	volatile uint32_t cbp; /* current buffer ptr, data to be transfered */
+	/**
+	 * Current buffer pointer.
+	 * Phys address of the first byte to be transferred. */
+	volatile uint32_t cbp;
+
+	/** Pointer to the next TD in chain. 16-byte aligned. */
 	volatile uint32_t next;
 #define TD_NEXT_PTR_MASK (0xfffffff0)
 #define TD_NEXT_PTR_SHIFT (0)
 
-	volatile uint32_t be; /* buffer end, address of the last byte */
+	/**
+	 * Buffer end.
+	 * Phys address of the last byte of the transfer.
+	 * @note this does not have to be on the same page as cbp.
+	 */
+	volatile uint32_t be;
 } __attribute__((packed)) td_t;
 
-void td_init(td_t *instance,
+void td_init(td_t *instance, const td_t *next,
     usb_direction_t dir, const void *buffer, size_t size, int toggle);
 
-inline static void td_set_next(td_t *instance, td_t *next)
+/**
+ * Check TD for completion.
+ * @param instance TD structure.
+ * @return true if the TD was accessed and processed by hw, false otherwise.
+ */
+inline static bool td_is_finished(const td_t *instance)
 {
 	assert(instance);
-	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
-}
-
-inline static bool td_is_finished(td_t *instance)
-{
-	assert(instance);
-	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
-	/* something went wrong, error code is set */
+	const int cc =
+	    (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	/* This value is changed on transfer completion,
+	 * either to CC_NOERROR or and error code.
+	 * See OHCI spec 4.3.1.3.5 p. 23 (pdf 37) */
 	if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2) {
-		return true;
-	}
-	/* everything done */
-	if (cc == CC_NOERROR && instance->cbp == 0) {
 		return true;
 	}
@@ -99,16 +111,29 @@
 }
 
-static inline int td_error(td_t *instance)
+/**
+ * Get error code that indicates transfer status.
+ * @param instance TD structure.
+ * @return Error code.
+ */
+static inline int td_error(const td_t *instance)
 {
 	assert(instance);
-	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	const int cc =
+	    (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
 	return cc_to_rc(cc);
 }
 
+/**
+ * Get remaining portion of buffer to be read/written
+ * @param instance TD structure
+ * @return size of remaining buffer.
+ */
 static inline size_t td_remain_size(td_t *instance)
 {
 	assert(instance);
+	/* Current buffer pointer is cleared on successful transfer */
 	if (instance->cbp == 0)
 		return 0;
+	/* Buffer end points to the last byte of transfer buffer, so add 1 */
 	return instance->be - instance->cbp + 1;
 }
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 9515f674f1653460bfb4650aefd98bd6c414bd1b)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 70d72dd220da84827ec57c3758a2a754578b812c)
@@ -248,7 +248,7 @@
 
 	/* setup stage */
-	td_init(ohci_batch->tds[0], USB_DIRECTION_BOTH, buffer,
-		ohci_batch->usb_batch->setup_size, toggle);
-	td_set_next(ohci_batch->tds[0], ohci_batch->tds[1]);
+	td_init(
+	    ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
+	    buffer, ohci_batch->usb_batch->setup_size, toggle);
 	usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
@@ -265,8 +265,7 @@
 		toggle = 1 - toggle;
 
-		td_init(ohci_batch->tds[td_current], data_dir, buffer,
-		    transfer_size, toggle);
-		td_set_next(ohci_batch->tds[td_current],
-		    ohci_batch->tds[td_current + 1]);
+		td_init(ohci_batch->tds[td_current],
+		    ohci_batch->tds[td_current + 1],
+		    data_dir, buffer, transfer_size, toggle);
 		usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.\n",
 		    ohci_batch->tds[td_current]->status,
@@ -283,7 +282,6 @@
 	/* status stage */
 	assert(td_current == ohci_batch->td_count - 1);
-	td_init(ohci_batch->tds[td_current], status_dir, NULL, 0, 1);
-	td_set_next(ohci_batch->tds[td_current],
-	    ohci_batch->tds[td_current + 1]);
+	td_init(ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
+	    status_dir, NULL, 0, 1);
 	usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[td_current]->status,
@@ -323,8 +321,7 @@
 		    ? OHCI_TD_MAX_TRANSFER : remain_size;
 
-		td_init(ohci_batch->tds[td_current], dir, buffer,
-		    transfer_size, -1);
-		td_set_next(ohci_batch->tds[td_current],
-		    ohci_batch->tds[td_current + 1]);
+		td_init(
+		    ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
+		    dir, buffer, transfer_size, -1);
 
 		usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.\n",
