Index: uspace/drv/bus/usb/ohci/Makefile
===================================================================
--- uspace/drv/bus/usb/ohci/Makefile	(revision f9745198a340eebcba63d52957d602d9fbb50a9d)
+++ uspace/drv/bus/usb/ohci/Makefile	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
@@ -44,9 +44,9 @@
 
 SOURCES = \
-	batch.c \
 	endpoint_list.c \
 	hc.c \
 	main.c \
 	ohci.c \
+	ohci_batch.c \
 	ohci_endpoint.c \
 	pci.c \
Index: uspace/drv/bus/usb/ohci/batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/batch.c	(revision f9745198a340eebcba63d52957d602d9fbb50a9d)
+++ 	(revision )
@@ -1,437 +1,0 @@
-/*
- * 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 USB transaction structure
- */
-#include <errno.h>
-#include <str_error.h>
-
-#include <usb/usb.h>
-#include <usb/debug.h>
-
-#include "batch.h"
-#include "ohci_endpoint.h"
-#include "utils/malloc32.h"
-#include "hw_struct/endpoint_descriptor.h"
-#include "hw_struct/transfer_descriptor.h"
-
-static void batch_control_write(usb_transfer_batch_t *instance);
-static void batch_control_read(usb_transfer_batch_t *instance);
-
-static void batch_interrupt_in(usb_transfer_batch_t *instance);
-static void batch_interrupt_out(usb_transfer_batch_t *instance);
-
-static void batch_bulk_in(usb_transfer_batch_t *instance);
-static void batch_bulk_out(usb_transfer_batch_t *instance);
-
-static void batch_setup_control(usb_transfer_batch_t *batch)
-{
-        // TODO Find a better way to do this
-        if (batch->setup_buffer[0] & (1 << 7))
-                batch_control_read(batch);
-        else
-                batch_control_write(batch);
-}
-/*----------------------------------------------------------------------------*/
-void (*batch_setup[4][3])(usb_transfer_batch_t*) =
-{
-        { NULL, NULL, batch_setup_control },
-        { NULL, NULL, NULL },
-        { batch_bulk_in, batch_bulk_out, NULL },
-        { batch_interrupt_in, batch_interrupt_out, NULL },
-};
-
-
-/** OHCI specific data required for USB transfer */
-typedef struct ohci_transfer_batch {
-	/** Endpoint descriptor of the target endpoint. */
-	ed_t *ed;
-	/** List of TDs needed for the transfer */
-	td_t **tds;
-	/** Number of TDs used by the transfer */
-	size_t td_count;
-	/** Dummy TD to be left at the ED and used by the next transfer */
-	size_t leave_td;
-	/** Data buffer, must be accessible byb the OHCI hw. */
-	void *device_buffer;
-} ohci_transfer_batch_t;
-/*----------------------------------------------------------------------------*/
-static void batch_control(usb_transfer_batch_t *instance,
-    usb_direction_t data_dir, usb_direction_t status_dir);
-static void batch_data(usb_transfer_batch_t *instance);
-/*----------------------------------------------------------------------------*/
-/** Safely destructs ohci_transfer_batch_t structure
- *
- * @param[in] ohci_batch Instance to destroy.
- */
-static void ohci_batch_dispose(void *ohci_batch)
-{
-	ohci_transfer_batch_t *instance = ohci_batch;
-	if (!instance)
-		return;
-	unsigned i = 0;
-	if (instance->tds) {
-		for (; i< instance->td_count; ++i) {
-			if (i != instance->leave_td)
-				free32(instance->tds[i]);
-		}
-		free(instance->tds);
-	}
-	free32(instance->device_buffer);
-	free(instance);
-}
-/*----------------------------------------------------------------------------*/
-int batch_init_ohci(usb_transfer_batch_t *batch)
-{
-	assert(batch);
-#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
-        if (ptr == NULL) { \
-                usb_log_error(message); \
-		if (data) { \
-			ohci_batch_dispose(data); \
-		} \
-                return ENOMEM; \
-        } else (void)0
-
-	ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1);
-	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
-
-	data->td_count = ((batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
-	    / OHCI_TD_MAX_TRANSFER);
-	/* Control transfer need Setup and Status stage */
-	if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
-		data->td_count += 2;
-	}
-
-	/* We need an extra place for TD that was left at ED */
-	data->tds = calloc(sizeof(td_t*), data->td_count + 1);
-	CHECK_NULL_DISPOSE_RETURN(data->tds,
-	    "Failed to allocate transfer descriptors.\n");
-
-	/* Add TD left over by the previous transfer */
-	data->ed = ohci_endpoint_get(batch->ep)->ed;
-	data->tds[0] = ohci_endpoint_get(batch->ep)->td;
-	data->leave_td = 0;
-	unsigned i = 1;
-	for (; i <= data->td_count; ++i) {
-		data->tds[i] = malloc32(sizeof(td_t));
-		CHECK_NULL_DISPOSE_RETURN(data->tds[i],
-		    "Failed to allocate TD %d.\n", i );
-	}
-
-
-	/* NOTE: OHCI is capable of handling buffer that crosses page boundaries
-	 * it is, however, not capable of handling buffer that occupies more
-	 * than two pages (the first page is computed using start pointer, the
-	 * other using the end pointer) */
-        if (batch->setup_size + batch->buffer_size > 0) {
-		data->device_buffer =
-		    malloc32(batch->setup_size + batch->buffer_size);
-                CHECK_NULL_DISPOSE_RETURN(data->device_buffer,
-                    "Failed to allocate device accessible buffer.\n");
-		/* Copy setup data */
-                memcpy(data->device_buffer, batch->setup_buffer,
-		    batch->setup_size);
-		batch->data_buffer = data->device_buffer + batch->setup_size;
-        }
-
-	batch->private_data = data;
-	batch->private_data_dtor = ohci_batch_dispose;
-
-        assert(batch_setup[batch->ep->transfer_type][batch->ep->direction]);
-        batch_setup[batch->ep->transfer_type][batch->ep->direction](batch);
-
-	return EOK;
-#undef CHECK_NULL_DISPOSE_RETURN
-}
-/*----------------------------------------------------------------------------*/
-/** Check batch TDs' status.
- *
- * @param[in] instance Batch structure to use.
- * @return False, if there is an active TD, true otherwise.
- *
- * Walk all TDs (usually there is just one). Stop with false if there is an
- * active TD. Stop with true if an error is found. Return true if the walk
- * completes with the last TD.
- */
-bool batch_is_complete(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	ohci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-	usb_log_debug("Batch(%p) checking %zu td(s) for completion.\n",
-	    instance, data->td_count);
-	usb_log_debug("ED: %x:%x:%x:%x.\n",
-	    data->ed->status, data->ed->td_head, data->ed->td_tail,
-	    data->ed->next);
-	size_t i = 0;
-	instance->transfered_size = instance->buffer_size;
-	for (; i < data->td_count; ++i) {
-		assert(data->tds[i] != NULL);
-		usb_log_debug("TD %zu: %x:%x:%x:%x.\n", i,
-		    data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next,
-		    data->tds[i]->be);
-		if (!td_is_finished(data->tds[i])) {
-			return false;
-		}
-		instance->error = td_error(data->tds[i]);
-		if (instance->error != EOK) {
-			usb_log_debug("Batch(%p) found error TD(%zu):%x.\n",
-			    instance, i, data->tds[i]->status);
-			/* Make sure TD queue is empty (one TD),
-			 * ED should be marked as halted */
-			data->ed->td_tail =
-			    (data->ed->td_head & ED_TDTAIL_PTR_MASK);
-			++i;
-			break;
-		}
-	}
-	data->leave_td = i;
-	assert(data->leave_td <= data->td_count);
-
-	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(instance->ep);
-	assert(ohci_ep);
-	ohci_ep->td = data->tds[data->leave_td];
-	assert(i > 0);
-	for (--i;i < data->td_count; ++i)
-		instance->transfered_size -= td_remain_size(data->tds[i]);
-
-	/* Clear possible ED HALT */
-	data->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
-	const uint32_t pa = addr_to_phys(ohci_ep->td);
-	assert(pa == (data->ed->td_head & ED_TDHEAD_PTR_MASK));
-	assert(pa == (data->ed->td_tail & ED_TDTAIL_PTR_MASK));
-
-	return true;
-}
-/*----------------------------------------------------------------------------*/
-/** Starts execution of the TD list
- *
- * @param[in] instance Batch structure to use
- */
-void batch_commit(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	ohci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-	ed_set_end_td(data->ed, data->tds[data->td_count]);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepares control write transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Uses generic control transfer using direction OUT(data stage) and
- * IN(status stage).
- */
-void batch_control_write(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	/* We are data out, we are supposed to provide data */
-	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
-	instance->next_step = usb_transfer_batch_call_out_and_dispose;
-	batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
-	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepares control read transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Uses generic control transfer using direction IN(data stage) and
- * OUT(status stage).
- */
-void batch_control_read(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	instance->next_step = usb_transfer_batch_call_in_and_dispose;
-	batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
-	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare interrupt in transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer.
- */
-void batch_interrupt_in(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	instance->next_step = usb_transfer_batch_call_in_and_dispose;
-	batch_data(instance);
-	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare interrupt out transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer.
- */
-void batch_interrupt_out(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	/* We are data out, we are supposed to provide data */
-	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
-	instance->next_step = usb_transfer_batch_call_out_and_dispose;
-	batch_data(instance);
-	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare bulk in transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer.
- */
-void batch_bulk_in(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	instance->next_step = usb_transfer_batch_call_in_and_dispose;
-	batch_data(instance);
-	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare bulk out transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer.
- */
-void batch_bulk_out(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	/* We are data out, we are supposed to provide data */
-	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
-	instance->next_step = usb_transfer_batch_call_out_and_dispose;
-	batch_data(instance);
-	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare generic control transfer
- *
- * @param[in] instance Batch structure to use.
- * @param[in] data_dir Direction to use for data stage.
- * @param[in] status_dir Direction to use for status stage.
- *
- * Setup stage with toggle 0 and direction BOTH(SETUP_PID)
- * Data stage with alternating toggle and direction supplied by parameter.
- * Status stage with toggle 1 and direction supplied by parameter.
- */
-void batch_control(usb_transfer_batch_t *instance,
-    usb_direction_t data_dir, usb_direction_t status_dir)
-{
-	assert(instance);
-	ohci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
-	    data->ed->status, data->ed->td_tail, data->ed->td_head,
-	    data->ed->next);
-	int toggle = 0;
-	/* setup stage */
-	td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,
-		instance->setup_size, toggle);
-	td_set_next(data->tds[0], data->tds[1]);
-	usb_log_debug("Created CONTROL SETUP TD: %x:%x:%x:%x.\n",
-	    data->tds[0]->status, data->tds[0]->cbp, data->tds[0]->next,
-	    data->tds[0]->be);
-
-	/* data stage */
-	size_t td_current = 1;
-	size_t remain_size = instance->buffer_size;
-	char *buffer = instance->data_buffer;
-	while (remain_size > 0) {
-		size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
-		    OHCI_TD_MAX_TRANSFER : remain_size;
-		toggle = 1 - toggle;
-
-		td_init(data->tds[td_current], data_dir, buffer,
-		    transfer_size, toggle);
-		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
-		usb_log_debug("Created CONTROL DATA TD: %x:%x:%x:%x.\n",
-		    data->tds[td_current]->status, data->tds[td_current]->cbp,
-		    data->tds[td_current]->next, data->tds[td_current]->be);
-
-		buffer += transfer_size;
-		remain_size -= transfer_size;
-		assert(td_current < data->td_count - 1);
-		++td_current;
-	}
-
-	/* status stage */
-	assert(td_current == data->td_count - 1);
-	td_init(data->tds[td_current], status_dir, NULL, 0, 1);
-	td_set_next(data->tds[td_current], data->tds[td_current + 1]);
-	usb_log_debug("Created CONTROL STATUS TD: %x:%x:%x:%x.\n",
-	    data->tds[td_current]->status, data->tds[td_current]->cbp,
-	    data->tds[td_current]->next, data->tds[td_current]->be);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare generic data transfer
- *
- * @param[in] instance Batch structure to use.
- *
- * Direction is supplied by the associated ep and toggle is maintained by the
- * OHCI hw in ED.
- */
-void batch_data(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	ohci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
-	    data->ed->status, data->ed->td_tail, data->ed->td_head,
-	    data->ed->next);
-
-	size_t td_current = 0;
-	size_t remain_size = instance->buffer_size;
-	char *buffer = instance->data_buffer;
-	while (remain_size > 0) {
-		const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
-		    ? OHCI_TD_MAX_TRANSFER : remain_size;
-
-		td_init(data->tds[td_current], instance->ep->direction,
-		    buffer, transfer_size, -1);
-		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
-		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
-		    data->tds[td_current]->status, data->tds[td_current]->cbp,
-		    data->tds[td_current]->next, data->tds[td_current]->be);
-
-		buffer += transfer_size;
-		remain_size -= transfer_size;
-		assert(td_current < data->td_count);
-		++td_current;
-	}
-}
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ohci/batch.h
===================================================================
--- uspace/drv/bus/usb/ohci/batch.h	(revision f9745198a340eebcba63d52957d602d9fbb50a9d)
+++ 	(revision )
@@ -1,49 +1,0 @@
-/*
- * 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 USB transaction structure
- */
-#ifndef DRV_OHCI_BATCH_H
-#define DRV_OHCI_BATCH_H
-
-#include <usbhc_iface.h>
-#include <usb/usb.h>
-#include <usb/host/device_keeper.h>
-#include <usb/host/endpoint.h>
-#include <usb/host/batch.h>
-
-int batch_init_ohci(usb_transfer_batch_t *batch);
-bool batch_is_complete(usb_transfer_batch_t *batch);
-void batch_commit(usb_transfer_batch_t *batch);
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision f9745198a340eebcba63d52957d602d9fbb50a9d)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
@@ -45,5 +45,5 @@
 #include <usb/host/hcd.h>
 
-#include "batch.h"
+#include "ohci_batch.h"
 #include "ohci_regs.h"
 #include "root_hub.h"
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision f9745198a340eebcba63d52957d602d9fbb50a9d)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
@@ -91,5 +91,5 @@
 	    &dev_to_ohci(fun->dev)->hc.generic.dev_manager;
 
-	usb_address_t addr = usb_device_keeper_find(manager, handle);
+	const usb_address_t addr = usb_device_keeper_find(manager, handle);
 	if (addr < 0) {
 		return addr;
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
@@ -0,0 +1,437 @@
+/*
+ * 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 USB transaction structure
+ */
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+
+#include "ohci_batch.h"
+#include "ohci_endpoint.h"
+#include "utils/malloc32.h"
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+static void batch_control_write(usb_transfer_batch_t *instance);
+static void batch_control_read(usb_transfer_batch_t *instance);
+
+static void batch_interrupt_in(usb_transfer_batch_t *instance);
+static void batch_interrupt_out(usb_transfer_batch_t *instance);
+
+static void batch_bulk_in(usb_transfer_batch_t *instance);
+static void batch_bulk_out(usb_transfer_batch_t *instance);
+
+static void batch_setup_control(usb_transfer_batch_t *batch)
+{
+        // TODO Find a better way to do this
+        if (batch->setup_buffer[0] & (1 << 7))
+                batch_control_read(batch);
+        else
+                batch_control_write(batch);
+}
+/*----------------------------------------------------------------------------*/
+void (*batch_setup[4][3])(usb_transfer_batch_t*) =
+{
+        { NULL, NULL, batch_setup_control },
+        { NULL, NULL, NULL },
+        { batch_bulk_in, batch_bulk_out, NULL },
+        { batch_interrupt_in, batch_interrupt_out, NULL },
+};
+
+
+/** OHCI specific data required for USB transfer */
+typedef struct ohci_transfer_batch {
+	/** Endpoint descriptor of the target endpoint. */
+	ed_t *ed;
+	/** List of TDs needed for the transfer */
+	td_t **tds;
+	/** Number of TDs used by the transfer */
+	size_t td_count;
+	/** Dummy TD to be left at the ED and used by the next transfer */
+	size_t leave_td;
+	/** Data buffer, must be accessible byb the OHCI hw. */
+	void *device_buffer;
+} ohci_transfer_batch_t;
+/*----------------------------------------------------------------------------*/
+static void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir);
+static void batch_data(usb_transfer_batch_t *instance);
+/*----------------------------------------------------------------------------*/
+/** Safely destructs ohci_transfer_batch_t structure
+ *
+ * @param[in] ohci_batch Instance to destroy.
+ */
+static void ohci_batch_dispose(void *ohci_batch)
+{
+	ohci_transfer_batch_t *instance = ohci_batch;
+	if (!instance)
+		return;
+	unsigned i = 0;
+	if (instance->tds) {
+		for (; i< instance->td_count; ++i) {
+			if (i != instance->leave_td)
+				free32(instance->tds[i]);
+		}
+		free(instance->tds);
+	}
+	free32(instance->device_buffer);
+	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+int batch_init_ohci(usb_transfer_batch_t *batch)
+{
+	assert(batch);
+#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
+        if (ptr == NULL) { \
+                usb_log_error(message); \
+		if (data) { \
+			ohci_batch_dispose(data); \
+		} \
+                return ENOMEM; \
+        } else (void)0
+
+	ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1);
+	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
+
+	data->td_count = ((batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
+	    / OHCI_TD_MAX_TRANSFER);
+	/* Control transfer need Setup and Status stage */
+	if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
+		data->td_count += 2;
+	}
+
+	/* We need an extra place for TD that was left at ED */
+	data->tds = calloc(sizeof(td_t*), data->td_count + 1);
+	CHECK_NULL_DISPOSE_RETURN(data->tds,
+	    "Failed to allocate transfer descriptors.\n");
+
+	/* Add TD left over by the previous transfer */
+	data->ed = ohci_endpoint_get(batch->ep)->ed;
+	data->tds[0] = ohci_endpoint_get(batch->ep)->td;
+	data->leave_td = 0;
+	unsigned i = 1;
+	for (; i <= data->td_count; ++i) {
+		data->tds[i] = malloc32(sizeof(td_t));
+		CHECK_NULL_DISPOSE_RETURN(data->tds[i],
+		    "Failed to allocate TD %d.\n", i );
+	}
+
+
+	/* NOTE: OHCI is capable of handling buffer that crosses page boundaries
+	 * it is, however, not capable of handling buffer that occupies more
+	 * than two pages (the first page is computed using start pointer, the
+	 * other using the end pointer) */
+        if (batch->setup_size + batch->buffer_size > 0) {
+		data->device_buffer =
+		    malloc32(batch->setup_size + batch->buffer_size);
+                CHECK_NULL_DISPOSE_RETURN(data->device_buffer,
+                    "Failed to allocate device accessible buffer.\n");
+		/* Copy setup data */
+                memcpy(data->device_buffer, batch->setup_buffer,
+		    batch->setup_size);
+		batch->data_buffer = data->device_buffer + batch->setup_size;
+        }
+
+	batch->private_data = data;
+	batch->private_data_dtor = ohci_batch_dispose;
+
+        assert(batch_setup[batch->ep->transfer_type][batch->ep->direction]);
+        batch_setup[batch->ep->transfer_type][batch->ep->direction](batch);
+
+	return EOK;
+#undef CHECK_NULL_DISPOSE_RETURN
+}
+/*----------------------------------------------------------------------------*/
+/** Check batch TDs' status.
+ *
+ * @param[in] instance Batch structure to use.
+ * @return False, if there is an active TD, true otherwise.
+ *
+ * Walk all TDs (usually there is just one). Stop with false if there is an
+ * active TD. Stop with true if an error is found. Return true if the walk
+ * completes with the last TD.
+ */
+bool batch_is_complete(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Batch(%p) checking %zu td(s) for completion.\n",
+	    instance, data->td_count);
+	usb_log_debug("ED: %x:%x:%x:%x.\n",
+	    data->ed->status, data->ed->td_head, data->ed->td_tail,
+	    data->ed->next);
+	size_t i = 0;
+	instance->transfered_size = instance->buffer_size;
+	for (; i < data->td_count; ++i) {
+		assert(data->tds[i] != NULL);
+		usb_log_debug("TD %zu: %x:%x:%x:%x.\n", i,
+		    data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next,
+		    data->tds[i]->be);
+		if (!td_is_finished(data->tds[i])) {
+			return false;
+		}
+		instance->error = td_error(data->tds[i]);
+		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%zu):%x.\n",
+			    instance, i, data->tds[i]->status);
+			/* Make sure TD queue is empty (one TD),
+			 * ED should be marked as halted */
+			data->ed->td_tail =
+			    (data->ed->td_head & ED_TDTAIL_PTR_MASK);
+			++i;
+			break;
+		}
+	}
+	data->leave_td = i;
+	assert(data->leave_td <= data->td_count);
+
+	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(instance->ep);
+	assert(ohci_ep);
+	ohci_ep->td = data->tds[data->leave_td];
+	assert(i > 0);
+	for (--i;i < data->td_count; ++i)
+		instance->transfered_size -= td_remain_size(data->tds[i]);
+
+	/* Clear possible ED HALT */
+	data->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
+	const uint32_t pa = addr_to_phys(ohci_ep->td);
+	assert(pa == (data->ed->td_head & ED_TDHEAD_PTR_MASK));
+	assert(pa == (data->ed->td_tail & ED_TDTAIL_PTR_MASK));
+
+	return true;
+}
+/*----------------------------------------------------------------------------*/
+/** Starts execution of the TD list
+ *
+ * @param[in] instance Batch structure to use
+ */
+void batch_commit(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	ed_set_end_td(data->ed, data->tds[data->td_count]);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control write transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control transfer using direction OUT(data stage) and
+ * IN(status stage).
+ */
+void batch_control_write(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
+	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control read transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control transfer using direction IN(data stage) and
+ * OUT(status stage).
+ */
+void batch_control_read(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
+	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_interrupt_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_interrupt_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_bulk_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_bulk_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic control transfer
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data_dir Direction to use for data stage.
+ * @param[in] status_dir Direction to use for status stage.
+ *
+ * Setup stage with toggle 0 and direction BOTH(SETUP_PID)
+ * Data stage with alternating toggle and direction supplied by parameter.
+ * Status stage with toggle 1 and direction supplied by parameter.
+ */
+void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+	int toggle = 0;
+	/* setup stage */
+	td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,
+		instance->setup_size, toggle);
+	td_set_next(data->tds[0], data->tds[1]);
+	usb_log_debug("Created CONTROL SETUP TD: %x:%x:%x:%x.\n",
+	    data->tds[0]->status, data->tds[0]->cbp, data->tds[0]->next,
+	    data->tds[0]->be);
+
+	/* data stage */
+	size_t td_current = 1;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
+		    OHCI_TD_MAX_TRANSFER : remain_size;
+		toggle = 1 - toggle;
+
+		td_init(data->tds[td_current], data_dir, buffer,
+		    transfer_size, toggle);
+		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+		usb_log_debug("Created CONTROL DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current]->status, data->tds[td_current]->cbp,
+		    data->tds[td_current]->next, data->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count - 1);
+		++td_current;
+	}
+
+	/* status stage */
+	assert(td_current == data->td_count - 1);
+	td_init(data->tds[td_current], status_dir, NULL, 0, 1);
+	td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+	usb_log_debug("Created CONTROL STATUS TD: %x:%x:%x:%x.\n",
+	    data->tds[td_current]->status, data->tds[td_current]->cbp,
+	    data->tds[td_current]->next, data->tds[td_current]->be);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic data transfer
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Direction is supplied by the associated ep and toggle is maintained by the
+ * OHCI hw in ED.
+ */
+void batch_data(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+
+	size_t td_current = 0;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
+		    ? OHCI_TD_MAX_TRANSFER : remain_size;
+
+		td_init(data->tds[td_current], instance->ep->direction,
+		    buffer, transfer_size, -1);
+		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current]->status, data->tds[td_current]->cbp,
+		    data->tds[td_current]->next, data->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count);
+		++td_current;
+	}
+}
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/ohci_batch.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.h	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
+++ uspace/drv/bus/usb/ohci/ohci_batch.h	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
@@ -0,0 +1,49 @@
+/*
+ * 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 USB transaction structure
+ */
+#ifndef DRV_OHCI_BATCH_H
+#define DRV_OHCI_BATCH_H
+
+#include <usbhc_iface.h>
+#include <usb/usb.h>
+#include <usb/host/device_keeper.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/batch.h>
+
+int batch_init_ohci(usb_transfer_batch_t *batch);
+bool batch_is_complete(usb_transfer_batch_t *batch);
+void batch_commit(usb_transfer_batch_t *batch);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/root_hub.h
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.h	(revision f9745198a340eebcba63d52957d602d9fbb50a9d)
+++ uspace/drv/bus/usb/ohci/root_hub.h	(revision ff6dd7317e8503b9c4de186441ff56be21415bca)
@@ -37,7 +37,7 @@
 #include <usb/usb.h>
 #include <usb/dev/driver.h>
+#include <usb/host/batch.h>
 
 #include "ohci_regs.h"
-#include "batch.h"
 
 #define HUB_DESCRIPTOR_MAX_SIZE (7 + 2 + 2)
