Index: uspace/app/usbinfo/dev.c
===================================================================
--- uspace/app/usbinfo/dev.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/app/usbinfo/dev.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -50,4 +50,5 @@
 
 	int rc;
+	bool transfer_started = false;
 
 	rc = usb_device_connection_initialize(&dev->wire, hc_handle, dev_addr);
@@ -76,11 +77,12 @@
 	}
 
-	rc = usb_pipe_start_session(&dev->ctrl_pipe);
+	rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
 	if (rc != EOK) {
 		fprintf(stderr,
-		    NAME ": failed to start session on control pipe: %s.\n",
+		    NAME ": failed to start transfer on control pipe: %s.\n",
 		    str_error(rc));
 		goto leave;
 	}
+	transfer_started = true;
 
 	rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
@@ -107,6 +109,6 @@
 
 leave:
-	if (usb_pipe_is_session_started(&dev->ctrl_pipe)) {
-		usb_pipe_end_session(&dev->ctrl_pipe);
+	if (transfer_started) {
+		usb_pipe_end_long_transfer(&dev->ctrl_pipe);
 	}
 
@@ -118,5 +120,5 @@
 void destroy_device(usbinfo_device_t *dev)
 {
-	usb_pipe_end_session(&dev->ctrl_pipe);
+	usb_pipe_end_long_transfer(&dev->ctrl_pipe);
 	free(dev);
 }
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/doc/doxygroups.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -269,4 +269,10 @@
 
 	/**
+	 * @defgroup drvusbohci OHCI driver
+	 * @ingroup usb
+	 * @brief Driver for OHCI host controller.
+	 */
+
+	/**
 	 * @defgroup drvusbehci EHCI driver
 	 * @ingroup usb
@@ -275,5 +281,5 @@
 
 	/**
-	 * @defgroup drvusbfallback USB fallback driver.
+	 * @defgroup drvusbfallback USB fallback driver
 	 * @ingroup usb
 	 * @brief Fallback driver for any USB device.
Index: uspace/drv/ehci-hcd/hc_iface.c
===================================================================
--- uspace/drv/ehci-hcd/hc_iface.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ehci-hcd/hc_iface.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -123,4 +123,5 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] address USB address of the device.
+ * @param[in] speed Endpoint speed (invalid means to use device one).
  * @param[in] endpoint Endpoint number.
  * @param[in] transfer_type USB transfer type.
@@ -131,5 +132,5 @@
  */
 static int register_endpoint(ddf_fun_t *fun,
-    usb_address_t address, usb_endpoint_t endpoint,
+    usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
     usb_transfer_type_t transfer_type, usb_direction_t direction,
     size_t max_packet_size, unsigned int interval)
@@ -165,5 +166,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
  *	by the caller).
@@ -174,5 +174,5 @@
  */
 static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size, void *data, size_t size,
+    void *data, size_t size,
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
@@ -191,5 +191,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Buffer where to store the data (in USB endianess,
  *	allocated and deallocated by the caller).
@@ -200,5 +199,5 @@
  */
 static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size, void *data, size_t size,
+    void *data, size_t size,
     usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
@@ -217,5 +216,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
  *	by the caller).
@@ -226,5 +224,5 @@
  */
 static int bulk_out(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size, void *data, size_t size,
+    void *data, size_t size,
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
@@ -243,5 +241,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Buffer where to store the data (in USB endianess,
  *	allocated and deallocated by the caller).
@@ -252,5 +249,5 @@
  */
 static int bulk_in(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size, void *data, size_t size,
+    void *data, size_t size,
     usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
@@ -269,5 +266,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
  *	and deallocated by the caller).
@@ -281,5 +277,4 @@
  */
 static int control_write(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size,
     void *setup_packet, size_t setup_packet_size,
     void *data_buffer, size_t data_buffer_size,
@@ -300,5 +295,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
  *	and deallocated by the caller).
@@ -312,5 +306,4 @@
  */
 static int control_read(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size,
     void *setup_packet, size_t setup_packet_size,
     void *data_buffer, size_t data_buffer_size,
Index: uspace/drv/ohci/Makefile
===================================================================
--- uspace/drv/ohci/Makefile	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/Makefile	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -33,11 +33,15 @@
 
 SOURCES = \
+	batch.c \
+	hc.c \
 	iface.c \
-	batch.c \
 	main.c \
-	hc.c \
 	ohci.c \
+	pci.c \
 	root_hub.c \
-	pci.c
+	transfer_list.c \
+	hw_struct/endpoint_descriptor.c \
+	hw_struct/transfer_descriptor.c
+
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/ohci/batch.c
===================================================================
--- uspace/drv/ohci/batch.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/batch.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -40,24 +40,23 @@
 #include "batch.h"
 #include "utils/malloc32.h"
-
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+typedef struct ohci_batch {
+	ed_t *ed;
+	td_t *tds;
+	size_t td_count;
+} ohci_batch_t;
+
+static void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir);
 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance);
 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance);
 
 #define DEFAULT_ERROR_COUNT 3
-usb_transfer_batch_t * batch_get(
-    ddf_fun_t *fun,
-		usb_target_t target,
-    usb_transfer_type_t transfer_type,
-		size_t max_packet_size,
-    usb_speed_t speed,
-		char *buffer,
-		size_t buffer_size,
-		char *setup_buffer,
-		size_t setup_size,
+usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
+    char *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,
-		usb_device_keeper_t *manager
-		)
+    usbhc_iface_transfer_out_callback_t func_out, void *arg)
 {
 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
@@ -73,7 +72,30 @@
 	CHECK_NULL_DISPOSE_RETURN(instance,
 	    "Failed to allocate batch instance.\n");
-	usb_transfer_batch_init(instance, target, transfer_type, speed,
-	    max_packet_size, buffer, NULL, buffer_size, NULL, setup_size,
-	    func_in, func_out, arg, fun, NULL, NULL);
+	usb_target_t target =
+	    { .address = ep->address, .endpoint = ep->endpoint };
+	usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed,
+	    ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size,
+	    func_in, func_out, arg, fun, ep, NULL);
+
+	ohci_batch_t *data = malloc(sizeof(ohci_batch_t));
+	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
+	bzero(data, sizeof(ohci_batch_t));
+	instance->private_data = data;
+
+	/* we needs + 1 transfer descriptor as the last one won't be executed */
+	data->td_count = 1 +
+	    ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER);
+	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
+		data->td_count += 2;
+	}
+
+	data->tds = malloc32(sizeof(td_t) * data->td_count);
+	CHECK_NULL_DISPOSE_RETURN(data->tds,
+	    "Failed to allocate transfer descriptors.\n");
+	bzero(data->tds, sizeof(td_t) * data->td_count);
+
+	data->ed = malloc32(sizeof(ed_t));
+	CHECK_NULL_DISPOSE_RETURN(data->ed,
+	    "Failed to allocate endpoint descriptor.\n");
 
         if (buffer_size > 0) {
@@ -90,5 +112,4 @@
         }
 
-
 	return instance;
 }
@@ -97,7 +118,37 @@
 {
 	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	free32(data->ed);
+	free32(data->tds);
+	free32(instance->setup_buffer);
 	free32(instance->transport_buffer);
-	free32(instance->setup_buffer);
+	free(data);
 	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+bool batch_is_complete(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	size_t tds = data->td_count - 1;
+	usb_log_debug2("Batch(%p) checking %d td(s) for completion.\n",
+	    instance, tds);
+	size_t i = 0;
+	for (; i < tds; ++i) {
+		if (!td_is_finished(&data->tds[i]))
+			return false;
+		instance->error = td_error(&data->tds[i]);
+		/* FIXME: calculate real transfered size */
+		instance->transfered_size = instance->buffer_size;
+		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
+			    instance, i, data->tds[i].status);
+			return true;
+//			endpoint_toggle_set(instance->ep,
+		}
+	}
+	return true;
 }
 /*----------------------------------------------------------------------------*/
@@ -109,5 +160,5 @@
 	    instance->buffer_size);
 	instance->next_step = batch_call_out_and_dispose;
-	/* TODO: implement */
+	batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
 	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
 }
@@ -117,5 +168,5 @@
 	assert(instance);
 	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
 	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
 }
@@ -124,5 +175,5 @@
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_IN;
+	assert(instance->direction == USB_DIRECTION_IN);
 	instance->next_step = batch_call_in_and_dispose;
 	/* TODO: implement */
@@ -133,5 +184,5 @@
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_OUT;
+	assert(instance->direction == USB_DIRECTION_OUT);
 	/* We are data out, we are supposed to provide data */
 	memcpy(instance->transport_buffer, instance->buffer,
@@ -160,4 +211,60 @@
 }
 /*----------------------------------------------------------------------------*/
+ed_t * batch_ed(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	return data->ed;
+}
+/*----------------------------------------------------------------------------*/
+void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir)
+{
+	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	ed_init(data->ed, instance->ep);
+	ed_add_tds(data->ed, &data->tds[0], &data->tds[data->td_count - 1]);
+	usb_log_debug("Created ED: %x:%x:%x:%x.\n", 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 *transfer_buffer = instance->transport_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, transfer_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);
+
+		transfer_buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count - 2);
+		++td_current;
+	}
+
+	/* status stage */
+	assert(td_current == data->td_count - 2);
+	td_init(&data->tds[td_current], status_dir, NULL, 0, 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);
+}
+/*----------------------------------------------------------------------------*/
 /** Helper function calls callback and correctly disposes of batch structure.
  *
Index: uspace/drv/ohci/batch.h
===================================================================
--- uspace/drv/ohci/batch.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/batch.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -26,36 +26,31 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup drvusbohci
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief OHCI driver USB transaction structure
+ * @brief UHCI driver USB transaction structure
  */
-#ifndef DRV_OHCI_BATCH_H
-#define DRV_OHCI_BATCH_H
-
+#ifndef DRV_UHCI_BATCH_H
+#define DRV_UHCI_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>
 
+#include "hw_struct/endpoint_descriptor.h"
+
 usb_transfer_batch_t * batch_get(
-    ddf_fun_t *fun,
-		usb_target_t target,
-    usb_transfer_type_t transfer_type,
-		size_t max_packet_size,
-    usb_speed_t speed,
-		char *buffer,
-		size_t size,
-		char *setup_buffer,
-		size_t setup_size,
+    ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t 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,
-		usb_device_keeper_t *manager
-		);
+    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);
@@ -70,4 +65,6 @@
 
 void batch_bulk_out(usb_transfer_batch_t *instance);
+
+ed_t * batch_ed(usb_transfer_batch_t *instance);
 #endif
 /**
Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/hc.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -47,4 +47,6 @@
 static void hc_gain_control(hc_t *instance);
 static void hc_init_hw(hc_t *instance);
+static int hc_init_transfer_lists(hc_t *instance);
+static int hc_init_memory(hc_t *instance);
 /*----------------------------------------------------------------------------*/
 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
@@ -59,9 +61,18 @@
 	    &instance->manager, hub_address, hub_fun->handle);
 
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	assert(ep);
+	int ret = endpoint_init(ep, hub_address, 0, USB_DIRECTION_BOTH,
+	    USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64);
+	assert(ret == EOK);
+	ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, 0);
+	assert(ret == EOK);
+
 	char *match_str = NULL;
-	int ret = asprintf(&match_str, "usb&class=hub");
-	ret = (match_str == NULL) ? ret : EOK;
+	ret = asprintf(&match_str, "usb&class=hub");
+//	ret = (match_str == NULL) ? ret : EOK;
 	if (ret < 0) {
-		usb_log_error("Failed to create root hub match-id string.\n");
+		usb_log_error(
+		    "Failed(%d) to create root hub match-id string.\n", ret);
 		return ret;
 	}
@@ -107,4 +118,5 @@
 	rh_init(&instance->rh, dev, instance->registers);
 
+	hc_init_memory(instance);
 	hc_init_hw(instance);
 
@@ -117,9 +129,24 @@
 	assert(instance);
 	assert(batch);
+
+	/* check for root hub communication */
 	if (batch->target.address == instance->rh.address) {
 		return rh_request(&instance->rh, batch);
 	}
-	/* TODO: implement */
-	return ENOTSUP;
+
+	transfer_list_add_batch(
+	    instance->transfers[batch->transfer_type], batch);
+
+	switch (batch->transfer_type) {
+	case USB_TRANSFER_CONTROL:
+		instance->registers->command_status |= CS_CLF;
+		break;
+	case USB_TRANSFER_BULK:
+		instance->registers->command_status |= CS_BLF;
+		break;
+	default:
+		break;
+	}
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -134,6 +161,17 @@
 	usb_log_info("OHCI interrupt: %x.\n", status);
 
