Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ boot/Makefile.common	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -166,4 +166,5 @@
 	$(USPACE_PATH)/app/lsusb/lsusb \
 	$(USPACE_PATH)/app/sbi/sbi \
+	$(USPACE_PATH)/app/sportdmp/sportdmp \
 	$(USPACE_PATH)/app/redir/redir \
 	$(USPACE_PATH)/app/taskdump/taskdump \
Index: rnel/arch/arm32/include/mainpage.h
===================================================================
--- kernel/arch/arm32/include/mainpage.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,49 +1,0 @@
-/*
- * Copyright (c) 2005 Michal Kebrt
- * 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.
- */
-
-/** @mainpage HelenOS ARM 32-bit port
- *
- *
- * @section sec_arm32 ARM 32-bit port
- *     arm32 port is the ninth port of SPARTAN, originally written by Michal Kebrt,
- *     Petr Stepan, Pavel Jancik. The goal is to support 32-bit ARM architecture.
- *     So far, it runs only in emulator.
- *
- * @subsection sec_arm32_doc Documentation
- * <ul>
- *	<li>See 'kernel/doc/arm32_HOWTO' for information about getting an emulator, 
- *	    building sources and running HelenOS.
- *	</li>
- *	<li>See <a href="http://www.helenos.eu/doc/slides/2007-05-21-Stepan-ARM.pdf">slides</a>
- *	    for some information about ARM architecture and porting HelenOS to ARM
- *	    (only in Czech).
- *	</li>
- * </ul>
- *
- *     
- */
Index: kernel/arch/arm32/src/ras.c
===================================================================
--- kernel/arch/arm32/src/ras.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ kernel/arch/arm32/src/ras.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -86,2 +86,4 @@
 }
 
+/** @}
+ */
Index: kernel/generic/include/adt/list.h
===================================================================
--- kernel/generic/include/adt/list.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ kernel/generic/include/adt/list.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -173,5 +173,5 @@
  *
  */
-NO_TRACE static inline int list_empty(list_t *list)
+NO_TRACE static inline int list_empty(const list_t *list)
 {
 	return (list->head.next == &list->head);
@@ -186,5 +186,5 @@
  *
  */
-static inline link_t *list_first(list_t *list)
+static inline link_t *list_first(const list_t *list)
 {
 	return ((list->head.next == &list->head) ? NULL : list->head.next);
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ kernel/generic/src/mm/frame.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -1142,5 +1142,4 @@
 	size_t znum = find_zone(pfn, 1, 0);
 
-	
 	ASSERT(znum != (size_t) -1);
 	
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -51,4 +51,5 @@
 	app/redir \
 	app/sbi \
+	app/sportdmp \
 	app/stats \
 	app/taskdump \
Index: uspace/app/sportdmp/Makefile
===================================================================
--- uspace/app/sportdmp/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/app/sportdmp/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 Martin Sucha
+# 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.
+#
+
+USPACE_PREFIX = ../..
+#LIBS = 
+#EXTRA_CFLAGS = 
+BINARY = sportdmp
+
+SOURCES = \
+	sportdmp.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/sportdmp/sportdmp.c
===================================================================
--- uspace/app/sportdmp/sportdmp.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/app/sportdmp/sportdmp.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <devman.h>
+#include <ipc/devman.h>
+#include <device/char_dev.h>
+#include <ipc/serial_ctl.h>
+
+#define BUF_SIZE 1
+
+static void syntax_print() {
+	fprintf(stderr, "Usage: sportdmp <baud> <device_path>\n");
+}
+
+int main(int argc, char **argv)
+{
+	const char* devpath = "/hw/pci0/00:01.0/com1/a";
+	sysarg_t baud = 9600;
+	
+	if (argc > 1) {
+		char *endptr;
+		baud = strtol(argv[1], &endptr, 10);
+		if (*endptr != '\0') {
+			fprintf(stderr, "Invalid value for baud\n");
+			syntax_print();
+			return 1;
+		}
+	}
+	
+	if (argc > 2) {
+		devpath = argv[2];
+	}
+	
+	if (argc > 3) {
+		syntax_print();
+		return 1;
+	}
+	
+	devman_handle_t device;
+	int rc = devman_fun_get_handle(devpath, &device, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		fprintf(stderr, "Cannot open device %s\n", devpath);
+		return 1;
+	}
+	
+	async_sess_t *sess = devman_device_connect(EXCHANGE_SERIALIZE, device,
+	    IPC_FLAG_BLOCKING);
+	if (!sess) {
+		fprintf(stderr, "Cannot connect device\n");
+	}
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	rc = async_req_4_0(exch, SERIAL_SET_COM_PROPS, baud,
+	    SERIAL_NO_PARITY, 8, 1);
+	async_exchange_end(exch);
+	
+	if (rc != EOK) {
+		fprintf(stderr, "Cannot set serial properties\n");
+		return 2;
+	}
+	
+	uint8_t *buf = (uint8_t *) malloc(BUF_SIZE);
+	if (buf == NULL) {
+		fprintf(stderr, "Cannot allocate buffer\n");
+		return 3;
+	}
+	
+	while (true) {
+		ssize_t read = char_dev_read(sess, buf, BUF_SIZE);
+		if (read < 0) {
+			fprintf(stderr, "Failed reading from serial device\n");
+			break;
+		}
+		ssize_t i;
+		for (i = 0; i < read; i++) {
+			if ((buf[i] >= 32) && (buf[i] < 128))
+				putchar((wchar_t) buf[i]);
+			else
+				putchar('.');
+			fflush(stdout);
+		}
+	}
+	
+	free(buf);
+	return 0;
+}
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/isa/isa.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -405,5 +405,5 @@
 static void fun_hw_res_alloc(isa_fun_t *fun)
 {
-	fun->hw_resources.resources = 
+	fun->hw_resources.resources =
 	    (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
 }
Index: uspace/drv/bus/usb/ehci/hc_iface.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc_iface.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ehci/hc_iface.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -145,162 +145,4 @@
 }
 
-/** Schedule interrupt out transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
- *	by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
-    void *data, size_t size,
-    usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	UNSUPPORTED("interrupt_out");
-
-	return ENOTSUP;
-}
-
-/** Schedule interrupt in transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
-    void *data, size_t size,
-    usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	UNSUPPORTED("interrupt_in");
-
-	return ENOTSUP;
-}
-
-/** Schedule bulk out transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
- *	by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int bulk_out(ddf_fun_t *fun, usb_target_t target,
-    void *data, size_t size,
-    usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	UNSUPPORTED("bulk_out");
-
-	return ENOTSUP;
-}
-
-/** Schedule bulk in transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int bulk_in(ddf_fun_t *fun, usb_target_t target,
-    void *data, size_t size,
-    usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	UNSUPPORTED("bulk_in");
-
-	return ENOTSUP;
-}
-
-/** Schedule control write transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
- *	and deallocated by the caller).
- * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
- * @param[in] data_buffer Data buffer (in USB endianess, allocated and
- *	deallocated by the caller).
- * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int control_write(ddf_fun_t *fun, usb_target_t target,
-    void *setup_packet, size_t setup_packet_size,
-    void *data_buffer, size_t data_buffer_size,
-    usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	UNSUPPORTED("control_write");
-
-	return ENOTSUP;
-}
-
-/** Schedule control read transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
- *	and deallocated by the caller).
- * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
- * @param[in] data_buffer Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int control_read(ddf_fun_t *fun, usb_target_t target,
-    void *setup_packet, size_t setup_packet_size,
-    void *data_buffer, size_t data_buffer_size,
-    usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	UNSUPPORTED("control_read");
-
-	return ENOTSUP;
-}
-
 /** Host controller interface implementation for EHCI. */
 usbhc_iface_t ehci_hc_iface = {
@@ -312,13 +154,4 @@
 	.register_endpoint = register_endpoint,
 	.unregister_endpoint = unregister_endpoint,
-
-	.interrupt_out = interrupt_out,
-	.interrupt_in = interrupt_in,
-
-	.bulk_out = bulk_out,
-	.bulk_in = bulk_in,
-
-	.control_write = control_write,
-	.control_read = control_read
 };
 
Index: uspace/drv/bus/usb/ohci/Makefile
===================================================================
--- uspace/drv/bus/usb/ohci/Makefile	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -44,11 +44,10 @@
 
 SOURCES = \
-	batch.c \
 	endpoint_list.c \
 	hc.c \
-	hcd_endpoint.c \
-	iface.c \
 	main.c \
 	ohci.c \
+	ohci_batch.c \
+	ohci_endpoint.c \
 	pci.c \
 	root_hub.c \
Index: pace/drv/bus/usb/ohci/batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/batch.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,429 +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 "hcd_endpoint.h"
-#include "utils/malloc32.h"
-#include "hw_struct/endpoint_descriptor.h"
-#include "hw_struct/transfer_descriptor.h"
-
-/** 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_transfer_batch_dispose(void *ohci_batch)
-{
-	ohci_transfer_batch_t *instance = ohci_batch;
-	if (!instance)
-		return;
-	free32(instance->device_buffer);
-	unsigned i = 0;
-	if (instance->tds) {
-		for (; i< instance->td_count; ++i) {
-			if (i != instance->leave_td)
-				free32(instance->tds[i]);
-		}
-		free(instance->tds);
-	}
-	free(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Allocate memory initialize internal structures
- *
- * @param[in] fun DDF function to pass to callback.
- * @param[in] ep Communication target
- * @param[in] buffer Data source/destination.
- * @param[in] buffer_size Size of the buffer.
- * @param[in] setup_buffer Setup data source (if not NULL)
- * @param[in] setup_size Size of setup_buffer (should be always 8)
- * @param[in] func_in function to call on inbound transfer completion
- * @param[in] func_out function to call on outbound transfer completion
- * @param[in] arg additional parameter to func_in or func_out
- * @return Valid pointer if all structures were successfully created,
- * NULL otherwise.
- *
- * Allocates and initializes structures needed by the OHCI hw for the transfer.
- */
-usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
-    char *buffer, size_t buffer_size,
-    const char *setup_buffer, size_t setup_size,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out, void *arg)
-{
-#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
-        if (ptr == NULL) { \
-                usb_log_error(message); \
-                if (instance) { \
-                        usb_transfer_batch_dispose(instance); \
-                } \
-                return NULL; \
-        } else (void)0
-
-	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
-	CHECK_NULL_DISPOSE_RETURN(instance,
-	    "Failed to allocate batch instance.\n");
-	usb_transfer_batch_init(instance, ep, buffer, NULL, buffer_size,
-	    NULL, setup_size, func_in, func_out, arg, fun, NULL,
-	    ohci_transfer_batch_dispose);
-
-	const hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
-	assert(hcd_ep);
-
-	ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1);
-	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
-	instance->private_data = data;
-
-	data->td_count =
-	    ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER);
-	/* Control transfer need Setup and Status stage */
-	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
-		data->td_count += 2;
-	}
-
-	/* We need an extra place for TD that is currently assigned to hcd_ep*/
-	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->tds[0] = hcd_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 );
-	}
-
-	data->ed = hcd_ep->ed;
-
-	/* 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 (setup_size + buffer_size > 0) {
-		data->device_buffer = malloc32(setup_size + buffer_size);
-                CHECK_NULL_DISPOSE_RETURN(data->device_buffer,
-                    "Failed to allocate device accessible buffer.\n");
-		instance->setup_buffer = data->device_buffer;
-		instance->data_buffer = data->device_buffer + setup_size;
-                memcpy(instance->setup_buffer, setup_buffer, setup_size);
-        }
-
-	return instance;
-}
-/*----------------------------------------------------------------------------*/
-/** 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);
-	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(instance->ep);
-	assert(hcd_ep);
-	hcd_ep->td = data->tds[i];
-	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(hcd_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 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 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 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: pace/drv/bus/usb/ohci/batch.h
===================================================================
--- uspace/drv/bus/usb/ohci/batch.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,68 +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>
-
-usb_transfer_batch_t * batch_get(
-    ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size,
-    const char *setup_buffer, size_t setup_size,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out,
-    void *arg);
-
-bool batch_is_complete(usb_transfer_batch_t *instance);
-
-void batch_commit(usb_transfer_batch_t *instance);
-
-void batch_control_write(usb_transfer_batch_t *instance);
-
-void batch_control_read(usb_transfer_batch_t *instance);
-
-void batch_interrupt_in(usb_transfer_batch_t *instance);
-
-void batch_interrupt_out(usb_transfer_batch_t *instance);
-
-void batch_bulk_in(usb_transfer_batch_t *instance);
-
-void batch_bulk_out(usb_transfer_batch_t *instance);
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ohci/endpoint_list.c
===================================================================
--- uspace/drv/bus/usb/ohci/endpoint_list.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/endpoint_list.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -87,10 +87,9 @@
  * The endpoint is added to the end of the list and queue.
  */
-void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep)
+void endpoint_list_add_ep(endpoint_list_t *instance, ohci_endpoint_t *ep)
 {
 	assert(instance);
-	assert(hcd_ep);
-	usb_log_debug2("Queue %s: Adding endpoint(%p).\n",
-	    instance->name, hcd_ep);
+	assert(ep);
+	usb_log_debug2("Queue %s: Adding endpoint(%p).\n", instance->name, ep);
 
 	fibril_mutex_lock(&instance->guard);
@@ -103,25 +102,25 @@
 	} else {
 		/* There are active EDs, get the last one */
-		hcd_endpoint_t *last = list_get_instance(
-		    list_last(&instance->endpoint_list), hcd_endpoint_t, link);
+		ohci_endpoint_t *last = list_get_instance(
+		    list_last(&instance->endpoint_list), ohci_endpoint_t, link);
 		last_ed = last->ed;
 	}
 	/* Keep link */
-	hcd_ep->ed->next = last_ed->next;
+	ep->ed->next = last_ed->next;
 	/* Make sure ED is written to the memory */
 	write_barrier();
 
 	/* Add ed to the hw queue */
-	ed_append_ed(last_ed, hcd_ep->ed);
+	ed_append_ed(last_ed, ep->ed);
 	/* Make sure ED is updated */
 	write_barrier();
 
 	/* Add to the sw list */
-	list_append(&hcd_ep->link, &instance->endpoint_list);
+	list_append(&ep->link, &instance->endpoint_list);
 
-	hcd_endpoint_t *first = list_get_instance(
-	    list_first(&instance->endpoint_list), hcd_endpoint_t, link);
+	ohci_endpoint_t *first = list_get_instance(
+	    list_first(&instance->endpoint_list), ohci_endpoint_t, link);
 	usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).\n",
-		hcd_ep, instance->name, first, first->ed);
+		ep, instance->name, first, first->ed);
 	if (last_ed == instance->list_head) {
 		usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x.\n",
@@ -138,39 +137,38 @@
  * @param[in] endpoint Endpoint to remove.
  */
-void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep)
+void endpoint_list_remove_ep(endpoint_list_t *instance, ohci_endpoint_t *ep)
 {
 	assert(instance);
 	assert(instance->list_head);
-	assert(hcd_ep);
-	assert(hcd_ep->ed);
+	assert(ep);
+	assert(ep->ed);
 
 	fibril_mutex_lock(&instance->guard);
 
-	usb_log_debug2(
-	    "Queue %s: removing endpoint(%p).\n", instance->name, hcd_ep);
+	usb_log_debug2("Queue %s: removing endpoint(%p).\n", instance->name, ep);
 
 	const char *qpos = NULL;
 	ed_t *prev_ed;
 	/* Remove from the hardware queue */
-	if (list_first(&instance->endpoint_list) == &hcd_ep->link) {
+	if (list_first(&instance->endpoint_list) == &ep->link) {
 		/* I'm the first one here */
 		prev_ed = instance->list_head;
 		qpos = "FIRST";
 	} else {
-		hcd_endpoint_t *prev =
-		    list_get_instance(hcd_ep->link.prev, hcd_endpoint_t, link);
+		ohci_endpoint_t *prev =
+		    list_get_instance(ep->link.prev, ohci_endpoint_t, link);
 		prev_ed = prev->ed;
 		qpos = "NOT FIRST";
 	}
-	assert((prev_ed->next & ED_NEXT_PTR_MASK) == addr_to_phys(hcd_ep->ed));
-	prev_ed->next = hcd_ep->ed->next;
+	assert((prev_ed->next & ED_NEXT_PTR_MASK) == addr_to_phys(ep->ed));
+	prev_ed->next = ep->ed->next;
 	/* Make sure ED is updated */
 	write_barrier();
 
 	usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.\n",
-	    hcd_ep, qpos, instance->name, hcd_ep->ed->next);
+	    ep, qpos, instance->name, ep->ed->next);
 
 	/* Remove from the endpoint list */
-	list_remove(&hcd_ep->link);
+	list_remove(&ep->link);
 	fibril_mutex_unlock(&instance->guard);
 }
Index: uspace/drv/bus/usb/ohci/endpoint_list.h
===================================================================
--- uspace/drv/bus/usb/ohci/endpoint_list.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/endpoint_list.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -37,5 +37,5 @@
 #include <fibril_synch.h>
 
-#include "hcd_endpoint.h"
+#include "ohci_endpoint.h"
 #include "hw_struct/endpoint_descriptor.h"
 #include "utils/malloc32.h"
@@ -69,6 +69,6 @@
 int endpoint_list_init(endpoint_list_t *instance, const char *name);
 void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next);
-void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep);
-void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep);
+void endpoint_list_add_ep(endpoint_list_t *instance, ohci_endpoint_t *ep);
+void endpoint_list_remove_ep(endpoint_list_t *instance, ohci_endpoint_t *ep);
 #endif
 /**
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -42,5 +42,5 @@
 
 #include "hc.h"
-#include "hcd_endpoint.h"
+#include "ohci_endpoint.h"
 
 #define OHCI_USED_INTERRUPTS \
@@ -61,5 +61,5 @@
 static int hc_init_memory(hc_t *instance);
 static int interrupt_emulator(hc_t *instance);
-
+static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
 /*----------------------------------------------------------------------------*/
 /** Get number of commands used in IRQ code.
@@ -128,5 +128,6 @@
 
 	const usb_address_t hub_address =
-	    device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
+	    usb_device_manager_get_free_address(
+	        &instance->generic.dev_manager, USB_SPEED_FULL);
 	if (hub_address <= 0) {
 		usb_log_error("Failed to get OHCI root hub address: %s\n",
@@ -135,26 +136,29 @@
 	}
 	instance->rh.address = hub_address;
-	usb_device_keeper_bind(
-	    &instance->manager, hub_address, hub_fun->handle);
-
-#define CHECK_RET_RELEASE(ret, message...) \
+	usb_device_manager_bind(
+	    &instance->generic.dev_manager, hub_address, hub_fun->handle);
+
+#define CHECK_RET_UNREG_RETURN(ret, message...) \
 if (ret != EOK) { \
 	usb_log_error(message); \
-	hc_remove_endpoint(instance, hub_address, 0, USB_DIRECTION_BOTH); \
-	usb_device_keeper_release(&instance->manager, hub_address); \
+	usb_endpoint_manager_unregister_ep( \
+	    &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH);\
+	usb_device_manager_release( \
+	    &instance->generic.dev_manager, hub_address); \
 	return ret; \
 } else (void)0
-
-	int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
-	    USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
-	CHECK_RET_RELEASE(ret,
-	    "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
+	int ret = usb_endpoint_manager_add_ep(
+	    &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH,
+	    USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 0);
+	CHECK_RET_UNREG_RETURN(ret,
+	    "Failed to register root hub control endpoint: %s.\n",
+	    str_error(ret));
 
 	ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
-	CHECK_RET_RELEASE(ret,
+	CHECK_RET_UNREG_RETURN(ret,
 	    "Failed to add root hub match-id: %s.\n", str_error(ret));
 
 	ret = ddf_fun_bind(hub_fun);
-	CHECK_RET_RELEASE(ret,
+	CHECK_RET_UNREG_RETURN(ret,
 	    "Failed to bind root hub function: %s.\n", str_error(ret));
 
@@ -187,10 +191,12 @@
 
 	list_initialize(&instance->pending_batches);
-	usb_device_keeper_init(&instance->manager);
-
-	ret = usb_endpoint_manager_init(&instance->ep_manager,
-	    BANDWIDTH_AVAILABLE_USB11);
-	CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
+
+	ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
+	    bandwidth_count_usb11);
+	CHECK_RET_RETURN(ret, "Failed to initialize generic driver: %s.\n",
 	    str_error(ret));
+	instance->generic.private_data = instance;
+	instance->generic.schedule = hc_schedule;
+	instance->generic.ep_add_hook = ohci_endpoint_init;
 
 	ret = hc_init_memory(instance);
@@ -215,47 +221,13 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Create and register endpoint structures.
- *
- * @param[in] instance OHCI driver structure.
- * @param[in] address USB address of the device.
- * @param[in] endpoint USB endpoint number.
- * @param[in] speed Communication speeed of the device.
- * @param[in] type Endpoint's transfer type.
- * @param[in] direction Endpoint's direction.
- * @param[in] mps Maximum packet size the endpoint accepts.
- * @param[in] size Maximum allowed buffer size.
- * @param[in] interval Time between transfers(interrupt transfers only).
- * @return Error code
- */
-int hc_add_endpoint(
-    hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
-    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
-    size_t mps, size_t size, unsigned interval)
-{
-	endpoint_t *ep =
-	    endpoint_get(address, endpoint, direction, type, speed, mps);
-	if (ep == NULL)
-		return ENOMEM;
-
-	hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
-	if (hcd_ep == NULL) {
-		endpoint_destroy(ep);
-		return ENOMEM;
-	}
-
-	int ret =
-	    usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
-	if (ret != EOK) {
-		hcd_endpoint_clear(ep);
-		endpoint_destroy(ep);
-		return ret;
-	}
-
-	/* Enqueue hcd_ep */
+void hc_enqueue_endpoint(hc_t *instance, endpoint_t *ep)
+{
+	endpoint_list_t *list = &instance->lists[ep->transfer_type];
+	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
+	/* Enqueue ep */
 	switch (ep->transfer_type) {
 	case USB_TRANSFER_CONTROL:
 		instance->registers->control &= ~C_CLE;
-		endpoint_list_add_ep(
-		    &instance->lists[ep->transfer_type], hcd_ep);
+		endpoint_list_add_ep(list, ohci_ep);
 		instance->registers->control_current = 0;
 		instance->registers->control |= C_CLE;
@@ -263,6 +235,5 @@
 	case USB_TRANSFER_BULK:
 		instance->registers->control &= ~C_BLE;
-		endpoint_list_add_ep(
-		    &instance->lists[ep->transfer_type], hcd_ep);
+		endpoint_list_add_ep(list, ohci_ep);
 		instance->registers->control |= C_BLE;
 		break;
@@ -270,89 +241,36 @@
 	case USB_TRANSFER_INTERRUPT:
 		instance->registers->control &= (~C_PLE & ~C_IE);
-		endpoint_list_add_ep(
-		    &instance->lists[ep->transfer_type], hcd_ep);
+		endpoint_list_add_ep(list, ohci_ep);
 		instance->registers->control |= C_PLE | C_IE;
 		break;
 	}
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Dequeue and delete endpoint structures
- *
- * @param[in] instance OHCI hc driver structure.
- * @param[in] address USB address of the device.
- * @param[in] endpoint USB endpoint number.
- * @param[in] direction Direction of the endpoint.
- * @return Error code
- */
-int hc_remove_endpoint(hc_t *instance, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
-	    address, endpoint, direction, NULL);
-	if (ep == NULL) {
-		usb_log_error("Endpoint unregister failed: No such EP.\n");
-		fibril_mutex_unlock(&instance->guard);
-		return ENOENT;
-	}
-
-	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
-	if (hcd_ep) {
-		/* Dequeue hcd_ep */
-		switch (ep->transfer_type) {
-		case USB_TRANSFER_CONTROL:
-			instance->registers->control &= ~C_CLE;
-			endpoint_list_remove_ep(
-			    &instance->lists[ep->transfer_type], hcd_ep);
-			instance->registers->control_current = 0;
-			instance->registers->control |= C_CLE;
-			break;
-		case USB_TRANSFER_BULK:
-			instance->registers->control &= ~C_BLE;
-			endpoint_list_remove_ep(
-			    &instance->lists[ep->transfer_type], hcd_ep);
-			instance->registers->control |= C_BLE;
-			break;
-		case USB_TRANSFER_ISOCHRONOUS:
-		case USB_TRANSFER_INTERRUPT:
-			instance->registers->control &= (~C_PLE & ~C_IE);
-			endpoint_list_remove_ep(
-			    &instance->lists[ep->transfer_type], hcd_ep);
-			instance->registers->control |= C_PLE | C_IE;
-			break;
-		default:
-			break;
-		}
-		hcd_endpoint_clear(ep);
-	} else {
-		usb_log_warning("Endpoint without hcd equivalent structure.\n");
-	}
-	int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
-	    address, endpoint, direction);
-	fibril_mutex_unlock(&instance->guard);
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Get access to endpoint structures
- *
- * @param[in] instance OHCI hc driver structure.
- * @param[in] address USB address of the device.
- * @param[in] endpoint USB endpoint number.
- * @param[in] direction Direction of the endpoint.
- * @param[out] bw Reserved bandwidth.
- * @return Error code
- */
-endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
-	    address, endpoint, direction, bw);
-	fibril_mutex_unlock(&instance->guard);
-	return ep;
+}
+/*----------------------------------------------------------------------------*/
+void hc_dequeue_endpoint(hc_t *instance, endpoint_t *ep)
+{
+	/* Dequeue ep */
+	endpoint_list_t *list = &instance->lists[ep->transfer_type];
+	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
+	switch (ep->transfer_type) {
+	case USB_TRANSFER_CONTROL:
+		instance->registers->control &= ~C_CLE;
+		endpoint_list_remove_ep(list, ohci_ep);
+		instance->registers->control_current = 0;
+		instance->registers->control |= C_CLE;
+		break;
+	case USB_TRANSFER_BULK:
+		instance->registers->control &= ~C_BLE;
+		endpoint_list_remove_ep(list, ohci_ep);
+		instance->registers->control |= C_BLE;
+		break;
+	case USB_TRANSFER_ISOCHRONOUS:
+	case USB_TRANSFER_INTERRUPT:
+		instance->registers->control &= (~C_PLE & ~C_IE);
+		endpoint_list_remove_ep(list, ohci_ep);
+		instance->registers->control |= C_PLE | C_IE;
+		break;
+	default:
+		break;
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -363,9 +281,9 @@
  * @return Error code.
  */
-int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
-{
-	assert(instance);
-	assert(batch);
-	assert(batch->ep);
+int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
+{
+	assert(hcd);
+	hc_t *instance = hcd->private_data;
+	assert(instance);
 
 	/* Check for root hub communication */
@@ -374,8 +292,11 @@
 		return EOK;
 	}
+	ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
+	if (!ohci_batch)
+		return ENOMEM;
 
 	fibril_mutex_lock(&instance->guard);
-	list_append(&batch->link, &instance->pending_batches);
-	batch_commit(batch);
+	list_append(&ohci_batch->link, &instance->pending_batches);
+	ohci_transfer_batch_commit(ohci_batch);
 
 	/* Control and bulk schedules need a kick to start working */
@@ -417,13 +338,13 @@
 		    instance->registers->periodic_current);
 
-		link_t *current = instance->pending_batches.head.next;
-		while (current != &instance->pending_batches.head) {
+		link_t *current = list_first(&instance->pending_batches);
+		while (current && current != &instance->pending_batches.head) {
 			link_t *next = current->next;
-			usb_transfer_batch_t *batch =
-			    usb_transfer_batch_from_link(current);
-
-			if (batch_is_complete(batch)) {
+			ohci_transfer_batch_t *batch =
+			    ohci_transfer_batch_from_link(current);
+
+			if (ohci_transfer_batch_is_complete(batch)) {
 				list_remove(current);
-				usb_transfer_batch_finish(batch);
+				ohci_transfer_batch_finish_dispose(batch);
 			}
 
@@ -434,4 +355,5 @@
 
 	if (status & I_UE) {
+		usb_log_fatal("Error like no other!\n");
 		hc_start(instance);
 	}
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -41,9 +41,7 @@
 
 #include <usb/usb.h>
-#include <usb/host/device_keeper.h>
-#include <usb/host/usb_endpoint_manager.h>
-#include <usbhc_iface.h>
+#include <usb/host/hcd.h>
 
-#include "batch.h"
+#include "ohci_batch.h"
 #include "ohci_regs.h"
 #include "root_hub.h"
@@ -53,8 +51,6 @@
 /** Main OHCI driver structure */
 typedef struct hc {
-	/** USB bus driver, devices and addresses */
-	usb_device_keeper_t manager;
-	/** USB bus driver, endpoints */
-	usb_endpoint_manager_t ep_manager;
+	/** Generic USB hc driver */
+	hcd_t generic;
 
 	/** Memory mapped I/O registers area */
@@ -81,6 +77,6 @@
 int hc_get_irq_commands(
     irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size);
+int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun);
 int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts);
-int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun);
 
 /** Safely dispose host controller internal structures
@@ -88,25 +84,10 @@
  * @param[in] instance Host controller structure to use.
  */
-static inline void hc_fini(hc_t *instance)
-	{ /* TODO: implement*/ };
+static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ };
 
-int hc_add_endpoint(hc_t *instance, usb_address_t address, usb_endpoint_t ep,
-    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
-    size_t max_packet_size, size_t size, unsigned interval);
-int hc_remove_endpoint(hc_t *instance, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction);
-endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw);
+void hc_enqueue_endpoint(hc_t *instance, endpoint_t *ep);
+void hc_dequeue_endpoint(hc_t *instance, endpoint_t *ep);
 
-int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
 void hc_interrupt(hc_t *instance, uint32_t status);
-
-/** Get and cast pointer to the driver data
- *
- * @param[in] fun DDF function pointer
- * @return cast pointer to driver_data
- */
-static inline hc_t * fun_to_hc(ddf_fun_t *fun)
-	{ return fun->driver_data; }
 #endif
 /**
Index: pace/drv/bus/usb/ohci/hcd_endpoint.c
===================================================================
--- uspace/drv/bus/usb/ohci/hcd_endpoint.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,110 +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
- */
-#include "utils/malloc32.h"
-#include "hcd_endpoint.h"
-
-/** Callback to set toggle on ED.
- *
- * @param[in] hcd_ep hcd endpoint structure
- * @param[in] toggle new value of toggle bit
- */
-static void hcd_ep_toggle_set(void *hcd_ep, int toggle)
-{
-	hcd_endpoint_t *instance = hcd_ep;
-	assert(instance);
-	assert(instance->ed);
-	ed_toggle_set(instance->ed, toggle);
-}
-/*----------------------------------------------------------------------------*/
-/** Callback to get value of toggle bit.
- *
- * @param[in] hcd_ep hcd endpoint structure
- * @return Current value of toggle bit.
- */
-static int hcd_ep_toggle_get(void *hcd_ep)
-{
-	hcd_endpoint_t *instance = hcd_ep;
-	assert(instance);
-	assert(instance->ed);
-	return ed_toggle_get(instance->ed);
-}
-/*----------------------------------------------------------------------------*/
-/** Creates new hcd endpoint representation.
- *
- * @param[in] ep USBD endpoint structure
- * @return pointer to a new hcd endpoint structure, NULL on failure.
- */
-hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep)
-{
-	assert(ep);
-	hcd_endpoint_t *hcd_ep = malloc(sizeof(hcd_endpoint_t));
-	if (hcd_ep == NULL)
-		return NULL;
-
-	hcd_ep->ed = malloc32(sizeof(ed_t));
-	if (hcd_ep->ed == NULL) {
-		free(hcd_ep);
-		return NULL;
-	}
-
-	hcd_ep->td = malloc32(sizeof(td_t));
-	if (hcd_ep->td == NULL) {
-		free32(hcd_ep->ed);
-		free(hcd_ep);
-		return NULL;
-	}
-
-	ed_init(hcd_ep->ed, ep);
-	ed_set_td(hcd_ep->ed, hcd_ep->td);
-	endpoint_set_hc_data(ep, hcd_ep, hcd_ep_toggle_get, hcd_ep_toggle_set);
-
-	return hcd_ep;
-}
-/*----------------------------------------------------------------------------*/
-/** Disposes assigned hcd endpoint structure
- *
- * @param[in] ep USBD endpoint structure
- */
-void hcd_endpoint_clear(endpoint_t *ep)
-{
-	assert(ep);
-	hcd_endpoint_t *hcd_ep = ep->hc_data.data;
-	assert(hcd_ep);
-	free32(hcd_ep->ed);
-	free32(hcd_ep->td);
-	free(hcd_ep);
-}
-/**
- * @}
- */
Index: pace/drv/bus/usb/ohci/hcd_endpoint.h
===================================================================
--- uspace/drv/bus/usb/ohci/hcd_endpoint.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,70 +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
- */
-#ifndef DRV_OHCI_HCD_ENDPOINT_H
-#define DRV_OHCI_HCD_ENDPOINT_H
-
-#include <assert.h>
-#include <adt/list.h>
-#include <usb/host/endpoint.h>
-
-#include "hw_struct/endpoint_descriptor.h"
-#include "hw_struct/transfer_descriptor.h"
-
-/** Connector structure linking ED to to prepared TD. */
-typedef struct hcd_endpoint {
-	/** OHCI endpoint descriptor */
-	ed_t *ed;
-	/** Currently enqueued transfer descriptor */
-	td_t *td;
-	/** Linked list used by driver software */
-	link_t link;
-} hcd_endpoint_t;
-
-hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep);
-void hcd_endpoint_clear(endpoint_t *ep);
-
-/** Get and convert assigned hcd_endpoint_t structure
- * @param[in] ep USBD endpoint structure.
- * @return Pointer to assigned hcd endpoint structure
- */
-static inline hcd_endpoint_t * hcd_endpoint_get(endpoint_t *ep)
-{
-	assert(ep);
-	return ep->hc_data.data;
-}
-
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -39,6 +39,6 @@
 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)
