Index: uspace/drv/ohci/batch.c
===================================================================
--- uspace/drv/ohci/batch.c	(revision e42dd3245c842ab3531270c8dd0c423f20cc2bd2)
+++ uspace/drv/ohci/batch.c	(revision f1be95c8d8aa7901c8ba3471400099d9c1a10b06)
@@ -118,6 +118,11 @@
 {
 	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	free32(data->ed);
+	free32(data->tds);
+	free32(instance->setup_buffer);
 	free32(instance->transport_buffer);
-	free32(instance->setup_buffer);
+	free(data);
 	free(instance);
 }
@@ -125,6 +130,25 @@
 bool batch_is_complete(usb_transfer_batch_t *instance)
 {
-	// TODO: implement
-	return false;
+	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	size_t tds = data->td_count - 1;
+	usb_log_debug2("Batch(%p) checking %d td(s) for completion.\n",
+	    instance, tds);
+	size_t i = 0;
+	for (; i < tds; ++i) {
+		if (!td_is_finished(&data->tds[i]))
+			return false;
+		instance->error = td_error(&data->tds[i]);
+		/* FIXME: calculate real transfered size */
+		instance->transfered_size = instance->buffer_size;
+		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
+			    instance, i, data->tds[i].status);
+			return true;
+//			endpoint_toggle_set(instance->ep,
+		}
+	}
+	return true;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/ohci/hw_struct/completion_codes.h
===================================================================
--- uspace/drv/ohci/hw_struct/completion_codes.h	(revision e42dd3245c842ab3531270c8dd0c423f20cc2bd2)
+++ uspace/drv/ohci/hw_struct/completion_codes.h	(revision f1be95c8d8aa7901c8ba3471400099d9c1a10b06)
@@ -35,4 +35,6 @@
 #define DRV_OHCI_HW_STRUCT_COMPLETION_CODES_H
 
+#include <errno.h>
+
 #define CC_NOERROR (0x0)
 #define CC_CRC (0x1)
@@ -50,4 +52,38 @@
 #define CC_NOACCESS2 (0xf)
 
+inline static int cc_to_rc(int cc)
+{
+	switch (cc) {
+	case CC_NOERROR:
+		return EOK;
+
+	case CC_CRC:
+		return EBADCHECKSUM;
+
+	case CC_PIDUNEXPECTED:
+	case CC_PIDFAIL:
+	case CC_BITSTUFF:
+		return EIO;
+
+	case CC_TOGGLE:
+	case CC_STALL:
+		return ESTALL;
+
+	case CC_NORESPONSE:
+		return ETIMEOUT;
+
+	case CC_DATAOVERRRUN:
+	case CC_DATAUNDERRRUN:
+	case CC_BUFFEROVERRRUN:
+	case CC_BUFFERUNDERRUN:
+		return EOVERFLOW;
+
+	case CC_NOACCESS1:
+	case CC_NOACCESS2:
+	default:
+		return ENOTSUP;
+	}
+}
+
 #endif
 /**
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision f1be95c8d8aa7901c8ba3471400099d9c1a10b06)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision f1be95c8d8aa7901c8ba3471400099d9c1a10b06)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include <usb/usb.h>
+#include "utils/malloc32.h"
+
+#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 };
+
+void td_init(
+    td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle)
+{
+	assert(instance);
+	bzero(instance, sizeof(td_t));
+	instance-> status = 0
+	    | ((dp[dir] & 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;
+	}
+	if (buffer != NULL) {
+		instance->cbp = addr_to_phys(buffer);
+		instance->be = addr_to_phys(buffer + size - 1);
+	}
+}
+/**
+ * @}
+ */
+
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision e42dd3245c842ab3531270c8dd0c423f20cc2bd2)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision f1be95c8d8aa7901c8ba3471400099d9c1a10b06)
@@ -35,4 +35,5 @@
 #define DRV_OHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H
 
+#include <bool.h>
 #include <stdint.h>
 #include "utils/malloc32.h"
@@ -79,4 +80,26 @@
 	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 */
+	if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2 && cc != CC_NOERROR) {
+		return true;
+	}
+	/* everything done */
+	if (cc == CC_NOERROR && instance->cbp == 0) {
+		return true;
+	}
+	return false;
+}
+
+static inline int td_error(td_t *instance)
+{
+	assert(instance);
+	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	return cc_to_rc(cc);
+}
 #endif
 /**