-	/* TODO: Check for further interrupt causes */
-	/* TODO: implement */
+	LIST_INITIALIZE(done);
+	transfer_list_remove_finished(&instance->transfers_interrupt, &done);
+	transfer_list_remove_finished(&instance->transfers_isochronous, &done);
+	transfer_list_remove_finished(&instance->transfers_control, &done);
+	transfer_list_remove_finished(&instance->transfers_bulk, &done);
+
+	while (!list_empty(&done)) {
+		link_t *item = done.next;
+		list_remove(item);
+		usb_transfer_batch_t *batch =
+		    list_get_instance(item, usb_transfer_batch_t, link);
+		usb_transfer_batch_finish(batch);
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -197,17 +235,89 @@
 	assert(instance);
 	const uint32_t fm_interval = instance->registers->fm_interval;
+
+	/* reset hc */
 	instance->registers->command_status = CS_HCR;
 	async_usleep(10);
+
+	/* restore fm_interval */
 	instance->registers->fm_interval = fm_interval;
 	assert((instance->registers->command_status & CS_HCR) == 0);
+
 	/* hc is now in suspend state */
-	/* TODO: init HCCA block */
-	/* TODO: init queues */
-	/* TODO: enable queues */
+
+	/* enable queues */
+	instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
 	/* TODO: enable interrupts */
-	/* TODO: set periodic start to 90% */
+	/* set periodic start to 90% */
+	instance->registers->periodic_start = (fm_interval / 10) * 9;
 
 	instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
 	usb_log_info("OHCI HC up and running.\n");
+}
+/*----------------------------------------------------------------------------*/
+int hc_init_transfer_lists(hc_t *instance)
+{
+	assert(instance);
+
+#define SETUP_TRANSFER_LIST(type, name) \
+do { \
+	int ret = transfer_list_init(&instance->type, name); \
+	if (ret != EOK) { \
+		usb_log_error("Failed(%d) to setup %s transfer list.\n", \
+		    ret, name); \
+		transfer_list_fini(&instance->transfers_isochronous); \
+		transfer_list_fini(&instance->transfers_interrupt); \
+		transfer_list_fini(&instance->transfers_control); \
+		transfer_list_fini(&instance->transfers_bulk); \
+	} \
+} while (0)
+
+	SETUP_TRANSFER_LIST(transfers_isochronous, "ISOCHRONOUS");
+	SETUP_TRANSFER_LIST(transfers_interrupt, "INTERRUPT");
+	SETUP_TRANSFER_LIST(transfers_control, "CONTROL");
+	SETUP_TRANSFER_LIST(transfers_bulk, "BULK");
+
+	transfer_list_set_next(&instance->transfers_interrupt,
+	    &instance->transfers_isochronous);
+
+	/* Assign pointers to be used during scheduling */
+	instance->transfers[USB_TRANSFER_INTERRUPT] =
+	  &instance->transfers_interrupt;
+	instance->transfers[USB_TRANSFER_ISOCHRONOUS] =
+	  &instance->transfers_interrupt;
+	instance->transfers[USB_TRANSFER_CONTROL] =
+	  &instance->transfers_control;
+	instance->transfers[USB_TRANSFER_BULK] =
+	  &instance->transfers_bulk;
+
+	return EOK;
+#undef CHECK_RET_CLEAR_RETURN
+}
+/*----------------------------------------------------------------------------*/
+int hc_init_memory(hc_t *instance)
+{
+	assert(instance);
+	/* init queues */
+	hc_init_transfer_lists(instance);
+
+	/* init HCCA */
+	instance->hcca = malloc32(sizeof(hcca_t));
+	if (instance->hcca == NULL)
+		return ENOMEM;
+	bzero(instance->hcca, sizeof(hcca_t));
+	instance->registers->hcca = addr_to_phys(instance->hcca);
+
+	/* use queues */
+	instance->registers->bulk_head = instance->transfers_bulk.list_head_pa;
+	instance->registers->control_head =
+	    instance->transfers_control.list_head_pa;
+
+	unsigned i = 0;
+	for (; i < 32; ++i) {
+		instance->hcca->int_ep[i] =
+		    instance->transfers_interrupt.list_head_pa;
+	}
+
+	return EOK;
 }
 /**
Index: uspace/drv/ohci/hc.h
===================================================================
--- uspace/drv/ohci/hc.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/hc.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -48,4 +48,5 @@
 #include "ohci_regs.h"
 #include "root_hub.h"
+#include "transfer_list.h"
 #include "hw_struct/hcca.h"
 
@@ -54,4 +55,14 @@
 	usb_address_t rh_address;
 	rh_t rh;
+
+	hcca_t *hcca;
+
+	transfer_list_t transfers_isochronous;
+	transfer_list_t transfers_interrupt;
+	transfer_list_t transfers_control;
+	transfer_list_t transfers_bulk;
+
+	transfer_list_t *transfers[4];
+
 	ddf_fun_t *ddf_instance;
 	usb_device_keeper_t manager;
Index: uspace/drv/ohci/hw_struct/completion_codes.h
===================================================================
--- uspace/drv/ohci/hw_struct/completion_codes.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/hw_struct/completion_codes.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -35,4 +35,6 @@
 #define DRV_OHCI_HW_STRUCT_COMPLETION_CODES_H
 
+#include <errno.h>
+
 #define CC_NOERROR (0x0)
 #define CC_CRC (0x1)
@@ -50,4 +52,38 @@
 #define CC_NOACCESS2 (0xf)
 
+inline static int cc_to_rc(int cc)
+{
+	switch (cc) {
+	case CC_NOERROR:
+		return EOK;
+
+	case CC_CRC:
+		return EBADCHECKSUM;
+
+	case CC_PIDUNEXPECTED:
+	case CC_PIDFAIL:
+	case CC_BITSTUFF:
+		return EIO;
+
+	case CC_TOGGLE:
+	case CC_STALL:
+		return ESTALL;
+
+	case CC_NORESPONSE:
+		return ETIMEOUT;
+
+	case CC_DATAOVERRRUN:
+	case CC_DATAUNDERRRUN:
+	case CC_BUFFEROVERRRUN:
+	case CC_BUFFERUNDERRUN:
+		return EOVERFLOW;
+
+	case CC_NOACCESS1:
+	case CC_NOACCESS2:
+	default:
+		return ENOTSUP;
+	}
+}
+
 #endif
 /**
Index: uspace/drv/ohci/hw_struct/endpoint_descriptor.c
===================================================================
--- uspace/drv/ohci/hw_struct/endpoint_descriptor.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
+++ uspace/drv/ohci/hw_struct/endpoint_descriptor.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -0,0 +1,64 @@
+/*
+ * 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 "endpoint_descriptor.h"
+
+static unsigned direc[3] =
+    { ED_STATUS_D_IN, ED_STATUS_D_OUT, ED_STATUS_D_TRANSFER };
+
+void ed_init(ed_t *instance, endpoint_t *ep)
+{
+	assert(instance);
+	bzero(instance, sizeof(ed_t));
+	if (ep == NULL) {
+		instance->status |= ED_STATUS_K_FLAG;
+		return;
+	}
+	assert(ep);
+	instance->status = 0
+	    | ((ep->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
+	    | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)
+	    | ((direc[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
+	    | ((ep->max_packet_size & ED_STATUS_MPS_MASK)
+	        << ED_STATUS_MPS_SHIFT);
+
+	if (ep->speed == USB_SPEED_LOW)
+		instance->status |= ED_STATUS_S_FLAG;
+	if (ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)
+		instance->status |= ED_STATUS_F_FLAG;
+
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/endpoint_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/endpoint_descriptor.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/hw_struct/endpoint_descriptor.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -35,5 +35,11 @@
 #define DRV_OHCI_HW_STRUCT_ENDPOINT_DESCRIPTOR_H
 
+#include <assert.h>
 #include <stdint.h>
+
+#include <usb/host/endpoint.h>
+
+#include "utils/malloc32.h"
+#include "transfer_descriptor.h"
 
 #include "completion_codes.h"
@@ -44,11 +50,12 @@
 #define ED_STATUS_FA_SHIFT (0)
 #define ED_STATUS_EN_MASK (0xf)    /* USB endpoint address */
-#define ED_STATUS_EN_SHIFT (6)
+#define ED_STATUS_EN_SHIFT (7)
 #define ED_STATUS_D_MASK (0x3)     /* direction */
-#define ED_STATUS_D_SHIFT (10)
+#define ED_STATUS_D_SHIFT (11)
 #define ED_STATUS_D_IN (0x1)
 #define ED_STATUS_D_OUT (0x2)
+#define ED_STATUS_D_TRANSFER (0x3)
 
-#define ED_STATUS_S_FLAG (1 << 13) /* speed flag */
+#define ED_STATUS_S_FLAG (1 << 13) /* speed flag: 1 = low */
 #define ED_STATUS_K_FLAG (1 << 14) /* skip flag (no not execute this ED) */
 #define ED_STATUS_F_FLAG (1 << 15) /* format: 1 = isochronous*/
@@ -71,4 +78,23 @@
 #define ED_NEXT_PTR_SHIFT (0)
 } __attribute__((packed)) ed_t;
+
+void ed_init(ed_t *instance, endpoint_t *ep);
+
+static inline void ed_add_tds(ed_t *instance, td_t *head, td_t *tail)
+{
+	assert(instance);
+	instance->td_head = addr_to_phys(head) & ED_TDHEAD_PTR_MASK;
+	instance->td_tail = addr_to_phys(tail) & ED_TDTAIL_PTR_MASK;
+}
+
+static inline void ed_append_ed(ed_t *instance, ed_t *next)
+{
+	assert(instance);
+	assert(next);
+	uint32_t pa = addr_to_phys(next);
+	assert((pa & ED_NEXT_PTR_MASK) << ED_NEXT_PTR_SHIFT == pa);
+	instance->next = pa;
+}
+
 #endif
 /**
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include <usb/usb.h>
+#include "utils/malloc32.h"
+
+#include "transfer_descriptor.h"
+
+static unsigned dp[3] =
+    { TD_STATUS_DP_IN, TD_STATUS_DP_OUT, TD_STATUS_DP_SETUP };
+static unsigned togg[2] = { TD_STATUS_T_0, TD_STATUS_T_1 };
+
+void td_init(
+    td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle)
+{
+	assert(instance);
+	bzero(instance, sizeof(td_t));
+	instance-> status = 0
+	    | ((dp[dir] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
+	    | ((CC_NOACCESS2 & TD_STATUS_CC_MASK) << TD_STATUS_CC_SHIFT);
+	if (toggle == 0 || toggle == 1) {
+		instance->status |= togg[toggle] << TD_STATUS_T_SHIFT;
+	}
+	if (buffer != NULL) {
+		instance->cbp = addr_to_phys(buffer);
+		instance->be = addr_to_phys(buffer + size - 1);
+	}
+}
+/**
+ * @}
+ */
+
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -35,7 +35,12 @@
 #define DRV_OHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H
 
+#include <bool.h>
 #include <stdint.h>
+#include "utils/malloc32.h"
 
 #include "completion_codes.h"
+
+/* OHCI TDs can handle up to 8KB buffers */
+#define OHCI_TD_MAX_TRANSFER (8 * 1024)
 
 typedef struct td {
@@ -52,4 +57,6 @@
 #define TD_STATUS_T_MASK (0x3)  /* data toggle 1x = use ED toggle carry */
 #define TD_STATUS_T_SHIFT (24)
+#define TD_STATUS_T_0 (0x2)
+#define TD_STATUS_T_1 (0x3)
 #define TD_STATUS_EC_MASK (0x3) /* error count */
 #define TD_STATUS_EC_SHIFT (26)
@@ -64,4 +71,35 @@
 	volatile uint32_t be; /* buffer end, address of the last byte */
 } __attribute__((packed)) td_t;
+
+void td_init(
+    td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle);
+
+inline static void td_set_next(td_t *instance, td_t *next)
+{
+	assert(instance);
+	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
+}
+
+inline static bool td_is_finished(td_t *instance)
+{
+	assert(instance);
+	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	/* something went wrong, error code is set */
+	if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2 && cc != CC_NOERROR) {
+		return true;
+	}
+	/* everything done */
+	if (cc == CC_NOERROR && instance->cbp == 0) {
+		return true;
+	}
+	return false;
+}
+
+static inline int td_error(td_t *instance)
+{
+	assert(instance);
+	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	return cc_to_rc(cc);
+}
 #endif
 /**
Index: uspace/drv/ohci/iface.c
===================================================================
--- uspace/drv/ohci/iface.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/iface.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Vojtech Horky, Jan Vesely
  * All rights reserved.
  *
@@ -30,5 +30,5 @@
  */
 /** @file
- * USB-HC interface implementation.
+ * @brief OHCI driver hc interface implementation
  */
 #include <ddf/driver.h>
@@ -36,19 +36,60 @@
 
 #include <usb/debug.h>
+#include <usb/host/endpoint.h>
 
 #include "iface.h"
 #include "hc.h"
 
-#define UNSUPPORTED(methodname) \
-	usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
-	    methodname, __FILE__, __LINE__)
-
-/** Reserve default address.
- *
- * This function may block the caller.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] speed Speed of the device for which the default address is
- *	reserved.
+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;
+	}
+
+	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",
+		    name, target.address, target.endpoint, bw, res_bw);
+		return ENOSPC;
+	}
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	assert(ep->speed ==
+	    usb_device_keeper_get_speed(&(*hc)->manager, target.address));
+//	assert(ep->max_packet_size == max_packet_size);
+//	assert(ep->transfer_type == USB_TRANSFER_CONTROL);
+
+	*batch =
+	    batch_get(fun, ep, data, size, setup_data, setup_size,
+		in, out, arg);
+	if (!batch)
+		return ENOMEM;
+	return EOK;
+}
+
+
+/** Reserve default address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
  * @return Error code.
  */