+void td_init(td_t *instance,
+    usb_direction_t dir, const void *buffer, size_t size, int toggle)
 {
 	assert(instance);
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -75,6 +75,6 @@
 } __attribute__((packed)) td_t;
 
-void td_init(
-    td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle);
+void td_init(td_t *instance,
+    usb_direction_t dir, const void *buffer, size_t size, int toggle);
 
 inline static void td_set_next(td_t *instance, td_t *next)
Index: pace/drv/bus/usb/ohci/iface.c
===================================================================
--- uspace/drv/bus/usb/ohci/iface.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,441 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky, 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 hc interface implementation
- */
-#include <ddf/driver.h>
-#include <errno.h>
-
-#include <usb/debug.h>
-#include <usb/host/endpoint.h>
-
-#include "iface.h"
-#include "hc.h"
-
-static inline int setup_batch(
-    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
-    void *data, size_t size, void * setup_data, size_t setup_size,
-    usbhc_iface_transfer_in_callback_t in,
-    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
-    hc_t **hc, usb_transfer_batch_t **batch)
-{
-	assert(hc);
-	assert(batch);
-	assert(fun);
-	*hc = fun_to_hc(fun);
-	assert(*hc);
-
-	size_t res_bw;
-	endpoint_t *ep = hc_get_endpoint(*hc,
-	    target.address, target.endpoint, direction, &res_bw);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
-		    target.address, target.endpoint, name);
-		return ENOENT;
-	}
-
-	usb_log_debug("%s %d:%d %zu(%zu).\n",
-	    name, target.address, target.endpoint, size, ep->max_packet_size);
-
-	const size_t bw = bandwidth_count_usb11(
-	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
-	if (res_bw < bw) {
-		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
-		    "but only %zu is reserved.\n",
-		    target.address, target.endpoint, name, bw, res_bw);
-		return ENOSPC;
-	}
-
-	*batch = batch_get(
-	    fun, ep, data, size, setup_data, setup_size, in, out, arg);
-	if (!*batch)
-		return ENOMEM;
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Request address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] speed Speed to associate with the new default address.
- * @param[out] address Place to write a new address.
- * @return Error code.
- */
-static int request_address(
-    ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	assert(address);
-
-	usb_log_debug("Address request with speed %d.\n", speed);
-	*address = device_keeper_get_free_address(&hc->manager, speed);
-	usb_log_debug("Address request with result: %d.\n", *address);
-	if (*address <= 0)
-		return *address;
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Bind address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address of the device
- * @param[in] handle Devman handle of the device driver.
- * @return Error code.
- */
-static int bind_address(
-  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
-	usb_device_keeper_bind(&hc->manager, address, handle);
-	return EOK;
-}
-
-
-/** Find device handle by address interface function.
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address in question.
- * @param[out] handle Where to store device handle if found.
- * @return Error code.
- */
-static int find_by_address(ddf_fun_t *fun, usb_address_t address,
-    devman_handle_t *handle)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	bool found =
-	    usb_device_keeper_find_by_address(&hc->manager, address, handle);
-	return found ? EOK : ENOENT;
-}
-
-/*----------------------------------------------------------------------------*/
-/** Release address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address USB address to be released.
- * @return Error code.
- */
-static int release_address(ddf_fun_t *fun, usb_address_t address)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Address release %d.\n", address);
-	usb_device_keeper_release(&hc->manager, address);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Register endpoint for bandwidth reservation.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] ep_speed Endpoint speed (invalid means to use device one).
- * @param[in] endpoint Endpoint number.
- * @param[in] transfer_type USB transfer type.
- * @param[in] direction Endpoint data direction.
- * @param[in] max_packet_size Max packet size of the endpoint.
- * @param[in] interval Polling interval.
- * @return Error code.
- */
-static int register_endpoint(ddf_fun_t *fun,
-    usb_address_t address, usb_speed_t ep_speed, usb_endpoint_t endpoint,
-    usb_transfer_type_t transfer_type, usb_direction_t direction,
-    size_t max_packet_size, unsigned int interval)
-{
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-
-	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
-	if (speed >= USB_SPEED_MAX) {
-		speed = ep_speed;
-	}
-	const size_t size = max_packet_size;
-
-	usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
-	    address, endpoint, usb_str_transfer_type(transfer_type),
-	    usb_str_speed(speed), direction, size, max_packet_size, interval);
-
-	return hc_add_endpoint(hc, address, endpoint, speed, transfer_type,
-	    direction, max_packet_size, size, interval);
-}
-/*----------------------------------------------------------------------------*/
-static int unregister_endpoint(
-    ddf_fun_t *fun, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Unregister endpoint %d:%d %d.\n",
-	    address, endpoint, direction);
-	return hc_remove_endpoint(hc, address, endpoint, direction);
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule interrupt out transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
- *	by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int interrupt_out(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
-	    NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	batch_interrupt_out(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule interrupt in transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int interrupt_in(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
-	    NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	batch_interrupt_in(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule bulk out transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
- *	by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int bulk_out(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
-	    NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	batch_bulk_out(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule bulk in transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] data Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of the @p data buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int bulk_in(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
-	    NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	batch_bulk_in(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule control write transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
- *	and deallocated by the caller).
- * @param[in] setup_size Size of @p setup_packet buffer in bytes.
- * @param[in] data_buffer Data buffer (in USB endianess, allocated and
- *	deallocated by the caller).
- * @param[in] size Size of @p data_buffer buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int control_write(
-    ddf_fun_t *fun, usb_target_t target,
-    void *setup_data, size_t setup_size, void *data, size_t size,
-    usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
-	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
-	    &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
-	batch_control_write(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Schedule control read transfer.
- *
- * The callback is supposed to be called once the transfer (on the wire) is
- * complete regardless of the outcome.
- * However, the callback could be called only when this function returns
- * with success status (i.e. returns EOK).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
- *	and deallocated by the caller).
- * @param[in] setup_size Size of @p setup_packet buffer in bytes.
- * @param[in] data_buffer Buffer where to store the data (in USB endianess,
- *	allocated and deallocated by the caller).
- * @param[in] size Size of @p data_buffer buffer in bytes.
- * @param[in] callback Callback to be issued once the transfer is complete.
- * @param[in] arg Pass-through argument to the callback.
- * @return Error code.
- */
-static int control_read(
-    ddf_fun_t *fun, usb_target_t target,
-    void *setup_data, size_t setup_size, void *data, size_t size,
-    usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
-	    setup_data, setup_size, callback, NULL, arg, "Control READ",
-	    &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	batch_control_read(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-usbhc_iface_t hc_iface = {
-	.request_address = request_address,
-	.bind_address = bind_address,
-	.find_by_address = find_by_address,
-	.release_address = release_address,
-
-	.register_endpoint = register_endpoint,
-	.unregister_endpoint = unregister_endpoint,
-
-	.interrupt_out = interrupt_out,
-	.interrupt_in = interrupt_in,
-
-	.bulk_out = bulk_out,
-	.bulk_in = bulk_in,
-
-	.control_write = control_write,
-	.control_read = control_read,
-};
-/**
- * @}
- */
Index: pace/drv/bus/usb/ohci/iface.h
===================================================================
--- uspace/drv/bus/usb/ohci/iface.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * 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
- * Common OHCI definitions.
- */
-#ifndef DRV_OHCI_IFACE_H
-#define DRV_OHCI_IFACE_H
-
-#include <usbhc_iface.h>
-
-extern usbhc_iface_t hc_iface;
-
-#endif
-/**
- * @}
- */
-
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -42,8 +42,6 @@
 
 #include "ohci.h"
-#include "iface.h"
 #include "pci.h"
 #include "hc.h"
-#include "root_hub.h"
 
 typedef struct ohci {
@@ -52,5 +50,4 @@
 
 	hc_t hc;
-	rh_t rh;
 } ohci_t;
 
@@ -89,7 +86,8 @@
 {
 	assert(fun);
-	usb_device_keeper_t *manager = &dev_to_ohci(fun->dev)->hc.manager;
-
-	usb_address_t addr = usb_device_keeper_find(manager, handle);
+	usb_device_manager_t *manager =
+	    &dev_to_ohci(fun->dev)->hc.generic.dev_manager;
+
+	const usb_address_t addr = usb_device_manager_find(manager, handle);
 	if (addr < 0) {
 		return addr;
@@ -129,5 +127,5 @@
 /** Standard USB HC options (HC interface) */
 static ddf_dev_ops_t hc_ops = {
-	.interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */
+	.interfaces[USBHC_DEV_IFACE] = &hcd_iface,
 };
 /*----------------------------------------------------------------------------*/
@@ -150,4 +148,6 @@
 int device_setup_ohci(ddf_dev_t *device)
 {
+	assert(device);
+
 	ohci_t *instance = malloc(sizeof(ohci_t));
 	if (instance == NULL) {
@@ -155,24 +155,20 @@
 		return ENOMEM;
 	}
+	instance->rh_fun = NULL;
+	instance->hc_fun = NULL;
 
 #define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
 if (ret != EOK) { \
 	if (instance->hc_fun) { \
-		instance->hc_fun->ops = NULL; \
-		instance->hc_fun->driver_data = NULL; \
 		ddf_fun_destroy(instance->hc_fun); \
 	} \
 	if (instance->rh_fun) { \
-		instance->rh_fun->ops = NULL; \
-		instance->rh_fun->driver_data = NULL; \
 		ddf_fun_destroy(instance->rh_fun); \
 	} \
 	free(instance); \
-	device->driver_data = NULL; \
 	usb_log_error(message); \
 	return ret; \
 } else (void)0
 
-	instance->rh_fun = NULL;
 	instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc");
 	int ret = instance->hc_fun ? EOK : ENOMEM;
@@ -194,5 +190,5 @@
 	ret = pci_get_my_registers(device, &reg_base, &reg_size, &irq);
 	CHECK_RET_DEST_FREE_RETURN(ret,
-	    "Failed to get memory addresses for %" PRIun ": %s.\n",
+	    "Failed to get register memory addresses for %" PRIun ": %s.\n",
 	    device->handle, str_error(ret));
 	usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
@@ -201,4 +197,6 @@
 	const size_t cmd_count = hc_irq_cmd_count();
 	irq_cmd_t irq_cmds[cmd_count];
+	irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = irq_cmds };
+
 	ret =
 	    hc_get_irq_commands(irq_cmds, sizeof(irq_cmds), reg_base, reg_size);
@@ -206,5 +204,4 @@
 	    "Failed to generate IRQ commands: %s.\n", str_error(ret));
 
-	irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = irq_cmds };
 
 	/* Register handler to avoid interrupt lockup */
@@ -234,6 +231,6 @@
 #define CHECK_RET_FINI_RETURN(ret, message...) \
 if (ret != EOK) { \
+	hc_fini(&instance->hc); \
 	unregister_interrupt_handler(device, irq); \
-	hc_fini(&instance->hc); \
 	CHECK_RET_DEST_FREE_RETURN(ret, message); \
 } else (void)0
@@ -248,8 +245,9 @@
 	    "Failed to add OHCI to HC class: %s.\n", str_error(ret));
 
-	hc_register_hub(&instance->hc, instance->rh_fun);
-	return EOK;
-
-#undef CHECK_RET_DEST_FUN_RETURN
+	ret = hc_register_hub(&instance->hc, instance->rh_fun);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed to register OHCI root hub: %s.\n", str_error(ret));
+	return ret;
+
 #undef CHECK_RET_FINI_RETURN
 }
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,358 @@
+/*
+ * 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"
+
+static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t);
+/*----------------------------------------------------------------------------*/
+/** Safely destructs ohci_transfer_batch_t structure
+ *
+ * @param[in] ohci_batch Instance to destroy.
+ */
+static void ohci_transfer_batch_dispose(ohci_transfer_batch_t *ohci_batch)
+{
+	if (!ohci_batch)
+		return;
+	unsigned i = 0;
+	if (ohci_batch->tds) {
+		for (; i< ohci_batch->td_count; ++i) {
+			if (i != ohci_batch->leave_td)
+				free32(ohci_batch->tds[i]);
+		}
+		free(ohci_batch->tds);
+	}
+	usb_transfer_batch_dispose(ohci_batch->usb_batch);
+	free32(ohci_batch->device_buffer);
+	free(ohci_batch);
+}
+/*----------------------------------------------------------------------------*/
+void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
+	assert(ohci_batch->usb_batch);
+	usb_transfer_batch_finish(ohci_batch->usb_batch,
+	    ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size,
+	    ohci_batch->usb_batch->buffer_size);
+	ohci_transfer_batch_dispose(ohci_batch);
+}
+/*----------------------------------------------------------------------------*/
+ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
+{
+	assert(usb_batch);
+#define CHECK_NULL_DISPOSE_RET(ptr, message...) \
+if (ptr == NULL) { \
+	usb_log_error(message); \
+	ohci_transfer_batch_dispose(ohci_batch); \
+	return NULL; \
+} else (void)0
+
+	ohci_transfer_batch_t *ohci_batch =
+	    calloc(1, sizeof(ohci_transfer_batch_t));
+	CHECK_NULL_DISPOSE_RET(ohci_batch,
+	    "Failed to allocate OHCI batch data.\n");
+	link_initialize(&ohci_batch->link);
+	ohci_batch->td_count =
+	    (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
+	    / OHCI_TD_MAX_TRANSFER;
+	/* Control transfer need Setup and Status stage */
+	if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
+		ohci_batch->td_count += 2;
+	}
+
+	/* We need an extra place for TD that was left at ED */
+	ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t*));
+	CHECK_NULL_DISPOSE_RET(ohci_batch->tds,
+	    "Failed to allocate OHCI transfer descriptors.\n");
+
+	/* Add TD left over by the previous transfer */
+	ohci_batch->ed = ohci_endpoint_get(usb_batch->ep)->ed;
+	ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td;
+	ohci_batch->leave_td = 0;
+	unsigned i = 1;
+	for (; i <= ohci_batch->td_count; ++i) {
+		ohci_batch->tds[i] = malloc32(sizeof(td_t));
+		CHECK_NULL_DISPOSE_RET(ohci_batch->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 (usb_batch->setup_size + usb_batch->buffer_size > 0) {
+		/* Use one buffer for setup and data stage */
+		ohci_batch->device_buffer =
+		    malloc32(usb_batch->setup_size + usb_batch->buffer_size);
+                CHECK_NULL_DISPOSE_RET(ohci_batch->device_buffer,
+                    "Failed to allocate device accessible buffer.\n");
+		/* Copy setup data */
+                memcpy(ohci_batch->device_buffer, usb_batch->setup_buffer,
+		    usb_batch->setup_size);
+		/* Copy generic data */
+		if (usb_batch->ep->direction != USB_DIRECTION_IN)
+			memcpy(
+			    ohci_batch->device_buffer + usb_batch->setup_size,
+			    usb_batch->buffer, usb_batch->buffer_size);
+        }
+	ohci_batch->usb_batch = usb_batch;
+
+	const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
+	assert(batch_setup[usb_batch->ep->transfer_type]);
+	batch_setup[usb_batch->ep->transfer_type](ohci_batch, dir);
+
+	return ohci_batch;
+#undef CHECK_NULL_DISPOSE_RET
+}
+/*----------------------------------------------------------------------------*/
+/** Check batch TDs' status.
+ *
+ * @param[in] ohci_batch 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 ohci_transfer_batch_is_complete(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
+	assert(ohci_batch->usb_batch);
+
+	usb_log_debug("Batch %p checking %zu td(s) for completion.\n",
+	    ohci_batch->usb_batch, ohci_batch->td_count);
+	usb_log_debug2("ED: %x:%x:%x:%x.\n",
+	    ohci_batch->ed->status, ohci_batch->ed->td_head,
+	    ohci_batch->ed->td_tail, ohci_batch->ed->next);
+
+	size_t i = 0;
+	for (; i < ohci_batch->td_count; ++i) {
+		assert(ohci_batch->tds[i] != NULL);
+		usb_log_debug("TD %zu: %x:%x:%x:%x.\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;
+		}
+		ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
+		if (ohci_batch->usb_batch->error != EOK) {
+			usb_log_debug("Batch %p found error TD(%zu):%x.\n",
+			    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;
+			break;
+		}
+	}
+
+	assert(i <= ohci_batch->td_count);
+	ohci_batch->leave_td = i;
+
+	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];
+	assert(i > 0);
+	ohci_batch->usb_batch->transfered_size =
+	    ohci_batch->usb_batch->buffer_size;
+	for (--i;i < ohci_batch->td_count; ++i)
+		ohci_batch->usb_batch->transfered_size
+		    -= 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 */
+	const uint32_t pa = addr_to_phys(ohci_ep->td);
+	assert(pa == (ohci_batch->ed->td_head & ED_TDHEAD_PTR_MASK));
+	assert(pa == (ohci_batch->ed->td_tail & ED_TDTAIL_PTR_MASK));
+
+	return true;
+}
+/*----------------------------------------------------------------------------*/
+/** Starts execution of the TD list
+ *
+ * @param[in] ohci_batch Batch structure to use
+ */
+void ohci_transfer_batch_commit(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
+	ed_set_end_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic control transfer
+ *
+ * @param[in] ohci_batch Batch structure to use.
+ * @param[in] dir Communication direction
+ *
+ * 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.
+ */
+static void batch_control(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
+{
+	assert(ohci_batch);
+	assert(ohci_batch->usb_batch);
+	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", ohci_batch->ed,
+	    ohci_batch->ed->status, ohci_batch->ed->td_tail,
+	    ohci_batch->ed->td_head, ohci_batch->ed->next);
+	static const usb_direction_t reverse_dir[] = {
+		[USB_DIRECTION_IN]  = USB_DIRECTION_OUT,
+		[USB_DIRECTION_OUT] = USB_DIRECTION_IN,
+	};
+
+	int toggle = 0;
+	const char* buffer = ohci_batch->device_buffer;
+	const usb_direction_t data_dir = dir;
+	const usb_direction_t status_dir = reverse_dir[dir];
+
+	/* 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]);
+	usb_log_debug("Created CONTROL SETUP TD: %x:%x:%x:%x.\n",
+	    ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
+	    ohci_batch->tds[0]->next, ohci_batch->tds[0]->be);
+	buffer += ohci_batch->usb_batch->setup_size;
+
+	/* data stage */
+	size_t td_current = 1;
+	size_t remain_size = ohci_batch->usb_batch->buffer_size;
+	while (remain_size > 0) {
+		const size_t transfer_size =
+		    remain_size > OHCI_TD_MAX_TRANSFER ?
+		    OHCI_TD_MAX_TRANSFER : remain_size;
+		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]);
+		usb_log_debug("Created CONTROL DATA TD: %x:%x:%x:%x.\n",
+		    ohci_batch->tds[td_current]->status,
+		    ohci_batch->tds[td_current]->cbp,
+		    ohci_batch->tds[td_current]->next,
+		    ohci_batch->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < ohci_batch->td_count - 1);
+		++td_current;
+	}
+
+	/* 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]);
+	usb_log_debug("Created CONTROL STATUS TD: %x:%x:%x:%x.\n",
+	    ohci_batch->tds[td_current]->status,
+	    ohci_batch->tds[td_current]->cbp,
+	    ohci_batch->tds[td_current]->next,
+	    ohci_batch->tds[td_current]->be);
+	usb_log_debug2(
+	    "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
+	    ohci_batch->usb_batch,
+	    usb_str_transfer_type(ohci_batch->usb_batch->ep->transfer_type),
+	    usb_str_direction(dir),
+	    USB_TRANSFER_BATCH_ARGS(*ohci_batch->usb_batch));
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic data transfer
+ *
+ * @param[in] ohci_batch Batch structure to use.
+ * @paramp[in] dir Communication direction.
+ *
+ * Direction is supplied by the associated ep and toggle is maintained by the
+ * OHCI hw in ED.
+ */
+static void batch_data(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
+{
+	assert(ohci_batch);
+	assert(ohci_batch->usb_batch);
+	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", ohci_batch->ed,
+	    ohci_batch->ed->status, ohci_batch->ed->td_tail,
+	    ohci_batch->ed->td_head, ohci_batch->ed->next);
+
+	size_t td_current = 0;
+	size_t remain_size = ohci_batch->usb_batch->buffer_size;
+	char *buffer = ohci_batch->device_buffer;
+	while (remain_size > 0) {
+		const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
+		    ? 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]);
+
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    ohci_batch->tds[td_current]->status,
+		    ohci_batch->tds[td_current]->cbp,
+		    ohci_batch->tds[td_current]->next,
+		    ohci_batch->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < ohci_batch->td_count);
+		++td_current;
+	}
+	usb_log_debug2(
+	    "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
+	    ohci_batch->usb_batch,
+	    usb_str_transfer_type(ohci_batch->usb_batch->ep->transfer_type),
+	    usb_str_direction(dir),
+	    USB_TRANSFER_BATCH_ARGS(*ohci_batch->usb_batch));
+}
+/*----------------------------------------------------------------------------*/
+static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t) =
+{
+	[USB_TRANSFER_CONTROL] = batch_control,
+	[USB_TRANSFER_BULK] = batch_data,
+	[USB_TRANSFER_INTERRUPT] = batch_data,
+	[USB_TRANSFER_ISOCHRONOUS] = NULL,
+};
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/ohci_batch.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/drv/bus/usb/ohci/ohci_batch.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,76 @@
+/*
+ * 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 <adt/list.h>
+#include <usbhc_iface.h>
+#include <usb/usb.h>
+#include <usb/host/usb_transfer_batch.h>
+
+#include "hw_struct/transfer_descriptor.h"
+#include "hw_struct/endpoint_descriptor.h"
+
+/** OHCI specific data required for USB transfer */
+typedef struct ohci_transfer_batch {
+	/** Link */
+	link_t link;
+	/** 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 by the OHCI hw. */
+	char *device_buffer;
+	/** Generic USB transfer structure */
+	usb_transfer_batch_t *usb_batch;
+} ohci_transfer_batch_t;
+
+ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *batch);
+bool ohci_transfer_batch_is_complete(ohci_transfer_batch_t *batch);
+void ohci_transfer_batch_commit(ohci_transfer_batch_t *batch);
+void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch);
+/*----------------------------------------------------------------------------*/
+static inline ohci_transfer_batch_t *ohci_transfer_batch_from_link(link_t *l)
+{
+	assert(l);
+	return list_get_instance(l, ohci_transfer_batch_t, link);
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,114 @@
+/*
+ * 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 "utils/malloc32.h"
+#include "ohci_endpoint.h"
+#include "hc.h"
+
+/** Callback to set toggle on ED.
+ *
+ * @param[in] hcd_ep hcd endpoint structure
+ * @param[in] toggle new value of toggle bit
+ */
+static void ohci_ep_toggle_set(void *ohci_ep, int toggle)
+{
+	ohci_endpoint_t *instance = ohci_ep;
+	assert(instance);
+	assert(instance->ed);
+	ed_toggle_set(instance->ed, toggle);
+}
+/*----------------------------------------------------------------------------*/
+/** Callback to get value of toggle bit.
+ *
+ * @param[in] hcd_ep hcd endpoint structure
+ * @return Current value of toggle bit.
+ */
+static int ohci_ep_toggle_get(void *ohci_ep)
+{
+	ohci_endpoint_t *instance = ohci_ep;
+	assert(instance);
+	assert(instance->ed);
+	return ed_toggle_get(instance->ed);
+}
+/*----------------------------------------------------------------------------*/
+/** Disposes hcd endpoint structure
+ *
+ * @param[in] hcd_ep endpoint structure
+ */
+static void ohci_endpoint_fini(endpoint_t *ep)
+{
+	ohci_endpoint_t *instance = ep->hc_data.data;
+	hc_dequeue_endpoint(instance->hcd->private_data, ep);
+	if (instance) {
+		free32(instance->ed);
+		free32(instance->td);
+		free(instance);
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Creates new hcd endpoint representation.
+ *
+ * @param[in] ep USBD endpoint structure
+ * @return pointer to a new hcd endpoint structure, NULL on failure.
+ */
+int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep)
+{
+	assert(ep);
+	ohci_endpoint_t *ohci_ep = malloc(sizeof(ohci_endpoint_t));
+	if (ohci_ep == NULL)
+		return ENOMEM;
+
+	ohci_ep->ed = malloc32(sizeof(ed_t));
+	if (ohci_ep->ed == NULL) {
+		free(ohci_ep);
+		return ENOMEM;
+	}
+
+	ohci_ep->td = malloc32(sizeof(td_t));
+	if (ohci_ep->td == NULL) {
+		free32(ohci_ep->ed);
+		free(ohci_ep);
+		return ENOMEM;
+	}
+
+	ed_init(ohci_ep->ed, ep);
+	ed_set_td(ohci_ep->ed, ohci_ep->td);
+	endpoint_set_hc_data(
+	    ep, ohci_ep, ohci_endpoint_fini, ohci_ep_toggle_get, ohci_ep_toggle_set);
+	ohci_ep->hcd = hcd;
+	hc_enqueue_endpoint(hcd->private_data, ep);
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/drv/bus/usb/ohci/ohci_endpoint.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,72 @@
+/*
+ * 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
+ */
+#ifndef DRV_OHCI_HCD_ENDPOINT_H
+#define DRV_OHCI_HCD_ENDPOINT_H
+
+#include <assert.h>
+#include <adt/list.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/hcd.h>
+
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+/** Connector structure linking ED to to prepared TD. */
+typedef struct ohci_endpoint {
+	/** OHCI endpoint descriptor */
+	ed_t *ed;
+	/** Currently enqueued transfer descriptor */
+	td_t *td;
+	/** Linked list used by driver software */
+	link_t link;
+	/** Device using this ep */
+	hcd_t *hcd;
+} ohci_endpoint_t;
+
+int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep);
+
+/** Get and convert assigned ohci_endpoint_t structure
+ * @param[in] ep USBD endpoint structure.
+ * @return Pointer to assigned hcd endpoint structure
+ */
+static inline ohci_endpoint_t * ohci_endpoint_get(endpoint_t *ep)
+{
+	assert(ep);
+	return ep->hc_data.data;
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/pci.c
===================================================================
--- uspace/drv/bus/usb/ohci/pci.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/pci.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -70,19 +70,19 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	hw_resource_list_t hw_resources;
 	int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	async_hangup(parent_sess);
 	if (rc != EOK) {
-		async_hangup(parent_sess);
 		return rc;
 	}
-	
+
 	uintptr_t mem_address = 0;
 	size_t mem_size = 0;
 	bool mem_found = false;
-	
+
 	int irq = 0;
 	bool irq_found = false;
-	
+
 	size_t i;
 	for (i = 0; i < hw_resources.count; i++) {
@@ -107,15 +107,13 @@
 		}
 	}
-	
+	free(hw_resources.resources);
+
 	if (mem_found && irq_found) {
 		*mem_reg_address = mem_address;
 		*mem_reg_size = mem_size;
 		*irq_no = irq;
-		rc = EOK;
-	} else
-		rc = ENOENT;
-	
-	async_hangup(parent_sess);
-	return rc;
+		return EOK;
+	}
+	return ENOENT;
 }
 