@@ -61,9 +102,28 @@
 	usb_device_keeper_reserve_default_address(&hc->manager, speed);
 	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Release default address.
- *
- * @param[in] fun Device function the action was invoked on.
+#if 0
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+	const size_t max_packet_size = speed == USB_SPEED_LOW ? 8 : 64;
+	endpoint_init(ep, USB_TRANSFER_CONTROL, speed, max_packet_size);
+	int ret;
+try_retgister:
+	ret = usb_endpoint_manager_register_ep(&hc->ep_manager,
+	    USB_ADDRESS_DEFAULT, 0, USB_DIRECTION_BOTH, ep, endpoint_destroy, 0);
+	if (ret == EEXISTS) {
+		async_usleep(1000);
+		goto try_retgister;
+	}
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+	}
+	return ret;
+#endif
+}
+/*----------------------------------------------------------------------------*/
+/** Release default address interface function
+ *
+ * @param[in] fun DDF function that was called.
  * @return Error code.
  */
@@ -74,13 +134,15 @@
 	assert(hc);
 	usb_log_debug("Default address release.\n");
+//	return usb_endpoint_manager_unregister_ep(&hc->ep_manager,
+//	    USB_ADDRESS_DEFAULT, 0, USB_DIRECTION_BOTH);
 	usb_device_keeper_release_default_address(&hc->manager);
 	return EOK;
 }
 /*----------------------------------------------------------------------------*/
-/** Found free USB address.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] speed Speed of the device that will get this address.
- * @param[out] address Non-null pointer where to store the free address.
+/** 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.
  */
@@ -101,13 +163,13 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Bind USB address with device devman handle.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] handle Devman handle of the device.
+/** 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)
+  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
 {
 	assert(fun);
@@ -119,7 +181,7 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Release previously requested address.
- *
- * @param[in] fun Device function the action was invoked on.
+/** Release address interface function
+ *
+ * @param[in] fun DDF function that was called.
  * @param[in] address USB address to be released.
  * @return Error code.
@@ -139,4 +201,5 @@
  * @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.
@@ -146,41 +209,59 @@
  * @return Error code.
  */
-static int register_endpoint(
-    ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
+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);
 	if (address == hc->rh.address)
 		return EOK;
-	const usb_speed_t speed =
-		usb_device_keeper_get_speed(&hc->manager, address);
-	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;
+	}
+	const size_t size =
+	    (transfer_type == USB_TRANSFER_INTERRUPT
+	    || transfer_type == USB_TRANSFER_ISOCHRONOUS) ?
+	    max_packet_size : 0;
+	int ret;
+
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+	ret = endpoint_init(ep, address, endpoint, direction,
+	    transfer_type, speed, max_packet_size);
+	if (ret != EOK) {
+		free(ep);
+		return ret;
+	}
+
 	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);
-	// TODO use real endpoint here!
-	return usb_endpoint_manager_register_ep(&hc->ep_manager,NULL, 0);
-}
-/*----------------------------------------------------------------------------*/
-/** Unregister endpoint (free some bandwidth reservation).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] endpoint Endpoint number.
- * @param[in] direction Endpoint data direction.
- * @return Error code.
- */
+
+	ret = usb_endpoint_manager_register_ep(&hc->ep_manager, ep, size);
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+	} else {
+		usb_device_keeper_add_ep(&hc->manager, address, 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);
 	hc_t *hc = fun_to_hc(fun);
 	assert(hc);
 	usb_log_debug("Unregister endpoint %d:%d %d.\n",
 	    address, endpoint, direction);
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
+	    address, endpoint, direction, NULL);
+	if (ep != NULL) {
+		usb_device_keeper_del_ep(&hc->manager, address, ep);
+	}
 	return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
 	    endpoint, direction);
@@ -196,5 +277,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
  *	by the caller).
@@ -205,23 +285,15 @@
  */
 static int interrupt_out(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Interrupt OUT %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size,
-	        speed, data, size, NULL, 0, NULL, callback, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	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);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -239,5 +311,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Buffer where to store the data (in USB endianess,
  *	allocated and deallocated by the caller).
@@ -248,22 +319,15 @@
  */
 static int interrupt_in(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Interrupt IN %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size,
-	        speed, data, size, NULL, 0, callback, NULL, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	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);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -281,5 +345,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
  *	by the caller).
@@ -290,23 +353,15 @@
  */
 static int bulk_out(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed,
-	        data, size, NULL, 0, NULL, callback, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	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);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -324,5 +379,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] data Buffer where to store the data (in USB endianess,
  *	allocated and deallocated by the caller).
@@ -333,22 +387,15 @@
  */
 static int bulk_in(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Bulk IN %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed,
-	        data, size, NULL, 0, callback, NULL, arg, &hc->manager);
-	if (!batch)
-		return ENOMEM;
+	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);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -366,5 +413,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
  *	and deallocated by the caller).
@@ -378,28 +424,18 @@
  */
 static int control_write(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
+    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)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-	usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n",
-	    speed, target.address, target.endpoint, size, max_packet_size);
-
-	if (setup_size != 8)
-		return EINVAL;
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size,
-	        speed, data, size, setup_data, setup_size, NULL, callback, arg,
-		&hc->manager);
-	if (!batch)
-		return ENOMEM;
+	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_device_keeper_reset_if_need(&hc->manager, target, setup_data);
 	batch_control_write(batch);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -417,5 +453,4 @@
  * @param[in] fun Device function the action was invoked on.
  * @param[in] target Target pipe (address and endpoint number) specification.
- * @param[in] max_packet_size Max packet size for the transfer.
  * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
  *	and deallocated by the caller).
@@ -429,24 +464,17 @@
  */
 static int control_read(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
+    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)
 {
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, target.address);
-
-	usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n",
-	    speed, target.address, target.endpoint, size, max_packet_size);
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size,
-	        speed, data, size, setup_data, setup_size, callback, NULL, arg,
-		&hc->manager);
-	if (!batch)
-		return ENOMEM;
+	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);
-	const int ret = hc_schedule(hc, batch);
+	ret = hc_schedule(hc, batch);
 	if (ret != EOK) {
 		batch_dispose(batch);
@@ -455,5 +483,4 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Host controller interface implementation for OHCI. */
 usbhc_iface_t hc_iface = {
 	.reserve_default_address = reserve_default_address,
@@ -475,5 +502,4 @@
 	.control_read = control_read,
 };
-
 /**
  * @}
Index: uspace/drv/ohci/ohci_regs.h
===================================================================
--- uspace/drv/ohci/ohci_regs.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/ohci_regs.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -41,68 +41,184 @@
 	const volatile uint32_t revision;
 	volatile uint32_t control;
-#define C_CSBR_MASK (0x3)
+#define C_CSBR_MASK (0x3) /* Control-bulk service ratio */
+#define C_CSBR_1_1  (0x0)
+#define C_CSBR_1_2  (0x1)
+#define C_CSBR_1_3  (0x2)
+#define C_CSBR_1_4  (0x3)
 #define C_CSBR_SHIFT (0)
-#define C_PLE (1 << 2)
-#define C_IE (1 << 3)
-#define C_CLE (1 << 4)
-#define C_BLE (1 << 5)
-
-#define C_HCFS_MASK (0x3)
-#define C_HCFS_SHIFT (6)
-#define C_HCFS_RESET (0x0)
+
+#define C_PLE (1 << 2)   /* Periodic list enable */
+#define C_IE  (1 << 3)   /* Isochronous enable */
+#define C_CLE (1 << 4)   /* Control list enable */
+#define C_BLE (1 << 5)   /* Bulk list enable */
+
+#define C_HCFS_MASK        (0x3) /* Host controller functional state */
+#define C_HCFS_RESET       (0x0)
 #define C_HCFS_OPERATIONAL (0x1)
-#define C_HCFS_RESUME (0x2)
-#define C_HCFS_SUSPEND (0x3)
-
-#define C_IR (1 << 8)
-#define C_RWC (1 << 9)
-#define C_RWE (1 << 10)
+#define C_HCFS_RESUME      (0x2)
+#define C_HCFS_SUSPEND     (0x3)
+#define C_HCFS_SHIFT       (6)
+
+#define C_IR  (1 << 8)   /* Interrupt routing, make sure it's 0 */
+#define C_RWC (1 << 9)   /* Remote wakeup connected, host specific */
+#define C_RWE (1 << 10)  /* Remote wakeup enable */
 
 	volatile uint32_t command_status;
-#define CS_HCR (1 << 0)
-#define CS_CLF (1 << 1)
-#define CS_BLF (1 << 2)
-#define CS_OCR (1 << 3)
-#define CS_SOC_MASK (0x3)
+#define CS_HCR (1 << 0)   /* Host controller reset */
+#define CS_CLF (1 << 1)   /* Control list filled */
+#define CS_BLF (1 << 2)   /* Bulk list filled */
+#define CS_OCR (1 << 3)   /* Ownership change request */
+#define CS_SOC_MASK (0x3) /* Scheduling overrun count */
 #define CS_SOC_SHIFT (16)
 
 	volatile uint32_t interrupt_status;
-#define IS_SO (1 << 0)
-#define IS_WDH (1 << 1)
-#define IS_SF (1 << 2)
-#define IS_RD (1 << 3)
-#define IS_UE (1 << 4)
-#define IS_FNO (1 << 5)
-#define IS_RHSC (1 << 6)
-#define IS_OC (1 << 30)
-
+#define IS_SO   (1 << 0)  /* Scheduling overrun */
+#define IS_WDH  (1 << 1)  /* Write-back done head */
+#define IS_SF   (1 << 2)  /* Start of frame */
+#define IS_RD   (1 << 3)  /* Resume detected */
+#define IS_UE   (1 << 4)  /* Unrecoverable error */
+#define IS_FNO  (1 << 5)  /* Frame number overflow */
+#define IS_RHSC (1 << 6)  /* Root hub status change */
+#define IS_OC   (1 << 30) /* Ownership change */
+
+	/** Interupt enable/disable, reads give the same value, writing causes
+	 * enable/disable */
 	volatile uint32_t interupt_enable;
-#define IE_SO   (1 << 0)
-#define IE_WDH  (1 << 1)
-#define IE_SF   (1 << 2)
-#define IE_RD   (1 << 3)
-#define IE_UE   (1 << 4)
-#define IE_FNO  (1 << 5)
-#define IE_RHSC (1 << 6)
-#define IE_OC   (1 << 30)
-#define IE_MIE  (1 << 31)
-
 	volatile uint32_t interrupt_disable;
+#define I_SO   (1 << 0)   /* Scheduling overrun */
+#define I_WDH  (1 << 1)   /* Done head write-back */
+#define I_SF   (1 << 2)   /* Start of frame */
+#define I_RD   (1 << 3)   /* Resume detect */
+#define I_UE   (1 << 4)   /* Unrecoverable error */
+#define I_FNO  (1 << 5)   /* Frame number overflow */
+#define I_RHSC (1 << 6)   /* Root hub status change */
+#define I_OC   (1 << 30)  /* Ownership change */
+#define I_MI   (1 << 31)  /* Master interrupt (all/any interrupts) */
+
+	/** HCCA pointer (see hw_struct hcca.h) */
 	volatile uint32_t hcca;
-	volatile uint32_t period_corrent;
+#define HCCA_PTR_MASK 0xffffff00 /* HCCA is 256B aligned */
+
+	/** Currently executed period endpoint */
+	const volatile uint32_t period_current;
+
+	/** The first control endpoint */
 	volatile uint32_t control_head;
+
+	/** Currently executed control endpoint */
 	volatile uint32_t control_current;
+
+	/** The first bulk endpoint */
 	volatile uint32_t bulk_head;
+
+	/** Currently executed bulk endpoint */
 	volatile uint32_t bulk_current;
-	volatile uint32_t done_head;
+
+	/** Done TD list, this value is periodically written to HCCA */
+	const volatile uint32_t done_head;
+
+	/** Frame time and max packet size for all transfers */
 	volatile uint32_t fm_interval;
-	volatile uint32_t fm_remaining;
-	volatile uint32_t fm_number;
+#define FMI_FI_MASK (0x1fff) /* Frame interval in bit times (should be 11999)*/
+#define FMI_FI_SHIFT (0)
+#define FMI_FSMPS_MASK (0x7fff) /* Full speed max packet size */
+#define FMI_FSMPS_SHIFT (16)
+#define FMI_TOGGLE_FLAG (1 << 31)
+
+	/** Bit times remaining in current frame */
+	const volatile uint32_t fm_remaining;
+#define FMR_FR_MASK FMI_FI_MASK
+#define FMR_FR_SHIFT FMI_FI_SHIFT
+#define FMR_TOGGLE_FLAG FMI_TOGGLE_FLAG
+
+	/** Frame number */
+	const volatile uint32_t fm_number;
+#define FMN_NUMBER_MASK (0xffff)
+
+	/** Remaining bit time in frame to start periodic transfers */
 	volatile uint32_t periodic_start;
+#define PS_PS_MASK (0x1fff) /* bit time when periodic get priority (0x3e67) */
+
+	/** Threshold for starting LS transaction */
 	volatile uint32_t ls_threshold;
+#define LST_LST_MASK (0x7fff)
+
+	/** The first root hub control register */
 	volatile uint32_t rh_desc_a;
+#define RHDA_NDS_MASK (0xff) /* Number of downstream ports, max 15 */
+#define RHDA_NDS_SHIFT (0)
+#define RHDA_PSM_FLAG  (1 << 8)  /* Power switching mode: 0-global, 1-per port*/
+#define RHDA_NPS_FLAG  (1 << 9)  /* No power switch: 1-power on, 0-use PSM*/
+#define RHDA_DT_FLAG   (1 << 10) /* 1-Compound device, must be 0 */
+#define RHDA_OCPM_FLAG (1 << 11) /* Over-current mode: 0-global, 1-per port */
+#define RHDA_NOCP      (1 << 12) /* OC control: 0-use OCPM, 1-OC off */
+#define RHDA_POTPGT_MASK (0xff)  /* Power on to power good time */
+#define RHDA_POTPGT_SHIFT (24)
+
+	/** The other root hub control register */
 	volatile uint32_t rh_desc_b;
+#define RHDB_DR_MASK (0xffff) /* Device removable mask */
+#define RHDB_DR_SHIFT (0)
+#define RHDB_PCC_MASK (0xffff) /* Power control mask */
+#define RHDB_PCC_SHIFT (16)
+
+/* Port device removable status */
+#define RHDB_DR_FLAG(port) (((1 << port) & RHDB_DR_MASK) << RHDB_DR_SHIFT)
+/* Port power control status: 1-per port power control, 0-global power switch */
+#define RHDB_PPC_FLAG(port) (((1 << port) & RHDB_DR_MASK) << RHDB_DR_SHIFT)
+
+	/** Root hub status register */
 	volatile uint32_t rh_status;
+#define RHS_LPS_FLAG  (1 <<  0)/* read: 0,
+                                * write: 0-no effect,
+                                *        1-turn off port power for ports
+                                *        specified in PPCM(RHDB), or all ports,
+                                *        if power is set globally */
+#define RHS_CLEAR_PORT_POWER RHS_LPS_FLAG /* synonym for the above */
+#define RHS_OCI_FLAG  (1 <<  1)/* Over-current indicator, if per-port: 0 */
+#define RHS_DRWE_FLAG (1 << 15)/* read: 0-connect status change does not wake HC
+                                *       1-connect status change wakes HC
+                                * write: 1-set DRWE, 0-no effect */
+#define RHS_SET_DRWE RHS_DRWE_FLAG
+#define RHS_LPSC_FLAG (1 << 16)/* read: 0,
+                                * write: 0-no effect
+                                *        1-turn on port power for ports
+                                *        specified in PPCM(RHDB), or all ports,
+                                *        if power is set globally */
+#define RHS_SET_PORT_POWER RHS_LPSC_FLAG /* synonym for the above */
+#define RHS_OCIC_FLAG (1 << 17)/* Over-current indicator change   */
+#define RHS_CLEAR_DRWE (1 << 31)
+
+	/** Root hub per port status */
 	volatile uint32_t rh_port_status[];
+#define RHPS_CCS_FLAG (1 << 0) /* r: current connect status,
+                                * w: 1-clear port enable, 0-nothing */
+#define RHPS_CLEAR_PORT_ENABLE RHPS_CCS_FLAG
+#define RHPS_PES_FLAG (1 << 1) /* r: port enable status
+                                * w: 1-set port enable, 0-nothing */
+#define RHPS_SET_PORT_ENABLE RHPS_PES_FLAG
+#define RHPS_PSS_FLAG (1 << 2) /* r: port suspend status
+                                * w: 1-set port suspend, 0-nothing */
+#define RHPS_SET_PORT_SUSPEND RHPS_PSS_FLAG
+#define RHPS_POCI_FLAG (1 << 3) /* r: port over-current (if reports are per-port
+                                 * w: 1-clear port suspend (start resume
+                                 *      if suspened)
+                                 *    0-nothing */
+#define RHPS_CLEAR_PORT_SUSPEND RHPS_POCI_FLAG
+#define RHPS_PRS_FLAG (1 << 4) /* r: port reset status
+                                * w: 1-set port reset, 0-nothing */
+#define RHPS_SET_PORT_RESET RHPS_PRS_FLAG
+#define RHPS_PPS_FLAG (1 << 8) /* r: port power status
+                                * w: 1-set port power, 0-nothing */
+#define RHPS_SET_PORT_POWER RHPS_PPS_FLAG
+#define RHPS_LSDA_FLAG (1 << 9) /* r: low speed device attached
+                                 * w: 1-clear port power, 0-nothing */
+#define RHPS_CLEAR_PORT_POWER RHPS_LSDA_FLAG
+#define RHPS_CSC_FLAG  (1 << 16) /* connect status change Write-Clean */
+#define RHPS_PESC_FLAG (1 << 17) /* port enable status change WC */
+#define RHPS_PSSC_FLAG (1 << 18) /* port suspend status change WC */
+#define RHPS_OCIC_FLAG (1 << 19) /* port over-current change WC */
+#define RHPS_PRSC_FLAG (1 << 20) /* port reset status change WC */
+#define RHPS_CHANGE_WC_MASK 0x1f0000
 } __attribute__((packed)) ohci_regs_t;
 #endif
Index: uspace/drv/ohci/transfer_list.c
===================================================================
--- uspace/drv/ohci/transfer_list.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
+++ uspace/drv/ohci/transfer_list.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -0,0 +1,219 @@
+/*
+ * 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 transfer list implementation
+ */
+#include <errno.h>
+#include <usb/debug.h>
+
+#include "transfer_list.h"
+
+static void transfer_list_remove_batch(
+    transfer_list_t *instance, usb_transfer_batch_t *batch);
+/*----------------------------------------------------------------------------*/
+/** Initialize transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ * @param[in] name Name of the new list.
+ * @return Error code
+ *
+ * Allocates memory for internal qh_t structure.
+ */
+int transfer_list_init(transfer_list_t *instance, const char *name)
+{
+	assert(instance);
+	instance->name = name;
+	instance->list_head = malloc32(sizeof(ed_t));
+	if (!instance->list_head) {
+		usb_log_error("Failed to allocate list head.\n");
+		return ENOMEM;
+	}
+	instance->list_head_pa = addr_to_phys(instance->list_head);
+	usb_log_debug2("Transfer list %s setup with ED: %p(%p).\n",
+	    name, instance->list_head, instance->list_head_pa);
+
+	ed_init(instance->list_head, NULL);
+	list_initialize(&instance->batch_list);
+	fibril_mutex_initialize(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Set the next list in transfer list chain.
+ *
+ * @param[in] instance List to lead.
+ * @param[in] next List to append.
+ * @return Error code
+ *
+ * Does not check whether this replaces an existing list .
+ */
+void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)
+{
+	assert(instance);
+	assert(next);
+	/* Set both queue_head.next to point to the follower */
+	ed_append_ed(instance->list_head, next->list_head);
+}
+/*----------------------------------------------------------------------------*/
+/** Submit transfer batch to the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] batch Transfer batch to submit.
+ * @return Error code
+ *
+ * The batch is added to the end of the list and queue.
+ */
+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);
+
+	fibril_mutex_lock(&instance->guard);
+
+	ed_t *last_ed = NULL;
+	/* Add to the hardware queue. */
+	if (list_empty(&instance->batch_list)) {
+		/* There is nothing scheduled */
+		last_ed = instance->list_head;
+	} else {
+		/* There is something scheduled */
+		usb_transfer_batch_t *last = list_get_instance(
+		    instance->batch_list.prev, usb_transfer_batch_t, link);
+		last_ed = batch_ed(last);
+	}
+	/* keep link */
+	batch_ed(batch)->next = last_ed->next;
+	ed_append_ed(last_ed, batch_ed(batch));
+
+	asm volatile ("": : :"memory");
+
+	/* Add to the driver list */
+	list_append(&batch->link, &instance->batch_list);
+
+	usb_transfer_batch_t *first = list_get_instance(
+	    instance->batch_list.next, usb_transfer_batch_t, link);
+	usb_log_debug("Batch(%p) added to queue %s, first is %p.\n",
+		batch, instance->name, first);
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Create list for finished batches.
+ *
+ * @param[in] instance List to use.
+ * @param[in] done list to fill
+ */
+void transfer_list_remove_finished(transfer_list_t *instance, link_t *done)
+{
+	assert(instance);
+	assert(done);
+
+	fibril_mutex_lock(&instance->guard);
+	link_t *current = instance->batch_list.next;
+	while (current != &instance->batch_list) {
+		link_t *next = current->next;
+		usb_transfer_batch_t *batch =
+		    list_get_instance(current, usb_transfer_batch_t, link);
+
+		if (batch_is_complete(batch)) {
+			/* Save for post-processing */
+			transfer_list_remove_batch(instance, batch);
+			list_append(current, done);
+		}
+		current = next;
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Walk the list and abort all batches.
+ *
+ * @param[in] instance List to use.
+ */
+void transfer_list_abort_all(transfer_list_t *instance)
+{
+	fibril_mutex_lock(&instance->guard);
+	while (!list_empty(&instance->batch_list)) {
+		link_t *current = instance->batch_list.next;
+		usb_transfer_batch_t *batch =
+		    list_get_instance(current, usb_transfer_batch_t, link);
+		transfer_list_remove_batch(instance, batch);
+		usb_transfer_batch_finish_error(batch, EIO);
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Remove a transfer batch from the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] batch Transfer batch to remove.
+ * @return Error code
+ *
+ * Does not lock the transfer list, caller is responsible for that.
+ */
+void transfer_list_remove_batch(
+    transfer_list_t *instance, usb_transfer_batch_t *batch)
+{
+	assert(instance);
+	assert(instance->list_head);
+	assert(batch);
+	assert(batch_ed(batch));
+	assert(fibril_mutex_is_locked(&instance->guard));
+
+	usb_log_debug2(
+	    "Queue %s: removing batch(%p).\n", instance->name, batch);
+
+	const char *qpos = NULL;
+	/* Remove from the hardware queue */
+	if (instance->batch_list.next == &batch->link) {
+		/* I'm the first one here */
+		assert((instance->list_head->next & ED_NEXT_PTR_MASK)
+		    == addr_to_phys(batch_ed(batch)));
+		instance->list_head->next = batch_ed(batch)->next;
+		qpos = "FIRST";
+	} else {
+		usb_transfer_batch_t *prev =
+		    list_get_instance(
+		        batch->link.prev, usb_transfer_batch_t, link);
+		assert((batch_ed(prev)->next & ED_NEXT_PTR_MASK)
+		    == addr_to_phys(batch_ed(batch)));
+		batch_ed(prev)->next = batch_ed(batch)->next;
+		qpos = "NOT FIRST";
+	}
+	asm volatile ("": : :"memory");
+	usb_log_debug("Batch(%p) removed (%s) from %s, next %x.\n",
+	    batch, qpos, instance->name, batch_ed(batch)->next);
+
+	/* Remove from the batch list */
+	list_remove(&batch->link);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/transfer_list.h
===================================================================
--- uspace/drv/ohci/transfer_list.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
+++ uspace/drv/ohci/transfer_list.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -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 transfer list structure
+ */
+#ifndef DRV_OHCI_TRANSFER_LIST_H
+#define DRV_OHCI_TRANSFER_LIST_H
+
+#include <fibril_synch.h>
+
+#include "batch.h"
+#include "hw_struct/endpoint_descriptor.h"
+#include "utils/malloc32.h"
+
+typedef struct transfer_list
+{
+	fibril_mutex_t guard;
+	ed_t *list_head;
+	uint32_t list_head_pa;
+	const char *name;
+	link_t batch_list;
+} transfer_list_t;
+
+/** Dispose transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ *
+ * Frees memory for internal qh_t structure.
+ */
+static inline void transfer_list_fini(transfer_list_t *instance)
+{
+	assert(instance);
+	free32(instance->list_head);
+}
+
+int transfer_list_init(transfer_list_t *instance, const char *name);
+
+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);
+
+void transfer_list_remove_finished(transfer_list_t *instance, link_t *done);
+
+void transfer_list_abort_all(transfer_list_t *instance);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/ohci/utils/malloc32.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/ohci/utils/malloc32.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -37,4 +37,5 @@
 #include <assert.h>
 #include <malloc.h>
+#include <errno.h>
 #include <mem.h>
 #include <as.h>
Index: uspace/drv/uhci-hcd/batch.c
===================================================================
--- uspace/drv/uhci-hcd/batch.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/uhci-hcd/batch.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -103,13 +103,11 @@
 	usb_target_t target =
 	    { .address = ep->address, .endpoint = ep->endpoint };
-	usb_transfer_batch_init(instance, target,
-	    ep->transfer_type, ep->speed, ep->max_packet_size,
-	    buffer, NULL, buffer_size, NULL, setup_size, func_in,
-	    func_out, arg, fun, ep, NULL);
+	usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed,
+	    ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size,
+	    func_in, func_out, arg, fun, ep, NULL);
 
 
 	uhci_batch_t *data = malloc(sizeof(uhci_batch_t));
-	CHECK_NULL_DISPOSE_RETURN(instance,
-	    "Failed to allocate batch instance.\n");
+	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
 	bzero(data, sizeof(uhci_batch_t));
 	instance->private_data = data;
Index: uspace/drv/uhci-hcd/hc.c
===================================================================
--- uspace/drv/uhci-hcd/hc.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/uhci-hcd/hc.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -240,7 +240,6 @@
 	usb_log_debug("Initialized device manager.\n");
 
-	ret =
-	    usb_endpoint_manager_init(&instance->ep_manager,
-	        BANDWIDTH_AVAILABLE_USB11);
+	ret = usb_endpoint_manager_init(&instance->ep_manager,
+	    BANDWIDTH_AVAILABLE_USB11);
 	assert(ret == EOK);
 
Index: uspace/drv/uhci-hcd/iface.c
===================================================================
--- uspace/drv/uhci-hcd/iface.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/uhci-hcd/iface.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -74,6 +74,6 @@
 	    name, target.address, target.endpoint, size, ep->max_packet_size);
 
-	assert(ep->speed ==
-	    usb_device_keeper_get_speed(&(*hc)->manager, target.address));
+//	assert(ep->speed ==
+//	    usb_device_keeper_get_speed(&(*hc)->manager, target.address));
 //	assert(ep->max_packet_size == max_packet_size);
 //	assert(ep->transfer_type == USB_TRANSFER_CONTROL);
@@ -198,5 +198,6 @@
 /*----------------------------------------------------------------------------*/
 static int register_endpoint(
-    ddf_fun_t *fun, usb_address_t address, usb_endpoint_t 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)
@@ -204,6 +205,8 @@
 	hc_t *hc = fun_to_hc(fun);
 	assert(hc);
-	const usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, address);
+	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
+	if (speed >= USB_SPEED_MAX) {
+		speed = ep_speed;
+	}
 	const size_t size =
 	    (transfer_type == USB_TRANSFER_INTERRUPT
@@ -243,4 +246,9 @@
 	usb_log_debug("Unregister endpoint %d:%d %d.\n",
 	    address, endpoint, direction);
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
+	    address, endpoint, direction, NULL);
+	if (ep != NULL) {
+		usb_device_keeper_del_ep(&hc->manager, address, ep);
+	}
 	return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
 	    endpoint, direction);