Index: uspace/drv/bus/usb/ohci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/root_hub.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -121,7 +121,6 @@
 	assert(request);
 
-	memcpy(request->data_buffer, &mask, size);
 	request->transfered_size = size;
-	usb_transfer_batch_finish_error(request, EOK);
+	usb_transfer_batch_finish_error(request, &mask, size, EOK);
 }
 
@@ -206,5 +205,5 @@
 		usb_log_debug("Root hub got CONTROL packet\n");
 		const int ret = control_request(instance, request);
-		usb_transfer_batch_finish_error(request, ret);
+		usb_transfer_batch_finish_error(request, NULL, 0, ret);
 		break;
 	case USB_TRANSFER_INTERRUPT:
@@ -215,5 +214,5 @@
 			assert(instance->unfinished_interrupt_transfer == NULL);
 			instance->unfinished_interrupt_transfer = request;
-			break;
+			return;
 		}
 		usb_log_debug("Processing changes...\n");
@@ -223,6 +222,7 @@
 	default:
 		usb_log_error("Root hub got unsupported request.\n");
-		usb_transfer_batch_finish_error(request, EINVAL);
-	}
+		usb_transfer_batch_finish_error(request, NULL, 0, EINVAL);
+	}
+	usb_transfer_batch_dispose(request);
 }
 /*----------------------------------------------------------------------------*/
@@ -244,4 +244,5 @@
 	interrupt_request(instance->unfinished_interrupt_transfer,
 	    mask, instance->interrupt_mask_size);
+	usb_transfer_batch_dispose(instance->unfinished_interrupt_transfer);
 
 	instance->unfinished_interrupt_transfer = NULL;
@@ -389,6 +390,6 @@
 		const uint32_t data = instance->registers->rh_status &
 		    (RHS_LPS_FLAG | RHS_LPSC_FLAG | RHS_OCI_FLAG | RHS_OCIC_FLAG);
-		memcpy(request->data_buffer, &data, 4);
-		TRANSFER_OK(4);
+		memcpy(request->buffer, &data, sizeof(data));
+		TRANSFER_OK(sizeof(data));
 	}
 
@@ -402,6 +403,6 @@
 		const uint32_t data =
 		    instance->registers->rh_port_status[port - 1];
-		memcpy(request->data_buffer, &data, 4);
-		TRANSFER_OK(4);
+		memcpy(request->buffer, &data, sizeof(data));
+		TRANSFER_OK(sizeof(data));
 	}
 
@@ -483,5 +484,5 @@
 	}
 
-	memcpy(request->data_buffer, descriptor, size);
+	memcpy(request->buffer, descriptor, size);
 	TRANSFER_OK(size);
 }
@@ -713,5 +714,5 @@
 		if (request->buffer_size != 1)
 			return EINVAL;
-		request->data_buffer[0] = 1;
+		request->buffer[0] = 1;
 		TRANSFER_OK(1);
 
Index: uspace/drv/bus/usb/ohci/root_hub.h
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/root_hub.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -37,7 +37,7 @@
 #include <usb/usb.h>
 #include <usb/dev/driver.h>
+#include <usb/host/usb_transfer_batch.h>
 
 #include "ohci_regs.h"
-#include "batch.h"
 
 #define HUB_DESCRIPTOR_MAX_SIZE (7 + 2 + 2)
@@ -66,5 +66,4 @@
 	/** size of hub descriptor */
 	size_t hub_descriptor_size;
-
 } rh_t;
 
Index: uspace/drv/bus/usb/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -46,5 +46,5 @@
  * @return Physical address if exists, NULL otherwise.
  */
-static inline uintptr_t addr_to_phys(void *addr)
+static inline uintptr_t addr_to_phys(const void *addr)
 {
 	uintptr_t result;
Index: uspace/drv/bus/usb/uhci/Makefile
===================================================================
--- uspace/drv/bus/usb/uhci/Makefile	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -42,13 +42,12 @@
 
 SOURCES = \
-	iface.c \
+	hc.c \
 	main.c \
+	pci.c \
+	root_hub.c \
 	transfer_list.c \
 	uhci.c \
-	hc.c \
-	root_hub.c \
-	hw_struct/transfer_descriptor.c \
-	pci.c \
-	batch.c
+	uhci_batch.c \
+	hw_struct/transfer_descriptor.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: pace/drv/bus/usb/uhci/batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/batch.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,428 +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 drvusbuhcihc
- * @{
- */
-/** @file
- * @brief UHCI driver USB transfer structure
- */
-#include <errno.h>
-#include <str_error.h>
-
-#include <usb/usb.h>
-#include <usb/debug.h>
-
-#include "batch.h"
-#include "transfer_list.h"
-#include "hw_struct/transfer_descriptor.h"
-#include "utils/malloc32.h"
-
-#define DEFAULT_ERROR_COUNT 3
-
-/** UHCI specific data required for USB transfer */
-typedef struct uhci_transfer_batch {
-	/** Queue head
-	 * This QH is used to maintain UHCI schedule structure and the element
-	 * pointer points to the first TD of this batch.
-	 */
-	qh_t *qh;
-	/** List of TDs needed for the transfer */
-	td_t *tds;
-	/** Number of TDs used by the transfer */
-	size_t td_count;
-	/** Data buffer, must be accessible by the UHCI hw */
-	void *device_buffer;
-} uhci_transfer_batch_t;
-/*----------------------------------------------------------------------------*/
-static void batch_control(usb_transfer_batch_t *instance,
-    usb_packet_id data_stage, usb_packet_id status_stage);
-static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid);
-/*----------------------------------------------------------------------------*/
-/** Safely destructs uhci_transfer_batch_t structure
- *
- * @param[in] uhci_batch Instance to destroy.
- */
-static void uhci_transfer_batch_dispose(void *uhci_batch)
-{
-	uhci_transfer_batch_t *instance = uhci_batch;
-	assert(instance);
-	free32(instance->device_buffer);
-	free(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Allocate memory and initialize internal data structure.
- *
- * @param[in] fun DDF function to pass to callback.
- * @param[in] ep Communication target
- * @param[in] buffer Data source/destination.
- * @param[in] buffer_size Size of the buffer.
- * @param[in] setup_buffer Setup data source (if not NULL)
- * @param[in] setup_size Size of setup_buffer (should be always 8)
- * @param[in] func_in function to call on inbound transfer completion
- * @param[in] func_out function to call on outbound transfer completion
- * @param[in] arg additional parameter to func_in or func_out
- * @return Valid pointer if all structures were successfully created,
- * NULL otherwise.
- *
- * Determines the number of needed transfer descriptors (TDs).
- * Prepares a transport buffer (that is accessible by the hardware).
- * Initializes parameters needed for the transfer and callback.
- */
-usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
-    char *buffer, size_t buffer_size,
-    const char* setup_buffer, size_t setup_size,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out, void *arg)
-{
-	assert(ep);
-	assert(func_in == NULL || func_out == NULL);
-	assert(func_in != NULL || func_out != NULL);
-
-#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
-	if (ptr == NULL) { \
-		usb_log_error(message); \
-		if (uhci_data) { \
-			uhci_transfer_batch_dispose(uhci_data); \
-		} \
-		return NULL; \
-	} else (void)0
-
-	uhci_transfer_batch_t *uhci_data =
-	    malloc(sizeof(uhci_transfer_batch_t));
-	CHECK_NULL_DISPOSE_RETURN(uhci_data,
-	    "Failed to allocate UHCI batch.\n");
-	bzero(uhci_data, sizeof(uhci_transfer_batch_t));
-
-	uhci_data->td_count =
-	    (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
-	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
-		uhci_data->td_count += 2;
-	}
-
-	assert((sizeof(td_t) % 16) == 0);
-	const size_t total_size = (sizeof(td_t) * uhci_data->td_count)
-	    + sizeof(qh_t) + setup_size + buffer_size;
-	uhci_data->device_buffer = malloc32(total_size);
-	CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,
-	    "Failed to allocate UHCI buffer.\n");
-	bzero(uhci_data->device_buffer, total_size);
-
-	uhci_data->tds = uhci_data->device_buffer;
-	uhci_data->qh =
-	    (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));
-
-	qh_init(uhci_data->qh);
-	qh_set_element_td(uhci_data->qh, uhci_data->tds);
-
-	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
-	CHECK_NULL_DISPOSE_RETURN(instance,
-	    "Failed to allocate batch instance.\n");
-	void *setup =
-	    uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)
-	    + sizeof(qh_t);
-	void *data_buffer = setup + setup_size;
-	usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size,
-	    setup, setup_size, func_in, func_out, arg, fun,
-	    uhci_data, uhci_transfer_batch_dispose);
-
-	memcpy(instance->setup_buffer, setup_buffer, setup_size);
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
-	    " memory structures ready.\n", instance,
-	    USB_TRANSFER_BATCH_ARGS(*instance));
-	return instance;
-}
-/*----------------------------------------------------------------------------*/
-/** Check batch TDs for activity.
- *
- * @param[in] instance Batch structure to use.
- * @return False, if there is an active TD, true otherwise.
- *
- * Walk all TDs. Stop with false if there is an active one (it is to be
- * processed). Stop with true if an error is found. Return true if the last TD
- * is reached.
- */
-bool batch_is_complete(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	uhci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-
-	usb_log_debug2("Batch(%p) checking %zu transfer(s) for completion.\n",
-	    instance, data->td_count);
-	instance->transfered_size = 0;
-	size_t i = 0;
-	for (;i < data->td_count; ++i) {
-		if (td_is_active(&data->tds[i])) {
-			return false;
-		}
-
-		instance->error = td_status(&data->tds[i]);
-		if (instance->error != EOK) {
-			usb_log_debug("Batch(%p) found error TD(%zu):%"
-			    PRIx32 ".\n", instance, i, data->tds[i].status);
-			td_print_status(&data->tds[i]);
-
-			assert(instance->ep != NULL);
-			endpoint_toggle_set(instance->ep,
-			    td_toggle(&data->tds[i]));
-			if (i > 0)
-				goto substract_ret;
-			return true;
-		}
-
-		instance->transfered_size += td_act_size(&data->tds[i]);
-		if (td_is_short(&data->tds[i]))
-			goto substract_ret;
-	}
-substract_ret:
-	instance->transfered_size -= instance->setup_size;
-	return true;
-}
-
-#define LOG_BATCH_INITIALIZED(batch, name) \
-	usb_log_debug2("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
-	    (batch), (name), USB_TRANSFER_BATCH_ARGS(*(batch)))
-
-/*----------------------------------------------------------------------------*/
-/** Prepares control write transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Uses generic control function with pids OUT and IN.
- */
-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);
-	batch_control(instance, USB_PID_OUT, USB_PID_IN);
-	instance->next_step = usb_transfer_batch_call_out_and_dispose;
-	LOG_BATCH_INITIALIZED(instance, "control write");
-}
-/*----------------------------------------------------------------------------*/
-/** Prepares control read transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Uses generic control with pids IN and OUT.
- */
-void batch_control_read(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	batch_control(instance, USB_PID_IN, USB_PID_OUT);
-	instance->next_step = usb_transfer_batch_call_in_and_dispose;
-	LOG_BATCH_INITIALIZED(instance, "control read");
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare interrupt in transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer with PID_IN.
- */
-void batch_interrupt_in(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	batch_data(instance, USB_PID_IN);
-	instance->next_step = usb_transfer_batch_call_in_and_dispose;
-	LOG_BATCH_INITIALIZED(instance, "interrupt in");
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare interrupt out transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer with PID_OUT.
- */
-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);
-	batch_data(instance, USB_PID_OUT);
-	instance->next_step = usb_transfer_batch_call_out_and_dispose;
-	LOG_BATCH_INITIALIZED(instance, "interrupt out");
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare bulk in transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer with PID_IN.
- */
-void batch_bulk_in(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	batch_data(instance, USB_PID_IN);
-	instance->next_step = usb_transfer_batch_call_in_and_dispose;
-	LOG_BATCH_INITIALIZED(instance, "bulk in");
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare bulk out transfer.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transfer with PID_OUT.
- */
-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);
-	batch_data(instance, USB_PID_OUT);
-	instance->next_step = usb_transfer_batch_call_out_and_dispose;
-	LOG_BATCH_INITIALIZED(instance, "bulk out");
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare generic data transfer
- *
- * @param[in] instance Batch structure to use.
- * @param[in] pid Pid to use for data transactions.
- *
- * Transactions with alternating toggle bit and supplied pid value.
- * The last transfer is marked with IOC flag.
- */
-void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid)
-{
-	assert(instance);
-	uhci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-
-	const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
-	int toggle = endpoint_toggle_get(instance->ep);
-	assert(toggle == 0 || toggle == 1);
-
-	size_t td = 0;
-	size_t remain_size = instance->buffer_size;
-	char *buffer = instance->data_buffer;
-	while (remain_size > 0) {
-		const size_t packet_size =
-		    (instance->ep->max_packet_size > remain_size) ?
-		    remain_size : instance->ep->max_packet_size;
-
-		td_t *next_td = (td + 1 < data->td_count)
-		    ? &data->tds[td + 1] : NULL;
-
-
-		usb_target_t target =
-		    { instance->ep->address, instance->ep->endpoint };
-
-		assert(td < data->td_count);
-		td_init(
-		    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
-		    toggle, false, low_speed, target, pid, buffer, next_td);
-
-		++td;
-		toggle = 1 - toggle;
-		buffer += packet_size;
-		assert(packet_size <= remain_size);
-		remain_size -= packet_size;
-	}
-	td_set_ioc(&data->tds[td - 1]);
-	endpoint_toggle_set(instance->ep, toggle);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare generic control transfer
- *
- * @param[in] instance Batch structure to use.
- * @param[in] data_stage Pid to use for data tds.
- * @param[in] status_stage Pid to use for data tds.
- *
- * Setup stage with toggle 0 and USB_PID_SETUP.
- * Data stage with alternating toggle and pid supplied by parameter.
- * Status stage with toggle 1 and pid supplied by parameter.
- * The last transfer is marked with IOC.
- */
-void batch_control(usb_transfer_batch_t *instance,
-   usb_packet_id data_stage, usb_packet_id status_stage)
-{
-	assert(instance);
-	uhci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-	assert(data->td_count >= 2);
-
-	const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
-	const usb_target_t target =
-	    { instance->ep->address, instance->ep->endpoint };
-
-	/* setup stage */
-	td_init(
-	    data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false,
-	    low_speed, target, USB_PID_SETUP, instance->setup_buffer,
-	    &data->tds[1]);
-
-	/* data stage */
-	size_t td = 1;
-	unsigned toggle = 1;
-	size_t remain_size = instance->buffer_size;
-	char *buffer = instance->data_buffer;
-	while (remain_size > 0) {
-		const size_t packet_size =
-		    (instance->ep->max_packet_size > remain_size) ?
-		    remain_size : instance->ep->max_packet_size;
-
-		td_init(
-		    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
-		    toggle, false, low_speed, target, data_stage,
-		    buffer, &data->tds[td + 1]);
-
-		++td;
-		toggle = 1 - toggle;
-		buffer += packet_size;
-		assert(td < data->td_count);
-		assert(packet_size <= remain_size);
-		remain_size -= packet_size;
-	}
-
-	/* status stage */
-	assert(td == data->td_count - 1);
-
-	td_init(
-	    &data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
-	    target, status_stage, NULL, NULL);
-	td_set_ioc(&data->tds[td]);
-
-	usb_log_debug2("Control last TD status: %x.\n",
-	    data->tds[td].status);
-}
-/*----------------------------------------------------------------------------*/
-/** Provides access to QH data structure.
- *
- * @param[in] instance Batch pointer to use.
- * @return Pointer to the QH used by the batch.
- */
-qh_t * batch_qh(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	uhci_transfer_batch_t *data = instance->private_data;
-	assert(data);
-	return data->qh;
-}
-/**
- * @}
- */
Index: pace/drv/bus/usb/uhci/batch.h
===================================================================
--- uspace/drv/bus/usb/uhci/batch.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,65 +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 drvusbuhcihc
- * @{
- */
-/** @file
- * @brief UHCI driver USB tranfer helper functions
- */
-#ifndef DRV_UHCI_BATCH_H
-#define DRV_UHCI_BATCH_H
-
-#include <usb/host/batch.h>
-
-#include "hw_struct/queue_head.h"
-
-usb_transfer_batch_t * batch_get(
-    ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size,
-    const char *setup_buffer, size_t setup_size,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out,
-    void *arg);
-
-void batch_dispose(usb_transfer_batch_t *instance);
-
-bool batch_is_complete(usb_transfer_batch_t *instance);
-
-void batch_control_write(usb_transfer_batch_t *instance);
-void batch_control_read(usb_transfer_batch_t *instance);
-
-void batch_interrupt_in(usb_transfer_batch_t *instance);
-void batch_interrupt_out(usb_transfer_batch_t *instance);
-
-void batch_bulk_in(usb_transfer_batch_t *instance);
-void batch_bulk_out(usb_transfer_batch_t *instance);
-
-qh_t * batch_qh(usb_transfer_batch_t *instance);
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -41,4 +41,5 @@
 
 #include "hc.h"
+#include "uhci_batch.h"
 
 #define UHCI_INTR_ALLOW_INTERRUPTS \
@@ -46,4 +47,5 @@
 #define UHCI_STATUS_USED_INTERRUPTS \
     (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
+
 
 static const irq_cmd_t uhci_irq_commands[] =
@@ -57,7 +59,8 @@
 };
 
+static void hc_init_hw(const hc_t *instance);
+static int hc_init_mem_structures(hc_t *instance);
 static int hc_init_transfer_lists(hc_t *instance);
-static int hc_init_mem_structures(hc_t *instance);
-static void hc_init_hw(hc_t *instance);
+static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
 
 static int hc_interrupt_emulator(void *arg);
@@ -95,4 +98,61 @@
 	cmds[3].addr = (void*)&registers->usbsts;
 	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Take action based on the interrupt cause.
+ *
+ * @param[in] instance UHCI structure to use.
+ * @param[in] status Value of the status register at the time of interrupt.
+ *
+ * Interrupt might indicate:
+ * - transaction completed, either by triggering IOC, SPD, or an error
+ * - some kind of device error
+ * - resume from suspend state (not implemented)
+ */
+void hc_interrupt(hc_t *instance, uint16_t status)
+{
+	assert(instance);
+	/* Lower 2 bits are transaction error and transaction complete */
+	if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
+		LIST_INITIALIZE(done);
+		transfer_list_remove_finished(
+		    &instance->transfers_interrupt, &done);
+		transfer_list_remove_finished(
+		    &instance->transfers_control_slow, &done);
+		transfer_list_remove_finished(
+		    &instance->transfers_control_full, &done);
+		transfer_list_remove_finished(
+		    &instance->transfers_bulk_full, &done);
+
+		while (!list_empty(&done)) {
+			link_t *item = list_first(&done);
+			list_remove(item);
+			uhci_transfer_batch_t *batch =
+			    uhci_transfer_batch_from_link(item);
+			uhci_transfer_batch_call_dispose(batch);
+		}
+	}
+	/* Resume interrupts are not supported */
+	if (status & UHCI_STATUS_RESUME) {
+		usb_log_error("Resume interrupt!\n");
+	}
+
+	/* Bits 4 and 5 indicate hc error */
+	if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
+		usb_log_error("UHCI hardware failure!.\n");
+		++instance->hw_failures;
+		transfer_list_abort_all(&instance->transfers_interrupt);
+		transfer_list_abort_all(&instance->transfers_control_slow);
+		transfer_list_abort_all(&instance->transfers_control_full);
+		transfer_list_abort_all(&instance->transfers_bulk_full);
+
+		if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
+			/* reinitialize hw, this triggers virtual disconnect*/
+			hc_init_hw(instance);
+		} else {
+			usb_log_fatal("Too many UHCI hardware failures!.\n");
+			hc_fini(instance);
+		}
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -132,8 +192,23 @@
 	    "Device registers at %p (%zuB) accessible.\n", io, reg_size);
 
+	ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
+	    bandwidth_count_usb11);
+	CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",
+	    str_error(ret));
+
+	instance->generic.private_data = instance;
+	instance->generic.schedule = hc_schedule;
+	instance->generic.ep_add_hook = NULL;
+
+#undef CHECK_RET_DEST_FUN_RETURN
+
 	ret = hc_init_mem_structures(instance);
-	CHECK_RET_RETURN(ret,
-	    "Failed to initialize UHCI memory structures: %s.\n",
-	    str_error(ret));
+	if (ret != EOK) {
+		usb_log_error(
+		    "Failed to initialize UHCI memory structures: %s.\n",
+		    str_error(ret));
+		hcd_destroy(&instance->generic);
+		return ret;
+	}
 
 	hc_init_hw(instance);
@@ -146,5 +221,4 @@
 
 	return EOK;
-#undef CHECK_RET_DEST_FUN_RETURN
 }
 /*----------------------------------------------------------------------------*/
@@ -154,5 +228,5 @@
  * For magic values see UHCI Design Guide
  */
-void hc_init_hw(hc_t *instance)
+void hc_init_hw(const hc_t *instance)
 {
 	assert(instance);
@@ -198,5 +272,4 @@
  *
  * Structures:
- *  - interrupt code (I/O addressses are customized per instance)
  *  - transfer lists (queue heads need to be accessible by the hw)
  *  - frame list page (needs to be one UHCI hw accessible 4K page)
@@ -205,32 +278,21 @@
 {
 	assert(instance);
-#define CHECK_RET_RETURN(ret, message...) \
-	if (ret != EOK) { \
-		usb_log_error(message); \
-		return ret; \
-	} else (void) 0
+
+	/* Init USB frame list page */
+	instance->frame_list = get_page();
+	if (!instance->frame_list) {
+		return ENOMEM;
+	}
+	usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
 
 	/* Init transfer lists */
 	int ret = hc_init_transfer_lists(instance);
-	CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n");
+	if (ret != EOK) {
+		usb_log_error("Failed to initialize transfer lists.\n");
+		return_page(instance->frame_list);
+		return ENOMEM;
+	}
 	usb_log_debug("Initialized transfer lists.\n");
 
-	/* Init device keeper */
-	usb_device_keeper_init(&instance->manager);
-	usb_log_debug("Initialized device keeper.\n");
-
-	ret = usb_endpoint_manager_init(&instance->ep_manager,
-	    BANDWIDTH_AVAILABLE_USB11);
-	CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
-	    str_error(ret));
-
-	/* Init USB frame list page*/
-	instance->frame_list = get_page();
-	if (!instance->frame_list) {
-		usb_log_error("Failed to get frame list page.\n");
-		usb_endpoint_manager_destroy(&instance->ep_manager);
-		return ENOMEM;
-	}
-	usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
 
 	/* Set all frames to point to the first queue head */
@@ -243,5 +305,4 @@
 
 	return EOK;
-#undef CHECK_RET_RETURN
 }
 /*----------------------------------------------------------------------------*/
@@ -316,72 +377,22 @@
  * Checks for bandwidth availability and appends the batch to the proper queue.
  */
-int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
-{
+int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
+{
+	assert(hcd);
+	hc_t *instance = hcd->private_data;
 	assert(instance);
 	assert(batch);
+	uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
+	if (!uhci_batch) {
+		usb_log_error("Failed to create UHCI transfer structures.\n");
+		return ENOMEM;
+	}
 
 	transfer_list_t *list =
 	    instance->transfers[batch->ep->speed][batch->ep->transfer_type];
 	assert(list);
-	transfer_list_add_batch(list, batch);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Take action based on the interrupt cause.
- *
- * @param[in] instance UHCI structure to use.
- * @param[in] status Value of the status register at the time of interrupt.
- *
- * Interrupt might indicate:
- * - transaction completed, either by triggering IOC, SPD, or an error
- * - some kind of device error
- * - resume from suspend state (not implemented)
- */
-void hc_interrupt(hc_t *instance, uint16_t status)
-{
-	assert(instance);
-	/* Lower 2 bits are transaction error and transaction complete */
-	if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
-		LIST_INITIALIZE(done);
-		transfer_list_remove_finished(
-		    &instance->transfers_interrupt, &done);
-		transfer_list_remove_finished(
-		    &instance->transfers_control_slow, &done);
-		transfer_list_remove_finished(
-		    &instance->transfers_control_full, &done);
-		transfer_list_remove_finished(
-		    &instance->transfers_bulk_full, &done);
-
-		while (!list_empty(&done)) {
-			link_t *item = list_first(&done);
-			list_remove(item);
-			usb_transfer_batch_t *batch =
-			    list_get_instance(item, usb_transfer_batch_t, link);
-			usb_transfer_batch_finish(batch);
-		}
-	}
-	/* Resume interrupts are not supported */
-	if (status & UHCI_STATUS_RESUME) {
-		usb_log_error("Resume interrupt!\n");
-	}
-
-	/* Bits 4 and 5 indicate hc error */
-	if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
-		usb_log_error("UHCI hardware failure!.\n");
-		++instance->hw_failures;
-		transfer_list_abort_all(&instance->transfers_interrupt);
-		transfer_list_abort_all(&instance->transfers_control_slow);
-		transfer_list_abort_all(&instance->transfers_control_full);
-		transfer_list_abort_all(&instance->transfers_bulk_full);
-
-		if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
-			/* reinitialize hw, this triggers virtual disconnect*/
-			hc_init_hw(instance);
-		} else {
-			usb_log_fatal("Too many UHCI hardware failures!.\n");
-			hc_fini(instance);
-		}
-	}
+	transfer_list_add_batch(list, uhci_batch);
+
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -403,8 +414,4 @@
 		if (status != 0)
 			usb_log_debug2("UHCI status: %x.\n", status);
-// Qemu fails to report stalled communication
-// see https://bugs.launchpad.net/qemu/+bug/757654
-// This is a simple workaround to force queue processing every time
-	//	status |= 1;
 		hc_interrupt(instance, status);
 		async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
@@ -412,5 +419,5 @@
 	return EOK;
 }
-/*---------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
 /** Debug function, checks consistency of memory structures.
  *
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -39,7 +39,5 @@
 #include <ddi.h>
 
-#include <usb/host/device_keeper.h>
-#include <usb/host/usb_endpoint_manager.h>
-#include <usb/host/batch.h>
+#include <usb/host/hcd.h>
 
 #include "transfer_list.h"
@@ -94,8 +92,6 @@
 /** Main UHCI driver structure */
 typedef struct hc {
-	/** USB bus driver, devices and addresses */
-	usb_device_keeper_t manager;
-	/** USB bus driver, endpoints */
-	usb_endpoint_manager_t ep_manager;
+	/** Generic HCD driver structure */
+	hcd_t generic;
 
 	/** Addresses of I/O registers */
@@ -124,10 +120,10 @@
 	unsigned hw_failures;
 } hc_t;
+
 size_t hc_irq_cmd_count(void);
 int hc_get_irq_commands(
     irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size);
+void hc_interrupt(hc_t *instance, uint16_t status);
 int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interupts);
-int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
-void hc_interrupt(hc_t *instance, uint16_t status);
 
 /** Safely dispose host controller internal structures
@@ -135,16 +131,5 @@
  * @param[in] instance Host controller structure to use.
  */
-static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ };
-
-/** Get and cast pointer to the driver data
- *
- * @param[in] fun DDF function pointer
- * @return cast pointer to driver_data
- */
-static inline hc_t * fun_to_hc(ddf_fun_t *fun)
-{
-	assert(fun);
-	return fun->driver_data;
-}
+static inline void hc_fini(hc_t *instance) {} /* TODO: implement*/
 #endif
 /**
Index: uspace/drv/bus/usb/uhci/hw_struct/link_pointer.h
===================================================================
--- uspace/drv/bus/usb/uhci/hw_struct/link_pointer.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/hw_struct/link_pointer.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -35,5 +35,5 @@
 #define DRV_UHCI_HW_STRUCT_LINK_POINTER_H
 
-/* UHCI link pointer, used by many data structures */
+/** UHCI link pointer, used by many data structures */
 typedef uint32_t link_pointer_t;
 
Index: uspace/drv/bus/usb/uhci/hw_struct/queue_head.h
===================================================================
--- uspace/drv/bus/usb/uhci/hw_struct/queue_head.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/hw_struct/queue_head.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -58,6 +58,6 @@
 	assert(instance);
 
-	instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
-	instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
+	instance->element = LINK_POINTER_TERM;
+	instance->next = LINK_POINTER_TERM;
 }
 /*----------------------------------------------------------------------------*/
@@ -71,5 +71,8 @@
 static inline void qh_set_next_qh(qh_t *instance, qh_t *next)
 {
-	uint32_t pa = addr_to_phys(next);
+	/* Physical address has to be below 4GB,
+	 * it is an UHCI limitation and malloc32
+	 * should guarantee this */
+	const uint32_t pa = addr_to_phys(next);
 	if (pa) {
 		instance->next = LINK_POINTER_QH(pa);
@@ -88,5 +91,8 @@
 static inline void qh_set_element_td(qh_t *instance, td_t *td)
 {
-	uint32_t pa = addr_to_phys(td);
+	/* Physical address has to be below 4GB,
+	 * it is an UHCI limitation and malloc32
+	 * should guarantee this */
+	const uint32_t pa = addr_to_phys(td);
 	if (pa) {
 		instance->element = LINK_POINTER_TD(pa);
Index: uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -61,6 +61,6 @@
  */
 void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso,
-    bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer,
-    td_t *next)
+    bool low_speed, usb_target_t target, usb_packet_id pid, const void *buffer,
+    const td_t *next)
 {
 	assert(instance);
@@ -113,5 +113,5 @@
  * @return Error code.
  */
-int td_status(td_t *instance)
+int td_status(const td_t *instance)
 {
 	assert(instance);
@@ -119,5 +119,5 @@
 	/* This is hc internal error it should never be reported. */
 	if ((instance->status & TD_STATUS_ERROR_BIT_STUFF) != 0)
-		return EAGAIN;
+		return EIO;
 
 	/* CRC or timeout error, like device not present or bad data,
@@ -150,5 +150,5 @@
  * @param[in] instance TD structure to use.
  */
-void td_print_status(td_t *instance)
+void td_print_status(const td_t *instance)
 {
 	assert(instance);
Index: uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -69,5 +69,5 @@
 #define TD_STATUS_ACTLEN_MASK 0x7ff
 
-	/* double word with USB device specific info */
+	/** Double word with USB device specific info */
 	volatile uint32_t device;
 #define TD_DEVICE_MAXLEN_POS 21
@@ -87,6 +87,6 @@
 	/* According to UHCI design guide, there is 16 bytes of
 	 * data available here.
-	 * According to linux kernel the hardware does not care,
-	 * it just needs to be aligned. We don't use it anyway.
+	 * According to Linux kernel the hardware does not care,
+	 * memory just needs to be aligned. We don't use it anyway.
 	 */
 } __attribute__((packed)) td_t;
@@ -95,9 +95,9 @@
 void td_init(td_t *instance, int error_count, size_t size, bool toggle,
     bool iso, bool low_speed, usb_target_t target, usb_packet_id pid,
-    void *buffer, td_t *next);
+    const void *buffer, const td_t *next);
 
-int td_status(td_t *instance);
+int td_status(const td_t *instance);
 
-void td_print_status(td_t *instance);
+void td_print_status(const td_t *instance);
 /*----------------------------------------------------------------------------*/
 /** Helper function for parsing actual size out of TD.
@@ -106,8 +106,9 @@
  * @return Parsed actual size.
  */
-static inline size_t td_act_size(td_t *instance)
+static inline size_t td_act_size(const td_t *instance)
 {
 	assert(instance);
 	const uint32_t s = instance->status;
+	/* Actual size is encoded as n-1 (UHCI design guide p. 23) */
 	return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
 }
@@ -119,5 +120,5 @@
  * false otherwise.
  */
-static inline bool td_is_short(td_t *instance)
+static inline bool td_is_short(const td_t *instance)
 {
 	const size_t act_size = td_act_size(instance);
@@ -134,5 +135,5 @@
  * @return Toggle bit value.
  */
-static inline int td_toggle(td_t *instance)
+static inline int td_toggle(const td_t *instance)
 {
 	assert(instance);
@@ -145,5 +146,5 @@
  * @return Active bit value.
  */
-static inline bool td_is_active(td_t *instance)
+static inline bool td_is_active(const td_t *instance)
 {
 	assert(instance);
Index: pace/drv/bus/usb/uhci/iface.c
===================================================================
--- uspace/drv/bus/usb/uhci/iface.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,405 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky, 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 drvusbuhcihc
- * @{
- */
-/** @file
- * @brief UHCI driver hc interface implementation
- */
-#include <ddf/driver.h>
-#include <errno.h>
-
-#include <usb/debug.h>
-#include <usb/host/endpoint.h>
-
-#include "iface.h"
-#include "batch.h"
-#include "hc.h"
-
-static inline int setup_batch(
-    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
-    void *data, size_t size, void * setup_data, size_t setup_size,
-    usbhc_iface_transfer_in_callback_t in,
-    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
-    hc_t **hc, usb_transfer_batch_t **batch)
-{
-	assert(hc);
-	assert(batch);
-	assert(fun);
-	*hc = fun_to_hc(fun);
-	assert(*hc);
-
-	size_t res_bw;
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,
-	    target.address, target.endpoint, direction, &res_bw);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
-		    target.address, target.endpoint, name);
-		return ENOENT;
-	}
-
-	usb_log_debug2("%s %d:%d %zu(%zu).\n",
-	    name, target.address, target.endpoint, size, ep->max_packet_size);
-
-	const size_t bw = bandwidth_count_usb11(
-	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
-	if (res_bw < bw) {
-		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
-		    "but only %zu is reserved.\n",
-		    target.address, target.endpoint, name, bw, res_bw);
-		return ENOSPC;
-	}
-
-	*batch = batch_get(
-	        fun, ep, data, size, setup_data, setup_size, in, out, arg);
-	if (!*batch)
-		return ENOMEM;
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Request address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] speed Speed to associate with the new default address.
- * @param[out] address Place to write a new address.
- * @return Error code.
- */
-static int request_address(
-    ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	assert(address);
-
-	usb_log_debug("Address request with speed %d.\n", speed);
-	*address = device_keeper_get_free_address(&hc->manager, speed);
-	usb_log_debug("Address request with result: %d.\n", *address);
-	if (*address <= 0)
-		return *address;
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Bind address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address of the device
- * @param[in] handle Devman handle of the device driver.
- * @return Error code.
- */
-static int bind_address(
-  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
-	usb_device_keeper_bind(&hc->manager, address, handle);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Find device handle by address interface function.
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address in question.
- * @param[out] handle Where to store device handle if found.
- * @return Error code.
- */
-static int find_by_address(ddf_fun_t *fun, usb_address_t address,
-    devman_handle_t *handle)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	const bool found =
-	    usb_device_keeper_find_by_address(&hc->manager, address, handle);
-	return found ? EOK : ENOENT;
-}
-/*----------------------------------------------------------------------------*/
-/** Release address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address USB address to be released.
- * @return Error code.
- */
-static int release_address(ddf_fun_t *fun, usb_address_t address)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Address release %d.\n", address);
-	usb_device_keeper_release(&hc->manager, address);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-static int register_endpoint(
-    ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed,
-    usb_endpoint_t endpoint,
-    usb_transfer_type_t transfer_type, usb_direction_t direction,
-    size_t max_packet_size, unsigned int interval)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	const size_t size = max_packet_size;
-	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
-	if (speed >= USB_SPEED_MAX) {
-		speed = ep_speed;
-	}
-	usb_log_debug("Register endpoint %d:%d %s-%s %s %zuB %ums.\n",
-	    address, endpoint, usb_str_transfer_type(transfer_type),
-	    usb_str_direction(direction), usb_str_speed(speed),
-	    max_packet_size, interval);
-
-	return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint,
-	    direction, transfer_type, speed, max_packet_size, size);
-}
-/*----------------------------------------------------------------------------*/
-static int unregister_endpoint(
-    ddf_fun_t *fun, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Unregister endpoint %d:%d %s.\n",
-	    address, endpoint, usb_str_direction(direction));
-	return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
-	    endpoint, direction);
-}
-/*----------------------------------------------------------------------------*/
-/** Interrupt out transaction interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] target USB device to write to.
- * @param[in] data Source of data.
- * @param[in] size Size of data source.
- * @param[in] callback Function to call on transaction completion
- * @param[in] arg Additional for callback function.
- * @return Error code.
- */
-static int interrupt_out(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
-	    NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	assert(batch);
-	assert(hc);
-	batch_interrupt_out(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Interrupt in transaction interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] target USB device to write to.
- * @param[out] data Data destination.
- * @param[in] size Size of data source.
- * @param[in] callback Function to call on transaction completion
- * @param[in] arg Additional for callback function.
- * @return Error code.
- */
-static int interrupt_in(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
-	    NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	assert(batch);
-	assert(hc);
-	batch_interrupt_in(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Bulk out transaction interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] target USB device to write to.
- * @param[in] data Source of data.
- * @param[in] size Size of data source.
- * @param[in] callback Function to call on transaction completion
- * @param[in] arg Additional for callback function.
- * @return Error code.
- */
-static int bulk_out(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
-	    NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	assert(batch);
-	assert(hc);
-	batch_bulk_out(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Bulk in transaction interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] target USB device to write to.
- * @param[out] data Data destination.
- * @param[in] size Size of data source.
- * @param[in] callback Function to call on transaction completion
- * @param[in] arg Additional for callback function.
- * @return Error code.
- */
-static int bulk_in(
-    ddf_fun_t *fun, usb_target_t target, void *data,
-    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
-	    NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	assert(batch);
-	assert(hc);
-	batch_bulk_in(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Control write transaction interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] target USB device to write to.
- * @param[in] setup_data Data to send with SETUP transfer.
- * @param[in] setup_size Size of data to send with SETUP transfer (always 8B).
- * @param[in] data Source of data.
- * @param[in] size Size of data source.
- * @param[in] callback Function to call on transaction completion.
- * @param[in] arg Additional for callback function.
- * @return Error code.
- */
-static int control_write(
-    ddf_fun_t *fun, usb_target_t target,
-    void *setup_data, size_t setup_size, void *data, size_t size,
-    usbhc_iface_transfer_out_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
-	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
-	    &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	assert(batch);
-	assert(hc);
-	usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
-	batch_control_write(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Control read transaction interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] target USB device to write to.
- * @param[in] setup_data Data to send with SETUP packet.
- * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
- * @param[out] data Source of data.
- * @param[in] size Size of data source.
- * @param[in] callback Function to call on transaction completion.
- * @param[in] arg Additional for callback function.
- * @return Error code.
- */
-static int control_read(
-    ddf_fun_t *fun, usb_target_t target,
-    void *setup_data, size_t setup_size, void *data, size_t size,
-    usbhc_iface_transfer_in_callback_t callback, void *arg)
-{
-	usb_transfer_batch_t *batch = NULL;
-	hc_t *hc = NULL;
-	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
-	    setup_data, setup_size, callback, NULL, arg, "Control READ",
-	    &hc, &batch);
-	if (ret != EOK)
-		return ret;
-	assert(batch);
-	assert(hc);
-	batch_control_read(batch);
-	ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		usb_transfer_batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-usbhc_iface_t hc_iface = {
-	.request_address = request_address,
-	.bind_address = bind_address,
-	.find_by_address = find_by_address,
-	.release_address = release_address,
-
-	.register_endpoint = register_endpoint,
-	.unregister_endpoint = unregister_endpoint,
-
-	.interrupt_out = interrupt_out,
-	.interrupt_in = interrupt_in,
-
-	.bulk_out = bulk_out,
-	.bulk_in = bulk_in,
-
-	.control_write = control_write,
-	.control_read = control_read,
-};
-/**
- * @}
- */
Index: pace/drv/bus/usb/uhci/iface.h
===================================================================
--- uspace/drv/bus/usb/uhci/iface.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * 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 drvusbuhcihc
- * @{
- */
-/** @file
- * @brief UHCI driver iface
- */
-#ifndef DRV_UHCI_IFACE_H
-#define DRV_UHCI_IFACE_H
-
-#include <usbhc_iface.h>
-
-extern usbhc_iface_t hc_iface;
-
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/main.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -64,13 +64,14 @@
 	assert(device);
 
-	int ret = device_setup_uhci(device);
+	const int ret = device_setup_uhci(device);
 	if (ret != EOK) {
 		usb_log_error("Failed to initialize UHCI driver: %s.\n",
 		    str_error(ret));
-		return ret;
+	} else {
+		usb_log_info("Controlling new UHCI device '%s'.\n",
+		    device->name);
 	}
-	usb_log_info("Controlling new UHCI device '%s'.\n", device->name);
 
-	return EOK;
+	return ret;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/uhci/pci.c
===================================================================
--- uspace/drv/bus/usb/uhci/pci.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/pci.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -61,5 +61,5 @@
 	assert(io_reg_size);
 	assert(irq_no);
-	
+
 	async_sess_t *parent_sess =
 	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
@@ -67,19 +67,19 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	hw_resource_list_t hw_resources;
-	int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	const int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	async_hangup(parent_sess);
 	if (rc != EOK) {
-		async_hangup(parent_sess);
 		return rc;
 	}
-	
+
 	uintptr_t io_address = 0;
 	size_t io_size = 0;
 	bool io_found = false;
-	
+
 	int irq = 0;
 	bool irq_found = false;
-	
+
 	size_t i;
 	for (i = 0; i < hw_resources.count; i++) {
@@ -102,17 +102,16 @@
 		}
 	}
-	
-	async_hangup(parent_sess);
-	
+	free(hw_resources.resources);
+
 	if (!io_found || !irq_found)
 		return ENOENT;
-	
+
 	*io_reg_address = io_address;
 	*io_reg_size = io_size;
 	*irq_no = irq;
-	
+
 	return EOK;
 }
-
+/*----------------------------------------------------------------------------*/
 /** Call the PCI driver with a request to enable interrupts
  *
@@ -127,11 +126,11 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	const bool enabled = hw_res_enable_interrupt(parent_sess);
 	async_hangup(parent_sess);
-	
+
 	return enabled ? EOK : EIO;
 }
-
+/*----------------------------------------------------------------------------*/
 /** Call the PCI driver with a request to clear legacy support register
  *
@@ -142,5 +141,5 @@
 {
 	assert(device);
-	
+
 	async_sess_t *parent_sess =
 	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle,
@@ -148,18 +147,18 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	/* See UHCI design guide for these values p.45,
 	 * write all WC bits in USB legacy register */
 	const sysarg_t address = 0xc0;
 	const sysarg_t value = 0xaf00;
-	
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
+
 	const int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
 	    IPC_M_CONFIG_SPACE_WRITE_16, address, value);
-	
+
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
-	
+
 	return rc;
 }
Index: uspace/drv/bus/usb/uhci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/uhci/root_hub.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/root_hub.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -50,14 +50,6 @@
 int rh_init(rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size)
 {
-	int ret;
-
+	assert(instance);
 	assert(fun);
-
-	ret = ddf_fun_add_match_id(fun, "usb&uhci&root-hub", 100);
-	if (ret != EOK) {
-		usb_log_error("Failed to add root hub match id: %s\n",
-		    str_error(ret));
-		return ret;
-	}
 
 	/* Initialize resource structure */
@@ -70,5 +62,10 @@
 	instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN;
 
-	return EOK;
+	const int ret = ddf_fun_add_match_id(fun, "usb&uhci&root-hub", 100);
+	if (ret != EOK) {
+		usb_log_error("Failed to add root hub match id: %s\n",
+		    str_error(ret));
+	}
+	return ret;
 }
 /**
Index: uspace/drv/bus/usb/uhci/transfer_list.c
===================================================================
--- uspace/drv/bus/usb/uhci/transfer_list.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/transfer_list.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -37,9 +37,9 @@
 #include <usb/debug.h>
 #include <libarch/barrier.h>
+
 #include "transfer_list.h"
-#include "batch.h"
 
 static void transfer_list_remove_batch(
-    transfer_list_t *instance, usb_transfer_batch_t *batch);
+    transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch);
 /*----------------------------------------------------------------------------*/
 /** Initialize transfer list structures.
@@ -106,24 +106,22 @@
  */
 void transfer_list_add_batch(
-    transfer_list_t *instance, usb_transfer_batch_t *batch)
-{
-	assert(instance);
-	assert(batch);
-	usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
+    transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch)
+{
+	assert(instance);
+	assert(uhci_batch);
+	usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name,
+	    uhci_batch->usb_batch);
 
 	fibril_mutex_lock(&instance->guard);
 
-	qh_t *last_qh = NULL;
+	/* Assume there is nothing scheduled */
+	qh_t *last_qh = instance->queue_head;
+	/* There is something scheduled */
+	if (!list_empty(&instance->batch_list)) {
+		last_qh = uhci_transfer_batch_from_link(
+		    list_last(&instance->batch_list))->qh;
+	}
 	/* Add to the hardware queue. */
-	if (list_empty(&instance->batch_list)) {
-		/* There is nothing scheduled */
-		last_qh = instance->queue_head;
-	} else {
-		/* There is something scheduled */
-		usb_transfer_batch_t *last = usb_transfer_batch_from_link(
-		    list_last(&instance->batch_list));
-		last_qh = batch_qh(last);
-	}
-	const uint32_t pa = addr_to_phys(batch_qh(batch));
+	const uint32_t pa = addr_to_phys(uhci_batch->qh);
 	assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
 
@@ -132,6 +130,6 @@
 
 	/* keep link */
-	batch_qh(batch)->next = last_qh->next;
-	qh_set_next_qh(last_qh, batch_qh(batch));
+	uhci_batch->qh->next = last_qh->next;
+	qh_set_next_qh(last_qh, uhci_batch->qh);
 
 	/* Make sure the pointer is updated */
@@ -139,8 +137,9 @@
 
 	/* Add to the driver's list */
-	list_append(&batch->link, &instance->batch_list);
+	list_append(&uhci_batch->link, &instance->batch_list);
 
 	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " scheduled in queue %s.\n",
-	    batch, USB_TRANSFER_BATCH_ARGS(*batch), instance->name);
+	    uhci_batch, USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch),
+	    instance->name);
 	fibril_mutex_unlock(&instance->guard);
 }
@@ -157,11 +156,11 @@
 
 	fibril_mutex_lock(&instance->guard);