@@ -251,5 +259,4 @@
  * @param[in] fun DDF function that was called.
  * @param[in] target USB device to write to.
- * @param[in] max_packet_size maximum size of data packet the device accepts
  * @param[in] data Source of data.
  * @param[in] size Size of data source.
@@ -259,5 +266,5 @@
  */
 static int interrupt_out(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
@@ -280,5 +287,4 @@
  * @param[in] fun DDF function that was called.
  * @param[in] target USB device to write to.
- * @param[in] max_packet_size maximum size of data packet the device accepts
  * @param[out] data Data destination.
  * @param[in] size Size of data source.
@@ -288,5 +294,5 @@
  */
 static int interrupt_in(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
@@ -309,5 +315,4 @@
  * @param[in] fun DDF function that was called.
  * @param[in] target USB device to write to.
- * @param[in] max_packet_size maximum size of data packet the device accepts
  * @param[in] data Source of data.
  * @param[in] size Size of data source.
@@ -317,5 +322,5 @@
  */
 static int bulk_out(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
@@ -338,5 +343,4 @@
  * @param[in] fun DDF function that was called.
  * @param[in] target USB device to write to.
- * @param[in] max_packet_size maximum size of data packet the device accepts
  * @param[out] data Data destination.
  * @param[in] size Size of data source.
@@ -346,5 +350,5 @@
  */
 static int bulk_in(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
+    ddf_fun_t *fun, usb_target_t target, void *data,
     size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
@@ -367,5 +371,4 @@
  * @param[in] fun DDF function that was called.
  * @param[in] target USB device to write to.
- * @param[in] max_packet_size maximum size of data packet the device accepts.
  * @param[in] setup_data Data to send with SETUP transfer.
  * @param[in] setup_size Size of data to send with SETUP transfer (always 8B).
@@ -377,5 +380,5 @@
  */
 static int control_write(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
+    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)
@@ -401,5 +404,4 @@
  * @param[in] fun DDF function that was called.
  * @param[in] target USB device to write to.
- * @param[in] max_packet_size maximum size of data packet the device accepts.
  * @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).
@@ -411,5 +413,5 @@
  */
 static int control_read(
-    ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
+    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)
Index: uspace/drv/usbmid/main.c
===================================================================
--- uspace/drv/usbmid/main.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/usbmid/main.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -55,7 +55,7 @@
 	int rc;
 
-	rc = usb_pipe_start_session(&dev->ctrl_pipe);
+	rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
 	if (rc != EOK) {
-		usb_log_error("Failed to start session on control pipe: %s.\n",
+		usb_log_error("Failed to start transfer on control pipe: %s.\n",
 		    str_error(rc));
 		return rc;
@@ -64,9 +64,5 @@
 	bool accept = usbmid_explore_device(dev);
 
-	rc = usb_pipe_end_session(&dev->ctrl_pipe);
-	if (rc != EOK) {
-		usb_log_warning("Failed to end session on control pipe: %s.\n",
-		    str_error(rc));
-	}
+	usb_pipe_end_long_transfer(&dev->ctrl_pipe);
 
 	if (!accept) {
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/drv/vhc/connhost.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -257,5 +257,4 @@
 
 static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size,
     void *data, size_t size,
     usbhc_iface_transfer_out_callback_t callback, void *arg)
@@ -267,5 +266,4 @@
 
 static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size,
     void *data, size_t size,
     usbhc_iface_transfer_in_callback_t callback, void *arg)
@@ -277,5 +275,4 @@
 
 static int control_write(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size,
     void *setup_packet, size_t setup_packet_size,
     void *data, size_t data_size,
@@ -295,5 +292,4 @@
 
 static int control_read(ddf_fun_t *fun, usb_target_t target,
-    size_t max_packet_size,
     void *setup_packet, size_t setup_packet_size,
     void *data, size_t data_size,
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -270,5 +270,4 @@
 	}
 
-	size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
 	usb_target_t target = {
 		.address = DEV_IPC_GET_ARG1(*call),
@@ -300,5 +299,5 @@
 	trans->size = len;
 
-	rc = transfer_func(fun, target, max_packet_size,
+	rc = transfer_func(fun, target,
 	    buffer, len,
 	    callback_out, trans);
@@ -326,5 +325,4 @@
 	}
 
-	size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
 	usb_target_t target = {
 		.address = DEV_IPC_GET_ARG1(*call),
@@ -348,5 +346,5 @@
 	trans->size = len;
 
-	int rc = transfer_func(fun, target, max_packet_size,
+	int rc = transfer_func(fun, target,
 	    trans->buffer, len,
 	    callback_in, trans);
@@ -414,5 +412,4 @@
 	};
 	size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
-	size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
 
 	int rc;
@@ -450,5 +447,5 @@
 	trans->size = data_buffer_len;
 
-	rc = usb_iface->control_write(fun, target, max_packet_size,
+	rc = usb_iface->control_write(fun, target,
 	    setup_packet, setup_packet_len,
 	    data_buffer, data_buffer_len,
@@ -477,5 +474,4 @@
 		.endpoint = DEV_IPC_GET_ARG2(*call)
 	};
-	size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
 
 	int rc;
@@ -515,5 +511,5 @@
 	}
 
-	rc = usb_iface->control_read(fun, target, max_packet_size,
+	rc = usb_iface->control_read(fun, target,
 	    setup_packet, setup_packet_len,
 	    trans->buffer, trans->size,
@@ -537,21 +533,32 @@
 	}
 
-#define INIT_FROM_HIGH_DATA(type, var, arg_no) \
-	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / 256
-#define INIT_FROM_LOW_DATA(type, var, arg_no) \
-	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % 256
-
-	INIT_FROM_HIGH_DATA(usb_address_t, address, 1);
-	INIT_FROM_LOW_DATA(usb_endpoint_t, endpoint, 1);
-	INIT_FROM_HIGH_DATA(usb_transfer_type_t, transfer_type, 2);
-	INIT_FROM_LOW_DATA(usb_direction_t, direction, 2);
-
-#undef INIT_FROM_HIGH_DATA
-#undef INIT_FROM_LOW_DATA
-
-	size_t max_packet_size = (size_t) DEV_IPC_GET_ARG3(*call);
-	unsigned int interval  = (unsigned int) DEV_IPC_GET_ARG4(*call);
-
-	int rc = usb_iface->register_endpoint(fun, address, endpoint,
+#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
+#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
+#define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
+#define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
+	type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
+#define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
+	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);
+
+	_INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
+	_INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
+	_INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
+
+	_INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
+	_INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
+
+#undef _INIT_FROM_HIGH_DATA2
+#undef _INIT_FROM_LOW_DATA2
+#undef _INIT_FROM_HIGH_DATA3
+#undef _INIT_FROM_MIDDLE_DATA3
+#undef _INIT_FROM_LOW_DATA3
+
+	int rc = usb_iface->register_endpoint(fun, address, speed, endpoint,
 	    transfer_type, direction, max_packet_size, interval);
 
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -66,5 +66,4 @@
  *   - argument #1 is target address
  *   - argument #2 is target endpoint
- *   - argument #3 is max packet size of the endpoint
  * - this call is immediately followed by IPC data read (async version)
  * - the call is not answered until the device returns some data (or until
@@ -169,9 +168,12 @@
 	/** Register endpoint attributes at host controller.
 	 * This is used to reserve portion of USB bandwidth.
+	 * When speed is invalid, speed of the device is used.
 	 * Parameters:
-	 * - USB address + endpoint number (ADDR * 256 + EP)
-	 * - transfer type + direction (TYPE * 256 + DIR)
-	 * - maximum packet size
-	 * - interval (in milliseconds)
+	 * - USB address + endpoint number
+	 *   - packed as ADDR << 16 + EP
+	 * - speed + transfer type + direction
+	 *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
+	 * - maximum packet size + interval (in milliseconds)
+	 *   - packed as MPS << 16 + INT
 	 * Answer:
 	 * - EOK - reservation successful
@@ -202,5 +204,5 @@
 
 /** Out transfer processing function prototype. */
-typedef int (*usbhc_iface_transfer_out_t)(ddf_fun_t *, usb_target_t, size_t,
+typedef int (*usbhc_iface_transfer_out_t)(ddf_fun_t *, usb_target_t,
     void *, size_t,
     usbhc_iface_transfer_out_callback_t, void *);
@@ -210,5 +212,5 @@
 
 /** In transfer processing function prototype. */
-typedef int (*usbhc_iface_transfer_in_t)(ddf_fun_t *, usb_target_t, size_t,
+typedef int (*usbhc_iface_transfer_in_t)(ddf_fun_t *, usb_target_t,
     void *, size_t,
     usbhc_iface_transfer_in_callback_t, void *);
@@ -222,5 +224,6 @@
 	int (*release_address)(ddf_fun_t *, usb_address_t);
 
-	int (*register_endpoint)(ddf_fun_t *, usb_address_t, usb_endpoint_t,
+	int (*register_endpoint)(ddf_fun_t *,
+	    usb_address_t, usb_speed_t, usb_endpoint_t,
 	    usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
 	int (*unregister_endpoint)(ddf_fun_t *, usb_address_t, usb_endpoint_t,
@@ -234,10 +237,8 @@
 
 	int (*control_write)(ddf_fun_t *, usb_target_t,
-	    size_t,
 	    void *, size_t, void *, size_t,
 	    usbhc_iface_transfer_out_callback_t, void *);
 
 	int (*control_read)(ddf_fun_t *, usb_target_t,
-	    size_t,
 	    void *, size_t, void *, size_t,
 	    usbhc_iface_transfer_in_callback_t, void *);
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/Makefile	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -43,4 +43,5 @@
 	src/hidparser.c \
 	src/hub.c \
+	src/pipepriv.c \
 	src/pipes.c \
 	src/pipesinit.c \
Index: uspace/lib/usb/include/usb/devdrv.h
===================================================================
--- uspace/lib/usb/include/usb/devdrv.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/include/usb/devdrv.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -169,4 +169,12 @@
     usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
 
+int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
+int usb_device_create_pipes(ddf_dev_t *, usb_device_connection_t *,
+    usb_endpoint_description_t **, uint8_t *, size_t, int, int,
+    usb_endpoint_mapping_t **, size_t *);
+int usb_device_destroy_pipes(ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
+
+size_t usb_interface_count_alternates(uint8_t *, size_t, uint8_t);
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/host/device_keeper.h
===================================================================
--- uspace/lib/usb/include/usb/host/device_keeper.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/include/usb/host/device_keeper.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -73,4 +73,6 @@
 void usb_device_keeper_add_ep(
     usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep);
+void usb_device_keeper_del_ep(
+    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep);
 
 void usb_device_keeper_reserve_default_address(
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/include/usb/pipes.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -42,4 +42,5 @@
 #include <ipc/devman.h>
 #include <ddf/driver.h>
+#include <fibril_synch.h>
 
 /** Abstraction of a physical connection to the device.
@@ -59,6 +60,14 @@
  * This endpoint must be bound with existing usb_device_connection_t
  * (i.e. the wire to send data over).
+ *
+ * Locking order: if you want to lock both mutexes
+ * (@c guard and @c hc_phone_mutex), lock @c guard first.
+ * It is not necessary to lock @c guard if you want to lock @c hc_phone_mutex
+ * only.
  */
 typedef struct {
+	/** Guard of the whole pipe. */
+	fibril_mutex_t guard;
+
 	/** The connection used for sending the data. */
 	usb_device_connection_t *wire;
@@ -78,6 +87,16 @@
 	/** Phone to the host controller.
 	 * Negative when no session is active.
+	 * It is an error to access this member without @c hc_phone_mutex
+	 * being locked.
+	 * If call over the phone is to be made, it must be preceeded by
+	 * call to pipe_add_ref() [internal libusb function].
 	 */
 	int hc_phone;
+
+	/** Guard for serialization of requests over the phone. */
+	fibril_mutex_t hc_phone_mutex;
+
+	/** Number of active transfers over the pipe. */
+	int refcount;
 } usb_pipe_t;
 
@@ -134,4 +153,6 @@
 int usb_pipe_initialize_from_configuration(usb_endpoint_mapping_t *,
     size_t, uint8_t *, size_t, usb_device_connection_t *);
+int usb_pipe_register_with_speed(usb_pipe_t *, usb_speed_t,
+    unsigned int, usb_hc_connection_t *);
 int usb_pipe_register(usb_pipe_t *, unsigned int, usb_hc_connection_t *);
 int usb_pipe_unregister(usb_pipe_t *, usb_hc_connection_t *);
@@ -140,4 +161,7 @@
 int usb_pipe_end_session(usb_pipe_t *);
 bool usb_pipe_is_session_started(usb_pipe_t *);
+
+int usb_pipe_start_long_transfer(usb_pipe_t *);
+void usb_pipe_end_long_transfer(usb_pipe_t *);
 
 int usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *);
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/include/usb/usb.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -77,5 +77,7 @@
 	USB_SPEED_FULL,
 	/** USB 2.0 high speed (480Mbits/s). */
-	USB_SPEED_HIGH
+	USB_SPEED_HIGH,
+	/** Psuedo-speed serving as a boundary. */
+	USB_SPEED_MAX
 } usb_speed_t;
 
Index: uspace/lib/usb/src/devdrv.c
===================================================================
--- uspace/lib/usb/src/devdrv.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/devdrv.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -72,14 +72,4 @@
 }
 
-/** Log out of memory error on given device.
- *
- * @param dev Device causing the trouble.
- */
-static void usb_log_oom(ddf_dev_t *dev)
-{
-	usb_log_error("Out of memory when adding device `%s'.\n",
-	    dev->name);
-}
-
 /** Count number of pipes the driver expects.
  *
@@ -108,93 +98,25 @@
  */
 static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
-    usb_device_t *dev)
-{
-	int rc;
-
-	size_t pipe_count = count_other_pipes(endpoints);
-	if (pipe_count == 0) {
-		return EOK;
-	}
-
-	dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
-	if (dev->pipes == NULL) {
-		usb_log_oom(dev->ddf_dev);
-		return ENOMEM;
-	}
-
-	size_t i;
-
-	/* Initialize to NULL first for rollback purposes. */
-	for (i = 0; i < pipe_count; i++) {
-		dev->pipes[i].pipe = NULL;
-	}
-
-	for (i = 0; i < pipe_count; i++) {
-		dev->pipes[i].pipe = malloc(sizeof(usb_pipe_t));
-		if (dev->pipes[i].pipe == NULL) {
-			usb_log_oom(dev->ddf_dev);
-			rc = ENOMEM;
-			goto rollback;
-		}
-
-		dev->pipes[i].description = endpoints[i];
-		dev->pipes[i].interface_no = dev->interface_no;
-		dev->pipes[i].interface_setting = 0;
-	}
-
-	rc = usb_pipe_initialize_from_configuration(dev->pipes, pipe_count,
+    usb_device_t *dev, int alternate_setting)
+{
+	usb_endpoint_mapping_t *pipes;
+	size_t pipes_count;
+
+	int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints,
 	    dev->descriptors.configuration, dev->descriptors.configuration_size,
-	    &dev->wire);
-	if (rc != EOK) {
-		usb_log_error("Failed initializing USB endpoints: %s.\n",
-		    str_error(rc));
-		goto rollback;
-	}
-
-	/* Register the endpoints. */
-	usb_hc_connection_t hc_conn;
-	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
+	    dev->interface_no, alternate_setting,
+	    &pipes, &pipes_count);
+
 	if (rc != EOK) {
 		usb_log_error(
-		    "Failed initializing connection to host controller: %s.\n",
-		    str_error(rc));
-		goto rollback;
-	}
-	rc = usb_hc_connection_open(&hc_conn);
-	if (rc != EOK) {
-		usb_log_error("Failed to connect to host controller: %s.\n",
-		    str_error(rc));
-		goto rollback;
-	}
-	for (i = 0; i < pipe_count; i++) {
-		if (dev->pipes[i].present) {
-			rc = usb_pipe_register(dev->pipes[i].pipe,
-			    dev->pipes[i].descriptor->poll_interval,
-			    &hc_conn);
-			/* Ignore error when operation not supported by HC. */
-			if ((rc != EOK) && (rc != ENOTSUP)) {
-				/* FIXME: what shall we do? */
-				dev->pipes[i].present = false;
-				free(dev->pipes[i].pipe);
-				dev->pipes[i].pipe = NULL;
-			}
-		}
-	}
-	/* Ignoring errors here. */
-	usb_hc_connection_close(&hc_conn);
-
-	dev->pipes_count = pipe_count;
+		    "Failed to create endpoint pipes for `%s': %s.\n",
+		    dev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	dev->pipes = pipes;
+	dev->pipes_count = pipes_count;
 
 	return EOK;
-
-rollback:
-	for (i = 0; i < pipe_count; i++) {
-		if (dev->pipes[i].pipe != NULL) {
-			free(dev->pipes[i].pipe);
-		}
-	}
-	free(dev->pipes);
-
-	return rc;
 }
 
@@ -239,38 +161,30 @@
 
 	/*
-	 * For further actions, we need open session on default control pipe.
+	 * We will do some querying of the device, it is worth to prepare
+	 * the long transfer.
 	 */
-	rc = usb_pipe_start_session(&dev->ctrl_pipe);
-	if (rc != EOK) {
-		usb_log_error("Failed to start an IPC session: %s.\n",
+	rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_error("Failed to start transfer: %s.\n",
 		    str_error(rc));
 		return rc;
 	}
 
-	/* Get the device descriptor. */
-	rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
-	    &dev->descriptors.device);
-	if (rc != EOK) {
-		usb_log_error("Failed to retrieve device descriptor: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
-
-	/* Get the full configuration descriptor. */
-	rc = usb_request_get_full_configuration_descriptor_alloc(
-	    &dev->ctrl_pipe, 0, (void **) &dev->descriptors.configuration,
-	    &dev->descriptors.configuration_size);
-	if (rc != EOK) {
-		usb_log_error("Failed retrieving configuration descriptor: %s. %s\n",
+	/* Retrieve the descriptors. */
+	rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
+	    &dev->descriptors);
+	if (rc != EOK) {
+		usb_log_error("Failed to retrieve standard device " \
+		    "descriptors of %s: %s.\n",
 		    dev->ddf_dev->name, str_error(rc));
 		return rc;
 	}
 
+
 	if (driver->endpoints != NULL) {
-		rc = initialize_other_pipes(driver->endpoints, dev);
-	}
-
-	/* No checking here. */
-	usb_pipe_end_session(&dev->ctrl_pipe);
+		rc = initialize_other_pipes(driver->endpoints, dev, 0);
+	}
+
+	usb_pipe_end_long_transfer(&dev->ctrl_pipe);
 
 	/* Rollback actions. */
@@ -291,8 +205,10 @@
  * @return Number of alternate interfaces for @p interface_no interface.
  */
-static size_t count_alternate_interfaces(uint8_t *config_descr,
-    size_t config_descr_size, int interface_no)
+size_t usb_interface_count_alternates(uint8_t *config_descr,
+    size_t config_descr_size, uint8_t interface_no)
 {
 	assert(config_descr != NULL);
+	assert(config_descr_size > 0);
+
 	usb_dp_parser_t dp_parser = {
 		.nesting = usb_dp_standard_descriptor_nesting
@@ -343,5 +259,5 @@
 
 	alternates->alternative_count
-	    = count_alternate_interfaces(dev->descriptors.configuration,
+	    = usb_interface_count_alternates(dev->descriptors.configuration,
 	    dev->descriptors.configuration_size, dev->interface_no);
 
@@ -457,36 +373,10 @@
 static int destroy_current_pipes(usb_device_t *dev)
 {
-	size_t i;
-	int rc;
-
-	/* TODO: this shall be done under some device mutex. */
-
-	/* First check that no session is opened. */
-	for (i = 0; i < dev->pipes_count; i++) {
-		if (usb_pipe_is_session_started(dev->pipes[i].pipe)) {
-			return EBUSY;
-		}
-	}
-
-	/* Prepare connection to HC. */
-	usb_hc_connection_t hc_conn;
-	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
-	if (rc != EOK) {
-		return rc;
-	}
-	rc = usb_hc_connection_open(&hc_conn);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	/* Destroy the pipes. */
-	for (i = 0; i < dev->pipes_count; i++) {
-		usb_pipe_unregister(dev->pipes[i].pipe, &hc_conn);
-		free(dev->pipes[i].pipe);
-	}
-
-	usb_hc_connection_close(&hc_conn);
-
-	free(dev->pipes);
+	int rc = usb_device_destroy_pipes(dev->ddf_dev,
+	    dev->pipes, dev->pipes_count);
+	if (rc != EOK) {
+		return rc;
+	}
+
 	dev->pipes = NULL;
 	dev->pipes_count = 0;
@@ -535,7 +425,218 @@
 
 	/* Create new pipes. */
-	rc = initialize_other_pipes(endpoints, dev);
+	rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
 
 	return rc;
+}
+
+/** Retrieve basic descriptors from the device.
+ *
+ * @param[in] ctrl_pipe Control pipe with opened session.
+ * @param[out] descriptors Where to store the descriptors.
+ * @return Error code.
+ */
+int usb_device_retrieve_descriptors(usb_pipe_t *ctrl_pipe,
+    usb_device_descriptors_t *descriptors)
+{
+	assert(descriptors != NULL);
+	assert(usb_pipe_is_session_started(ctrl_pipe));
+
+	descriptors->configuration = NULL;
+
+	int rc;
+
+	/* Get the device descriptor. */
+	rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Get the full configuration descriptor. */
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    ctrl_pipe, 0, (void **) &descriptors->configuration,
+	    &descriptors->configuration_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Create pipes for a device.
+ *
+ * This is more or less a wrapper that does following actions:
+ * - allocate and initialize pipes
+ * - map endpoints to the pipes based on the descriptions
+ * - registers endpoints with the host controller
+ *
+ * @param[in] dev Generic DDF device backing the USB one.
+ * @param[in] wire Initialized backing connection to the host controller.
+ * @param[in] endpoints Endpoints description, NULL terminated.
+ * @param[in] config_descr Configuration descriptor of active configuration.
+ * @param[in] config_descr_size Size of @p config_descr in bytes.
+ * @param[in] interface_no Interface to map from.
+ * @param[in] interface_setting Interface setting (default is usually 0).
+ * @param[out] pipes_ptr Where to store array of created pipes
+ *	(not NULL terminated).
+ * @param[out] pipes_count_ptr Where to store number of pipes
+ *	(set to if you wish to ignore the count).
+ * @return Error code.
+ */
+int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,
+    usb_endpoint_description_t **endpoints,
+    uint8_t *config_descr, size_t config_descr_size,
+    int interface_no, int interface_setting,
+    usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)
+{
+	assert(dev != NULL);
+	assert(wire != NULL);
+	assert(endpoints != NULL);
+	assert(config_descr != NULL);
+	assert(config_descr_size > 0);
+	assert(pipes_ptr != NULL);
+
+	size_t i;
+	int rc;
+
+	size_t pipe_count = count_other_pipes(endpoints);
+	if (pipe_count == 0) {
+		*pipes_ptr = NULL;
+		return EOK;
+	}
+
+	usb_endpoint_mapping_t *pipes
+	    = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
+	if (pipes == NULL) {
+		return ENOMEM;
+	}
+
+	/* Initialize to NULL to allow smooth rollback. */
+	for (i = 0; i < pipe_count; i++) {
+		pipes[i].pipe = NULL;
+	}
+
+	/* Now allocate and fully initialize. */
+	for (i = 0; i < pipe_count; i++) {
+		pipes[i].pipe = malloc(sizeof(usb_pipe_t));
+		if (pipes[i].pipe == NULL) {
+			rc = ENOMEM;
+			goto rollback_free_only;
+		}
+		pipes[i].description = endpoints[i];
+		pipes[i].interface_no = interface_no;
+		pipes[i].interface_setting = interface_setting;
+	}
+
+	/* Find the mapping from configuration descriptor. */
+	rc = usb_pipe_initialize_from_configuration(pipes, pipe_count,
+	    config_descr, config_descr_size, wire);
+	if (rc != EOK) {
+		goto rollback_free_only;
+	}
+
+	/* Register the endpoints with HC. */
+	usb_hc_connection_t hc_conn;
+	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
+	if (rc != EOK) {
+		goto rollback_free_only;
+	}
+
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		goto rollback_free_only;
+	}
+
+	for (i = 0; i < pipe_count; i++) {
+		if (pipes[i].present) {
+			rc = usb_pipe_register(pipes[i].pipe,
+			    pipes[i].descriptor->poll_interval, &hc_conn);
+			if (rc != EOK) {
+				goto rollback_unregister_endpoints;
+			}
+		}
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	*pipes_ptr = pipes;
+	if (pipes_count_ptr != NULL) {
+		*pipes_count_ptr = pipe_count;
+	}
+
+	return EOK;
+
+	/*
+	 * Jump here if something went wrong after endpoints have
+	 * been registered.
+	 * This is also the target when the registration of
+	 * endpoints fails.
+	 */
+rollback_unregister_endpoints:
+	for (i = 0; i < pipe_count; i++) {
+		if (pipes[i].present) {
+			usb_pipe_unregister(pipes[i].pipe, &hc_conn);
+		}
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	/*
+	 * Jump here if something went wrong before some actual communication
+	 * with HC. Then the only thing that needs to be done is to free
+	 * allocated memory.
+	 */
+rollback_free_only:
+	for (i = 0; i < pipe_count; i++) {
+		if (pipes[i].pipe != NULL) {
+			free(pipes[i].pipe);
+		}
+	}
+	free(pipes);
+
+	return rc;
+}
+
+/** Destroy pipes previously created by usb_device_create_pipes.
+ *
+ * @param[in] dev Generic DDF device backing the USB one.
+ * @param[in] pipes Endpoint mapping to be destroyed.
+ * @param[in] pipes_count Number of endpoints.
+ */
+int usb_device_destroy_pipes(ddf_dev_t *dev,
+    usb_endpoint_mapping_t *pipes, size_t pipes_count)
+{
+	assert(dev != NULL);
+	assert(((pipes != NULL) && (pipes_count > 0))
+	    || ((pipes == NULL) && (pipes_count == 0)));
+
+	if (pipes_count == 0) {
+		return EOK;
+	}
+
+	int rc;
+
+	/* Prepare connection to HC to allow endpoint unregistering. */
+	usb_hc_connection_t hc_conn;
+	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Destroy the pipes. */
+	size_t i;
+	for (i = 0; i < pipes_count; i++) {
+		usb_pipe_unregister(pipes[i].pipe, &hc_conn);
+		free(pipes[i].pipe);
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	free(pipes);
+
+	return EOK;
 }
 
Index: uspace/lib/usb/src/devpoll.c
===================================================================
--- uspace/lib/usb/src/devpoll.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/devpoll.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -77,16 +77,8 @@
 		int rc;
 
-		rc = usb_pipe_start_session(pipe);
-		if (rc != EOK) {
-			failed_attempts++;
-			continue;
-		}
-
 		size_t actual_size;
 		rc = usb_pipe_read(pipe, polling_data->buffer,
 		    polling_data->request_size, &actual_size);
 
-		/* Quit the session regardless of errors. */
-		usb_pipe_end_session(pipe);
 		
 //		if (rc == ESTALL) {
Index: uspace/lib/usb/src/host/batch.c
===================================================================
--- uspace/lib/usb/src/host/batch.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/host/batch.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -63,5 +63,5 @@
 	instance->transfer_type = transfer_type;
 	instance->speed = speed;
-	instance->direction = USB_DIRECTION_BOTH;
+	instance->direction = ep->direction;
 	instance->callback_in = func_in;
 	instance->callback_out = func_out;
Index: uspace/lib/usb/src/host/device_keeper.c
===================================================================
--- uspace/lib/usb/src/host/device_keeper.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/host/device_keeper.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -56,6 +56,10 @@
 		instance->devices[i].control_used = 0;
 		instance->devices[i].handle = 0;
+		instance->devices[i].speed = USB_SPEED_MAX;
 		list_initialize(&instance->devices[i].endpoints);
 	}
+	// TODO: is this hack enough?
+	// (it is needed to allow smooth registration at default address)
+	instance->devices[0].occupied = true;
 }
 /*----------------------------------------------------------------------------*/
@@ -67,4 +71,15 @@
 	assert(instance->devices[address].occupied);
 	list_append(&ep->same_device_eps, &instance->devices[address].endpoints);
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+void usb_device_keeper_del_ep(
+    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	assert(instance->devices[address].occupied);
+	list_remove(&ep->same_device_eps);
+	list_initialize(&ep->same_device_eps);
 	fibril_mutex_unlock(&instance->guard);
 }
Index: uspace/lib/usb/src/hub.c
===================================================================
--- uspace/lib/usb/src/hub.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/hub.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -40,4 +40,5 @@
 #include <errno.h>
 #include <assert.h>
+#include <usb/debug.h>
 
 /** Check that HC connection is alright.
@@ -55,4 +56,5 @@
 
 /** Tell host controller to reserve default address.
+ * @deprecated
  *
  * @param connection Opened connection to host controller.
@@ -65,4 +67,6 @@
 	CHECK_CONNECTION(connection);
 
+	usb_log_warning("usb_hc_reserve_default_address() considered obsolete");
+
 	return async_req_2_0(connection->hc_phone,
 	    DEV_IFACE_ID(USBHC_DEV_IFACE),
@@ -71,4 +75,5 @@
 
 /** Tell host controller to release default address.
+ * @deprecated
  *
  * @param connection Opened connection to host controller.
@@ -78,4 +83,6 @@
 {
 	CHECK_CONNECTION(connection);
+
+	usb_log_warning("usb_hc_release_default_address() considered obsolete");
 
 	return async_req_1_0(connection->hc_phone,
@@ -235,25 +242,9 @@
 	}
 
-
-	/*
-	 * Reserve the default address.
-	 */
-	rc = usb_hc_reserve_default_address(&hc_conn, dev_speed);
-	if (rc != EOK) {
-		rc = EBUSY;
-		goto leave_release_free_address;
-	}
-
-	/*
-	 * Enable the port (i.e. allow signaling through this port).
-	 */
-	rc = enable_port(port_no, arg);
-	if (rc != EOK) {
-		goto leave_release_default_address;
-	}
-
-	/*
-	 * Change the address from default to the free one.
-	 * We need to create a new control pipe for that.
+	/*
+	 * We will not register control pipe on default address.
+	 * The registration might fail. That means that someone else already
+	 * registered that endpoint. We will simply wait and try again.
+	 * (Someone else already wants to add a new device.)
 	 */
 	usb_device_connection_t dev_conn;
@@ -262,5 +253,5 @@
 	if (rc != EOK) {
 		rc = ENOTCONN;
-		goto leave_release_default_address;
+		goto leave_release_free_address;
 	}
 
@@ -270,54 +261,50 @@
 	if (rc != EOK) {
 		rc = ENOTCONN;
+		goto leave_release_free_address;
+	}
+
+	do {
+		rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
+		    &hc_conn);
+		if (rc != EOK) {
+			/* Do not overheat the CPU ;-). */
+			async_usleep(10);
+		}
+	} while (rc != EOK);
+
+	/*
+	 * Endpoint is registered. We can enable the port and change
+	 * device address.
+	 */
+	rc = enable_port(port_no, arg);
+	if (rc != EOK) {
 		goto leave_release_default_address;
 	}
 
-	/* Before sending any traffic, we need to register this
-	 * endpoint.
+	rc = usb_pipe_probe_default_control(&ctrl_pipe);
+	if (rc != EOK) {
+		rc = ESTALL;
+		goto leave_release_default_address;
+	}
+
+	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
+	if (rc != EOK) {
+		rc = ESTALL;
+		goto leave_release_default_address;
+	}
+
+	/*
+	 * Address changed. We can release the original endpoint, thus
+	 * allowing other to access the default address.
+	 */
+	unregister_control_endpoint_on_default_address(&hc_conn);
+
+	/*
+	 * Time to register the new endpoint.
 	 */
 	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
 	if (rc != EOK) {
-		rc = EREFUSED;
-		goto leave_release_default_address;
-	}
-	rc = usb_pipe_probe_default_control(&ctrl_pipe);
-	if (rc != EOK) {
-		rc = ENOTCONN;
-		goto leave_release_default_address;
-	}
-
-	rc = usb_pipe_start_session(&ctrl_pipe);
-	if (rc != EOK) {
-		rc = ENOTCONN;
-		goto leave_unregister_endpoint;
-	}
-
-	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
-	if (rc != EOK) {
-		rc = ESTALL;
-		goto leave_stop_session;
-	}
-
-	usb_pipe_end_session(&ctrl_pipe);
-
-	/*
-	 * Register the control endpoint for the new device.
-	 */
-	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
-	if (rc != EOK) {
-		rc = EREFUSED;
-		goto leave_unregister_endpoint;
-	}
-
-	/*
-	 * Release the original endpoint.
-	 */
-	unregister_control_endpoint_on_default_address(&hc_conn);
-
-	/*
-	 * Once the address is changed, we can return the default address.
-	 */
-	usb_hc_release_default_address(&hc_conn);
-
+		goto leave_release_free_address;
+	}
 
 	/*
@@ -334,6 +321,4 @@
 	}
 
-
-
 	/*
 	 * And now inform the host controller about the handle.
@@ -367,13 +352,6 @@
 	 * Completely ignoring errors here.
 	 */
-
-leave_stop_session:
-	usb_pipe_end_session(&ctrl_pipe);
-
-leave_unregister_endpoint:
+leave_release_default_address:
 	usb_pipe_unregister(&ctrl_pipe, &hc_conn);
-
-leave_release_default_address:
-	usb_hc_release_default_address(&hc_conn);
 
 leave_release_free_address:
Index: uspace/lib/usb/src/pipepriv.c
===================================================================
--- uspace/lib/usb/src/pipepriv.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
+++ uspace/lib/usb/src/pipepriv.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -0,0 +1,129 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Library internal functions on USB pipes (implementation).
+ */
+#include "pipepriv.h"
+#include <devman.h>
+#include <errno.h>
+#include <assert.h>
+
+/** Ensure exclusive access to the IPC phone of given pipe.
+ *
+ * @param pipe Pipe to be exclusively accessed.
+ */
+void pipe_start_transaction(usb_pipe_t *pipe)
+{
+	fibril_mutex_lock(&pipe->hc_phone_mutex);
+}
+
+/** Terminate exclusive access to the IPC phone of given pipe.
+ *
+ * @param pipe Pipe to be released from exclusive usage.
+ */
+void pipe_end_transaction(usb_pipe_t *pipe)
+{
+	fibril_mutex_unlock(&pipe->hc_phone_mutex);
+}
+
+/** Ensure exclusive access to the pipe as a whole.
+ *
+ * @param pipe Pipe to be exclusively accessed.
+ */
+void pipe_acquire(usb_pipe_t *pipe)
+{
+	fibril_mutex_lock(&pipe->guard);
+}
+
+/** Terminate exclusive access to the pipe as a whole.
+ *
+ * @param pipe Pipe to be released from exclusive usage.
+ */
+void pipe_release(usb_pipe_t *pipe)
+{
+	fibril_mutex_unlock(&pipe->guard);
+}
+
+/** Add reference of active transfers over the pipe.
+ *
+ * @param pipe The USB pipe.
+ * @return Error code.
+ * @retval EOK Currently always.
+ */
+int pipe_add_ref(usb_pipe_t *pipe)
+{
+another_try:
+	pipe_acquire(pipe);
+
+	if (pipe->refcount == 0) {
+		/* Need to open the phone by ourselves. */
+		int phone = devman_device_connect(pipe->wire->hc_handle, 0);
+		if (phone < 0) {
+			// TODO: treat some error as non-recoverable
+			// and return error from here
+			pipe_release(pipe);
+			goto another_try;
+		}
+		/*
+		 * No locking is needed, refcount is zero and whole pipe
+		 * mutex is locked.
+		 */
+		pipe->hc_phone = phone;
+	}
+	pipe->refcount++;
+
+	pipe_release(pipe);
+
+	return EOK;
+}
+
+/** Drop active transfer reference on the pipe.
+ *
+ * @param pipe The USB pipe.
+ */
+void pipe_drop_ref(usb_pipe_t *pipe)
+{
+	pipe_acquire(pipe);
+	assert(pipe->refcount > 0);
+	pipe->refcount--;
+	if (pipe->refcount == 0) {
+		/* We were the last users, let's hang-up. */
+		async_hangup(pipe->hc_phone);
+		pipe->hc_phone = -1;
+	}
+	pipe_release(pipe);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/pipepriv.h
===================================================================
--- uspace/lib/usb/src/pipepriv.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
+++ uspace/lib/usb/src/pipepriv.h	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -0,0 +1,53 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Library internal functions on USB pipes.
+ */
+#ifndef LIBUSB_PIPEPRIV_H_
+#define LIBUSB_PIPEPRIV_H_
+
+#include <usb/pipes.h>
+
+void pipe_acquire(usb_pipe_t *);
+void pipe_release(usb_pipe_t *);
+
+void pipe_start_transaction(usb_pipe_t *);
+void pipe_end_transaction(usb_pipe_t *);
+
+int pipe_add_ref(usb_pipe_t *);
+void pipe_drop_ref(usb_pipe_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/pipes.c
===================================================================
--- uspace/lib/usb/src/pipes.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/pipes.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -41,4 +41,5 @@
 #include <errno.h>
 #include <assert.h>
+#include "pipepriv.h"
 
 #define IPC_AGAIN_DELAY (1000 * 2) /* 2ms */
@@ -241,4 +242,7 @@
  * necessary.
  *
+ * @deprecated
+ * Obsoleted with introduction of usb_pipe_start_long_transfer
+ *
  * @param pipe Endpoint pipe to start the session on.
  * @return Error code.
@@ -246,17 +250,5 @@
 int usb_pipe_start_session(usb_pipe_t *pipe)
 {
-	assert(pipe);
-
-	if (usb_pipe_is_session_started(pipe)) {
-		return EBUSY;
-	}
-
-	int phone = devman_device_connect(pipe->wire->hc_handle, 0);
-	if (phone < 0) {
-		return phone;
-	}
-
-	pipe->hc_phone = phone;
-
+	usb_log_warning("usb_pipe_start_session() was deprecated.\n");
 	return EOK;
 }
@@ -265,4 +257,7 @@
 /** Ends a session on the endpoint pipe.
  *
+ * @deprecated
+ * Obsoleted with introduction of usb_pipe_end_long_transfer
+ *
  * @see usb_pipe_start_session
  *
@@ -272,17 +267,5 @@
 int usb_pipe_end_session(usb_pipe_t *pipe)
 {
-	assert(pipe);
-
-	if (!usb_pipe_is_session_started(pipe)) {
-		return ENOENT;
-	}
-
-	int rc = async_hangup(pipe->hc_phone);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	pipe->hc_phone = -1;
-
+	usb_log_warning("usb_pipe_end_session() was deprecated.\n");
 	return EOK;
 }
@@ -298,5 +281,34 @@
 bool usb_pipe_is_session_started(usb_pipe_t *pipe)
 {
-	return (pipe->hc_phone >= 0);
+	pipe_acquire(pipe);
+	bool started = pipe->refcount > 0;
+	pipe_release(pipe);
+	return started;
+}
+
+/** Prepare pipe for a long transfer.
+ *
+ * By a long transfer is mean transfer consisting of several
+ * requests to the HC.
+ * Calling such function is optional and it has positive effect of
+ * improved performance because IPC session is initiated only once.
+ *
+ * @param pipe Pipe over which the transfer will happen.
+ * @return Error code.
+ */
+int usb_pipe_start_long_transfer(usb_pipe_t *pipe)
+{
+	return pipe_add_ref(pipe);
+}
+
+/** Terminate a long transfer on a pipe.
+ *
+ * @see usb_pipe_start_long_transfer
+ *
+ * @param pipe Pipe where to end the long transfer.
+ */
+void usb_pipe_end_long_transfer(usb_pipe_t *pipe)
+{
+	pipe_drop_ref(pipe);
 }
 
Index: uspace/lib/usb/src/pipesinit.c
===================================================================
--- uspace/lib/usb/src/pipesinit.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/pipesinit.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -356,10 +356,13 @@
 	assert(connection);
 
+	fibril_mutex_initialize(&pipe->guard);
 	pipe->wire = connection;
 	pipe->hc_phone = -1;
+	fibril_mutex_initialize(&pipe->hc_phone_mutex);
 	pipe->endpoint_no = endpoint_no;
 	pipe->transfer_type = transfer_type;
 	pipe->max_packet_size = max_packet_size;
 	pipe->direction = direction;
+	pipe->refcount = 0;
 
 	return EOK;
@@ -413,10 +416,5 @@
 	int rc;
 
-	TRY_LOOP(failed_attempts) {
-		rc = usb_pipe_start_session(pipe);
-		if (rc == EOK) {
-			break;
-		}
-	}
+	rc = usb_pipe_start_long_transfer(pipe);
 	if (rc != EOK) {
 		return rc;
@@ -439,5 +437,5 @@
 		}
 	}
-	usb_pipe_end_session(pipe);
+	usb_pipe_end_long_transfer(pipe);
 	if (rc != EOK) {
 		return rc;
@@ -461,4 +459,25 @@
     usb_hc_connection_t *hc_connection)
 {
+	return usb_pipe_register_with_speed(pipe, USB_SPEED_MAX + 1,
+	    interval, hc_connection);
+}
+
+/** Register endpoint with a speed at the host controller.
+ *
+ * You will rarely need to use this function because it is needed only
+ * if the registered endpoint is of address 0 and there is no other way
+ * to tell speed of the device at address 0.
+ *
+ * @param pipe Pipe to be registered.
+ * @param speed Speed of the device
+ *	(invalid speed means use previously specified one).
+ * @param interval Polling interval.
+ * @param hc_connection Connection to the host controller (must be opened).
+ * @return Error code.
+ */
+int usb_pipe_register_with_speed(usb_pipe_t *pipe, usb_speed_t speed,
+    unsigned int interval,
+    usb_hc_connection_t *hc_connection)
+{
 	assert(pipe);
 	assert(hc_connection);
@@ -468,13 +487,15 @@
 	}
 
-#define _PACK(high, low) ((high) * 256 + (low))
-
-	return async_req_5_0(hc_connection->hc_phone,
+#define _PACK2(high, low) (((high) << 16) + (low))
+#define _PACK3(high, middle, low) (((((high) << 8) + (middle)) << 8) + (low))
+
+	return async_req_4_0(hc_connection->hc_phone,
 	    DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_REGISTER_ENDPOINT,
-	    _PACK(pipe->wire->address, pipe->endpoint_no),
-	    _PACK(pipe->transfer_type, pipe->direction),
-	    pipe->max_packet_size, interval);
-
-#undef _PACK
+	    _PACK2(pipe->wire->address, pipe->endpoint_no),
+	    _PACK3(speed, pipe->transfer_type, pipe->direction),
+	    _PACK2(pipe->max_packet_size, interval));
+
+#undef _PACK2
+#undef _PACK3
 }
 
Index: uspace/lib/usb/src/pipesio.c
===================================================================
--- uspace/lib/usb/src/pipesio.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/pipesio.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -49,4 +49,5 @@
 #include <assert.h>
 #include <usbhc_iface.h>
+#include "pipepriv.h"
 
 /** Request an in transfer, no checking of input parameters.
@@ -78,13 +79,16 @@
 	}
 
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+
 	/*
 	 * Make call identifying target USB device and type of transfer.
 	 */
-	aid_t opening_request = async_send_4(pipe->hc_phone,
+	aid_t opening_request = async_send_3(pipe->hc_phone,
 	    DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
 	    pipe->wire->address, pipe->endpoint_no,
-	    pipe->max_packet_size,
 	    NULL);
 	if (opening_request == 0) {
+		pipe_end_transaction(pipe);
 		return ENOMEM;
 	}
@@ -96,4 +100,10 @@
 	aid_t data_request = async_data_read(pipe->hc_phone, buffer, size,
 	    &data_request_call);
+
+	/*
+	 * Since now on, someone else might access the backing phone
+	 * without breaking the transfer IPC protocol.
+	 */
+	pipe_end_transaction(pipe);
 
 	if (data_request == 0) {
@@ -146,13 +156,9 @@
 
 	if (buffer == NULL) {
-			return EINVAL;
+		return EINVAL;
 	}
 
 	if (size == 0) {
 		return EINVAL;
-	}
-
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
 	}
 
@@ -165,8 +171,17 @@
 	}
 
+	int rc;
+	rc = pipe_add_ref(pipe);
+	if (rc != EOK) {
+		return rc;
+	}
+
+
 	size_t act_size = 0;
-	int rc;
 
 	rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
+
+	pipe_drop_ref(pipe);
+
 	if (rc != EOK) {
 		return rc;
@@ -210,13 +225,16 @@
 	}
 
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+
 	/*
 	 * Make call identifying target USB device and type of transfer.
 	 */
-	aid_t opening_request = async_send_4(pipe->hc_phone,
+	aid_t opening_request = async_send_3(pipe->hc_phone,
 	    DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
 	    pipe->wire->address, pipe->endpoint_no,
-	    pipe->max_packet_size,
 	    NULL);
 	if (opening_request == 0) {
+		pipe_end_transaction(pipe);
 		return ENOMEM;
 	}
@@ -226,4 +244,11 @@
 	 */
 	int rc = async_data_write_start(pipe->hc_phone, buffer, size);
+
+	/*
+	 * Since now on, someone else might access the backing phone
+	 * without breaking the transfer IPC protocol.
+	 */
+	pipe_end_transaction(pipe);
+
 	if (rc != EOK) {
 		async_wait_for(opening_request, NULL);
@@ -260,8 +285,4 @@
 	}
 
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
-	}
-
 	if (pipe->direction != USB_DIRECTION_OUT) {
 		return EBADF;
@@ -272,5 +293,14 @@
 	}
 
-	int rc = usb_pipe_write_no_check(pipe, buffer, size);
+	int rc;
+
+	rc = pipe_add_ref(pipe);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_pipe_write_no_check(pipe, buffer, size);
+
+	pipe_drop_ref(pipe);
 
 	return rc;
@@ -293,11 +323,13 @@
     void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
 {
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+
 	/*
 	 * Make call identifying target USB device and control transfer type.
 	 */
-	aid_t opening_request = async_send_4(pipe->hc_phone,
+	aid_t opening_request = async_send_3(pipe->hc_phone,
 	    DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_READ,
 	    pipe->wire->address, pipe->endpoint_no,
-	    pipe->max_packet_size,
 	    NULL);
 	if (opening_request == 0) {
@@ -311,4 +343,5 @@
 	    setup_buffer, setup_buffer_size);
 	if (rc != EOK) {
+		pipe_end_transaction(pipe);
 		async_wait_for(opening_request, NULL);
 		return rc;
@@ -322,4 +355,12 @@
 	    data_buffer, data_buffer_size,
 	    &data_request_call);
+
+	/*
+	 * Since now on, someone else might access the backing phone
+	 * without breaking the transfer IPC protocol.
+	 */
+	pipe_end_transaction(pipe);
+
+
 	if (data_request == 0) {
 		async_wait_for(opening_request, NULL);
@@ -379,8 +420,4 @@
 	}
 
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
-	}
-
 	if ((pipe->direction != USB_DIRECTION_BOTH)
 	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
@@ -388,8 +425,17 @@
 	}
 
+	int rc;
+
+	rc = pipe_add_ref(pipe);
+	if (rc != EOK) {
+		return rc;
+	}
+
 	size_t act_size = 0;
-	int rc = usb_pipe_control_read_no_check(pipe,
+	rc = usb_pipe_control_read_no_check(pipe,
 	    setup_buffer, setup_buffer_size,
 	    data_buffer, data_buffer_size, &act_size);
+
+	pipe_drop_ref(pipe);
 
 	if (rc != EOK) {
@@ -418,14 +464,17 @@
     void *data_buffer, size_t data_buffer_size)
 {
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+
 	/*
 	 * Make call identifying target USB device and control transfer type.
 	 */
-	aid_t opening_request = async_send_5(pipe->hc_phone,
+	aid_t opening_request = async_send_4(pipe->hc_phone,
 	    DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_WRITE,
 	    pipe->wire->address, pipe->endpoint_no,
 	    data_buffer_size,
-	    pipe->max_packet_size,
 	    NULL);
 	if (opening_request == 0) {
+		pipe_end_transaction(pipe);
 		return ENOMEM;
 	}
@@ -437,4 +486,5 @@
 	    setup_buffer, setup_buffer_size);
 	if (rc != EOK) {
+		pipe_end_transaction(pipe);
 		async_wait_for(opening_request, NULL);
 		return rc;
@@ -447,8 +497,15 @@
 		rc = async_data_write_start(pipe->hc_phone,
 		    data_buffer, data_buffer_size);
+
+		/* All data sent, pipe can be released. */
+		pipe_end_transaction(pipe);
+
 		if (rc != EOK) {
 			async_wait_for(opening_request, NULL);
 			return rc;
 		}
+	} else {
+		/* No data to send, we can release the pipe for others. */
+		pipe_end_transaction(pipe);
 	}
 
@@ -491,8 +548,4 @@
 	}
 
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
-	}
-
 	if ((pipe->direction != USB_DIRECTION_BOTH)
 	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
@@ -500,6 +553,15 @@
 	}
 
-	int rc = usb_pipe_control_write_no_check(pipe,
+	int rc;
+
+	rc = pipe_add_ref(pipe);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_pipe_control_write_no_check(pipe,
 	    setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
+
+	pipe_drop_ref(pipe);
 
 	return rc;
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision f35b2942f93a409eb40a17d0d303cf1aec814999)
+++ uspace/lib/usb/src/recognise.c	(revision a43f1d1803f452027e7beaecba090ca3e630eb93)
@@ -404,15 +404,5 @@
 	child->driver_data = dev_data;
 
-	rc = usb_pipe_start_session(&ctrl_pipe);
-	if (rc != EOK) {
-		goto failure;
-	}
-
 	rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids);
-	if (rc != EOK) {
-		goto failure;
-	}
-
-	rc = usb_pipe_end_session(&ctrl_pipe);
 	if (rc != EOK) {
 		goto failure;