-	link_t *current = instance->batch_list.head.next;
-	while (current != &instance->batch_list.head) {
+	link_t *current = list_first(&instance->batch_list);
+	while (current && current != &instance->batch_list.head) {
 		link_t * const next = current->next;
-		usb_transfer_batch_t *batch =
-		    usb_transfer_batch_from_link(current);
-
-		if (batch_is_complete(batch)) {
+		uhci_transfer_batch_t *batch =
+		    uhci_transfer_batch_from_link(current);
+
+		if (uhci_transfer_batch_is_complete(batch)) {
 			/* Save for processing */
 			transfer_list_remove_batch(instance, batch);
@@ -182,8 +181,9 @@
 	while (!list_empty(&instance->batch_list)) {
 		link_t * const current = list_first(&instance->batch_list);
-		usb_transfer_batch_t *batch =
-		    usb_transfer_batch_from_link(current);
+		uhci_transfer_batch_t *batch =
+		    uhci_transfer_batch_from_link(current);
 		transfer_list_remove_batch(instance, batch);
-		usb_transfer_batch_finish_error(batch, EINTR);
+		batch->usb_batch->error = EINTR;
+		uhci_transfer_batch_call_dispose(batch);
 	}
 	fibril_mutex_unlock(&instance->guard);
@@ -198,32 +198,28 @@
  */
 void transfer_list_remove_batch(
-    transfer_list_t *instance, usb_transfer_batch_t *batch)
+    transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch)
 {
 	assert(instance);
 	assert(instance->queue_head);
-	assert(batch);
-	assert(batch_qh(batch));
+	assert(uhci_batch);
+	assert(uhci_batch->qh);
 	assert(fibril_mutex_is_locked(&instance->guard));
 
-	usb_log_debug2(
-	    "Queue %s: removing batch(%p).\n", instance->name, batch);
-
-	const char *qpos = NULL;
-	qh_t *prev_qh = NULL;
+	usb_log_debug2("Queue %s: removing batch(%p).\n",
+	    instance->name, uhci_batch->usb_batch);
+
+	/* Assume I'm the first */
+	const char *qpos = "FIRST";
+	qh_t *prev_qh = instance->queue_head;
 	/* Remove from the hardware queue */
-	if (list_first(&instance->batch_list) == &batch->link) {
-		/* I'm the first one here */
-		prev_qh = instance->queue_head;
-		qpos = "FIRST";
-	} else {
-		/* The thing before me is a batch too */
-		usb_transfer_batch_t *prev =
-		    usb_transfer_batch_from_link(batch->link.prev);
-		prev_qh = batch_qh(prev);
+	if (list_first(&instance->batch_list) != &uhci_batch->link) {
+		/* There is a batch in front of me */
+		prev_qh =
+		    uhci_transfer_batch_from_link(uhci_batch->link.prev)->qh;
 		qpos = "NOT FIRST";
 	}
 	assert((prev_qh->next & LINK_POINTER_ADDRESS_MASK)
-	    == addr_to_phys(batch_qh(batch)));
-	prev_qh->next = batch_qh(batch)->next;
+	    == addr_to_phys(uhci_batch->qh));
+	prev_qh->next = uhci_batch->qh->next;
 
 	/* Make sure the pointer is updated */
@@ -231,9 +227,9 @@
 
 	/* Remove from the batch list */
-	list_remove(&batch->link);
+	list_remove(&uhci_batch->link);
 	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " removed (%s) "
 	    "from %s, next: %x.\n",
-	    batch, USB_TRANSFER_BATCH_ARGS(*batch),
-	    qpos, instance->name, batch_qh(batch)->next);
+	    uhci_batch, USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch),
+	    qpos, instance->name, uhci_batch->qh->next);
 }
 /**
Index: uspace/drv/bus/usb/uhci/transfer_list.h
===================================================================
--- uspace/drv/bus/usb/uhci/transfer_list.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/transfer_list.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -36,8 +36,7 @@
 
 #include <fibril_synch.h>
-#include <usb/host/batch.h>
 
 #include "hw_struct/queue_head.h"
-
+#include "uhci_batch.h"
 /** Structure maintaining both hw queue and software list
  * of currently executed transfers
@@ -46,5 +45,5 @@
 	/** Guard against multiple add/remove races */
 	fibril_mutex_t guard;
-	/** UHCI hw structure represeting this queue */
+	/** UHCI hw structure representing this queue */
 	qh_t *queue_head;
 	/** Assigned name, for nicer debug output */
@@ -58,5 +57,5 @@
 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);
 void transfer_list_add_batch(
-    transfer_list_t *instance, usb_transfer_batch_t *batch);
+    transfer_list_t *instance, uhci_transfer_batch_t *batch);
 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done);
 void transfer_list_abort_all(transfer_list_t *instance);
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -41,5 +41,4 @@
 
 #include "uhci.h"
-#include "iface.h"
 #include "pci.h"
 
@@ -87,5 +86,5 @@
 /** Operations supported by the HC driver */
 static ddf_dev_ops_t hc_ops = {
-	.interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */
+	.interfaces[USBHC_DEV_IFACE] = &hcd_iface, /* see iface.h/c */
 };
 /*----------------------------------------------------------------------------*/
@@ -100,6 +99,7 @@
 {
 	assert(fun);
-	usb_device_keeper_t *manager = &dev_to_uhci(fun->dev)->hc.manager;
-	usb_address_t addr = usb_device_keeper_find(manager, handle);
+	usb_device_manager_t *manager =
+	    &dev_to_uhci(fun->dev)->hc.generic.dev_manager;
+	const usb_address_t addr = usb_device_manager_find(manager, handle);
 
 	if (addr < 0) {
@@ -202,5 +202,5 @@
 	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI HC function.\n");
 	instance->hc_fun->ops = &hc_ops;
-	instance->hc_fun->driver_data = &instance->hc;
+	instance->hc_fun->driver_data = &instance->hc.generic;
 
 	instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci_rh");
Index: uspace/drv/bus/usb/uhci/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,347 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI driver USB transfer structure
+ */
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+
+#include "uhci_batch.h"
+#include "transfer_list.h"
+#include "hw_struct/transfer_descriptor.h"
+#include "utils/malloc32.h"
+
+#define DEFAULT_ERROR_COUNT 3
+
+static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch)
+{
+	if (uhci_batch) {
+		usb_transfer_batch_dispose(uhci_batch->usb_batch);
+		free32(uhci_batch->device_buffer);
+		free(uhci_batch);
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Safely destructs uhci_transfer_batch_t structure
+ *
+ * @param[in] uhci_batch Instance to destroy.
+ */
+void uhci_transfer_batch_call_dispose(uhci_transfer_batch_t *uhci_batch)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->usb_batch);
+	usb_transfer_batch_finish(uhci_batch->usb_batch,
+	    uhci_transfer_batch_data_buffer(uhci_batch),
+	    uhci_batch->usb_batch->buffer_size);
+	uhci_transfer_batch_dispose(uhci_batch);
+}
+/*----------------------------------------------------------------------------*/
+static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t);
+/*----------------------------------------------------------------------------*/
+/** Allocate memory and initialize internal data structure.
+ *
+ * @param[in] fun DDF function to pass to callback.
+ * @param[in] ep Communication target
+ * @param[in] buffer Data source/destination.
+ * @param[in] buffer_size Size of the buffer.
+ * @param[in] setup_buffer Setup data source (if not NULL)
+ * @param[in] setup_size Size of setup_buffer (should be always 8)
+ * @param[in] func_in function to call on inbound transfer completion
+ * @param[in] func_out function to call on outbound transfer completion
+ * @param[in] arg additional parameter to func_in or func_out
+ * @return Valid pointer if all structures were successfully created,
+ * NULL otherwise.
+ *
+ * Determines the number of needed transfer descriptors (TDs).
+ * Prepares a transport buffer (that is accessible by the hardware).
+ * Initializes parameters needed for the transfer and callback.
+ */
+uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
+{
+	assert((sizeof(td_t) % 16) == 0);
+#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
+	if (ptr == NULL) { \
+		usb_log_error(message); \
+		uhci_transfer_batch_dispose(uhci_batch); \
+		return NULL; \
+	} else (void)0
+
+	uhci_transfer_batch_t *uhci_batch =
+	    calloc(1, sizeof(uhci_transfer_batch_t));
+	CHECK_NULL_DISPOSE_RETURN(uhci_batch,
+	    "Failed to allocate UHCI batch.\n");
+	link_initialize(&uhci_batch->link);
+	uhci_batch->td_count =
+	    (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1)
+	    / usb_batch->ep->max_packet_size;
+	if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
+		uhci_batch->td_count += 2;
+	}
+
+	const size_t total_size = (sizeof(td_t) * uhci_batch->td_count)
+	    + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size;
+	uhci_batch->device_buffer = malloc32(total_size);
+	CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer,
+	    "Failed to allocate UHCI buffer.\n");
+	bzero(uhci_batch->device_buffer, total_size);
+
+	uhci_batch->tds = uhci_batch->device_buffer;
+	uhci_batch->qh =
+	    (uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count));
+
+	qh_init(uhci_batch->qh);
+	qh_set_element_td(uhci_batch->qh, &uhci_batch->tds[0]);
+
+	void *dest =
+	    uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count)
+	    + sizeof(qh_t);
+	/* Copy SETUP packet data to the device buffer */
+	memcpy(dest, usb_batch->setup_buffer, usb_batch->setup_size);
+	dest += usb_batch->setup_size;
+	/* Copy generic data unless they are provided by the device */
+	if (usb_batch->ep->direction != USB_DIRECTION_IN) {
+		memcpy(dest, usb_batch->buffer, usb_batch->buffer_size);
+	}
+	uhci_batch->usb_batch = usb_batch;
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
+	    " memory structures ready.\n", usb_batch,
+	    USB_TRANSFER_BATCH_ARGS(*usb_batch));
+
+	const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
+
+	assert(batch_setup[usb_batch->ep->transfer_type]);
+	batch_setup[usb_batch->ep->transfer_type](uhci_batch, dir);
+
+	return uhci_batch;
+}
+/*----------------------------------------------------------------------------*/
+/** Check batch TDs for activity.
+ *
+ * @param[in] uhci_batch Batch structure to use.
+ * @return False, if there is an active TD, true otherwise.
+ *
+ * Walk all TDs. Stop with false if there is an active one (it is to be
+ * processed). Stop with true if an error is found. Return true if the last TD
+ * is reached.
+ */
+bool uhci_transfer_batch_is_complete(uhci_transfer_batch_t *uhci_batch)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->usb_batch);
+
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
+	    " checking %zu transfer(s) for completion.\n",
+	    uhci_batch->usb_batch,
+	    USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch),
+	    uhci_batch->td_count);
+	uhci_batch->usb_batch->transfered_size = 0;
+	size_t i = 0;
+	for (;i < uhci_batch->td_count; ++i) {
+		if (td_is_active(&uhci_batch->tds[i])) {
+			return false;
+		}
+
+		uhci_batch->usb_batch->error = td_status(&uhci_batch->tds[i]);
+		if (uhci_batch->usb_batch->error != EOK) {
+			assert(uhci_batch->usb_batch->ep != NULL);
+
+			usb_log_debug("Batch(%p) found error TD(%zu):%"
+			    PRIx32 ".\n", uhci_batch->usb_batch, i,
+			    uhci_batch->tds[i].status);
+			td_print_status(&uhci_batch->tds[i]);
+
+			endpoint_toggle_set(uhci_batch->usb_batch->ep,
+			    td_toggle(&uhci_batch->tds[i]));
+			if (i > 0)
+				goto substract_ret;
+			return true;
+		}
+
+		uhci_batch->usb_batch->transfered_size
+		    += td_act_size(&uhci_batch->tds[i]);
+		if (td_is_short(&uhci_batch->tds[i]))
+			goto substract_ret;
+	}
+substract_ret:
+	uhci_batch->usb_batch->transfered_size
+	    -= uhci_batch->usb_batch->setup_size;
+	return true;
+}
+/*----------------------------------------------------------------------------*/
+static const usb_packet_id direction_pids[] = {
+	[USB_DIRECTION_IN] = USB_PID_IN,
+	[USB_DIRECTION_OUT] = USB_PID_OUT,
+};
+/*----------------------------------------------------------------------------*/
+/** Prepare generic data transfer
+ *
+ * @param[in] uhci_batch Batch structure to use.
+ * @param[in] dir Communication direction.
+ *
+ * Transactions with alternating toggle bit and supplied pid value.
+ * The last transfer is marked with IOC flag.
+ */
+static void batch_data(uhci_transfer_batch_t *uhci_batch, usb_direction_t dir)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->usb_batch);
+	assert(uhci_batch->usb_batch->ep);
+	assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN);
+
+
+	const usb_packet_id pid = direction_pids[dir];
+	const bool low_speed =
+	    uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW;
+	const size_t mps = uhci_batch->usb_batch->ep->max_packet_size;
+	const usb_target_t target = {{
+	    uhci_batch->usb_batch->ep->address,
+	    uhci_batch->usb_batch->ep->endpoint }};
+
+	int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep);
+	assert(toggle == 0 || toggle == 1);
+
+	size_t td = 0;
+	size_t remain_size = uhci_batch->usb_batch->buffer_size;
+	char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
+
+	while (remain_size > 0) {
+		const size_t packet_size =
+		    (remain_size < mps) ? remain_size : mps;
+
+		const td_t *next_td = (td + 1 < uhci_batch->td_count)
+		    ? &uhci_batch->tds[td + 1] : NULL;
+
+		assert(td < uhci_batch->td_count);
+		td_init(
+		    &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, target, pid, buffer, next_td);
+
+		++td;
+		toggle = 1 - toggle;
+		buffer += packet_size;
+		remain_size -= packet_size;
+	}
+	td_set_ioc(&uhci_batch->tds[td - 1]);
+	endpoint_toggle_set(uhci_batch->usb_batch->ep, toggle);
+	usb_log_debug2(
+	    "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
+	    uhci_batch->usb_batch,
+	    usb_str_transfer_type(uhci_batch->usb_batch->ep->transfer_type),
+	    usb_str_direction(uhci_batch->usb_batch->ep->direction),
+	    USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch));
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic control transfer
+ *
+ * @param[in] uhci_batch Batch structure to use.
+ * @param[in] dir Communication direction.
+ *
+ * Setup stage with toggle 0 and USB_PID_SETUP.
+ * Data stage with alternating toggle and pid determined by the communication
+ * direction.
+ * Status stage with toggle 1 and pid determined by the communication direction.
+ * The last transfer is marked with IOC.
+ */
+static void batch_control(uhci_transfer_batch_t *uhci_batch, usb_direction_t dir)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->usb_batch);
+	assert(uhci_batch->usb_batch->ep);
+	assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN);
+	assert(uhci_batch->td_count >= 2);
+	static const usb_packet_id status_stage_pids[] = {
+		[USB_DIRECTION_IN] = USB_PID_OUT,
+		[USB_DIRECTION_OUT] = USB_PID_IN,
+	};
+
+	const usb_packet_id data_stage_pid = direction_pids[dir];
+	const usb_packet_id status_stage_pid = status_stage_pids[dir];
+	const bool low_speed =
+	    uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW;
+	const size_t mps = uhci_batch->usb_batch->ep->max_packet_size;
+	const usb_target_t target = {{
+	    uhci_batch->usb_batch->ep->address,
+	    uhci_batch->usb_batch->ep->endpoint }};
+
+	/* setup stage */
+	td_init(
+	    &uhci_batch->tds[0], DEFAULT_ERROR_COUNT,
+	    uhci_batch->usb_batch->setup_size, 0, false,
+	    low_speed, target, USB_PID_SETUP,
+	    uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]);
+
+	/* data stage */
+	size_t td = 1;
+	unsigned toggle = 1;
+	size_t remain_size = uhci_batch->usb_batch->buffer_size;
+	char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
+
+	while (remain_size > 0) {
+		const size_t packet_size =
+		    (remain_size < mps) ? remain_size : mps;
+
+		td_init(
+		    &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, target, data_stage_pid,
+		    buffer, &uhci_batch->tds[td + 1]);
+
+		++td;
+		toggle = 1 - toggle;
+		buffer += packet_size;
+		remain_size -= packet_size;
+		assert(td < uhci_batch->td_count);
+	}
+
+	/* status stage */
+	assert(td == uhci_batch->td_count - 1);
+
+	td_init(
+	    &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
+	    target, status_stage_pid, NULL, NULL);
+	td_set_ioc(&uhci_batch->tds[td]);
+
+	usb_log_debug2("Control last TD status: %x.\n",
+	    uhci_batch->tds[td].status);
+}
+/*----------------------------------------------------------------------------*/
+static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t) =
+{
+	[USB_TRANSFER_CONTROL] = batch_control,
+	[USB_TRANSFER_BULK] = batch_data,
+	[USB_TRANSFER_INTERRUPT] = batch_data,
+	[USB_TRANSFER_ISOCHRONOUS] = NULL,
+};
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/uhci/uhci_batch.h
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/drv/bus/usb/uhci/uhci_batch.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,93 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI driver USB tranfer helper functions
+ */
+#ifndef DRV_UHCI_BATCH_H
+#define DRV_UHCI_BATCH_H
+
+#include <usb/host/usb_transfer_batch.h>
+#include <adt/list.h>
+
+#include "hw_struct/queue_head.h"
+#include "hw_struct/transfer_descriptor.h"
+
+/** UHCI specific data required for USB transfer */
+typedef struct uhci_transfer_batch {
+	/** Queue head
+	 * This QH is used to maintain UHCI schedule structure and the element
+	 * pointer points to the first TD of this batch.
+	 */
+	qh_t *qh;
+	/** List of TDs needed for the transfer */
+	td_t *tds;
+	/** Number of TDs used by the transfer */
+	size_t td_count;
+	/** Data buffer, must be accessible by the UHCI hw */
+	void *device_buffer;
+	/** Generic transfer data */
+	usb_transfer_batch_t *usb_batch;
+	/** List element */
+	link_t link;
+} uhci_transfer_batch_t;
+
+uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch);
+void uhci_transfer_batch_call_dispose(uhci_transfer_batch_t *uhci_batch);
+bool uhci_transfer_batch_is_complete(uhci_transfer_batch_t *uhci_batch);
+
+static inline void * uhci_transfer_batch_setup_buffer(
+    const uhci_transfer_batch_t *uhci_batch)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->device_buffer);
+	return uhci_batch->device_buffer + sizeof(qh_t) +
+	    uhci_batch->td_count * sizeof(td_t);
+}
+/*----------------------------------------------------------------------------*/
+static inline void * uhci_transfer_batch_data_buffer(
+    const uhci_transfer_batch_t *uhci_batch)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->usb_batch);
+	return uhci_transfer_batch_setup_buffer(uhci_batch) +
+	    uhci_batch->usb_batch->setup_size;
+}
+/*----------------------------------------------------------------------------*/
+static inline uhci_transfer_batch_t *uhci_transfer_batch_from_link(link_t *l)
+{
+	assert(l);
+	return list_get_instance(l, uhci_transfer_batch_t, link);
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/uhci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -50,5 +50,5 @@
  * @return Physical address if exists, NULL otherwise.
  */
-static inline uintptr_t addr_to_phys(void *addr)
+static inline uintptr_t addr_to_phys(const void *addr)
 {
 	if (addr == NULL)
@@ -102,9 +102,15 @@
 	if (free_address == 0)
 		return NULL;
-	void *ret = as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE,
+	void *address = as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE,
 		  AS_AREA_READ | AS_AREA_WRITE);
-	if (ret != free_address)
+	if (address != free_address)
 		return NULL;
-	return ret;
+	return address;
+}
+/*----------------------------------------------------------------------------*/
+static inline void return_page(void *page)
+{
+	if (page)
+		as_area_destroy(page);
 }
 
Index: uspace/drv/bus/usb/vhc/connhost.c
===================================================================
--- uspace/drv/bus/usb/vhc/connhost.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/vhc/connhost.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -62,6 +62,6 @@
 	VHC_DATA(vhc, fun);
 
-	usb_address_t addr = device_keeper_get_free_address(&vhc->dev_keeper,
-	    USB_SPEED_HIGH);
+	usb_address_t addr = usb_device_manager_get_free_address(
+	    &vhc->dev_manager, USB_SPEED_HIGH);
 	if (addr < 0) {
 		return addr;
@@ -88,5 +88,5 @@
 	usb_log_debug("Binding handle %" PRIun " to address %d.\n",
 	    handle, address);
-	usb_device_keeper_bind(&vhc->dev_keeper, address, handle);
+	usb_device_manager_bind(&vhc->dev_manager, address, handle);
 
 	return EOK;
@@ -105,5 +105,5 @@
 	VHC_DATA(vhc, fun);
 	bool found =
-	    usb_device_keeper_find_by_address(&vhc->dev_keeper, address, handle);
+	    usb_device_manager_find_by_address(&vhc->dev_manager, address, handle);
 	return found ? EOK : ENOENT;
 }
@@ -119,5 +119,5 @@
 	VHC_DATA(vhc, fun);
 	usb_log_debug("Releasing address %d...\n", address);
-	usb_device_keeper_release(&vhc->dev_keeper, address);
+	usb_device_manager_release(&vhc->dev_manager, address);
 
 	return ENOTSUP;
@@ -172,10 +172,4 @@
 	VHC_DATA(vhc, fun);
 
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
-	    address, endpoint, direction, NULL);
-	if (ep == NULL) {
-		return ENOENT;
-	}
-
 	int rc = usb_endpoint_manager_unregister_ep(&vhc->ep_manager,
 	    address, endpoint, direction);
@@ -183,5 +177,5 @@
 	return rc;
 }
-
+#if 0
 /** Schedule interrupt out transfer.
  *
@@ -413,4 +407,84 @@
 	return EOK;
 }
+#endif
+static int usb_read(ddf_fun_t *fun, usb_target_t target, uint64_t setup_buffer,
+    uint8_t *data_buffer, size_t data_buffer_size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	VHC_DATA(vhc, fun);
+
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
+	    target.address, target.endpoint, USB_DIRECTION_IN, NULL);
+	if (ep == NULL) {
+		return ENOENT;
+	}
+	const usb_transfer_type_t transfer_type = ep->transfer_type;
+
+
+	vhc_transfer_t *transfer = vhc_transfer_create(target.address,
+	    target.endpoint, USB_DIRECTION_IN, transfer_type,
+	    fun, arg);
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+	if (transfer_type == USB_TRANSFER_CONTROL) {
+		transfer->setup_buffer = malloc(sizeof(uint64_t));
+		assert(transfer->setup_buffer);
+		memcpy(transfer->setup_buffer, &setup_buffer, sizeof(uint64_t));
+		transfer->setup_buffer_size = sizeof(uint64_t);
+	}
+	transfer->data_buffer = data_buffer;
+	transfer->data_buffer_size = data_buffer_size;
+	transfer->callback_in = callback;
+
+	int rc = vhc_virtdev_add_transfer(vhc, transfer);
+	if (rc != EOK) {
+		free(transfer->setup_buffer);
+		free(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+static int usb_write(ddf_fun_t *fun, usb_target_t target, uint64_t setup_buffer,
+    const uint8_t *data_buffer, size_t data_buffer_size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	VHC_DATA(vhc, fun);
+
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
+	    target.address, target.endpoint, USB_DIRECTION_OUT, NULL);
+	if (ep == NULL) {
+		return ENOENT;
+	}
+	const usb_transfer_type_t transfer_type = ep->transfer_type;
+
+
+	vhc_transfer_t *transfer = vhc_transfer_create(target.address,
+	    target.endpoint, USB_DIRECTION_OUT, transfer_type,
+	    fun, arg);
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+	if (transfer_type == USB_TRANSFER_CONTROL) {
+		transfer->setup_buffer = malloc(sizeof(uint64_t));
+		assert(transfer->setup_buffer);
+		memcpy(transfer->setup_buffer, &setup_buffer, sizeof(uint64_t));
+		transfer->setup_buffer_size = sizeof(uint64_t);
+	}
+	transfer->data_buffer = (void*)data_buffer;
+	transfer->data_buffer_size = data_buffer_size;
+	transfer->callback_out = callback;
+
+	int rc = vhc_virtdev_add_transfer(vhc, transfer);
+	if (rc != EOK) {
+		free(transfer->setup_buffer);
+		free(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
 
 static int tell_address(ddf_fun_t *fun, devman_handle_t handle,
@@ -442,5 +516,5 @@
 
 	usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
-	usb_address_t addr = usb_device_keeper_find(&vhc->dev_keeper, handle);
+	usb_address_t addr = usb_device_manager_find(&vhc->dev_manager, handle);
 	if (addr < 0) {
 		return addr;
@@ -460,12 +534,6 @@
 	.unregister_endpoint = unregister_endpoint,
 
-	.interrupt_out = interrupt_out,
-	.interrupt_in = interrupt_in,
-
-	.bulk_in = bulk_in,
-	.bulk_out = bulk_out,
-
-	.control_write = control_write,
-	.control_read = control_read
+	.write = usb_write,
+	.read = usb_read,
 };
 
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/vhc/main.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -73,5 +73,6 @@
 	}
 	data->magic = 0xDEADBEEF;
-	rc = usb_endpoint_manager_init(&data->ep_manager, (size_t) -1);
+	rc = usb_endpoint_manager_init(&data->ep_manager, (size_t) -1,
+	    bandwidth_count_usb11);
 	if (rc != EOK) {
 		usb_log_fatal("Failed to initialize endpoint manager.\n");
@@ -79,5 +80,5 @@
 		return rc;
 	}
-	usb_device_keeper_init(&data->dev_keeper);
+	usb_device_manager_init(&data->dev_manager);
 
 	ddf_fun_t *hc = ddf_fun_create(dev, fun_exposed, "hc");
Index: uspace/drv/bus/usb/vhc/vhcd.h
===================================================================
--- uspace/drv/bus/usb/vhc/vhcd.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/bus/usb/vhc/vhcd.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -39,5 +39,5 @@
 #include <usbvirt/device.h>
 #include <usb/host/usb_endpoint_manager.h>
-#include <usb/host/device_keeper.h>
+#include <usb/host/usb_device_manager.h>
 #include <usbhc_iface.h>
 #include <async.h>
@@ -60,5 +60,5 @@
 	fibril_mutex_t guard;
 	usb_endpoint_manager_t ep_manager;
-	usb_device_keeper_t dev_keeper;
+	usb_device_manager_t dev_manager;
 	usbvirt_device_t *hub;
 	ddf_fun_t *hc_fun;
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/drv/char/ns8250/ns8250.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -59,5 +59,8 @@
 
 #include <devman.h>
+#include <ns.h>
 #include <ipc/devman.h>
+#include <ipc/services.h>
+#include <ipc/irc.h>
 #include <device/hw_res.h>
 #include <ipc/serial_ctl.h>
@@ -409,4 +412,22 @@
 static int ns8250_interrupt_enable(ns8250_t *ns)
 {
+	/*
+	 * Enable interrupt using IRC service.
+	 * TODO: This is a temporary solution until the device framework
+	 * takes care of this itself.
+	 */
+	async_sess_t *irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_IRC, 0, 0);
+	if (!irc_sess) {
+		return EIO;
+	}
+
+	async_exch_t *exch = async_exchange_begin(irc_sess);
+	if (!exch) {
+		return EIO;
+	}
+	async_msg_1(exch, IRC_ENABLE_INTERRUPT, ns->irq);
+	async_exchange_end(exch);
+
 	/* Enable interrupt on the serial port. */
 	ns8250_port_interrupts_enable(ns->port);
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -63,4 +63,5 @@
 	generic/as.c \
 	generic/cap.c \
+	generic/cfg.c \
 	generic/clipboard.c \
 	generic/devman.c \
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -152,6 +152,4 @@
 	
 	if (keys == h->max_keys) {
-		link_t *cur;
-		
 		/*
 		 * All keys are known, hash_table_find() can be used to find the
@@ -159,5 +157,5 @@
 		 */
 		
-		cur = hash_table_find(h, key);
+		link_t *cur = hash_table_find(h, key);
 		if (cur) {
 			list_remove(cur);
@@ -174,7 +172,6 @@
 	hash_index_t chain;
 	for (chain = 0; chain < h->entries; chain++) {
-		link_t *cur;
-		
-		for (cur = h->entry[chain].head.next; cur != &h->entry[chain].head;
+		for (link_t *cur = h->entry[chain].head.next;
+		    cur != &h->entry[chain].head;
 		    cur = cur->next) {
 			if (h->op->compare(key, keys, cur)) {
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/generic/as.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -123,5 +123,5 @@
  * @retval ENOENT Mapping not found.
  */
-int as_get_physical_mapping(void *address, uintptr_t *frame)
+int as_get_physical_mapping(const void *address, uintptr_t *frame)
 {
 	uintptr_t tmp_frame;
Index: uspace/lib/c/generic/cfg.c
===================================================================
--- uspace/lib/c/generic/cfg.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/c/generic/cfg.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libc
+ * @{
+ */
+/** @file cfg.c
+ * @brief Configuration files manipulation implementation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <errno.h>
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <cfg.h>
+
+/**
+ * @param data Configuration file data
+ *
+ * @return Anonymous section in the configuration file.
+ * @return NULL if there is no such section (it is empty)
+ *
+ */
+const cfg_section_t *cfg_anonymous(const cfg_file_t *data)
+{
+	assert(data != NULL);
+	
+	if (list_empty(&data->sections))
+		return NULL;
+	
+	link_t *link = list_first(&data->sections);
+	const cfg_section_t *section = cfg_section_instance(link);
+	if (section->title[0] != 0)
+		return NULL;
+	
+	return section;
+}
+
+/**
+ * @param data Configuration file data
+ *
+ * @return True if the file contains no data
+ *         (no sections, neither anonymous).
+ * @return False otherwise.
+ *
+ */
+bool cfg_empty(const cfg_file_t *data)
+{
+	assert(data != NULL);
+	
+	if (list_empty(&data->sections))
+		return true;
+	
+	list_foreach(data->sections, link) {
+		const cfg_section_t *section = cfg_section_instance(link);
+		
+		if (!list_empty(&section->entries))
+			return false;
+	}
+	
+	return true;
+}
+
+/** Read file contents into memory.
+ *
+ * @param path Path to the file
+ * @param buf  Pointer to pointer to buffer where
+ *             the file contents will be stored
+ *
+ * @return EOK if the file was successfully loaded.
+ * @return ENOMEM if there was not enough memory to load the file
+ * @return EIO if there was a problem with reading the file
+ * @return Other error code if there was a problem openening the file
+ *
+ */
+static int cfg_read(const char *path, char **buf)
+{
+	assert(buf != NULL);
+	
+	int fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return fd;
+	
+	size_t len = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_SET);
+	
+	*buf = malloc(len + 1);
+	if (*buf == NULL) {
+		close(fd);
+		return ENOMEM;
+	}
+	
+	ssize_t rd = read_all(fd, *buf, len);
+	if (rd < 0) {
+		free(*buf);
+		close(fd);
+		return EIO;
+	}
+	
+	(*buf)[len] = 0;
+	close(fd);
+	
+	return EOK;
+}
+
+static inline void null_back(char *back)
+{
+	do {
+		*back = 0;
+		back--;
+	} while (isspace(*back));
+}
+
+/** Allocate and initialize a new entry.
+ *
+ * @param key   Entry key
+ * @param value Entry value
+ *
+ * @return New entry
+ * @return NULL if there was not enough memory
+ *
+ */
+static cfg_entry_t *cfg_new_entry(const char *key, const char *value)
+{
+	cfg_entry_t *entry = malloc(sizeof(cfg_entry_t));
+	if (entry == NULL)
+		return NULL;
+	
+	link_initialize(&entry->link);
+	entry->key = key;
+	entry->value = value;
+	
+	return entry;
+}
+
+/** Allocate and initialize a new section.
+ *
+ * @param title Section title
+ *
+ * @return New section
+ * @return NULL if there was not enough memory
+ *
+ */
+static cfg_section_t *cfg_new_section(const char *title)
+{
+	cfg_section_t *sec = malloc(sizeof(cfg_section_t));
+	if (sec == NULL)
+		return NULL;
+	
+	link_initialize(&sec->link);
+	
+	if (title != NULL)
+		sec->title = title;
+	else
+		sec->title = "";
+	
+	list_initialize(&sec->entries);
+	sec->entry_count = 0;
+	
+	return sec;
+}
+
+/** Skip whitespaces
+ *
+ */
+static inline void skip_whitespaces(char **buffer)
+{
+	while (isspace(**buffer))
+		(*buffer)++;
+}
+
+static inline int starts_comment(char c)
+{
+	return ((c == ';') || (c == '#'));
+}
+
+/** Load file content into memory
+ *
+ * Parse the file into sections and entries
+ * and initialize data with this info.
+ *
+ * @param path Path to the configuration file
+ * @param data Configuration file data
+ *
+ * @return EOK if the file was successfully loaded
+ * @return EBADF if the configuration file has bad format.
+ * @return ENOMEM if there was not enough memory
+ * @return Error code from cfg_read()
+ *
+ */
+int cfg_load(const char *path, cfg_file_t *data)
+{
+	char *buffer;
+	int res = cfg_read(path, &buffer);
+	if (res != EOK)
+		return res;
+	
+	list_initialize(&data->sections);
+	data->section_count = 0;
+	data->data = buffer;
+	
+	cfg_section_t *curr_section = NULL;
+	skip_whitespaces(&buffer);
+	
+	while (*buffer) {
+		while (starts_comment(*buffer)) {
+			while ((*buffer) && (*buffer != '\n'))
+				buffer++;
+			
+			skip_whitespaces(&buffer);
+		}
+		
+		if (*buffer == '[') {
+			buffer++;
+			skip_whitespaces(&buffer);
+			
+			const char *title = buffer;
+			while ((*buffer) && (*buffer != ']') && (*buffer != '\n'))
+				buffer++;
+			
+			if (*buffer != ']') {
+				cfg_unload(data);
+				return EBADF;
+			}
+			
+			null_back(buffer);
+			buffer++;
+			
+			cfg_section_t *sec = cfg_new_section(title);
+			if (sec == NULL) {
+				cfg_unload(data);
+				return ENOMEM;
+			}
+			
+			list_append(&sec->link, &data->sections);
+			data->section_count++;
+			curr_section = sec;
+		} else if (*buffer) {
+			const char *key = buffer;
+			while ((*buffer) && (*buffer != '=') && (*buffer != '\n'))
+				buffer++;
+			
+			if (*buffer != '=') {
+				cfg_unload(data);
+				return EBADF;
+			}
+			
+			/* null = and whitespaces before */
+			null_back(buffer);
+			buffer++;
+			skip_whitespaces(&buffer);
+			
+			while (starts_comment(*buffer)) {
+				while ((*buffer) && (*buffer != '\n'))
+					buffer++;
+				
+				skip_whitespaces(&buffer);
+			}
+			
+			const char *value = buffer;
+			/* Empty value is correct value */
+			if (*buffer) {
+				while ((*buffer) && (*buffer != '\n'))
+					buffer++;
+				
+				if (*buffer) {
+					null_back(buffer);
+					buffer++;
+				} else
+					null_back(buffer);
+			}
+			
+			/* Create anonymous section if not present */
+			if (curr_section == NULL) {
+				curr_section = cfg_new_section(NULL);
+				if (curr_section == NULL) {
+					cfg_unload(data);
+					return ENOMEM;
+				}
+				
+				list_append(&curr_section->link, &data->sections);
+			}
+			
+			cfg_entry_t *entry = cfg_new_entry(key, value);
+			if (entry == NULL) {
+				cfg_unload(data);
+				return ENOMEM;
+			}
+			
+			list_append(&entry->link, &curr_section->entries);
+			curr_section->entry_count++;
+		}
+		
+		skip_whitespaces(&buffer);
+	}
+	
+	return EOK;
+}
+
+/** Load file content into memory (with path)
+ *
+ * Parse the file (with path) into sections and entries
+ * and initialize data with this info.
+ *
+ */
+int cfg_load_path(const char *path, const char *fname, cfg_file_t *data)
+{
+	size_t sz = str_size(path) + str_size(fname) + 2;
+	char *name = malloc(sz);
+	if (name == NULL)
+		return ENOMEM;
+	
+	snprintf(name, sz, "%s/%s", path, fname);
+	int rc = cfg_load(name, data);
+	
+	free(name);
+	
+	return rc;
+}
+
+/** Deallocate memory used by entry
+ *
+ */
+static void cfg_free_entry(const cfg_entry_t *entry)
+{
+	assert(entry != NULL);
+	free(entry);
+}
+
+/** Deallocate memory used by all entries
+ *
+ * Deallocate memory used by all entries within a section
+ * and the memory used by the section itself.
+ *
+ */
+static void cfg_free_section(const cfg_section_t *section)
+{
+	assert(section != NULL);
+	
+	link_t *cur;
+	link_t *next;
+	
+	for (cur = section->entries.head.next;
+	    cur != &section->entries.head;
+	    cur = next) {
+		next = cur->next;
+		cfg_free_entry(cfg_entry_instance(cur));
+	}
+	
+	free(section);
+}
+
+/** Deallocate memory used by configuration data
+ *
+ * Deallocate all inner sections and entries.
+ *
+ */
+void cfg_unload(cfg_file_t *data)
+{
+	assert(data != NULL);
+	
+	link_t *cur, *next;
+	for (cur = data->sections.head.next;
+	    cur != &data->sections.head;
+	    cur = next) {
+		next = cur->next;
+		cfg_free_section(cfg_section_instance(cur));
+	}
+	
+	free(data->data);
+}
+
+/** Find a section in the configuration data
+ *
+ * @param data  Configuration data
+ * @param title Title of the section to search for
+ *
+ * @return Found section
+ * @return NULL if there is no section with such title
+ *
+ */
+const cfg_section_t *cfg_find_section(const cfg_file_t *data, const char *title)
+{
+	list_foreach(data->sections, link) {
+		const cfg_section_t *section = cfg_section_instance(link);
+		
+		if (str_cmp(section->title, title) == 0)
+			return section;
+	}
+	
+	return NULL;
+}
+
+/** Find entry value in the configuration data
+ *
+ * @param section Section in which to search
+ * @param key     Key of the entry we to search for
+ *
+ * @return Value of the entry
+ * @return NULL if there is no entry with such key
+ *
+ */
+const char *cfg_find_value(const cfg_section_t *section, const char *key)
+{
+	list_foreach(section->entries, link) {
+		const cfg_entry_t *entry = cfg_entry_instance(link);
+		
+		if (str_cmp(entry->key, key) == 0)
+			return entry->value;
+	}
+	
+	return NULL;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/generic/io/io.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -418,13 +418,11 @@
 
 	bytes_used = stream->buf_head - stream->buf_tail;
-	if (bytes_used == 0)
-		return;
 
 	/* If buffer has prefetched read data, we need to seek back. */
-	if (stream->buf_state == _bs_read)
+	if (bytes_used > 0 && stream->buf_state == _bs_read)
 		lseek(stream->fd, - (ssize_t) bytes_used, SEEK_CUR);
 
 	/* If buffer has unwritten data, we need to write them out. */
-	if (stream->buf_state == _bs_write)
+	if (bytes_used > 0 && stream->buf_state == _bs_write)
 		(void) _fwrite(stream->buf_tail, 1, bytes_used, stream);
 
Index: uspace/lib/c/generic/ns.c
===================================================================
--- uspace/lib/c/generic/ns.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/generic/ns.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -52,7 +52,12 @@
 {
 	async_exch_t *exch = async_exchange_begin(session_ns);
+	if (!exch)
+		return NULL;
 	async_sess_t *sess =
 	    async_connect_me_to(mgmt, exch, service, arg2, arg3);
 	async_exchange_end(exch);
+
+	if (!sess)
+		return NULL;
 	
 	/*
Index: uspace/lib/c/include/adt/list.h
===================================================================
--- uspace/lib/c/include/adt/list.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/include/adt/list.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -173,5 +173,5 @@
  *
  */
-static inline int list_empty(list_t *list)
+static inline int list_empty(const list_t *list)
 {
 	return (list->head.next == &list->head);
@@ -186,5 +186,5 @@
  *
  */
-static inline link_t *list_first(list_t *list)
+static inline link_t *list_first(const list_t *list)
 {
 	return ((list->head.next == &list->head) ? NULL : list->head.next);
Index: uspace/lib/c/include/as.h
===================================================================
--- uspace/lib/c/include/as.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/include/as.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -60,5 +60,5 @@
 extern void *set_maxheapsize(size_t);
 extern void *as_get_mappable_page(size_t);
-extern int as_get_physical_mapping(void *, uintptr_t *);
+extern int as_get_physical_mapping(const void *, uintptr_t *);
 
 #endif
Index: uspace/lib/c/include/cfg.h
===================================================================
--- uspace/lib/c/include/cfg.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/c/include/cfg.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libc
+ * @{
+ */
+/**
+ * @file cfg.h
+ * @brief Simple interface for configuration files manipulation.
+ */
+
+#ifndef LIBC_CFG_H_
+#define LIBC_CFG_H_
+
+#include <adt/list.h>
+#include <sys/types.h>
+#include <bool.h>
+
+/**
+ * One key-value pair
+ */
+typedef struct {
+	link_t link;
+	
+	const char *key;
+	const char *value;
+} cfg_entry_t;
+
+/**
+ * One section in the configuration file.
+ * Has own title (or is anonymous) and contains entries.
+ */
+typedef struct {
+	link_t link;
+	
+	const char *title;
+	list_t entries;
+	size_t entry_count;
+} cfg_section_t;
+
+/**
+ * The configuration file data. The whole file is loaded
+ * into memory and strings in sections (titles) or entries
+ * (keys and values) are only pointers to this memory.
+ * Therefore all the text data are allocated and deallocated
+ * only once, if you want to use the strings after unloading
+ * the configuration file, you have to copy them.
+ */
+typedef struct {
+	list_t sections;
+	size_t section_count;
+	const char *data;
+} cfg_file_t;
+
+#define cfg_file_foreach(file, cur) \
+	list_foreach((file)->sections, (cur))
+
+#define cfg_section_instance(cur) \
+	list_get_instance((cur), const cfg_section_t, link)
+
+#define cfg_section_foreach(section, cur) \
+	list_foreach((section)->entries, (cur))
+
+#define cfg_entry_instance(cur) \
+	list_get_instance((cur), const cfg_entry_t, link)
+
+extern int cfg_load(const char *, cfg_file_t *);
+extern int cfg_load_path(const char *, const char *, cfg_file_t *);
+extern void cfg_unload(cfg_file_t *);
+extern bool cfg_empty(const cfg_file_t *);
+extern const cfg_section_t *cfg_find_section(const cfg_file_t *, const char *);
+extern const char *cfg_find_value(const cfg_section_t *, const char *);
+extern const cfg_section_t *cfg_anonymous(const cfg_file_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/loc.h
===================================================================
--- uspace/lib/c/include/ipc/loc.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/c/include/ipc/loc.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -97,2 +97,5 @@
 
 #endif
+
+/** @}
+ */
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/drv/generic/dev_iface.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -46,6 +46,4 @@
 #include "remote_pci.h"
 
-#include <stdio.h>
-
 static iface_dipatch_table_t remote_ifaces = {
 	.ifaces = {
@@ -68,8 +66,7 @@
 get_remote_method(remote_iface_t *rem_iface, sysarg_t iface_method_idx)
 {
-	if (iface_method_idx >= rem_iface->method_count) {
+	if (iface_method_idx >= rem_iface->method_count)
 		return NULL;
-	}
-
+	
 	return rem_iface->methods[iface_method_idx];
 }
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/drv/generic/driver.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -271,5 +271,5 @@
 	
 	devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
-    	devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
+	devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
 	
 	ddf_dev_t *dev = create_device();
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -41,13 +41,5 @@
 
 #define USB_MAX_PAYLOAD_SIZE 1020
-#define HACK_MAX_PACKET_SIZE 8
-#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
-
-static void remote_usbhc_interrupt_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_interrupt_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_bulk_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_bulk_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
 static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
@@ -56,24 +48,20 @@
 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 //static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 
 /** Remote USB host controller interface operations. */
-static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
-	remote_usbhc_request_address,
-	remote_usbhc_bind_address,
-	remote_usbhc_find_by_address,
-	remote_usbhc_release_address,
-
-	remote_usbhc_interrupt_out,
-	remote_usbhc_interrupt_in,
-
-	remote_usbhc_bulk_out,
-	remote_usbhc_bulk_in,
-
-	remote_usbhc_control_write,
-	remote_usbhc_control_read,
-
-	remote_usbhc_register_endpoint,
-	remote_usbhc_unregister_endpoint
+static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
+	[IPC_M_USBHC_REQUEST_ADDRESS] = remote_usbhc_request_address,
+	[IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
+	[IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address,
+	[IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
+
+	[IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
+	[IPC_M_USBHC_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
+
+	[IPC_M_USBHC_READ] = remote_usbhc_read,
+	[IPC_M_USBHC_WRITE] = remote_usbhc_write,
 };
 
@@ -90,5 +78,4 @@
 	ipc_callid_t data_caller;
 	void *buffer;
-	void *setup_packet;
 	size_t size;
 } async_transaction_t;
@@ -98,8 +85,4 @@
 	if (trans == NULL) {
 		return;
-	}
-
-	if (trans->setup_packet != NULL) {
-		free(trans->setup_packet);
 	}
 	if (trans->buffer != NULL) {
@@ -120,5 +103,4 @@
 	trans->data_caller = 0;
 	trans->buffer = NULL;
-	trans->setup_packet = NULL;
 	trans->size = 0;
 
@@ -135,5 +117,5 @@
 		return;
 	}
-	
+
 	usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
 
@@ -239,278 +221,4 @@
 	async_transaction_destroy(trans);
 }
-
-/** Process an outgoing transfer (both OUT and SETUP).
- *
- * @param device Target device.
- * @param callid Initiating caller.
- * @param call Initiating call.
- * @param transfer_func Transfer function (might be NULL).
- */
-static void remote_usbhc_out_transfer(ddf_fun_t *fun,
-    ipc_callid_t callid, ipc_call_t *call,
-    usbhc_iface_transfer_out_t transfer_func)
-{
-	if (!transfer_func) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_target_t target = {
-		.address = DEV_IPC_GET_ARG1(*call),
-		.endpoint = DEV_IPC_GET_ARG2(*call)
-	};
-
-	size_t len = 0;
-	void *buffer = NULL;
-
-	int rc = async_data_write_accept(&buffer, false,
-	    1, USB_MAX_PAYLOAD_SIZE,
-	    0, &len);
-
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	async_transaction_t *trans = async_transaction_create(callid);
-	if (trans == NULL) {
-		if (buffer != NULL) {
-			free(buffer);
-		}
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-
-	trans->buffer = buffer;
-	trans->size = len;
-
-	rc = transfer_func(fun, target,
-	    buffer, len,
-	    callback_out, trans);
-
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
-}
-
-/** Process an incoming transfer.
- *
- * @param device Target device.
- * @param callid Initiating caller.
- * @param call Initiating call.
- * @param transfer_func Transfer function (might be NULL).
- */
-static void remote_usbhc_in_transfer(ddf_fun_t *fun,
-    ipc_callid_t callid, ipc_call_t *call,
-    usbhc_iface_transfer_in_t transfer_func)
-{
-	if (!transfer_func) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_target_t target = {
-		.address = DEV_IPC_GET_ARG1(*call),
-		.endpoint = DEV_IPC_GET_ARG2(*call)
-	};
-
-	size_t len;
-	ipc_callid_t data_callid;
-	if (!async_data_read_receive(&data_callid, &len)) {
-		async_answer_0(callid, EPARTY);
-		return;
-	}
-
-	async_transaction_t *trans = async_transaction_create(callid);
-	if (trans == NULL) {
-		async_answer_0(data_callid, ENOMEM);
-		async_answer_0(callid, ENOMEM);
-		return;
-	}
-	trans->data_caller = data_callid;
-	trans->buffer = malloc(len);
-	trans->size = len;
-
-	int rc = transfer_func(fun, target,
-	    trans->buffer, len,
-	    callback_in, trans);
-
-	if (rc != EOK) {
-		async_answer_0(data_callid, rc);
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
-}
-
-void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-	assert(usb_iface != NULL);
-
-	return remote_usbhc_out_transfer(fun, callid, call,
-	    usb_iface->interrupt_out);
-}
-
-void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-	assert(usb_iface != NULL);
-
-	return remote_usbhc_in_transfer(fun, callid, call,
-	    usb_iface->interrupt_in);
-}
-
-void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-	assert(usb_iface != NULL);
-
-	return remote_usbhc_out_transfer(fun, callid, call,
-	    usb_iface->bulk_out);
-}
-
-void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-	assert(usb_iface != NULL);
-
-	return remote_usbhc_in_transfer(fun, callid, call,
-	    usb_iface->bulk_in);
-}
-
-void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
-ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-	assert(usb_iface != NULL);
-
-	if (!usb_iface->control_write) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_target_t target = {
-		.address = DEV_IPC_GET_ARG1(*call),
-		.endpoint = DEV_IPC_GET_ARG2(*call)
-	};
-	size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
-
-	int rc;
-
-	void *setup_packet = NULL;
-	void *data_buffer = NULL;
-	size_t setup_packet_len = 0;
-
-	rc = async_data_write_accept(&setup_packet, false,
-	    1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	if (data_buffer_len > 0) {
-		rc = async_data_write_accept(&data_buffer, false,
-		    1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
-		if (rc != EOK) {
-			async_answer_0(callid, rc);
-			free(setup_packet);
-			return;
-		}
-	}
-
-	async_transaction_t *trans = async_transaction_create(callid);
-	if (trans == NULL) {
-		async_answer_0(callid, ENOMEM);
-		free(setup_packet);
-		free(data_buffer);
-		return;
-	}
-	trans->setup_packet = setup_packet;
-	trans->buffer = data_buffer;
-	trans->size = data_buffer_len;
-
-	rc = usb_iface->control_write(fun, target,
-	    setup_packet, setup_packet_len,
-	    data_buffer, data_buffer_len,
-	    callback_out, trans);
-
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
-}
-
-
-void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
-ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-	assert(usb_iface != NULL);
-
-	if (!usb_iface->control_read) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_target_t target = {
-		.address = DEV_IPC_GET_ARG1(*call),
-		.endpoint = DEV_IPC_GET_ARG2(*call)
-	};
-
-	int rc;
-
-	void *setup_packet = NULL;
-	size_t setup_packet_len = 0;
-	size_t data_len = 0;
-
-	rc = async_data_write_accept(&setup_packet, false,
-	    1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		return;
-	}
-
-	ipc_callid_t data_callid;
-	if (!async_data_read_receive(&data_callid, &data_len)) {
-		async_answer_0(callid, EPARTY);
-		free(setup_packet);
-		return;
-	}
-
-	async_transaction_t *trans = async_transaction_create(callid);
-	if (trans == NULL) {
-		async_answer_0(data_callid, ENOMEM);
-		async_answer_0(callid, ENOMEM);
-		free(setup_packet);
-		return;
-	}
-	trans->data_caller = data_callid;
-	trans->setup_packet = setup_packet;
-	trans->size = data_len;
-	trans->buffer = malloc(data_len);
-	if (trans->buffer == NULL) {
-		async_answer_0(data_callid, ENOMEM);
-		async_answer_0(callid, ENOMEM);
-		async_transaction_destroy(trans);
-		return;
-	}
-
-	rc = usb_iface->control_read(fun, target,
-	    setup_packet, setup_packet_len,
-	    trans->buffer, trans->size,
-	    callback_in, trans);
-
-	if (rc != EOK) {
-		async_answer_0(data_callid, rc);
-		async_answer_0(callid, rc);
-		async_transaction_destroy(trans);
-	}
-}
-
 
 void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
@@ -535,6 +243,5 @@
 	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
 
-	_INIT_FROM_HIGH_DATA2(usb_address_t, address, 1);
-	_INIT_FROM_LOW_DATA2(usb_endpoint_t, endpoint, 1);
+	const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
 
 	_INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
@@ -551,10 +258,9 @@
 #undef _INIT_FROM_LOW_DATA3
 
-	int rc = usb_iface->register_endpoint(fun, address, speed, endpoint,
-	    transfer_type, direction, max_packet_size, interval);
+	int rc = usb_iface->register_endpoint(fun, target.address, speed,
+	    target.endpoint, transfer_type, direction, max_packet_size, interval);
 
 	async_answer_0(callid, rc);
 }
-
 
 void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
@@ -578,4 +284,98 @@
 }
 
+void remote_usbhc_read(
+    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usbhc_iface_t *hc_iface = iface;
+
+	if (!hc_iface->read) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
+	const uint64_t setup =
+	    ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
+	    (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (!async_data_read_receive(&trans->data_caller, &trans->size)) {
+		async_answer_0(callid, EPARTY);
+		return;
+	}
+
+	trans->buffer = malloc(trans->size);
+	if (trans->buffer == NULL) {
+		async_answer_0(trans->data_caller, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		async_transaction_destroy(trans);
+	}
+
+	const int rc = hc_iface->read(
+	    fun, target, setup, trans->buffer, trans->size, callback_in, trans);
+
+	if (rc != EOK) {
+		async_answer_0(trans->data_caller, rc);
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+void remote_usbhc_write(
+    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(fun);
+	assert(iface);
+	assert(call);
+
+	const usbhc_iface_t *hc_iface = iface;
+
+	if (!hc_iface->write) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
+	const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
+	const uint64_t setup =
+	    ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
+	    (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	if (data_buffer_len > 0) {
+		int rc = async_data_write_accept(&trans->buffer, false,
+		    1, USB_MAX_PAYLOAD_SIZE,
+		    0, &trans->size);
+
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			async_transaction_destroy(trans);
+			return;
+		}
+	}
+
+	int rc = hc_iface->write(
+	    fun, target, setup, trans->buffer, trans->size, callback_out, trans);
+
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
 
 /**
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -123,41 +123,4 @@
 	IPC_M_USBHC_RELEASE_ADDRESS,
 
-
-	/** Send interrupt data to device.
-	 * See explanation at usb_iface_funcs_t (OUT transaction).
-	 */
-	IPC_M_USBHC_INTERRUPT_OUT,
-
-	/** Get interrupt data from device.
-	 * See explanation at usb_iface_funcs_t (IN transaction).
-	 */
-	IPC_M_USBHC_INTERRUPT_IN,
-
-	/** Send bulk data to device.
-	 * See explanation at usb_iface_funcs_t (OUT transaction).
-	 */
-	IPC_M_USBHC_BULK_OUT,
-
-	/** Get bulk data from device.
-	 * See explanation at usb_iface_funcs_t (IN transaction).
-	 */
-	IPC_M_USBHC_BULK_IN,
-
-	/** Issue control WRITE transfer.
-	 * See explanation at usb_iface_funcs_t (OUT transaction) for
-	 * call parameters.
-	 * This call is immediately followed by two IPC data writes
-	 * from the caller (setup packet and actual data).
-	 */
-	IPC_M_USBHC_CONTROL_WRITE,
-
-	/** Issue control READ transfer.
-	 * See explanation at usb_iface_funcs_t (IN transaction) for
-	 * call parameters.
-	 * This call is immediately followed by IPC data write from the caller
-	 * (setup packet) and IPC data read (buffer that was read).
-	 */
-	IPC_M_USBHC_CONTROL_READ,
-
 	/** Register endpoint attributes at host controller.
 	 * This is used to reserve portion of USB bandwidth.
@@ -185,28 +148,23 @@
 	 * - ENOENT - unknown endpoint
 	 */
-	IPC_M_USBHC_UNREGISTER_ENDPOINT
+	IPC_M_USBHC_UNREGISTER_ENDPOINT,
+
+	/** Get data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_READ,
+
+	/** Send data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_WRITE,
 } usbhc_iface_funcs_t;
 
 /** Callback for outgoing transfer. */
-typedef void (*usbhc_iface_transfer_out_callback_t)(ddf_fun_t *,
-    int, void *);
+typedef void (*usbhc_iface_transfer_out_callback_t)(ddf_fun_t *, int, void *);
 
 /** Callback for incoming transfer. */
 typedef void (*usbhc_iface_transfer_in_callback_t)(ddf_fun_t *,
     int, size_t, void *);
-
-
-/** Out transfer processing function prototype. */
-typedef int (*usbhc_iface_transfer_out_t)(ddf_fun_t *, usb_target_t,
-    void *, size_t,
-    usbhc_iface_transfer_out_callback_t, void *);
-
-/** Setup transfer processing function prototype. @deprecated */
-typedef usbhc_iface_transfer_out_t usbhc_iface_transfer_setup_t;
-
-/** In transfer processing function prototype. */
-typedef int (*usbhc_iface_transfer_in_t)(ddf_fun_t *, usb_target_t,
-    void *, size_t,
-    usbhc_iface_transfer_in_callback_t, void *);
 
 /** USB host controller communication interface. */
@@ -223,17 +181,9 @@
 	    usb_direction_t);
 
-	usbhc_iface_transfer_out_t interrupt_out;
-	usbhc_iface_transfer_in_t interrupt_in;
+	int (*read)(ddf_fun_t *, usb_target_t, uint64_t, uint8_t *, size_t,
+	    usbhc_iface_transfer_in_callback_t, void *);
 
-	usbhc_iface_transfer_out_t bulk_out;
-	usbhc_iface_transfer_in_t bulk_in;
-
-	int (*control_write)(ddf_fun_t *, usb_target_t,
-	    void *, size_t, void *, size_t,
-	    usbhc_iface_transfer_out_callback_t, void *);
-
-	int (*control_read)(ddf_fun_t *, usb_target_t,
-	    void *, size_t, void *, size_t,
-	    usbhc_iface_transfer_in_callback_t, void *);
+	int (*write)(ddf_fun_t *, usb_target_t, uint64_t, const uint8_t *,
+	    size_t, usbhc_iface_transfer_out_callback_t, void *);
 } usbhc_iface_t;
 
Index: uspace/lib/usb/include/usb/hc.h
===================================================================
--- uspace/lib/usb/include/usb/hc.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usb/include/usb/hc.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -62,5 +62,5 @@
     devman_handle_t *);
 
-int usb_hc_get_address_by_handle(devman_handle_t);
+usb_address_t usb_hc_get_address_by_handle(devman_handle_t);
 
 int usb_hc_find(devman_handle_t, devman_handle_t *);
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usb/include/usb/usb.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -36,4 +36,5 @@
 #define LIBUSB_USB_H_
 
+#include <bool.h>
 #include <sys/types.h>
 #include <byteorder.h>
@@ -105,5 +106,5 @@
  * Negative values could be used to indicate error.
  */
-typedef int usb_address_t;
+typedef int16_t usb_address_t;
 
 /** Default USB address. */
@@ -115,5 +116,5 @@
  * Negative values could be used to indicate error.
  */
-typedef int usb_endpoint_t;
+typedef int16_t usb_endpoint_t;
 
 /** Maximum endpoint number in USB 1.1.
@@ -125,8 +126,22 @@
  * Pair address + endpoint is identification of transaction recipient.
  */
-typedef struct {
-	usb_address_t address;
-	usb_endpoint_t endpoint;
+typedef union {
+	struct {
+		usb_address_t address;
+		usb_endpoint_t endpoint;
+	} __attribute__((packed));
+	uint32_t packed;
 } usb_target_t;
+
+/** Check USB target for allowed values (address and endpoint).
+ *
+ * @param target.
+ * @return True, if values are wihtin limits, false otherwise.
+ */
+static inline bool usb_target_is_valid(usb_target_t target)
+{
+	return !(target.endpoint > 15 || target.endpoint < 0
+	    || target.address >= USB11_ADDRESS_MAX || target.address < 0);
+}
 
 /** Compare USB targets (addresses and endpoints).
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -486,4 +486,6 @@
 		return EBADF;
 	
+	const usb_target_t target =
+	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
 #define _PACK2(high, low) (((high) << 16) + (low))
 #define _PACK3(high, middle, low) (((((high) << 8) + (middle)) << 8) + (low))
@@ -491,6 +493,5 @@
 	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
 	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_REGISTER_ENDPOINT,
-	    _PACK2(pipe->wire->address, pipe->endpoint_no),
+	    IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
 	    _PACK3(speed, pipe->transfer_type, pipe->direction),
 	    _PACK2(pipe->max_packet_size, interval));
Index: uspace/lib/usbdev/src/pipesio.c
===================================================================
--- uspace/lib/usbdev/src/pipesio.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbdev/src/pipesio.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -65,20 +65,11 @@
     void *buffer, size_t size, size_t *size_transfered)
 {
-	/*
-	 * Get corresponding IPC method.
-	 * In future, replace with static array of mappings
-	 * transfer type -> method.
-	 */
-	usbhc_iface_funcs_t ipc_method;
-	switch (pipe->transfer_type) {
-		case USB_TRANSFER_INTERRUPT:
-			ipc_method = IPC_M_USBHC_INTERRUPT_IN;
-			break;
-		case USB_TRANSFER_BULK:
-			ipc_method = IPC_M_USBHC_BULK_IN;
-			break;
-		default:
-			return ENOTSUP;
-	}
+	/* Only interrupt and bulk transfers are supported */
+	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
+	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    return ENOTSUP;
+
+	const usb_target_t target =
+	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
 	
 	/* Ensure serialization over the phone. */
@@ -89,6 +80,6 @@
 	 * Make call identifying target USB device and type of transfer.
 	 */
-	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    ipc_method, pipe->wire->address, pipe->endpoint_no, NULL);
+	aid_t opening_request = async_send_2(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_READ, target.packed, NULL);
 	
 	if (opening_request == 0) {
@@ -213,20 +204,11 @@
     void *buffer, size_t size)
 {
-	/*
-	 * Get corresponding IPC method.
-	 * In future, replace with static array of mappings
-	 * transfer type -> method.
-	 */
-	usbhc_iface_funcs_t ipc_method;
-	switch (pipe->transfer_type) {
-		case USB_TRANSFER_INTERRUPT:
-			ipc_method = IPC_M_USBHC_INTERRUPT_OUT;
-			break;
-		case USB_TRANSFER_BULK:
-			ipc_method = IPC_M_USBHC_BULK_OUT;
-			break;
-		default:
-			return ENOTSUP;
-	}
+	/* Only interrupt and bulk transfers are supported */
+	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
+	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    return ENOTSUP;
+
+	const usb_target_t target =
+	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
 
 	/* Ensure serialization over the phone. */
@@ -238,5 +220,5 @@
 	 */
 	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    ipc_method, pipe->wire->address, pipe->endpoint_no, NULL);
+	    IPC_M_USBHC_WRITE, target.packed, size, NULL);
 	
 	if (opening_request == 0) {
@@ -352,28 +334,23 @@
 	pipe_start_transaction(pipe);
 
+	const usb_target_t target =
+	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
+
+	assert(setup_buffer_size == 8);
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
 	/*
 	 * Make call identifying target USB device and control transfer type.
 	 */
 	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_CONTROL_READ, pipe->wire->address, pipe->endpoint_no,
-	    NULL);
-	
+	aid_t opening_request = async_send_4(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_READ, target.packed,
+	    (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
+
 	if (opening_request == 0) {
 		async_exchange_end(exch);
 		return ENOMEM;
 	}
-	
-	/*
-	 * Send the setup packet.
-	 */
-	int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-	
+
 	/*
 	 * Retrieve the data.
@@ -498,11 +475,17 @@
 	pipe_start_transaction(pipe);
 
+	const usb_target_t target =
+	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
+	assert(setup_buffer_size == 8);
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
+
 	/*
 	 * Make call identifying target USB device and control transfer type.
 	 */
 	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	aid_t opening_request = async_send_4(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_CONTROL_WRITE, pipe->wire->address, pipe->endpoint_no,
-	    data_buffer_size, NULL);
+	aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_WRITE, target.packed, data_buffer_size,
+	    (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
 	
 	if (opening_request == 0) {
@@ -511,21 +494,10 @@
 		return ENOMEM;
 	}
-	
-	/*
-	 * Send the setup packet.
-	 */
-	int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
-	if (rc != EOK) {
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-	
+
 	/*
 	 * Send the data (if any).
 	 */
 	if (data_buffer_size > 0) {
-		rc = async_data_write_start(exch, data_buffer, data_buffer_size);
+		int rc = async_data_write_start(exch, data_buffer, data_buffer_size);
 		
 		/* All data sent, pipe can be released. */
Index: uspace/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbhost/Makefile	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -32,11 +32,12 @@
 	-I$(LIBUSB_PREFIX)/include \
 	-I$(LIBDRV_PREFIX)/include \
-	-Iinclude
+	-Iinclude 
 
 SOURCES = \
-	src/batch.c \
-	src/device_keeper.c \
 	src/endpoint.c \
-	src/usb_endpoint_manager.c
+	src/iface.c \
+	src/usb_device_manager.c \
+	src/usb_endpoint_manager.c \
+	src/usb_transfer_batch.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: pace/lib/usbhost/include/usb/host/batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/batch.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,115 +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 libusbhost
- * @{
- */
-/** @file
- * USB transfer transaction structures.
- */
-#ifndef LIBUSBHOST_HOST_BATCH_H
-#define LIBUSBHOST_HOST_BATCH_H
-
-#include <adt/list.h>
-
-#include <usbhc_iface.h>
-#include <usb/usb.h>
-#include <usb/host/endpoint.h>
-
-typedef struct usb_transfer_batch usb_transfer_batch_t;
-struct usb_transfer_batch {
-	endpoint_t *ep;
-	link_t link;
-	usbhc_iface_transfer_in_callback_t callback_in;
-	usbhc_iface_transfer_out_callback_t callback_out;
-	void *arg;
-	char *buffer;
-	char *data_buffer;
-	size_t buffer_size;
-	char *setup_buffer;
-	size_t setup_size;
-	size_t transfered_size;
-	void (*next_step)(usb_transfer_batch_t *);
-	int error;
-	ddf_fun_t *fun;
-	void *private_data;
-	void (*private_data_dtor)(void *p_data);
-};
-
-/** Printf formatting string for dumping usb_transfer_batch_t. */
-#define USB_TRANSFER_BATCH_FMT "[%d:%d %s %s-%s %zuB/%zu]"
-
-/** Printf arguments for dumping usb_transfer_batch_t.
- * @param batch USB transfer batch to be dumped.
- */
-#define USB_TRANSFER_BATCH_ARGS(batch) \
-	(batch).ep->address, (batch).ep->endpoint, \
-	usb_str_speed((batch).ep->speed), \
-	usb_str_transfer_type_short((batch).ep->transfer_type), \
-	usb_str_direction((batch).ep->direction), \
-	(batch).buffer_size, (batch).ep->max_packet_size
-
-
-void usb_transfer_batch_init(
-    usb_transfer_batch_t *instance,
-    endpoint_t *ep,
-    char *buffer,
-    char *data_buffer,
-    size_t buffer_size,
-    char *setup_buffer,
-    size_t setup_size,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out,
-    void *arg,
-    ddf_fun_t *fun,
-    void *private_data,
-    void (*private_data_dtor)(void *p_data)
-);
-
-void usb_transfer_batch_call_in_and_dispose(usb_transfer_batch_t *instance);
-void usb_transfer_batch_call_out_and_dispose(usb_transfer_batch_t *instance);
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance);
-void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);
-
-static inline void usb_transfer_batch_finish_error(
-    usb_transfer_batch_t *instance, int error)
-{
-	assert(instance);
-	instance->error = error;
-	usb_transfer_batch_finish(instance);
-}
-
-static inline usb_transfer_batch_t *usb_transfer_batch_from_link(link_t *l)
-{
-	assert(l);
-	return list_get_instance(l, usb_transfer_batch_t, link);
-}
-
-#endif
-/**
- * @}
- */
Index: pace/lib/usbhost/include/usb/host/device_keeper.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/device_keeper.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,90 +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 libusbhost
- * @{
- */
-/** @file
- * Device keeper structure and functions.
- *
- * Typical USB host controller needs to keep track of various settings for
- * each device that is connected to it.
- * State of toggle bit, device speed etc. etc.
- * This structure shall simplify the management.
- */
-#ifndef LIBUSBHOST_HOST_DEVICE_KEEPER_H
-#define LIBUSBHOST_HOST_DEVICE_KEEPER_H
-
-#include <adt/list.h>
-#include <devman.h>
-#include <fibril_synch.h>
-#include <usb/usb.h>
-#include <usb/host/endpoint.h>
-
-/** Number of USB address for array dimensions. */
-#define USB_ADDRESS_COUNT (USB11_ADDRESS_MAX + 1)
-
-/** Information about attached USB device. */
-struct usb_device_info {
-	usb_speed_t speed;
-	bool occupied;
-	devman_handle_t handle;
-};
-
-/** Host controller device keeper.
- * You shall not access members directly but only using functions below.
- */
-typedef struct {
-	struct usb_device_info devices[USB_ADDRESS_COUNT];
-	fibril_mutex_t guard;
-	usb_address_t last_address;
-} usb_device_keeper_t;
-
-void usb_device_keeper_init(usb_device_keeper_t *instance);
-
-usb_address_t device_keeper_get_free_address(usb_device_keeper_t *instance,
-    usb_speed_t speed);
-
-void usb_device_keeper_bind(usb_device_keeper_t *instance,
-    usb_address_t address, devman_handle_t handle);
-
-void usb_device_keeper_release(usb_device_keeper_t *instance,
-    usb_address_t address);
-
-usb_address_t usb_device_keeper_find(usb_device_keeper_t *instance,
-    devman_handle_t handle);
-
-bool usb_device_keeper_find_by_address(usb_device_keeper_t *instance,
-    usb_address_t address, devman_handle_t *handle);
-
-usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
-    usb_address_t address);
-#endif
-/**
- * @}
- */
Index: uspace/lib/usbhost/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -54,4 +54,5 @@
 	fibril_condvar_t avail;
 	volatile bool active;
+	void (*destroy_hook)(struct endpoint *);
 	struct {
 		void *data;
@@ -68,5 +69,6 @@
 
 void endpoint_set_hc_data(endpoint_t *instance,
-    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int));
+    void *data, void (*destroy_hook)(endpoint_t *),
+    int (*toggle_get)(void *), void (*toggle_set)(void *, int));
 
 void endpoint_clear_hc_data(endpoint_t *instance);
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,87 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ *
+ */
+#ifndef LIBUSBHOST_HOST_HCD_H
+#define LIBUSBHOST_HOST_HCD_H
+
+#include <assert.h>
+#include <usb/host/usb_device_manager.h>
+#include <usb/host/usb_endpoint_manager.h>
+#include <usb/host/usb_transfer_batch.h>
+#include <usbhc_iface.h>
+
+typedef struct hcd hcd_t;
+
+struct hcd {
+	usb_device_manager_t dev_manager;
+	usb_endpoint_manager_t ep_manager;
+	void *private_data;
+
+	int (*schedule)(hcd_t *, usb_transfer_batch_t *);
+	int (*ep_add_hook)(hcd_t *, endpoint_t *);
+};
+/*----------------------------------------------------------------------------*/
+static inline int hcd_init(hcd_t *hcd, size_t bandwidth,
+    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
+{
+	assert(hcd);
+	usb_device_manager_init(&hcd->dev_manager);
+	return usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
+}
+/*----------------------------------------------------------------------------*/
+static inline void hcd_destroy(hcd_t *hcd)
+{
+	usb_endpoint_manager_destroy(&hcd->ep_manager);
+}
+/*----------------------------------------------------------------------------*/
+static inline void reset_ep_if_need(
+    hcd_t *hcd, usb_target_t target, const char* setup_data)
+{
+	assert(hcd);
+	usb_endpoint_manager_reset_if_need(
+	    &hcd->ep_manager, target, (const uint8_t *)setup_data);
+}
+/*----------------------------------------------------------------------------*/
+static inline hcd_t * fun_to_hcd(ddf_fun_t *fun)
+{
+	assert(fun);
+	return fun->driver_data;
+}
+/*----------------------------------------------------------------------------*/
+extern usbhc_iface_t hcd_iface;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/usb_device_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,89 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * Device manager structure and functions.
+ *
+ * Typical USB host controller needs to keep track of various settings for
+ * each device that is connected to it.
+ * State of toggle bit, device speed etc. etc.
+ * This structure shall simplify the management.
+ */
+#ifndef LIBUSBHOST_HOST_USB_DEVICE_MANAGER_H
+#define LIBUSBHOST_HOST_USB_DEVICE_MANAGER_H
+
+#include <adt/list.h>
+#include <devman.h>
+#include <fibril_synch.h>
+#include <usb/usb.h>
+#include <usb/host/endpoint.h>
+
+/** Number of USB address for array dimensions. */
+#define USB_ADDRESS_COUNT (USB11_ADDRESS_MAX + 1)
+
+/** Information about attached USB device. */
+struct usb_device_info {
+	usb_speed_t speed;
+	bool occupied;
+	devman_handle_t handle;
+};
+
+/** Host controller device manager.
+ * You shall not access members directly but only using functions below.
+ */
+typedef struct {
+	struct usb_device_info devices[USB_ADDRESS_COUNT];
+	fibril_mutex_t guard;
+	usb_address_t last_address;
+} usb_device_manager_t;
+
+void usb_device_manager_init(usb_device_manager_t *instance);
+
+usb_address_t usb_device_manager_get_free_address(
+    usb_device_manager_t *instance, usb_speed_t speed);
+
+void usb_device_manager_bind(usb_device_manager_t *instance,
+    usb_address_t address, devman_handle_t handle);
+
+void usb_device_manager_release(usb_device_manager_t *instance,
+    usb_address_t address);
+
+usb_address_t usb_device_manager_find(usb_device_manager_t *instance,
+    devman_handle_t handle);
+
+bool usb_device_manager_find_by_address(usb_device_manager_t *instance,
+    usb_address_t address, devman_handle_t *handle);
+
+usb_speed_t usb_device_manager_get_speed(usb_device_manager_t *instance,
+    usb_address_t address);
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -38,5 +38,5 @@
  */
 #ifndef LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
-#define LIBUSBHOST_HOST_YSB_ENDPOINT_MANAGER_H
+#define LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
 
 #include <stdlib.h>
@@ -52,6 +52,6 @@
 	hash_table_t ep_table;
 	fibril_mutex_t guard;
-	fibril_condvar_t change;
 	size_t free_bw;
+	size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t);
 } usb_endpoint_manager_t;
 
@@ -60,5 +60,6 @@
 
 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
-    size_t available_bandwidth);
+    size_t available_bandwidth,
+    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t));
 
 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance);
@@ -77,4 +78,5 @@
     usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
 
+/** Wrapper combining allocation and insertion */
 static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
     usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
Index: uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,180 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * USB transfer transaction structures.
+ */
+#ifndef LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H
+#define LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H
+
+#include <adt/list.h>
+
+#include <usbhc_iface.h>
+#include <usb/usb.h>
+#include <usb/host/endpoint.h>
+
+#define USB_SETUP_PACKET_SIZE 8
+
+typedef struct usb_transfer_batch usb_transfer_batch_t;
+/** Structure stores additional data needed for communication with EP */
+struct usb_transfer_batch {
+	/** Endpoint used for communication */
+	endpoint_t *ep;
+	/** Function called on completion (IN version) */
+	usbhc_iface_transfer_in_callback_t callback_in;
+	/** Function called on completion (OUT version) */
+	usbhc_iface_transfer_out_callback_t callback_out;
+	/** Argument to pass to the completion function */
+	void *arg;
+	/** Place for data to send/receive */
+	char *buffer;
+	/** Size of memory pointed to by buffer member */
+	size_t buffer_size;
+	/** Place to store SETUP data needed by control transfers */
+	char setup_buffer[USB_SETUP_PACKET_SIZE];
+	/** Used portion of setup_buffer member
+	 *
+	 * SETUP buffer must be 8 bytes for control transfers and is left
+	 * unused for all other transfers. Thus, this field is either 0 or 8.
+	 */
+	size_t setup_size;
+	/** Actually used portion of the buffer */
+	size_t transfered_size;
+	/** Indicates success/failure of the communication */
+	int error;
+	/** Host controller function, passed to callback function */
+	ddf_fun_t *fun;
+
+	/** Driver specific data */
+	void *private_data;
+	/** Callback to properly remove driver data during destruction */
+	void (*private_data_dtor)(void *p_data);
+};
+
+/** Printf formatting string for dumping usb_transfer_batch_t. */
+#define USB_TRANSFER_BATCH_FMT "[%d:%d %s %s-%s %zuB/%zu]"
+
+/** Printf arguments for dumping usb_transfer_batch_t.
+ * @param batch USB transfer batch to be dumped.
+ */
+#define USB_TRANSFER_BATCH_ARGS(batch) \
+	(batch).ep->address, (batch).ep->endpoint, \
+	usb_str_speed((batch).ep->speed), \
+	usb_str_transfer_type_short((batch).ep->transfer_type), \
+	usb_str_direction((batch).ep->direction), \
+	(batch).buffer_size, (batch).ep->max_packet_size
+
+
+usb_transfer_batch_t * usb_transfer_batch_get(
+    endpoint_t *ep,
+    char *buffer,
+    size_t buffer_size,
+    uint64_t setup_buffer,
+    usbhc_iface_transfer_in_callback_t func_in,
+    usbhc_iface_transfer_out_callback_t func_out,
+    void *arg,
+    ddf_fun_t *fun,
+    void *private_data,
+    void (*private_data_dtor)(void *p_data)
+);
+
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance,
+    const void* data, size_t size);
+void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
+void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
+void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);
+
+/** Helper function, calls callback and correctly destroys batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+static inline void usb_transfer_batch_call_in_and_dispose(
+    usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_transfer_batch_call_in(instance);
+	usb_transfer_batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function calls callback and correctly destroys batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+static inline void usb_transfer_batch_call_out_and_dispose(
+    usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_transfer_batch_call_out(instance);
+	usb_transfer_batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function, sets error value and finishes transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data Data to copy to the output buffer.
+ * @param[in] size Size of @p data.
+ * @param[in] error Set batch status to this error value.
+ */
+static inline void usb_transfer_batch_finish_error(
+    usb_transfer_batch_t *instance, const void* data, size_t size, int error)
+{
+	assert(instance);
+	instance->error = error;
+	usb_transfer_batch_finish(instance, data, size);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function, determines batch direction absed on the present callbacks
+ * @param[in] instance Batch structure to use.
+ * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT.
+ */
+static inline usb_direction_t usb_transfer_batch_direction(
+    const usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	if (instance->callback_in) {
+		assert(instance->callback_out == NULL);
+		assert(instance->ep == NULL
+		    || instance->ep->transfer_type == USB_TRANSFER_CONTROL
+		    || instance->ep->direction == USB_DIRECTION_IN);
+		return USB_DIRECTION_IN;
+	}
+	if (instance->callback_out) {
+		assert(instance->callback_in == NULL);
+		assert(instance->ep == NULL
+		    || instance->ep->transfer_type == USB_TRANSFER_CONTROL
+		    || instance->ep->direction == USB_DIRECTION_OUT);
+		return USB_DIRECTION_OUT;
+	}
+	assert(false);
+}
+#endif
+/**
+ * @}
+ */
Index: pace/lib/usbhost/src/batch.c
===================================================================
--- uspace/lib/usbhost/src/batch.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,173 +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 libusbhost
- * @{
- */
-/** @file
- * USB transfer transaction structures (implementation).
- */
-#include <errno.h>
-#include <str_error.h>
-
-#include <usb/usb.h>
-#include <usb/debug.h>
-#include <usb/host/batch.h>
-
-void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
-void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
-
-void usb_transfer_batch_init(
-    usb_transfer_batch_t *instance,
-    endpoint_t *ep,
-    char *buffer,
-    char *data_buffer,
-    size_t buffer_size,
-    char *setup_buffer,
-    size_t setup_size,
-    usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out,
-    void *arg,
-    ddf_fun_t *fun,
-    void *private_data,
-    void (*private_data_dtor)(void *p_data)
-    )
-{
-	assert(instance);
-	link_initialize(&instance->link);
-	instance->ep = ep;
-	instance->callback_in = func_in;
-	instance->callback_out = func_out;
-	instance->arg = arg;
-	instance->buffer = buffer;
-	instance->data_buffer = data_buffer;
-	instance->buffer_size = buffer_size;
-	instance->setup_buffer = setup_buffer;
-	instance->setup_size = setup_size;
-	instance->fun = fun;
-	instance->private_data = private_data;
-	instance->private_data_dtor = private_data_dtor;
-	instance->transfered_size = 0;
-	instance->next_step = NULL;
-	instance->error = EOK;
-	endpoint_use(instance->ep);
-}
-/*----------------------------------------------------------------------------*/
-/** Helper function, calls callback and correctly destroys batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-void usb_transfer_batch_call_in_and_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_in(instance);
-	usb_transfer_batch_dispose(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Helper function calls callback and correctly destroys batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-void usb_transfer_batch_call_out_and_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_out(instance);
-	usb_transfer_batch_dispose(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Mark batch as finished and continue with next step.
- *
- * @param[in] instance Batch structure to use.
- *
- */
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	assert(instance->ep);
-	assert(instance->next_step);
-	endpoint_release(instance->ep);
-	instance->next_step(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare data, get error status and call callback in.
- *
- * @param[in] instance Batch structure to use.
- * Copies data from transport buffer, and calls callback with appropriate
- * parameters.
- */
-void usb_transfer_batch_call_in(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	assert(instance->callback_in);
-	assert(instance->ep);
-
-	/* We are data in, we need data */
-	memcpy(instance->buffer, instance->data_buffer, instance->buffer_size);
-
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed (%zuB): %s.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance),
-	    instance->transfered_size, str_error(instance->error));
-
-	instance->callback_in(instance->fun, instance->error,
-	    instance->transfered_size, instance->arg);
-}
-/*----------------------------------------------------------------------------*/
-/** Get error status and call callback out.
- *
- * @param[in] instance Batch structure to use.
- */
-void usb_transfer_batch_call_out(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	assert(instance->callback_out);
-
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed: %s.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance),
-	    str_error(instance->error));
-
-	instance->callback_out(instance->fun,
-	    instance->error, instance->arg);
-}
-/*----------------------------------------------------------------------------*/
-/** Correctly dispose all used data structures.
- *
- * @param[in] instance Batch structure to use.
- */
-void usb_transfer_batch_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance));
-	if (instance->private_data) {
-		assert(instance->private_data_dtor);
-		instance->private_data_dtor(instance->private_data);
-	}
-	free(instance);
-}
-/**
- * @}
- */
Index: pace/lib/usbhost/src/device_keeper.c
===================================================================
--- uspace/lib/usbhost/src/device_keeper.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ 	(revision )
@@ -1,208 +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 libusbhost
- * @{
- */
-/** @file
- * Device keeper structure and functions (implementation).
- */
-#include <assert.h>
-#include <errno.h>
-#include <usb/debug.h>
-#include <usb/host/device_keeper.h>
-
-/*----------------------------------------------------------------------------*/
-/** Initialize device keeper structure.
- *
- * @param[in] instance Memory place to initialize.
- *
- * Set all values to false/0.
- */
-void usb_device_keeper_init(usb_device_keeper_t *instance)
-{
-	assert(instance);
-	unsigned i = 0;
-	for (; i < USB_ADDRESS_COUNT; ++i) {
-		instance->devices[i].occupied = false;
-		instance->devices[i].handle = 0;
-		instance->devices[i].speed = USB_SPEED_MAX;
-	}
-	// TODO: is this hack enough?
-	// (it is needed to allow smooth registration at default address)
-	instance->devices[0].occupied = true;
-	instance->last_address = 0;
-	fibril_mutex_initialize(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-/** Get a free USB address
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] speed Speed of the device requiring address.
- * @return Free address, or error code.
- */
-usb_address_t device_keeper_get_free_address(
-    usb_device_keeper_t *instance, usb_speed_t speed)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-
-	usb_address_t new_address = instance->last_address;
-	do {
-		++new_address;
-		if (new_address > USB11_ADDRESS_MAX)
-			new_address = 1;
-		if (new_address == instance->last_address) {
-			fibril_mutex_unlock(&instance->guard);
-			return ENOSPC;
-		}
-	} while (instance->devices[new_address].occupied);
-
-	assert(new_address != USB_ADDRESS_DEFAULT);
-	assert(instance->devices[new_address].occupied == false);
-
-	instance->devices[new_address].occupied = true;
-	instance->devices[new_address].speed = speed;
-	instance->last_address = new_address;
-
-	fibril_mutex_unlock(&instance->guard);
-	return new_address;
-}
-/*----------------------------------------------------------------------------*/
-/** Bind USB address to devman handle.
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] address Device address
- * @param[in] handle Devman handle of the device.
- */
-void usb_device_keeper_bind(usb_device_keeper_t *instance,
-    usb_address_t address, devman_handle_t handle)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-
-	assert(address > 0);
-	assert(address <= USB11_ADDRESS_MAX);
-	assert(instance->devices[address].occupied);
-
-	instance->devices[address].handle = handle;
-	fibril_mutex_unlock(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-/** Release used USB address.
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] address Device address
- */
-void usb_device_keeper_release(
-    usb_device_keeper_t *instance, usb_address_t address)
-{
-	assert(instance);
-	assert(address > 0);
-	assert(address <= USB11_ADDRESS_MAX);
-
-	fibril_mutex_lock(&instance->guard);
-	assert(instance->devices[address].occupied);
-
-	instance->devices[address].occupied = false;
-	fibril_mutex_unlock(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-/** Find USB address associated with the device
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] handle Devman handle of the device seeking its address.
- * @return USB Address, or error code.
- */
-usb_address_t usb_device_keeper_find(
-    usb_device_keeper_t *instance, devman_handle_t handle)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	usb_address_t address = 1;
-	while (address <= USB11_ADDRESS_MAX) {
-		if (instance->devices[address].handle == handle) {
-			assert(instance->devices[address].occupied);
-			fibril_mutex_unlock(&instance->guard);
-			return address;
-		}
-		++address;
-	}
-	fibril_mutex_unlock(&instance->guard);
-	return ENOENT;
-}
-
-/** Find devman handle assigned to USB address.
- * Intentionally refuse to find handle of default address.
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] address Address the caller wants to find.
- * @param[out] handle Where to store found handle.
- * @return Whether such address is currently occupied.
- */
-bool usb_device_keeper_find_by_address(usb_device_keeper_t *instance,
-    usb_address_t address, devman_handle_t *handle)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
-		fibril_mutex_unlock(&instance->guard);
-		return false;
-	}
-	if (!instance->devices[address].occupied) {
-		fibril_mutex_unlock(&instance->guard);
-		return false;
-	}
-
-	if (handle != NULL) {
-		*handle = instance->devices[address].handle;
-	}
-
-	fibril_mutex_unlock(&instance->guard);
-	return true;
-}
-
-/*----------------------------------------------------------------------------*/
-/** Get speed associated with the address
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] address Address of the device.
- * @return USB speed.
- */
-usb_speed_t usb_device_keeper_get_speed(
-    usb_device_keeper_t *instance, usb_address_t address)
-{
-	assert(instance);
-	assert(address >= 0);
-	assert(address <= USB11_ADDRESS_MAX);
-
-	return instance->devices[address].speed;
-}
-/**
- * @}
- */
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbhost/src/endpoint.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -53,4 +53,8 @@
 		instance->toggle = 0;
 		instance->active = false;
+		instance->destroy_hook = NULL;
+		instance->hc_data.data = NULL;
+		instance->hc_data.toggle_get = NULL;
+		instance->hc_data.toggle_set = NULL;
 		fibril_mutex_initialize(&instance->guard);
 		fibril_condvar_initialize(&instance->avail);
@@ -64,11 +68,17 @@
 	assert(instance);
 	assert(!instance->active);
+	if (instance->hc_data.data) {
+		assert(instance->destroy_hook);
+		instance->destroy_hook(instance);
+	}
 	free(instance);
 }
 /*----------------------------------------------------------------------------*/
 void endpoint_set_hc_data(endpoint_t *instance,
-    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int))
+    void *data, void (*destroy_hook)(endpoint_t *),
+    int (*toggle_get)(void *), void (*toggle_set)(void *, int))
 {
 	assert(instance);
+	instance->destroy_hook = destroy_hook;
 	instance->hc_data.data = data;
 	instance->hc_data.toggle_get = toggle_get;
@@ -79,4 +89,5 @@
 {
 	assert(instance);
+	instance->destroy_hook = NULL;
 	instance->hc_data.data = NULL;
 	instance->hc_data.toggle_get = NULL;
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/usbhost/src/iface.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,254 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * @brief HCD DDF interface implementation
+ */
+#include <ddf/driver.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/hcd.h>
+
+static inline int send_batch(
+    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
+    void *data, size_t size, uint64_t setup_data,
+    usbhc_iface_transfer_in_callback_t in,
+    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+
+	int ret;
+
+	size_t res_bw;
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&hcd->ep_manager,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	usb_log_debug2("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    target.address, target.endpoint, name, bw, res_bw);
+		return ENOSPC;
+	}
+	if (!hcd->schedule) {
+		usb_log_error("HCD does not implement scheduler.\n");
+		return ENOTSUP;
+	}
+
+	/* No private data and no private data dtor */
+	usb_transfer_batch_t *batch =
+	    usb_transfer_batch_get(ep, data, size, setup_data,
+	    in, out, arg, fun, NULL, NULL);
+	if (!batch) {
+		return ENOMEM;
+	}
+
+	ret = hcd->schedule(hcd, batch);
+	if (ret != EOK)
+		usb_transfer_batch_dispose(batch);
+
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Request address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
+ * @param[out] address Place to write a new address.
+ * @return Error code.
+ */
+static int request_address(
+    ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	assert(address);
+
+	usb_log_debug("Address request speed: %s.\n", usb_str_speed(speed));
+	*address =
+	    usb_device_manager_get_free_address(&hcd->dev_manager, speed);
+	usb_log_debug("Address request with result: %d.\n", *address);
+	if (*address <= 0)
+		return *address;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Bind address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address of the device
+ * @param[in] handle Devman handle of the device driver.
+ * @return Error code.
+ */
+static int bind_address(
+  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+
+	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
+	usb_device_manager_bind(&hcd->dev_manager, address, handle);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Find device handle by address interface function.
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address in question.
+ * @param[out] handle Where to store device handle if found.
+ * @return Error code.
+ */
+static int find_by_address(ddf_fun_t *fun, usb_address_t address,
+    devman_handle_t *handle)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	const bool found =
+	    usb_device_manager_find_by_address(&hcd->dev_manager, address, handle);
+	return found ? EOK : ENOENT;
+}
+/*----------------------------------------------------------------------------*/
+/** Release address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address USB address to be released.
+ * @return Error code.
+ */
+static int release_address(ddf_fun_t *fun, usb_address_t address)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	usb_log_debug("Address release %d.\n", address);
+	usb_device_manager_release(&hcd->dev_manager, address);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static int register_endpoint(
+    ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed,
+    usb_endpoint_t endpoint,
+    usb_transfer_type_t transfer_type, usb_direction_t direction,
+    size_t max_packet_size, unsigned int interval)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	const size_t size = max_packet_size;
+	/* Default address is not bound or registered,
+	 * thus it does not provide speed info. */
+	const usb_speed_t speed = (address == 0) ? ep_speed :
+	    usb_device_manager_get_speed(&hcd->dev_manager, address);
+
+	usb_log_debug("Register endpoint %d:%d %s-%s %s %zuB %ums.\n",
+	    address, endpoint, usb_str_transfer_type(transfer_type),
+	    usb_str_direction(direction), usb_str_speed(speed),
+	    max_packet_size, interval);
+
+	endpoint_t *ep = endpoint_get(
+	    address, endpoint, direction, transfer_type, speed, max_packet_size);
+	if (!ep)
+		return ENOMEM;
+	int ret = EOK;
+
+	if (hcd->ep_add_hook) {
+		ret = hcd->ep_add_hook(hcd, ep);
+	}
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+		return ret;
+	}
+
+	ret = usb_endpoint_manager_register_ep(&hcd->ep_manager, ep, size);
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+static int unregister_endpoint(
+    ddf_fun_t *fun, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	usb_log_debug("Unregister endpoint %d:%d %s.\n",
+	    address, endpoint, usb_str_direction(direction));
+	return usb_endpoint_manager_unregister_ep(&hcd->ep_manager, address,
+	    endpoint, direction);
+}
+/*----------------------------------------------------------------------------*/
+static int usb_read(ddf_fun_t *fun, usb_target_t target, uint64_t setup_data,
+    uint8_t *data, size_t size, usbhc_iface_transfer_in_callback_t callback,
+    void *arg)
+{
+	return send_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    setup_data, callback, NULL, arg, "READ");
+}
+/*----------------------------------------------------------------------------*/
+static int usb_write(ddf_fun_t *fun, usb_target_t target, uint64_t setup_data,
+    const uint8_t *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return send_batch(fun, target, USB_DIRECTION_OUT, (uint8_t*)data, size,
+	    setup_data, NULL, callback, arg, "WRITE");
+}
+/*----------------------------------------------------------------------------*/
+usbhc_iface_t hcd_iface = {
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.find_by_address = find_by_address,
+	.release_address = release_address,
+
+	.register_endpoint = register_endpoint,
+	.unregister_endpoint = unregister_endpoint,
+
+	.read = usb_read,
+	.write = usb_write,
+};
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/usb_device_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_device_manager.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/usbhost/src/usb_device_manager.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,208 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * Device manager structure and functions (implementation).
+ */
+#include <assert.h>
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/host/usb_device_manager.h>
+
+/*----------------------------------------------------------------------------*/
+/** Initialize device manager structure.
+ *
+ * @param[in] instance Memory place to initialize.
+ *
+ * Set all values to false/0.
+ */
+void usb_device_manager_init(usb_device_manager_t *instance)
+{
+	assert(instance);
+	unsigned i = 0;
+	for (; i < USB_ADDRESS_COUNT; ++i) {
+		instance->devices[i].occupied = false;
+		instance->devices[i].handle = 0;
+		instance->devices[i].speed = USB_SPEED_MAX;
+	}
+	// TODO: is this hack enough?
+	// (it is needed to allow smooth registration at default address)
+	instance->devices[0].occupied = true;
+	instance->last_address = 0;
+	fibril_mutex_initialize(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Get a free USB address
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] speed Speed of the device requiring address.
+ * @return Free address, or error code.
+ */
+usb_address_t usb_device_manager_get_free_address(
+    usb_device_manager_t *instance, usb_speed_t speed)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+
+	usb_address_t new_address = instance->last_address;
+	do {
+		++new_address;
+		if (new_address > USB11_ADDRESS_MAX)
+			new_address = 1;
+		if (new_address == instance->last_address) {
+			fibril_mutex_unlock(&instance->guard);
+			return ENOSPC;
+		}
+	} while (instance->devices[new_address].occupied);
+
+	assert(new_address != USB_ADDRESS_DEFAULT);
+	assert(instance->devices[new_address].occupied == false);
+
+	instance->devices[new_address].occupied = true;
+	instance->devices[new_address].speed = speed;
+	instance->last_address = new_address;
+
+	fibril_mutex_unlock(&instance->guard);
+	return new_address;
+}
+/*----------------------------------------------------------------------------*/
+/** Bind USB address to devman handle.
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] address Device address
+ * @param[in] handle Devman handle of the device.
+ */
+void usb_device_manager_bind(usb_device_manager_t *instance,
+    usb_address_t address, devman_handle_t handle)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+
+	assert(address > 0);
+	assert(address <= USB11_ADDRESS_MAX);
+	assert(instance->devices[address].occupied);
+
+	instance->devices[address].handle = handle;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Release used USB address.
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] address Device address
+ */
+void usb_device_manager_release(
+    usb_device_manager_t *instance, usb_address_t address)
+{
+	assert(instance);
+	assert(address > 0);
+	assert(address <= USB11_ADDRESS_MAX);
+
+	fibril_mutex_lock(&instance->guard);
+	assert(instance->devices[address].occupied);
+
+	instance->devices[address].occupied = false;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Find USB address associated with the device
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] handle Devman handle of the device seeking its address.
+ * @return USB Address, or error code.
+ */
+usb_address_t usb_device_manager_find(
+    usb_device_manager_t *instance, devman_handle_t handle)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	usb_address_t address = 1;
+	while (address <= USB11_ADDRESS_MAX) {
+		if (instance->devices[address].handle == handle) {
+			assert(instance->devices[address].occupied);
+			fibril_mutex_unlock(&instance->guard);
+			return address;
+		}
+		++address;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return ENOENT;
+}
+
+/** Find devman handle assigned to USB address.
+ * Intentionally refuse to find handle of default address.
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] address Address the caller wants to find.
+ * @param[out] handle Where to store found handle.
+ * @return Whether such address is currently occupied.
+ */
+bool usb_device_manager_find_by_address(usb_device_manager_t *instance,
+    usb_address_t address, devman_handle_t *handle)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
+		fibril_mutex_unlock(&instance->guard);
+		return false;
+	}
+	if (!instance->devices[address].occupied) {
+		fibril_mutex_unlock(&instance->guard);
+		return false;
+	}
+
+	if (handle != NULL) {
+		*handle = instance->devices[address].handle;
+	}
+
+	fibril_mutex_unlock(&instance->guard);
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+/** Get speed associated with the address
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] address Address of the device.
+ * @return USB speed.
+ */
+usb_speed_t usb_device_manager_get_speed(
+    usb_device_manager_t *instance, usb_address_t address)
+{
+	assert(instance);
+	assert(address >= 0);
+	assert(address <= USB11_ADDRESS_MAX);
+
+	return instance->devices[address].speed;
+}
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/usb_endpoint_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -45,11 +45,7 @@
 static hash_index_t node_hash(unsigned long key[])
 {
-	hash_index_t hash = 0;
-	unsigned i = 0;
-	for (;i < MAX_KEYS; ++i) {
-		hash ^= key[i];
-	}
-	hash %= BUCKET_COUNT;
-	return hash;
+	/* USB endpoints use 4 bits, thus ((key[0] << 4) | key[1])
+	 * produces unique value for every address.endpoint pair */
+	return ((key[0] << 4) | key[1]) % BUCKET_COUNT;
 }
 /*----------------------------------------------------------------------------*/
@@ -63,5 +59,7 @@
 	switch (keys) {
 	case 3:
-		match = match && (key[2] == node->ep->direction);
+		match = match &&
+		    ((key[2] == node->ep->direction)
+		    || (node->ep->direction == USB_DIRECTION_BOTH));
 	case 2:
 		match = match && (key[1] == (unsigned long)node->ep->endpoint);
@@ -140,11 +138,12 @@
 /*----------------------------------------------------------------------------*/
 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
-    size_t available_bandwidth)
+    size_t available_bandwidth,
+    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
 {
 	assert(instance);
 	fibril_mutex_initialize(&instance->guard);
-	fibril_condvar_initialize(&instance->change);
 	instance->free_bw = available_bandwidth;
-	bool ht =
+	instance->bw_count = bw_count;
+	const bool ht =
 	    hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
 	return ht ? EOK : ENOMEM;
@@ -159,23 +158,25 @@
     endpoint_t *ep, size_t data_size)
 {
+	assert(instance);
+	assert(instance->bw_count);
 	assert(ep);
-	size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type,
+	const size_t bw = instance->bw_count(ep->speed, ep->transfer_type,
 	    data_size, ep->max_packet_size);
-	assert(instance);
+
+	fibril_mutex_lock(&instance->guard);
+
+	if (bw > instance->free_bw) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOSPC;
+	}
 
 	unsigned long key[MAX_KEYS] =
 	    {ep->address, ep->endpoint, ep->direction};
-	fibril_mutex_lock(&instance->guard);
-
-	link_t *item =
+
+	const link_t *item =
 	    hash_table_find(&instance->ep_table, key);
 	if (item != NULL) {
 		fibril_mutex_unlock(&instance->guard);
 		return EEXISTS;
-	}
-
-	if (bw > instance->free_bw) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOSPC;
 	}
 
@@ -193,5 +194,4 @@
 	instance->free_bw -= bw;
 	fibril_mutex_unlock(&instance->guard);
-	fibril_condvar_broadcast(&instance->change);
 	return EOK;
 }
@@ -211,6 +211,8 @@
 
 	node_t *node = hash_table_get_instance(item, node_t, link);
-	if (node->ep->active)
+	if (node->ep->active) {
+		fibril_mutex_unlock(&instance->guard);
 		return EBUSY;
+	}
 
 	instance->free_bw += node->bw;
@@ -218,5 +220,4 @@
 
 	fibril_mutex_unlock(&instance->guard);
-	fibril_condvar_broadcast(&instance->change);
 	return EOK;
 }
@@ -230,10 +231,10 @@
 
 	fibril_mutex_lock(&instance->guard);
-	link_t *item = hash_table_find(&instance->ep_table, key);
+	const link_t *item = hash_table_find(&instance->ep_table, key);
 	if (item == NULL) {
 		fibril_mutex_unlock(&instance->guard);
 		return NULL;
 	}
-	node_t *node = hash_table_get_instance(item, node_t, link);
+	const node_t *node = hash_table_get_instance(item, node_t, link);
 	if (bw)
 		*bw = node->bw;
@@ -255,14 +256,14 @@
 {
 	assert(instance);
-	if (target.endpoint > 15 || target.endpoint < 0
-	    || target.address >= USB11_ADDRESS_MAX || target.address < 0) {
+	if (!usb_target_is_valid(target)) {
 		usb_log_error("Invalid data when checking for toggle reset.\n");
 		return;
 	}
 
+	assert(data);
 	switch (data[1])
 	{
-	case 0x01: /*clear feature*/
-		/* recipient is endpoint, value is zero (ENDPOINT_STALL) */
+	case 0x01: /* Clear Feature -- resets only cleared ep */
+		/* Recipient is endpoint, value is zero (ENDPOINT_STALL) */
 		if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
 			/* endpoint number is < 16, thus first byte is enough */
@@ -276,7 +277,7 @@
 	break;
 
-	case 0x9: /* set configuration */
-	case 0x11: /* set interface */
-		/* target must be device */
+	case 0x9: /* Set Configuration */
+	case 0x11: /* Set Interface */
+		/* Recipient must be device */
 		if ((data[0] & 0xf) == 0) {
 			usb_target_t reset_target =
Index: uspace/lib/usbhost/src/usb_transfer_batch.c
===================================================================
--- uspace/lib/usbhost/src/usb_transfer_batch.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -0,0 +1,170 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * USB transfer transaction structures (implementation).
+ */
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+#include <usb/host/usb_transfer_batch.h>
+#include <usb/host/hcd.h>
+
+usb_transfer_batch_t * usb_transfer_batch_get(
+    endpoint_t *ep,
+    char *buffer,
+    size_t buffer_size,
+    uint64_t setup_buffer,
+    usbhc_iface_transfer_in_callback_t func_in,
+    usbhc_iface_transfer_out_callback_t func_out,
+    void *arg,
+    ddf_fun_t *fun,
+    void *private_data,
+    void (*private_data_dtor)(void *)
+    )
+{
+	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
+	if (instance) {
+		instance->ep = ep;
+		instance->callback_in = func_in;
+		instance->callback_out = func_out;
+		instance->arg = arg;
+		instance->buffer = buffer;
+		instance->buffer_size = buffer_size;
+		instance->setup_size = 0;
+		instance->fun = fun;
+		instance->private_data = private_data;
+		instance->private_data_dtor = private_data_dtor;
+		instance->transfered_size = 0;
+		instance->error = EOK;
+		if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) {
+			memcpy(instance->setup_buffer, &setup_buffer,
+			    USB_SETUP_PACKET_SIZE);
+			instance->setup_size = USB_SETUP_PACKET_SIZE;
+		}
+		if (instance->ep)
+			endpoint_use(instance->ep);
+	}
+	return instance;
+}
+/*----------------------------------------------------------------------------*/
+/** Mark batch as finished and run callback.
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data Data to copy to the output buffer.
+ * @param[in] size Size of @p data.
+ */
+void usb_transfer_batch_finish(
+    usb_transfer_batch_t *instance, const void *data, size_t size)
+{
+	assert(instance);
+	assert(instance->ep);
+	/* we care about the data and there are some to copy */
+        if (instance->ep->direction != USB_DIRECTION_OUT
+	    && data) {
+		const size_t min_size =
+		    size < instance->buffer_size ? size : instance->buffer_size;
+                memcpy(instance->buffer, data, min_size);
+        }
+        if (instance->callback_out)
+                usb_transfer_batch_call_out(instance);
+        if (instance->callback_in)
+                usb_transfer_batch_call_in(instance);
+
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare data, get error status and call callback in.
+ *
+ * @param[in] instance Batch structure to use.
+ * Copies data from transport buffer, and calls callback with appropriate
+ * parameters.
+ */
+void usb_transfer_batch_call_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	assert(instance->callback_in);
+
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed (%zuB): %s.\n",
+	    instance, USB_TRANSFER_BATCH_ARGS(*instance),
+	    instance->transfered_size, str_error(instance->error));
+
+	instance->callback_in(instance->fun, instance->error,
+	    instance->transfered_size, instance->arg);
+}
+/*----------------------------------------------------------------------------*/
+/** Get error status and call callback out.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_call_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	assert(instance->callback_out);
+
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed: %s.\n",
+	    instance, USB_TRANSFER_BATCH_ARGS(*instance),
+	    str_error(instance->error));
+
+	if (instance->ep->transfer_type == USB_TRANSFER_CONTROL
+	    && instance->error == EOK) {
+		const usb_target_t target =
+		    {{ instance->ep->address, instance->ep->endpoint }};
+		reset_ep_if_need(
+		    fun_to_hcd(instance->fun), target, instance->setup_buffer);
+	}
+
+	instance->callback_out(instance->fun,
+	    instance->error, instance->arg);
+}
+/*----------------------------------------------------------------------------*/
+/** Correctly dispose all used data structures.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_dispose(usb_transfer_batch_t *instance)
+{
+	if (!instance)
+		return;
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n",
+	    instance, USB_TRANSFER_BATCH_ARGS(*instance));
+	if (instance->ep) {
+		endpoint_release(instance->ep);
+	}
+	if (instance->private_data) {
+		assert(instance->private_data_dtor);
+		instance->private_data_dtor(instance->private_data);
+	}
+	free(instance);
+}
+/**
+ * @}
+ */
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/srv/hid/console/console.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -60,5 +60,5 @@
 #define CONSOLE_MARGIN  12
 
-#define STATE_START   110
+#define STATE_START   100
 #define STATE_TOP     8
 #define STATE_SPACE   4
@@ -368,5 +368,6 @@
 static console_t *cons_find_icon(sysarg_t x, sysarg_t y)
 {
-	sysarg_t status_start = STATE_START + (xres - 800) / 2;
+	sysarg_t status_start =
+	    STATE_START + (xres - 800) / 2 + CONSOLE_MARGIN;
 	
 	if ((y < STATE_TOP) || (y >= STATE_TOP + STATE_HEIGHT))
@@ -379,5 +380,5 @@
 		return NULL;
 	
-	if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) < STATE_SPACE)
+	if (((x - status_start) % (STATE_WIDTH + STATE_SPACE)) >= STATE_WIDTH)
 		return NULL;
 	
@@ -894,4 +895,6 @@
 	fb_vp_get_caps(fb_sess, console_vp, &ccaps);
 	
+	mouse.x = xres / 2;
+	mouse.y = yres / 2;
 	mouse.pressed = false;
 	
Index: uspace/srv/hid/fb/port/kfb.c
===================================================================
--- uspace/srv/hid/fb/port/kfb.c	(revision 85ff862c8e671c25e6519e7b413df4741a121b5a)
+++ uspace/srv/hid/fb/port/kfb.c	(revision f1d6866f8c36bca71fbb74e645c7d9c487d3ff60)
@@ -422,10 +422,14 @@
 {
 	if (kfb.backbuf == NULL) {
-		kfb.backbuf = malloc(kfb.size);
+		kfb.backbuf =
+		    malloc(kfb.width * kfb.height * kfb.pixel_bytes);
 		if (kfb.backbuf == NULL)
 			return ENOMEM;
 	}
 	
-	memcpy(kfb.backbuf, kfb.addr, kfb.size);
+	for (sysarg_t y = 0; y < kfb.height; y++)
+		memcpy(kfb.backbuf + y * kfb.width * kfb.pixel_bytes,
+		    kfb.addr + FB_POS(0, y), kfb.width * kfb.pixel_bytes);
+	
 	return EOK;
 }
@@ -436,5 +440,9 @@
 		return ENOENT;
 	
-	memcpy(kfb.addr, kfb.backbuf, kfb.size);
+	for (sysarg_t y = 0; y < kfb.height; y++)
+		memcpy(kfb.addr + FB_POS(0, y),
+		    kfb.backbuf + y * kfb.width * kfb.pixel_bytes,
+		    kfb.width * kfb.pixel_bytes);
+	
 	return EOK;
 }
