Index: .bzrignore
===================================================================
--- .bzrignore	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ .bzrignore	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -94,4 +94,5 @@
 ./uspace/drv/usbhid/usbhid
 ./uspace/drv/usbkbd/usbkbd
+./uspace/drv/usbmast/usbmast
 ./uspace/drv/usbmid/usbmid
 ./uspace/drv/usbmouse/usbmouse
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ boot/arch/amd64/Makefile.inc	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -50,4 +50,6 @@
 	usbhub \
 	usbkbd \
+	usbhid \
+	usbmast \
 	usbmid \
 	usbmouse \
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ kernel/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -226,5 +226,4 @@
 	generic/src/proc/task.c \
 	generic/src/proc/the.c \
-	generic/src/proc/tasklet.c \
 	generic/src/syscall/syscall.c \
 	generic/src/syscall/copy.c \
@@ -382,5 +381,4 @@
 		generic/src/main/kinit.c \
 		generic/src/proc/the.c \
-		generic/src/proc/tasklet.c \
 		generic/src/mm/frame.c \
 		generic/src/mm/page.c \
Index: kernel/arch/mips32/include/atomic.h
===================================================================
--- kernel/arch/mips32/include/atomic.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ kernel/arch/mips32/include/atomic.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -91,4 +91,5 @@
 		"	sc %0, %1\n"
 		"	beqz %0, 1b\n"
+		"	nop\n"
 		"2:\n"
 		: "=&r" (tmp),
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ kernel/generic/include/ipc/ipc.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -115,4 +115,10 @@
  */
 #define IPC_FF_ROUTE_FROM_ME  (1 << 0)
+
+/* Data transfer flags. */
+#define IPC_XF_NONE		0
+
+/** Restrict the transfer size if necessary. */
+#define IPC_XF_RESTRICT		(1 << 0)
 
 /** Kernel IPC interfaces
Index: rnel/generic/include/proc/tasklet.h
===================================================================
--- kernel/generic/include/proc/tasklet.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ 	(revision )
@@ -1,73 +1,0 @@
-/*
- * Copyright (c) 2007 Jan Hudecek
- * Copyright (c) 2008 Martin Decky
- * 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 genericproc
- * @{
- */
-/** @file tasklet.h
- * @brief Tasklets declarations
- */
-
-#ifndef KERN_TASKLET_H_
-#define KERN_TASKLET_H_
-
-#include <adt/list.h>
-
-/** Tasklet callback type */
-typedef void (* tasklet_callback_t)(void *arg);
-
-/** Tasklet state */
-typedef enum {
-	NotActive,
-	Scheduled,
-	InProgress,
-	Disabled
-} tasklet_state_t;
-
-/** Structure describing a tasklet */
-typedef struct tasklet_descriptor {
-	link_t link;
-	
-	/** Callback to call */
-	tasklet_callback_t callback;
-	
-	/** Argument passed to the callback */
-	void *arg;
-	
-	/** State of the tasklet */
-	tasklet_state_t state;
-} tasklet_descriptor_t;
-
-
-extern void tasklet_init(void);
-
-#endif
-
-/** @}
- */
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ kernel/generic/src/ipc/sysipc.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -426,7 +426,13 @@
 	case IPC_M_DATA_READ: {
 		size_t size = IPC_GET_ARG2(call->data);
-		if ((size <= 0 || (size > DATA_XFER_LIMIT)))
+		if (size <= 0)
 			return ELIMIT;
-		
+		if (size > DATA_XFER_LIMIT) {
+			int flags = IPC_GET_ARG3(call->data);
+			if (flags & IPC_XF_RESTRICT)
+				IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
+			else
+				return ELIMIT;
+		}
 		break;
 	}
@@ -435,6 +441,12 @@
 		size_t size = IPC_GET_ARG2(call->data);
 		
-		if (size > DATA_XFER_LIMIT)
-			return ELIMIT;
+		if (size > DATA_XFER_LIMIT) {
+			int flags = IPC_GET_ARG3(call->data);
+			if (flags & IPC_XF_RESTRICT) {
+				size = DATA_XFER_LIMIT;
+				IPC_SET_ARG2(call->data, size);
+			} else
+				return ELIMIT;
+		}
 		
 		call->buffer = (uint8_t *) malloc(size, 0);
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ kernel/generic/src/main/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -58,5 +58,4 @@
 #include <proc/thread.h>
 #include <proc/task.h>
-#include <proc/tasklet.h>
 #include <main/kinit.h>
 #include <main/version.h>
@@ -217,5 +216,4 @@
 	tlb_init();
 	ddi_init();
-	tasklet_init();
 	arch_post_mm_init();
 	arch_pre_smp_init();
Index: rnel/generic/src/proc/tasklet.c
===================================================================
--- kernel/generic/src/proc/tasklet.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ 	(revision )
@@ -1,64 +1,0 @@
-/*
- * Copyright (c) 2007 Jan Hudecek
- * Copyright (c) 2008 Martin Decky
- * 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 genericproc
- * @{
- */
-/** @file tasklet.c
- *  @brief Tasklet implementation
- */
-
-#include <proc/tasklet.h>
-#include <synch/spinlock.h>
-#include <mm/slab.h>
-#include <config.h>
-
-/** Spinlock protecting list of tasklets */
-SPINLOCK_INITIALIZE(tasklet_lock);
-
-/** Array of tasklet lists for every CPU */
-tasklet_descriptor_t **tasklet_list;
-
-void tasklet_init(void)
-{
-	unsigned int i;
-	
-	tasklet_list = malloc(sizeof(tasklet_descriptor_t *) * config.cpu_count, 0);
-	if (!tasklet_list)
-		panic("Error initializing tasklets.");
-	
-	for (i = 0; i < config.cpu_count; i++)
-		tasklet_list[i] = NULL;
-	
-	spinlock_initialize(&tasklet_lock, "tasklet_lock");
-}
-
-
-/** @}
- */
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -123,5 +123,7 @@
 		drv/usbflbk \
 		drv/usbkbd \
+		drv/usbhid \
 		drv/usbhub \
+		drv/usbmast \
 		drv/usbmid \
 		drv/usbmouse \
@@ -143,5 +145,7 @@
 		drv/usbflbk \
 		drv/usbkbd \
+		drv/usbhid \
 		drv/usbhub \
+		drv/usbmast \
 		drv/usbmid \
 		drv/usbmouse \
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -195,5 +195,5 @@
 					wchar_t c = str_decode(buff, &offset, bytes);
 					if (c == 0) {
-						// reached end of string
+						/* Reached end of string */
 						break;
 					}
@@ -228,6 +228,8 @@
 	int rc;
 	
-	// reset global state
-	// TODO: move to structure?
+	/*
+	 * reset global state
+	 * TODO: move to structure?
+	 */
 	paging_enabled = false;
 	chars_remaining = 0;
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/app/trace/trace.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -53,5 +53,5 @@
 #include <libc.h>
 
-// Temporary: service and method names
+/* Temporary: service and method names */
 #include "proto.h"
 #include <ipc/services.h>
Index: uspace/app/usbinfo/dev.c
===================================================================
--- uspace/app/usbinfo/dev.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/app/usbinfo/dev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/doc/doxygroups.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -251,4 +251,12 @@
 
 	/**
+	 * @defgroup drvusbmast USB mass storage driver
+	 * @ingroup usb
+	 * @brief USB driver for mass storage devices (bulk-only protocol).
+	 * This driver is a only a stub and is currently used only for
+	 * testing that bulk transfers work.
+	 */
+
+	/**
 	 * @defgroup drvusbuhci UHCI driver
 	 * @ingroup usb
@@ -269,4 +277,10 @@
 
 	/**
+	 * @defgroup drvusbohci OHCI driver
+	 * @ingroup usb
+	 * @brief Driver for OHCI host controller.
+	 */
+
+	/**
 	 * @defgroup drvusbehci EHCI driver
 	 * @ingroup usb
@@ -275,5 +289,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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ehci-hcd/hc_iface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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/isa/isa.c
===================================================================
--- uspace/drv/isa/isa.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/isa/isa.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -83,5 +83,5 @@
 static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
 {
-	// TODO
+	/* TODO */
 
 	return false;
Index: uspace/drv/ohci/Makefile
===================================================================
--- uspace/drv/ohci/Makefile	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -33,11 +33,16 @@
 
 SOURCES = \
+	batch.c \
+	endpoint_list.c \
+	hc.c \
+	hcd_endpoint.c \
 	iface.c \
-	batch.c \
 	main.c \
-	hc.c \
 	ohci.c \
+	pci.c \
 	root_hub.c \
-	pci.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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/batch.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -39,25 +39,42 @@
 
 #include "batch.h"
+#include "hcd_endpoint.h"
 #include "utils/malloc32.h"
-
-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,
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+typedef struct ohci_transfer_batch {
+	ed_t *ed;
+	td_t **tds;
+	size_t td_count;
+	size_t leave_td;
+	char *device_buffer;
+} ohci_transfer_batch_t;
+
+static void ohci_transfer_batch_dispose(void *ohci_batch)
+{
+	ohci_transfer_batch_t *instance = ohci_batch;
+	if (!instance)
+		return;
+	free32(instance->device_buffer);
+	unsigned i = 0;
+	if (instance->tds) {
+		for (; i< instance->td_count; ++i) {
+			if (i != instance->leave_td)
+				free32(instance->tds[i]);
+		}
+		free(instance->tds);
+	}
+	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+static void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir);
+static void batch_data(usb_transfer_batch_t *instance);
+/*----------------------------------------------------------------------------*/
+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...) \
@@ -65,5 +82,5 @@
                 usb_log_error(message); \
                 if (instance) { \
-                        batch_dispose(instance); \
+                        usb_transfer_batch_dispose(instance); \
                 } \
                 return NULL; \
@@ -73,31 +90,105 @@
 	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);
-
-        if (buffer_size > 0) {
-                instance->transport_buffer = malloc32(buffer_size);
-                CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
+	usb_transfer_batch_init(instance, ep, buffer, NULL, buffer_size,
+	    NULL, setup_size, func_in, func_out, arg, fun, NULL,
+	    ohci_transfer_batch_dispose);
+
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
+	assert(hcd_ep);
+
+	ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1);
+	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
+	instance->private_data = data;
+
+	data->td_count =
+	    ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER);
+	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
+		data->td_count += 2;
+	}
+
+	/* we need one extra place for td that is currently assigned to hcd_ep*/
+	data->tds = calloc(sizeof(td_t*), data->td_count + 1);
+	CHECK_NULL_DISPOSE_RETURN(data->tds,
+	    "Failed to allocate transfer descriptors.\n");
+
+	data->tds[0] = hcd_ep->td;
+	data->leave_td = 0;
+	unsigned i = 1;
+	for (; i <= data->td_count; ++i) {
+		data->tds[i] = malloc32(sizeof(td_t));
+		CHECK_NULL_DISPOSE_RETURN(data->tds[i],
+		    "Failed to allocate TD %d.\n", i );
+	}
+
+	data->ed = hcd_ep->ed;
+
+        if (setup_size + buffer_size > 0) {
+		data->device_buffer = malloc32(setup_size + buffer_size);
+                CHECK_NULL_DISPOSE_RETURN(data->device_buffer,
                     "Failed to allocate device accessible buffer.\n");
-        }
-
-        if (setup_size > 0) {
-                instance->setup_buffer = malloc32(setup_size);
-                CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
-                    "Failed to allocate device accessible setup buffer.\n");
+		instance->setup_buffer = data->device_buffer;
+		instance->data_buffer = data->device_buffer + setup_size;
                 memcpy(instance->setup_buffer, setup_buffer, setup_size);
         }
 
-
 	return instance;
 }
 /*----------------------------------------------------------------------------*/
-void batch_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	free32(instance->transport_buffer);
-	free32(instance->setup_buffer);
-	free(instance);
+bool batch_is_complete(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	size_t tds = data->td_count;
+	usb_log_debug("Batch(%p) checking %d td(s) for completion.\n",
+	    instance, tds);
+	usb_log_debug("ED: %x:%x:%x:%x.\n",
+	    data->ed->status, data->ed->td_head, data->ed->td_tail,
+	    data->ed->next);
+	size_t i = 0;
+	instance->transfered_size = instance->buffer_size;
+	for (; i < tds; ++i) {
+		assert(data->tds[i] != NULL);
+		usb_log_debug("TD %d: %x:%x:%x:%x.\n", i,
+		    data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next,
+		    data->tds[i]->be);
+		if (!td_is_finished(data->tds[i])) {
+			return false;
+		}
+		instance->error = td_error(data->tds[i]);
+		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
+			    instance, i, data->tds[i]->status);
+			/* Make sure TD queue is empty (one TD),
+			 * ED should be marked as halted */
+			data->ed->td_tail =
+			    (data->ed->td_head & ED_TDTAIL_PTR_MASK);
+			++i;
+			break;
+		}
+	}
+	data->leave_td = i;
+	assert(data->leave_td <= data->td_count);
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(instance->ep);
+	assert(hcd_ep);
+	hcd_ep->td = data->tds[i];
+	if (i > 0)
+		instance->transfered_size -= td_remain_size(data->tds[i - 1]);
+
+	/* Clear possible ED HALT */
+	data->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
+	uint32_t pa = addr_to_phys(hcd_ep->td);
+	assert(pa == (data->ed->td_head & ED_TDHEAD_PTR_MASK));
+	assert(pa == (data->ed->td_tail & ED_TDTAIL_PTR_MASK));
+
+	return true;
+}
+/*----------------------------------------------------------------------------*/
+void batch_commit(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	ed_set_end_td(data->ed, data->tds[data->td_count]);
 }
 /*----------------------------------------------------------------------------*/
@@ -106,8 +197,7 @@
 	assert(instance);
 	/* We are data out, we are supposed to provide data */
-	memcpy(instance->transport_buffer, instance->buffer,
-	    instance->buffer_size);
-	instance->next_step = batch_call_out_and_dispose;
-	/* TODO: implement */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
 	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
 }
@@ -116,6 +206,6 @@
 {
 	assert(instance);
-	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
 	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
 }
@@ -124,7 +214,6 @@
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_IN;
-	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_data(instance);
 	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
 }
@@ -133,10 +222,8 @@
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_OUT;
 	/* We are data out, we are supposed to provide data */
-	memcpy(instance->transport_buffer, instance->buffer,
-	    instance->buffer_size);
-	instance->next_step = batch_call_out_and_dispose;
-	/* TODO: implement */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_data(instance);
 	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
 }
@@ -145,7 +232,6 @@
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_IN;
-	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_data(instance);
 	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
 }
@@ -154,30 +240,95 @@
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_IN;
-	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
-	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Helper function calls callback and correctly disposes of batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-void batch_call_in_and_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_in(instance);
-	batch_dispose(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Helper function calls callback and correctly disposes of batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-void batch_call_out_and_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_out(instance);
-	batch_dispose(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+ed_t * batch_ed(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_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_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+	int toggle = 0;
+	/* setup stage */
+	td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,
+		instance->setup_size, toggle);
+	td_set_next(data->tds[0], data->tds[1]);
+	usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0]->status,
+	    data->tds[0]->cbp, data->tds[0]->next, data->tds[0]->be);
+
+	/* data stage */
+	size_t td_current = 1;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
+		    OHCI_TD_MAX_TRANSFER : remain_size;
+		toggle = 1 - toggle;
+
+		td_init(data->tds[td_current], data_dir, buffer,
+		    transfer_size, toggle);
+		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current]->status, data->tds[td_current]->cbp,
+		    data->tds[td_current]->next, data->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count - 1);
+		++td_current;
+	}
+
+	/* status stage */
+	assert(td_current == data->td_count - 1);
+	td_init(data->tds[td_current], status_dir, NULL, 0, 1);
+	td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+	usb_log_debug("Created STATUS TD: %x:%x:%x:%x.\n",
+	    data->tds[td_current]->status, data->tds[td_current]->cbp,
+	    data->tds[td_current]->next, data->tds[td_current]->be);
+}
+/*----------------------------------------------------------------------------*/
+void batch_data(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+
+	size_t td_current = 0;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
+		    OHCI_TD_MAX_TRANSFER : remain_size;
+
+		td_init(data->tds[td_current], instance->ep->direction,
+		    buffer, transfer_size, -1);
+		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current]->status, data->tds[td_current]->cbp,
+		    data->tds[td_current]->next, data->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count);
+		++td_current;
+	}
 }
 /**
Index: uspace/drv/ohci/batch.h
===================================================================
--- uspace/drv/ohci/batch.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/batch.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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_commit(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/endpoint_list.c
===================================================================
--- uspace/drv/ohci/endpoint_list.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/ohci/endpoint_list.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,225 @@
+/*
+ * 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 "endpoint_list.h"
+
+/** 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 endpoint_list_init(endpoint_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->endpoint_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 endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next)
+{
+	assert(instance);
+	assert(next);
+	ed_append_ed(instance->list_head, next->list_head);
+}
+/*----------------------------------------------------------------------------*/
+/** Submit transfer endpoint to the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] endpoint Transfer endpoint to submit.
+ * @return Error code
+ *
+ * The endpoint is added to the end of the list and queue.
+ */
+void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep)
+{
+	assert(instance);
+	assert(hcd_ep);
+	usb_log_debug2("Queue %s: Adding endpoint(%p).\n",
+	    instance->name, hcd_ep);
+
+	fibril_mutex_lock(&instance->guard);
+
+	ed_t *last_ed = NULL;
+	/* Add to the hardware queue. */
+	if (list_empty(&instance->endpoint_list)) {
+		/* There is nothing scheduled */
+		last_ed = instance->list_head;
+	} else {
+		/* There is something scheduled */
+		hcd_endpoint_t *last = list_get_instance(
+		    instance->endpoint_list.prev, hcd_endpoint_t, link);
+		last_ed = last->ed;
+	}
+	/* keep link */
+	hcd_ep->ed->next = last_ed->next;
+	ed_append_ed(last_ed, hcd_ep->ed);
+
+	asm volatile ("": : :"memory");
+
+	/* Add to the driver list */
+	list_append(&hcd_ep->link, &instance->endpoint_list);
+
+	hcd_endpoint_t *first = list_get_instance(
+	    instance->endpoint_list.next, hcd_endpoint_t, link);
+	usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).\n",
+		hcd_ep, instance->name, first, first->ed);
+	if (last_ed == instance->list_head) {
+		usb_log_debug2("%s head ED(%p-%p): %x:%x:%x:%x.\n",
+		    instance->name, last_ed, instance->list_head_pa,
+		    last_ed->status, last_ed->td_tail, last_ed->td_head,
+		    last_ed->next);
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+#if 0
+/** Create list for finished endpoints.
+ *
+ * @param[in] instance List to use.
+ * @param[in] done list to fill
+ */
+void endpoint_list_remove_finished(endpoint_list_t *instance, link_t *done)
+{
+	assert(instance);
+	assert(done);
+
+	fibril_mutex_lock(&instance->guard);
+	usb_log_debug2("Checking list %s for completed endpointes(%d).\n",
+	    instance->name, list_count(&instance->endpoint_list));
+	link_t *current = instance->endpoint_list.next;
+	while (current != &instance->endpoint_list) {
+		link_t *next = current->next;
+		hcd_endpoint_t *endpoint =
+		    list_get_instance(current, hcd_endpoint_t, link);
+
+		if (endpoint_is_complete(endpoint)) {
+			/* Save for post-processing */
+			endpoint_list_remove_endpoint(instance, endpoint);
+			list_append(current, done);
+		}
+		current = next;
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Walk the list and abort all endpointes.
+ *
+ * @param[in] instance List to use.
+ */
+void endpoint_list_abort_all(endpoint_list_t *instance)
+{
+	fibril_mutex_lock(&instance->guard);
+	while (!list_empty(&instance->endpoint_list)) {
+		link_t *current = instance->endpoint_list.next;
+		hcd_endpoint_t *endpoint =
+		    list_get_instance(current, hcd_endpoint_t, link);
+		endpoint_list_remove_endpoint(instance, endpoint);
+		hcd_endpoint_finish_error(endpoint, EIO);
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+#endif
+/*----------------------------------------------------------------------------*/
+/** Remove a transfer endpoint from the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] endpoint Transfer endpoint to remove.
+ * @return Error code
+ *
+ * Does not lock the transfer list, caller is responsible for that.
+ */
+void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep)
+{
+	assert(instance);
+	assert(instance->list_head);
+	assert(hcd_ep);
+	assert(hcd_ep->ed);
+
+	fibril_mutex_lock(&instance->guard);
+
+	usb_log_debug2(
+	    "Queue %s: removing endpoint(%p).\n", instance->name, hcd_ep);
+
+	const char *qpos = NULL;
+	ed_t *prev_ed;
+	/* Remove from the hardware queue */
+	if (instance->endpoint_list.next == &hcd_ep->link) {
+		/* I'm the first one here */
+		prev_ed = instance->list_head;
+		qpos = "FIRST";
+	} else {
+		hcd_endpoint_t *prev =
+		    list_get_instance(hcd_ep->link.prev, hcd_endpoint_t, link);
+		prev_ed = prev->ed;
+		qpos = "NOT FIRST";
+	}
+	assert((prev_ed->next & ED_NEXT_PTR_MASK) == addr_to_phys(hcd_ep->ed));
+	prev_ed->next = hcd_ep->ed->next;
+
+	asm volatile ("": : :"memory");
+	usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.\n",
+	    hcd_ep, qpos, instance->name, hcd_ep->ed->next);
+
+	/* Remove from the endpoint list */
+	list_remove(&hcd_ep->link);
+	fibril_mutex_unlock(&instance->guard);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/endpoint_list.h
===================================================================
--- uspace/drv/ohci/endpoint_list.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/ohci/endpoint_list.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,79 @@
+/*
+ * 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_ENDPOINT_LIST_H
+#define DRV_OHCI_ENDPOINT_LIST_H
+
+#include <fibril_synch.h>
+
+#include "hcd_endpoint.h"
+#include "hw_struct/endpoint_descriptor.h"
+#include "utils/malloc32.h"
+
+typedef struct endpoint_list
+{
+	fibril_mutex_t guard;
+	ed_t *list_head;
+	uint32_t list_head_pa;
+	const char *name;
+	link_t endpoint_list;
+} endpoint_list_t;
+
+/** Dispose transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ *
+ * Frees memory for internal qh_t structure.
+ */
+static inline void endpoint_list_fini(endpoint_list_t *instance)
+{
+	assert(instance);
+	free32(instance->list_head);
+}
+
+int endpoint_list_init(endpoint_list_t *instance, const char *name);
+
+void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next);
+
+void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep);
+
+void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep);
+#if 0
+void endpoint_list_remove_finished(endpoint_list_t *instance, link_t *done);
+
+void endpoint_list_abort_all(endpoint_list_t *instance);
+#endif
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/hc.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -43,8 +43,11 @@
 
 #include "hc.h"
+#include "hcd_endpoint.h"
 
 static int interrupt_emulator(hc_t *instance);
 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)
@@ -52,16 +55,32 @@
 	assert(instance);
 	assert(hub_fun);
+
+	int ret;
 
 	usb_address_t hub_address =
 	    device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
+	if (hub_address <= 0) {
+		usb_log_error("Failed to get OHCI root hub address.\n");
+		return hub_address;
+	}
 	instance->rh.address = hub_address;
 	usb_device_keeper_bind(
 	    &instance->manager, hub_address, hub_fun->handle);
 
+	ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
+	    USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to add OHCI rh endpoint 0.\n");
+		usb_device_keeper_release(&instance->manager, hub_address);
+		return ret;
+	}
+
 	char *match_str = NULL;
-	int ret = asprintf(&match_str, "usb&class=hub");
-	ret = (match_str == NULL) ? ret : EOK;
+	/* DDF needs heap allocated string */
+	ret = asprintf(&match_str, "usb&class=hub");
 	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);
+		usb_device_keeper_release(&instance->manager, hub_address);
 		return ret;
 	}
@@ -69,5 +88,5 @@
 	ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
 	if (ret != EOK) {
-		usb_log_error("Failed add create root hub match-id.\n");
+		usb_log_error("Failed add root hub match-id.\n");
 	}
 	return ret;
@@ -90,5 +109,4 @@
 	    ret, str_error(ret));
 
-	instance->ddf_instance = fun;
 	usb_device_keeper_init(&instance->manager);
 	ret = usb_endpoint_manager_init(&instance->ep_manager,
@@ -97,4 +115,13 @@
 	    ret, str_error(ret));
 
+	hc_gain_control(instance);
+	ret = hc_init_memory(instance);
+	CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures:%s.\n",
+	    ret, str_error(ret));
+	hc_init_hw(instance);
+	fibril_mutex_initialize(&instance->guard);
+
+	rh_init(&instance->rh, instance->registers);
+
 	if (!interrupts) {
 		instance->interrupt_emulator =
@@ -103,12 +130,125 @@
 	}
 
-	hc_gain_control(instance);
-
-	rh_init(&instance->rh, dev, instance->registers);
-
-	hc_init_hw(instance);
-
-	/* TODO: implement */
-	return EOK;
+	list_initialize(&instance->pending_batches);
+#undef CHECK_RET_RETURN
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+int hc_add_endpoint(
+    hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
+    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
+    size_t mps, size_t size, unsigned interval)
+{
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+	int ret =
+	    endpoint_init(ep, address, endpoint, direction, type, speed, mps);
+	if (ret != EOK) {
+		free(ep);
+		return ret;
+	}
+
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
+	if (hcd_ep == NULL) {
+		endpoint_destroy(ep);
+		return ENOMEM;
+	}
+
+	ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
+	if (ret != EOK) {
+		hcd_endpoint_clear(ep);
+		endpoint_destroy(ep);
+		return ret;
+	}
+
+	/* Enqueue hcd_ep */
+	switch (ep->transfer_type) {
+	case USB_TRANSFER_CONTROL:
+		instance->registers->control &= ~C_CLE;
+		endpoint_list_add_ep(
+		    &instance->lists[ep->transfer_type], hcd_ep);
+		instance->registers->control_current = 0;
+		instance->registers->control |= C_CLE;
+		break;
+	case USB_TRANSFER_BULK:
+		instance->registers->control &= ~C_BLE;
+		endpoint_list_add_ep(
+		    &instance->lists[ep->transfer_type], hcd_ep);
+		instance->registers->control |= C_BLE;
+		break;
+	case USB_TRANSFER_ISOCHRONOUS:
+	case USB_TRANSFER_INTERRUPT:
+		instance->registers->control &= (~C_PLE & ~C_IE);
+		endpoint_list_add_ep(
+		    &instance->lists[ep->transfer_type], hcd_ep);
+		instance->registers->control |= C_PLE | C_IE;
+		break;
+	default:
+		break;
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+int hc_remove_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
+	    address, endpoint, direction, NULL);
+	if (ep == NULL) {
+		usb_log_error("Endpoint unregister failed: No such EP.\n");
+		fibril_mutex_unlock(&instance->guard);
+		return ENOENT;
+	}
+
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
+	if (hcd_ep) {
+		/* Dequeue hcd_ep */
+		switch (ep->transfer_type) {
+		case USB_TRANSFER_CONTROL:
+			instance->registers->control &= ~C_CLE;
+			endpoint_list_remove_ep(
+			    &instance->lists[ep->transfer_type], hcd_ep);
+			instance->registers->control_current = 0;
+			instance->registers->control |= C_CLE;
+			break;
+		case USB_TRANSFER_BULK:
+			instance->registers->control &= ~C_BLE;
+			endpoint_list_remove_ep(
+			    &instance->lists[ep->transfer_type], hcd_ep);
+			instance->registers->control |= C_BLE;
+			break;
+		case USB_TRANSFER_ISOCHRONOUS:
+		case USB_TRANSFER_INTERRUPT:
+			instance->registers->control &= (~C_PLE & ~C_IE);
+			endpoint_list_remove_ep(
+			    &instance->lists[ep->transfer_type], hcd_ep);
+			instance->registers->control |= C_PLE | C_IE;
+			break;
+		default:
+			break;
+		}
+		hcd_endpoint_clear(ep);
+	} else {
+		usb_log_warning("Endpoint without hcd equivalent structure.\n");
+	}
+	int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
+	    address, endpoint, direction);
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
+	    address, endpoint, direction, bw);
+	fibril_mutex_unlock(&instance->guard);
+	return ep;
 }
 /*----------------------------------------------------------------------------*/
@@ -117,9 +257,27 @@
 	assert(instance);
 	assert(batch);
-	if (batch->target.address == instance->rh.address) {
+	assert(batch->ep);
+
+	/* check for root hub communication */
+	if (batch->ep->address == instance->rh.address) {
 		return rh_request(&instance->rh, batch);
 	}
-	/* TODO: implement */
-	return ENOTSUP;
+
+	fibril_mutex_lock(&instance->guard);
+	list_append(&batch->link, &instance->pending_batches);
+	batch_commit(batch);
+	switch (batch->ep->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;
+	}
+
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -127,13 +285,32 @@
 {
 	assert(instance);
-	if (status == 0)
+	if ((status & ~IS_SF) == 0) /* ignore sof status */
 		return;
 	if (status & IS_RHSC)
 		rh_interrupt(&instance->rh);
 
-	usb_log_info("OHCI interrupt: %x.\n", status);
-
-	/* TODO: Check for further interrupt causes */
-	/* TODO: implement */
+	usb_log_debug("OHCI interrupt: %x.\n", status);
+
+	if (status & IS_WDH) {
+		fibril_mutex_lock(&instance->guard);
+		usb_log_debug2("HCCA: %p-%p(%p).\n", instance->hcca,
+		    instance->registers->hcca, addr_to_phys(instance->hcca));
+		usb_log_debug2("Periodic current: %p.\n",
+		    instance->registers->periodic_current);
+
+		link_t *current = instance->pending_batches.next;
+		while (current != &instance->pending_batches) {
+			link_t *next = current->next;
+			usb_transfer_batch_t *batch =
+			    usb_transfer_batch_from_link(current);
+
+			if (batch_is_complete(batch)) {
+				list_remove(current);
+				usb_transfer_batch_finish(batch);
+			}
+			current = next;
+		}
+		fibril_mutex_unlock(&instance->guard);
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -146,5 +323,5 @@
 		instance->registers->interrupt_status = status;
 		hc_interrupt(instance, status);
-		async_usleep(1000);
+		async_usleep(50000);
 	}
 	return EOK;
@@ -154,12 +331,19 @@
 {
 	assert(instance);
+	/* Turn off legacy emulation */
+	volatile uint32_t *ohci_emulation_reg =
+	    (uint32_t*)((char*)instance->registers + 0x100);
+	usb_log_debug("OHCI legacy register %p: %x.\n",
+		ohci_emulation_reg, *ohci_emulation_reg);
+	*ohci_emulation_reg = 0;
+
 	/* Interrupt routing enabled => smm driver is active */
 	if (instance->registers->control & C_IR) {
-		usb_log_info("Found SMM driver requesting ownership change.\n");
+		usb_log_debug("SMM driver: request ownership change.\n");
 		instance->registers->command_status |= CS_OCR;
 		while (instance->registers->control & C_IR) {
 			async_usleep(1000);
 		}
-		usb_log_info("Ownership taken from SMM driver.\n");
+		usb_log_info("SMM driver: Ownership taken.\n");
 		return;
 	}
@@ -169,7 +353,7 @@
 	/* Interrupt routing disabled && status != USB_RESET => BIOS active */
 	if (hc_status != C_HCFS_RESET) {
-		usb_log_info("Found BIOS driver.\n");
+		usb_log_debug("BIOS driver found.\n");
 		if (hc_status == C_HCFS_OPERATIONAL) {
-			usb_log_info("HC operational(BIOS).\n");
+			usb_log_info("BIOS driver: HC operational.\n");
 			return;
 		}
@@ -177,4 +361,5 @@
 		instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
 		async_usleep(20000);
+		usb_log_info("BIOS driver: HC resumed.\n");
 		return;
 	}
@@ -182,32 +367,129 @@
 	/* HC is in reset (hw startup) => no other driver
 	 * maintain reset for at least the time specified in USB spec (50 ms)*/
+	usb_log_info("HC found in reset.\n");
 	async_usleep(50000);
-
-	/* turn off legacy emulation */
-	volatile uint32_t *ohci_emulation_reg =
-	    (uint32_t*)((char*)instance->registers + 0x100);
-	usb_log_info("OHCI legacy register status %p: %x.\n",
-		ohci_emulation_reg, *ohci_emulation_reg);
-	*ohci_emulation_reg = 0;
-
 }
 /*----------------------------------------------------------------------------*/
 void hc_init_hw(hc_t *instance)
 {
-	assert(instance);
+	/* OHCI guide page 42 */
+	assert(instance);
+	usb_log_debug2("Started hc initialization routine.\n");
+
+	/* Save contents of fm_interval register */
 	const uint32_t fm_interval = instance->registers->fm_interval;
+	usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
+
+	/* Reset hc */
+	usb_log_debug2("HC reset.\n");
+	size_t time = 0;
 	instance->registers->command_status = CS_HCR;
-	async_usleep(10);
+	while (instance->registers->command_status & CS_HCR) {
+		async_usleep(10);
+		time += 10;
+	}
+	usb_log_debug2("HC reset complete in %zu us.\n", time);
+
+	/* 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 */
-	/* TODO: enable interrupts */
-	/* TODO: set periodic start to 90% */
+	usb_log_debug2("HC should be in suspend state(%x).\n",
+	    instance->registers->control);
+
+	/* Use HCCA */
+	instance->registers->hcca = addr_to_phys(instance->hcca);
+
+	/* Use queues */
+	instance->registers->bulk_head =
+	    instance->lists[USB_TRANSFER_BULK].list_head_pa;
+	usb_log_debug2("Bulk HEAD set to: %p(%p).\n",
+	    instance->lists[USB_TRANSFER_BULK].list_head,
+	    instance->lists[USB_TRANSFER_BULK].list_head_pa);
+
+	instance->registers->control_head =
+	    instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
+	usb_log_debug2("Control HEAD set to: %p(%p).\n",
+	    instance->lists[USB_TRANSFER_CONTROL].list_head,
+	    instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
+
+	/* Enable queues */
+	instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
+	usb_log_debug2("All queues enabled(%x).\n",
+	    instance->registers->control);
+
+	/* Disable interrupts */
+	instance->registers->interrupt_disable = I_SF | I_OC;
+	usb_log_debug2("Disabling interrupts: %x.\n",
+	    instance->registers->interrupt_disable);
+	instance->registers->interrupt_disable = I_MI;
+	usb_log_debug2("Enabled interrupts: %x.\n",
+	    instance->registers->interrupt_enable);
+
+	/* Set periodic start to 90% */
+	uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
+	instance->registers->periodic_start = (frame_length / 10) * 9;
+	usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
+	    instance->registers->periodic_start,
+	    instance->registers->periodic_start, frame_length);
 
 	instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
-	usb_log_info("OHCI HC up and running.\n");
+	usb_log_info("OHCI HC up and running(%x).\n",
+	    instance->registers->control);
+}
+/*----------------------------------------------------------------------------*/
+int hc_init_transfer_lists(hc_t *instance)
+{
+	assert(instance);
+
+#define SETUP_ENDPOINT_LIST(type) \
+do { \
+	const char *name = usb_str_transfer_type(type); \
+	int ret = endpoint_list_init(&instance->lists[type], name); \
+	if (ret != EOK) { \
+		usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
+		    ret, name); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \
+	} \
+} while (0)
+
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS);
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT);
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL);
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK);
+#undef SETUP_ENDPOINT_LIST
+	endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT],
+	    &instance->lists[USB_TRANSFER_ISOCHRONOUS]);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+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));
+	usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
+
+	unsigned i = 0;
+	for (; i < 32; ++i) {
+		instance->hcca->int_ep[i] =
+		    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
+	}
+	usb_log_debug2("Interrupt HEADs set to: %p(%p).\n",
+	    instance->lists[USB_TRANSFER_INTERRUPT].list_head,
+	    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
+
+	return EOK;
 }
 /**
Index: uspace/drv/ohci/hc.h
===================================================================
--- uspace/drv/ohci/hc.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/hc.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -48,14 +48,21 @@
 #include "ohci_regs.h"
 #include "root_hub.h"
+#include "endpoint_list.h"
 #include "hw_struct/hcca.h"
 
 typedef struct hc {
 	ohci_regs_t *registers;
+	hcca_t *hcca;
+
 	usb_address_t rh_address;
 	rh_t rh;
-	ddf_fun_t *ddf_instance;
+
+	endpoint_list_t lists[4];
+	link_t pending_batches;
+
 	usb_device_keeper_t manager;
 	usb_endpoint_manager_t ep_manager;
 	fid_t interrupt_emulator;
+	fibril_mutex_t guard;
 } hc_t;
 
@@ -65,8 +72,4 @@
      uintptr_t regs, size_t reg_size, bool interrupts);
 
-int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
-
-void hc_interrupt(hc_t *instance, uint32_t status);
-
 /** Safely dispose host controller internal structures
  *
@@ -74,4 +77,18 @@
  */
 static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ };
+
+int hc_add_endpoint(hc_t *instance, usb_address_t address, usb_endpoint_t ep,
+    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
+    size_t max_packet_size, size_t size, unsigned interval);
+
+int hc_remove_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction);
+
+endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw);
+
+int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
+
+void hc_interrupt(hc_t *instance, uint32_t status);
 
 /** Get and cast pointer to the driver data
Index: uspace/drv/ohci/hcd_endpoint.c
===================================================================
--- uspace/drv/ohci/hcd_endpoint.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/ohci/hcd_endpoint.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include "utils/malloc32.h"
+#include "hcd_endpoint.h"
+
+static void hcd_ep_toggle_set(void *hcd_ep, int toggle)
+{
+	hcd_endpoint_t *instance = hcd_ep;
+	assert(instance);
+	assert(instance->ed);
+	ed_toggle_set(instance->ed, toggle);
+}
+static int hcd_ep_toggle_get(void *hcd_ep)
+{
+	hcd_endpoint_t *instance = hcd_ep;
+	assert(instance);
+	assert(instance->ed);
+	return ed_toggle_get(instance->ed);
+}
+
+
+hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep)
+{
+	assert(ep);
+	hcd_endpoint_t *hcd_ep = malloc(sizeof(hcd_endpoint_t));
+	if (hcd_ep == NULL)
+		return NULL;
+
+	hcd_ep->ed = malloc32(sizeof(ed_t));
+	if (hcd_ep->ed == NULL) {
+		free(hcd_ep);
+		return NULL;
+	}
+
+	hcd_ep->td = malloc32(sizeof(td_t));
+	if (hcd_ep->td == NULL) {
+		free32(hcd_ep->ed);
+		free(hcd_ep);
+		return NULL;
+	}
+
+	ed_init(hcd_ep->ed, ep);
+	ed_set_td(hcd_ep->ed, hcd_ep->td);
+	endpoint_set_hc_data(ep, hcd_ep, hcd_ep_toggle_get, hcd_ep_toggle_set);
+
+	return hcd_ep;
+}
+/*----------------------------------------------------------------------------*/
+hcd_endpoint_t * hcd_endpoint_get(endpoint_t *ep)
+{
+	assert(ep);
+	return ep->hc_data.data;
+}
+/*----------------------------------------------------------------------------*/
+void hcd_endpoint_clear(endpoint_t *ep)
+{
+	assert(ep);
+	hcd_endpoint_t *hcd_ep = ep->hc_data.data;
+	assert(hcd_ep);
+	free32(hcd_ep->ed);
+	free32(hcd_ep->td);
+	free(hcd_ep);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hcd_endpoint.h
===================================================================
--- uspace/drv/ohci/hcd_endpoint.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/ohci/hcd_endpoint.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HCD_ENDPOINT_H
+#define DRV_OHCI_HCD_ENDPOINT_H
+
+#include <assert.h>
+#include <adt/list.h>
+
+#include <usb/host/endpoint.h>
+
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+typedef struct hcd_endpoint {
+	ed_t *ed;
+	td_t *td;
+	link_t link;
+} hcd_endpoint_t;
+
+hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep);
+
+hcd_endpoint_t * hcd_endpoint_get(endpoint_t *ep);
+
+void hcd_endpoint_clear(endpoint_t *ep);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/completion_codes.h
===================================================================
--- uspace/drv/ohci/hw_struct/completion_codes.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/hw_struct/completion_codes.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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 e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/ohci/hw_struct/endpoint_descriptor.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+	if (ep->toggle)
+		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/endpoint_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/endpoint_descriptor.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/hw_struct/endpoint_descriptor.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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_IN (0x1)
-#define ED_STATUS_D_OUT (0x2)
+#define ED_STATUS_D_SHIFT (11)
+#define ED_STATUS_D_OUT (0x1)
+#define ED_STATUS_D_IN (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*/
@@ -66,4 +73,5 @@
 #define ED_TDHEAD_ZERO_SHIFT (2)
 #define ED_TDHEAD_TOGGLE_CARRY (0x2)
+#define ED_TDHEAD_HALTED_FLAG (0x1)
 
 	volatile uint32_t next;
@@ -71,4 +79,51 @@
 #define ED_NEXT_PTR_SHIFT (0)
 } __attribute__((packed)) ed_t;
+
+void ed_init(ed_t *instance, endpoint_t *ep);
+
+static inline void ed_set_td(ed_t *instance, td_t *td)
+{
+	assert(instance);
+	uintptr_t pa = addr_to_phys(td);
+	instance->td_head =
+	    ((pa & ED_TDHEAD_PTR_MASK)
+	    | (instance->td_head & ~ED_TDHEAD_PTR_MASK));
+	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
+}
+
+static inline void ed_set_end_td(ed_t *instance, td_t *td)
+{
+	assert(instance);
+	uintptr_t pa = addr_to_phys(td);
+	instance->td_tail = pa & 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;
+}
+
+static inline int ed_toggle_get(ed_t *instance)
+{
+	assert(instance);
+	return (instance->td_head & ED_TDHEAD_TOGGLE_CARRY) ? 1 : 0;
+}
+
+static inline void ed_toggle_set(ed_t *instance, int toggle)
+{
+	assert(instance);
+	assert(toggle == 0 || toggle == 1);
+	if (toggle == 1) {
+		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
+	} else {
+		/* clear halted flag when reseting toggle */
+		instance->td_head &= ~ED_TDHEAD_TOGGLE_CARRY;
+		instance->td_head &= ~ED_TDHEAD_HALTED_FLAG;
+	}
+}
 #endif
 /**
Index: uspace/drv/ohci/hw_struct/hcca.h
===================================================================
--- uspace/drv/ohci/hw_struct/hcca.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/hw_struct/hcca.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -43,5 +43,5 @@
 	uint32_t done_head;
 	uint32_t reserved[29];
-} __attribute__((packed)) hcca_t;
+} __attribute__((packed, aligned)) hcca_t;
 
 #endif
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,66 @@
+/*
+ * 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 (dir == USB_DIRECTION_IN) {
+		instance->status |= TD_STATUS_ROUND_FLAG;
+	}
+	if (buffer != NULL) {
+		assert(size != 0);
+		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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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 {
@@ -45,6 +50,6 @@
 #define TD_STATUS_DP_SHIFT (19)
 #define TD_STATUS_DP_SETUP (0x0)
-#define TD_STATUS_DP_IN (0x1)
-#define TD_STATUS_DP_OUT (0x2)
+#define TD_STATUS_DP_OUT (0x1)
+#define TD_STATUS_DP_IN (0x2)
 #define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */
 #define TD_STATUS_DI_SHIFT (21)
@@ -52,4 +57,7 @@
 #define TD_STATUS_T_MASK (0x3)  /* data toggle 1x = use ED toggle carry */
 #define TD_STATUS_T_SHIFT (24)
+#define TD_STATUS_T_0 (0x2)
+#define TD_STATUS_T_1 (0x3)
+#define TD_STATUS_T_ED (0)
 #define TD_STATUS_EC_MASK (0x3) /* error count */
 #define TD_STATUS_EC_SHIFT (26)
@@ -64,4 +72,43 @@
 	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) {
+		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);
+}
+
+static inline size_t td_remain_size(td_t *instance)
+{
+	assert(instance);
+	if (instance->cbp == 0)
+		return 0;
+	return instance->be - instance->cbp + 1;
+}
 #endif
 /**
Index: uspace/drv/ohci/iface.c
===================================================================
--- uspace/drv/ohci/iface.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/iface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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,51 +36,55 @@
 
 #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.
- * @return Error code.
- */
-static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
-{
+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_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Default address request with speed %d.\n", speed);
-	usb_device_keeper_reserve_default_address(&hc->manager, speed);
+	*hc = fun_to_hc(fun);
+	assert(*hc);
+
+	size_t res_bw;
+	endpoint_t *ep = hc_get_endpoint(*hc,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    target.address, target.endpoint, name, bw, res_bw);
+		return ENOSPC;
+	}
+
+	*batch = batch_get(
+	    fun, ep, data, size, setup_data, setup_size, in, out, arg);
+	if (!*batch)
+		return ENOMEM;
 	return EOK;
 }
 /*----------------------------------------------------------------------------*/
-/** Release default address.
- *
- * @param[in] fun Device function the action was invoked on.
- * @return Error code.
- */
-static int release_default_address(ddf_fun_t *fun)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Default address release.\n");
-	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 +105,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 +123,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 +143,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,43 +151,35 @@
  * @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);
+
+	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
+	if (speed >= USB_SPEED_MAX) {
+		speed = ep_speed;
+	}
 	const size_t size = max_packet_size;
+
 	usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
 	    address, endpoint, usb_str_transfer_type(transfer_type),
 	    usb_str_speed(speed), direction, size, max_packet_size, interval);
-	// 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.
- */
+
+	return hc_add_endpoint(hc, address, endpoint, speed, transfer_type,
+	    direction, max_packet_size, size, interval);
+}
+/*----------------------------------------------------------------------------*/
 static int unregister_endpoint(
     ddf_fun_t *fun, usb_address_t address,
     usb_endpoint_t endpoint, usb_direction_t direction)
 {
-	assert(fun);
 	hc_t *hc = fun_to_hc(fun);
 	assert(hc);
 	usb_log_debug("Unregister endpoint %d:%d %d.\n",
 	    address, endpoint, direction);
-	return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
-	    endpoint, direction);
+	return hc_remove_endpoint(hc, address, endpoint, direction);
 }
 /*----------------------------------------------------------------------------*/
@@ -196,5 +193,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,25 +201,17 @@
  */
 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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -239,5 +227,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,24 +235,17 @@
  */
 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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -281,5 +261,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,25 +269,17 @@
  */
 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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -324,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] data Buffer where to store the data (in USB endianess,
  *	allocated and deallocated by the caller).
@@ -333,24 +303,17 @@
  */
 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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -366,11 +329,10 @@
  * @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).
- * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
+ * @param[in] setup_size Size of @p setup_packet buffer in bytes.
  * @param[in] data_buffer Data buffer (in USB endianess, allocated and
  *	deallocated by the caller).
- * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
+ * @param[in] size Size of @p data_buffer buffer in bytes.
  * @param[in] callback Callback to be issued once the transfer is complete.
  * @param[in] arg Pass-through argument to the callback.
@@ -378,30 +340,20 @@
  */
 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_device_keeper_reset_if_need(&hc->manager, target, setup_data);
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
 	batch_control_write(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -417,11 +369,10 @@
  * @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).
- * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
+ * @param[in] setup_size Size of @p setup_packet buffer in bytes.
  * @param[in] data_buffer Buffer where to store the data (in USB endianess,
  *	allocated and deallocated by the caller).
- * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
+ * @param[in] size Size of @p data_buffer buffer in bytes.
  * @param[in] callback Callback to be issued once the transfer is complete.
  * @param[in] arg Pass-through argument to the callback.
@@ -429,34 +380,24 @@
  */
 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);
-	if (ret != EOK) {
-		batch_dispose(batch);
-	}
-	return ret;
-}
-/*----------------------------------------------------------------------------*/
-/** Host controller interface implementation for OHCI. */
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
 usbhc_iface_t hc_iface = {
-	.reserve_default_address = reserve_default_address,
-	.release_default_address = release_default_address,
 	.request_address = request_address,
 	.bind_address = bind_address,
@@ -475,5 +416,4 @@
 	.control_read = control_read,
 };
-
 /**
  * @}
Index: uspace/drv/ohci/ohci.ma
===================================================================
--- uspace/drv/ohci/ohci.ma	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/ohci.ma	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -1,1 +1,3 @@
 10 pci/ven=106b&dev=003f
+10 pci/ven=10de&dev=0aa5
+10 pci/ven=10de&dev=0aa5
Index: uspace/drv/ohci/ohci_regs.h
===================================================================
--- uspace/drv/ohci/ohci_regs.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/ohci_regs.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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_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_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_RESUME      (0x1)
+#define C_HCFS_OPERATIONAL (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)
-
-	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)
-
+#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 interrupt_enable;
 	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 periodic endpoint */
+	const volatile uint32_t periodic_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 (0x3fff) /* 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 (0x3fff) /* 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/root_hub.c
===================================================================
--- uspace/drv/ohci/root_hub.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/root_hub.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -47,20 +47,19 @@
  *	standart device descriptor for ohci root hub
  */
-static const usb_standard_device_descriptor_t ohci_rh_device_descriptor =
-{
-		.configuration_count = 1,
-		.descriptor_type = USB_DESCTYPE_DEVICE,
-		.device_class = USB_CLASS_HUB,
-		.device_protocol = 0,
-		.device_subclass = 0,
-		.device_version = 0,
-		.length = sizeof(usb_standard_device_descriptor_t),
-		/// \TODO this value is guessed
-		.max_packet_size = 8,
-		.vendor_id = 0x16db,
-		.product_id = 0x0001,
-		/// \TODO these values migt be different
-		.str_serial_number = 0,
-		.usb_spec_version = 0x110,
+static const usb_standard_device_descriptor_t ohci_rh_device_descriptor = {
+	.configuration_count = 1,
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.device_class = USB_CLASS_HUB,
+	.device_protocol = 0,
+	.device_subclass = 0,
+	.device_version = 0,
+	.length = sizeof (usb_standard_device_descriptor_t),
+	/// \TODO this value is guessed
+	.max_packet_size = 8,
+	.vendor_id = 0x16db,
+	.product_id = 0x0001,
+	/// \TODO these values migt be different
+	.str_serial_number = 0,
+	.usb_spec_version = 0x110,
 };
 
@@ -69,12 +68,11 @@
  * for ohci root hubs
  */
-static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor =
-{
+static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor = {
 	/// \TODO some values are default or guessed
-	.attributes = 1<<7,
+	.attributes = 1 << 7,
 	.configuration_number = 1,
 	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
 	.interface_count = 1,
-	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.length = sizeof (usb_standard_configuration_descriptor_t),
 	.max_power = 100,
 	.str_configuration = 0,
@@ -84,6 +82,5 @@
  * standart ohci root hub interface descriptor
  */
-static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor =
-{
+static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor = {
 	.alternate_setting = 0,
 	.descriptor_type = USB_DESCTYPE_INTERFACE,
@@ -94,5 +91,5 @@
 	.interface_protocol = 0,
 	.interface_subclass = 0,
-	.length = sizeof(usb_standard_interface_descriptor_t),
+	.length = sizeof (usb_standard_interface_descriptor_t),
 	.str_interface = 0,
 };
@@ -101,10 +98,9 @@
  * standart ohci root hub endpoint descriptor
  */
-static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor =
-{
+static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor = {
 	.attributes = USB_TRANSFER_INTERRUPT,
 	.descriptor_type = USB_DESCTYPE_ENDPOINT,
-	.endpoint_address = 1 + (1<<7),
-	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.endpoint_address = 1 + (1 << 7),
+	.length = sizeof (usb_standard_endpoint_descriptor_t),
 	.max_packet_size = 8,
 	.poll_interval = 255,
@@ -112,6 +108,6 @@
 
 static const uint32_t hub_clear_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER) +
-	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
+	(1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER) |
+(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
 
 static const uint32_t hub_clear_feature_by_writing_one_mask =
@@ -119,30 +115,169 @@
 
 static const uint32_t hub_set_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
-
-	
+	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT) |
+(1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER);
+
+
 static const uint32_t hub_set_feature_direct_mask =
 	(1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);
 
 static const uint32_t port_set_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_PORT_ENABLE) +
-	(1 << USB_HUB_FEATURE_PORT_SUSPEND) +
-	(1 << USB_HUB_FEATURE_PORT_RESET) +
-	(1 << USB_HUB_FEATURE_PORT_POWER);
+	(1 << USB_HUB_FEATURE_PORT_ENABLE) |
+(1 << USB_HUB_FEATURE_PORT_SUSPEND) |
+(1 << USB_HUB_FEATURE_PORT_RESET) |
+(1 << USB_HUB_FEATURE_PORT_POWER);
 
 static const uint32_t port_clear_feature_valid_mask =
-	(1 << USB_HUB_FEATURE_PORT_CONNECTION) +
-	(1 << USB_HUB_FEATURE_PORT_SUSPEND) +
-	(1 << USB_HUB_FEATURE_PORT_OVER_CURRENT) +
-	(1 << USB_HUB_FEATURE_PORT_POWER) +
-	(1 << USB_HUB_FEATURE_C_PORT_CONNECTION) +
-	(1 << USB_HUB_FEATURE_C_PORT_ENABLE) +
-	(1 << USB_HUB_FEATURE_C_PORT_SUSPEND) +
-	(1 << USB_HUB_FEATURE_C_PORT_OVER_CURRENT) +
-	(1 << USB_HUB_FEATURE_C_PORT_RESET);
-//note that USB_HUB_FEATURE_PORT_POWER bit is translated into USB_HUB_FEATURE_PORT_LOW_SPEED
-
-
-
+	(1 << USB_HUB_FEATURE_PORT_CONNECTION) |
+(1 << USB_HUB_FEATURE_PORT_SUSPEND) |
+(1 << USB_HUB_FEATURE_PORT_OVER_CURRENT) |
+(1 << USB_HUB_FEATURE_PORT_POWER) |
+(1 << USB_HUB_FEATURE_C_PORT_CONNECTION) |
+(1 << USB_HUB_FEATURE_C_PORT_ENABLE) |
+(1 << USB_HUB_FEATURE_C_PORT_SUSPEND) |
+(1 << USB_HUB_FEATURE_C_PORT_OVER_CURRENT) |
+(1 << USB_HUB_FEATURE_C_PORT_RESET);
+//note that USB_HUB_FEATURE_PORT_POWER bit is translated into
+//USB_HUB_FEATURE_PORT_LOW_SPEED
+
+static const uint32_t port_status_change_mask =
+(1<< USB_HUB_FEATURE_C_PORT_CONNECTION) |
+(1<< USB_HUB_FEATURE_C_PORT_ENABLE) |
+(1<< USB_HUB_FEATURE_C_PORT_OVER_CURRENT) |
+(1<< USB_HUB_FEATURE_C_PORT_RESET) |
+(1<< USB_HUB_FEATURE_C_PORT_SUSPEND);
+
+
+static void usb_create_serialized_hub_descriptor(rh_t *instance,
+	uint8_t ** out_result,
+	size_t * out_size);
+
+static void rh_init_descriptors(rh_t *instance);
+
+static int process_get_port_status_request(rh_t *instance, uint16_t port,
+	usb_transfer_batch_t * request);
+
+static int process_get_hub_status_request(rh_t *instance,
+	usb_transfer_batch_t * request);
+
+static int process_get_status_request(rh_t *instance,
+	usb_transfer_batch_t * request);
+
+static void create_interrupt_mask(rh_t *instance, void ** buffer,
+	size_t * buffer_size);
+
+static int process_get_descriptor_request(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_get_configuration_request(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_hub_feature_set_request(rh_t *instance, uint16_t feature);
+
+static int process_hub_feature_clear_request(rh_t *instance,
+	uint16_t feature);
+
+static int process_port_feature_set_request(rh_t *instance,
+	uint16_t feature, uint16_t port);
+
+static int process_port_feature_clear_request(rh_t *instance,
+	uint16_t feature, uint16_t port);
+
+static int process_address_set_request(rh_t *instance,
+	uint16_t address);
+
+static int process_request_with_output(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_request_with_input(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_request_without_data(rh_t *instance,
+	usb_transfer_batch_t *request);
+
+static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
+
+static int process_interrupt(rh_t *instance, usb_transfer_batch_t * request,
+    void * change_buffer, size_t buffe_size);
+
+static bool is_zeros(void * buffer, size_t size);
+
+
+
+/** Root hub initialization
+ * @return Error code.
+ */
+int rh_init(rh_t *instance, ohci_regs_t *regs) {
+	assert(instance);
+	instance->registers = regs;
+	instance->port_count =
+	    (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;
+	rh_init_descriptors(instance);
+	// set port power mode to no-power-switching
+	instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
+	instance->unfinished_interrupt_transfer = NULL;
+	usb_log_info("OHCI root hub with %d ports.\n", instance->port_count);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process root hub request
+ *
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+int rh_request(rh_t *instance, usb_transfer_batch_t *request) {
+	assert(instance);
+	assert(request);
+	int opResult;
+	if (request->ep->transfer_type == USB_TRANSFER_CONTROL) {
+		usb_log_info("Root hub got CONTROL packet\n");
+		opResult = process_ctrl_request(instance, request);
+		usb_transfer_batch_finish_error(request, opResult);
+	} else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) {
+		usb_log_info("Root hub got INTERRUPT packet\n");
+		void * buffer;
+		size_t buffer_size;
+		create_interrupt_mask(instance, &buffer,
+			&buffer_size);
+		if(is_zeros(buffer,buffer_size)){
+			usb_log_debug("no changes..");
+			instance->unfinished_interrupt_transfer=
+			    request;
+			//will be finished later
+		}else{
+			usb_log_debug("processing changes..");
+			process_interrupt(instance, request,
+			    buffer, buffer_size);
+		}
+		free(buffer);
+		opResult = EOK;
+	} else {
+		opResult = EINVAL;
+		usb_transfer_batch_finish_error(request, opResult);
+	}
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+
+void rh_interrupt(rh_t *instance) {
+	//usb_log_info("Whoa whoa wait, I`m not supposed to receive any "
+	//	"interrupts, am I?\n");
+	if(!instance->unfinished_interrupt_transfer){
+		return;
+	}
+	size_t size;
+	void * buffer;
+	create_interrupt_mask(instance, &buffer,
+			&size);
+	process_interrupt(instance,instance->unfinished_interrupt_transfer,
+	    buffer,size);
+	free(buffer);
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -157,14 +292,14 @@
  */
 static void usb_create_serialized_hub_descriptor(rh_t *instance,
-		uint8_t ** out_result,
-		size_t * out_size) {
+	uint8_t ** out_result,
+	size_t * out_size) {
 	//base size
 	size_t size = 7;
 	//variable size according to port count
 	size_t var_size = instance->port_count / 8 +
-			((instance->port_count % 8 > 0) ? 1 : 0);
+		((instance->port_count % 8 > 0) ? 1 : 0);
 	size += 2 * var_size;
 	uint8_t * result = (uint8_t*) malloc(size);
-	bzero(result,size);
+	bzero(result, size);
 	//size
 	result[0] = size;
@@ -174,9 +309,9 @@
 	uint32_t hub_desc_reg = instance->registers->rh_desc_a;
 	result[3] =
-			((hub_desc_reg >> 8) %2) +
-			(((hub_desc_reg >> 9) %2) << 1) +
-			(((hub_desc_reg >> 10) %2) << 2) +
-			(((hub_desc_reg >> 11) %2) << 3) +
-			(((hub_desc_reg >> 12) %2) << 4);
+		((hub_desc_reg >> 8) % 2) +
+		(((hub_desc_reg >> 9) % 2) << 1) +
+		(((hub_desc_reg >> 10) % 2) << 2) +
+		(((hub_desc_reg >> 11) % 2) << 3) +
+		(((hub_desc_reg >> 12) % 2) << 4);
 	result[4] = 0;
 	result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
@@ -185,6 +320,8 @@
 	int port;
 	for (port = 1; port <= instance->port_count; ++port) {
-		result[7 + port/8] +=
-				((instance->registers->rh_desc_b >> port)%2) << (port%8);
+		uint8_t is_non_removable =
+			instance->registers->rh_desc_b >> port % 2;
+		result[7 + port / 8] +=
+			is_non_removable << (port % 8);
 	}
 	size_t i;
@@ -195,5 +332,5 @@
 	(*out_size) = size;
 }
-
+/*----------------------------------------------------------------------------*/
 
 /** initialize hub descriptors
@@ -203,60 +340,38 @@
  * @instance root hub instance
  */
-static void rh_init_descriptors(rh_t *instance){
+static void rh_init_descriptors(rh_t *instance) {
 	memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
-		sizeof(ohci_rh_device_descriptor)
-	);
+		sizeof (ohci_rh_device_descriptor)
+		);
 	usb_standard_configuration_descriptor_t descriptor;
-	memcpy(&descriptor,&ohci_rh_conf_descriptor,
-			sizeof(ohci_rh_conf_descriptor));
+	memcpy(&descriptor, &ohci_rh_conf_descriptor,
+		sizeof (ohci_rh_conf_descriptor));
 	uint8_t * hub_descriptor;
 	size_t hub_desc_size;
 	usb_create_serialized_hub_descriptor(instance, &hub_descriptor,
-			&hub_desc_size);
+		&hub_desc_size);
 
 	descriptor.total_length =
-			sizeof(usb_standard_configuration_descriptor_t)+
-			sizeof(usb_standard_endpoint_descriptor_t)+
-			sizeof(usb_standard_interface_descriptor_t)+
-			hub_desc_size;
-	
+		sizeof (usb_standard_configuration_descriptor_t) +
+		sizeof (usb_standard_endpoint_descriptor_t) +
+		sizeof (usb_standard_interface_descriptor_t) +
+		hub_desc_size;
+
 	uint8_t * full_config_descriptor =
-			(uint8_t*) malloc(descriptor.total_length);
-	memcpy(full_config_descriptor, &descriptor, sizeof(descriptor));
-	memcpy(full_config_descriptor + sizeof(descriptor),
-			&ohci_rh_iface_descriptor, sizeof(ohci_rh_iface_descriptor));
-	memcpy(full_config_descriptor + sizeof(descriptor) +
-				sizeof(ohci_rh_iface_descriptor),
-			&ohci_rh_ep_descriptor, sizeof(ohci_rh_ep_descriptor));
-	memcpy(full_config_descriptor + sizeof(descriptor) +
-				sizeof(ohci_rh_iface_descriptor) +
-				sizeof(ohci_rh_ep_descriptor),
-			hub_descriptor, hub_desc_size);
-	
+		(uint8_t*) malloc(descriptor.total_length);
+	memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor),
+		&ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor) +
+		sizeof (ohci_rh_iface_descriptor),
+		&ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor) +
+		sizeof (ohci_rh_iface_descriptor) +
+		sizeof (ohci_rh_ep_descriptor),
+		hub_descriptor, hub_desc_size);
+
 	instance->descriptors.configuration = full_config_descriptor;
 	instance->descriptors.configuration_size = descriptor.total_length;
 }
-
-/** Root hub initialization
- * @return Error code.
- */
-int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs)
-{
-	assert(instance);
-	instance->address = -1;
-	instance->registers = regs;
-	instance->device = dev;
-	instance->port_count = instance->registers->rh_desc_a & 0xff;
-	rh_init_descriptors(instance);
-	/// \TODO set port power mode
-
-
-	usb_log_info("OHCI root hub with %d ports.\n", instance->port_count);
-
-	//start generic usb hub driver
-	
-	/* TODO: implement */
-	return EOK;
-}
 /*----------------------------------------------------------------------------*/
 
@@ -272,12 +387,21 @@
  */
 static int process_get_port_status_request(rh_t *instance, uint16_t port,
-		usb_transfer_batch_t * request){
-	if(port<1 || port>instance->port_count)
-		return EINVAL;
-	uint32_t * uint32_buffer = (uint32_t*)request->transport_buffer;
+	usb_transfer_batch_t * request) {
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	uint32_t * uint32_buffer = (uint32_t*) request->data_buffer;
 	request->transfered_size = 4;
-	uint32_buffer[0] = instance->registers->rh_port_status[port -1];
-	return EOK;
-}
+	uint32_buffer[0] = instance->registers->rh_port_status[port - 1];
+#if 0
+	int i;
+	for (i = 0; i < instance->port_count; ++i) {
+		usb_log_debug("port status %d,x%x\n",
+			instance->registers->rh_port_status[i],
+			instance->registers->rh_port_status[i]);
+	}
+#endif
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -291,15 +415,13 @@
  */
 static int process_get_hub_status_request(rh_t *instance,
-		usb_transfer_batch_t * request){
-	uint32_t * uint32_buffer = (uint32_t*)request->transport_buffer;
+	usb_transfer_batch_t * request) {
+	uint32_t * uint32_buffer = (uint32_t*) request->data_buffer;
+	request->transfered_size = 4;
 	//bits, 0,1,16,17
-	request->transfered_size = 4;
-	uint32_t mask = 1 & (1<<1) & (1<<16) & (1<<17);
+	uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17);
 	uint32_buffer[0] = mask & instance->registers->rh_status;
 	return EOK;
-
-}
-
-
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -313,24 +435,25 @@
  */
 static int process_get_status_request(rh_t *instance,
-		usb_transfer_batch_t * request)
-{
+	usb_transfer_batch_t * request) {
 	size_t buffer_size = request->buffer_size;
 	usb_device_request_setup_packet_t * request_packet =
-			(usb_device_request_setup_packet_t*)
-			request->setup_buffer;
+		(usb_device_request_setup_packet_t*)
+		request->setup_buffer;
 
 	usb_hub_bm_request_type_t request_type = request_packet->request_type;
-	if(buffer_size<4/*request_packet->length*/){///\TODO
+	if (buffer_size < 4/*request_packet->length*/) {///\TODO
 		usb_log_warning("requested more data than buffer size\n");
 		return EINVAL;
 	}
 
-	if(request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
+	if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
 		return process_get_hub_status_request(instance, request);
-	if(request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
-		return process_get_port_status_request(instance, request_packet->index,
-				request);
+	if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
+		return process_get_port_status_request(instance,
+		request_packet->index,
+		request);
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -339,5 +462,6 @@
  * Result contains bitmap where bit 0 indicates change on hub and
  * bit i indicates change on i`th port (i>0). For more info see
- * Hub and Port status bitmap specification in USB specification.
+ * Hub and Port status bitmap specification in USB specification
+ * (chapter 11.13.4)
  * @param instance root hub instance
  * @param@out buffer pointer to created interrupt mas
@@ -345,26 +469,26 @@
  */
 static void create_interrupt_mask(rh_t *instance, void ** buffer,
-		size_t * buffer_size){
+	size_t * buffer_size) {
 	int bit_count = instance->port_count + 1;
-	(*buffer_size) = (bit_count / 8) + (bit_count%8==0)?0:1;
+	(*buffer_size) = (bit_count / 8) + ((bit_count % 8 == 0) ? 0 : 1);
+
 	(*buffer) = malloc(*buffer_size);
-	uint8_t * bitmap = (uint8_t*)(*buffer);
-	uint32_t mask = (1<<16) + (1<<17);
-	bzero(bitmap,(*buffer_size));
-	if(instance->registers->rh_status & mask){
+	uint8_t * bitmap = (uint8_t*) (*buffer);
+	uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
+		| (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
+	bzero(bitmap, (*buffer_size));
+	if (instance->registers->rh_status & mask) {
 		bitmap[0] = 1;
 	}
 	int port;
-	mask = 0;
-	int i;
-	for(i=16;i<=20;++i)
-		mask += 1<<i;
-	for(port = 1; port<=instance->port_count;++port){
-		if(mask & instance->registers->rh_port_status[port-1]){
-			bitmap[(port+1)/8] += 1<<(port%8);
-		}
-	}
-}
- 
+	mask = port_status_change_mask;
+	for (port = 1; port <= instance->port_count; ++port) {
+		if (mask & instance->registers->rh_port_status[port - 1]) {
+			bitmap[(port) / 8] += 1 << (port % 8);
+		}
+	}
+}
+/*----------------------------------------------------------------------------*/
+
 /**
  * create answer to a descriptor request
@@ -377,29 +501,31 @@
  */
 static int process_get_descriptor_request(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
 	size_t size;
 	const void * result_descriptor = NULL;
 	const uint16_t setup_request_value = setup_request->value_high;
-			//(setup_request->value_low << 8);
+	//(setup_request->value_low << 8);
 	bool del = false;
-	switch (setup_request_value)
-	{
-		case USB_DESCTYPE_HUB: {
+	switch (setup_request_value) {
+		case USB_DESCTYPE_HUB:
+		{
 			uint8_t * descriptor;
 			usb_create_serialized_hub_descriptor(
 				instance, &descriptor, &size);
 			result_descriptor = descriptor;
-			if(result_descriptor) del = true;
+			if (result_descriptor) del = true;
 			break;
 		}
-		case USB_DESCTYPE_DEVICE: {
+		case USB_DESCTYPE_DEVICE:
+		{
 			usb_log_debug("USB_DESCTYPE_DEVICE\n");
 			result_descriptor = &ohci_rh_device_descriptor;
-			size = sizeof(ohci_rh_device_descriptor);
+			size = sizeof (ohci_rh_device_descriptor);
 			break;
 		}
-		case USB_DESCTYPE_CONFIGURATION: {
+		case USB_DESCTYPE_CONFIGURATION:
+		{
 			usb_log_debug("USB_DESCTYPE_CONFIGURATION\n");
 			result_descriptor = instance->descriptors.configuration;
@@ -407,39 +533,43 @@
 			break;
 		}
-		case USB_DESCTYPE_INTERFACE: {
+		case USB_DESCTYPE_INTERFACE:
+		{
 			usb_log_debug("USB_DESCTYPE_INTERFACE\n");
 			result_descriptor = &ohci_rh_iface_descriptor;
-			size = sizeof(ohci_rh_iface_descriptor);
+			size = sizeof (ohci_rh_iface_descriptor);
 			break;
 		}
-		case USB_DESCTYPE_ENDPOINT: {
+		case USB_DESCTYPE_ENDPOINT:
+		{
 			usb_log_debug("USB_DESCTYPE_ENDPOINT\n");
 			result_descriptor = &ohci_rh_ep_descriptor;
-			size = sizeof(ohci_rh_ep_descriptor);
+			size = sizeof (ohci_rh_ep_descriptor);
 			break;
 		}
-		default: {
-			usb_log_debug("USB_DESCTYPE_EINVAL %d \n",setup_request->value);
-			usb_log_debug("\ttype %d\n\trequest %d\n\tvalue %d\n\tindex %d\n\tlen %d\n ",
-					setup_request->request_type,
-					setup_request->request,
-					setup_request_value,
-					setup_request->index,
-					setup_request->length
-					);
+		default:
+		{
+			usb_log_debug("USB_DESCTYPE_EINVAL %d \n",
+				setup_request->value);
+			usb_log_debug("\ttype %d\n\trequest %d\n\tvalue "
+				"%d\n\tindex %d\n\tlen %d\n ",
+				setup_request->request_type,
+				setup_request->request,
+				setup_request_value,
+				setup_request->index,
+				setup_request->length
+				);
 			return EINVAL;
 		}
 	}
-	if(request->buffer_size < size){
+	if (request->buffer_size < size) {
 		size = request->buffer_size;
 	}
 	request->transfered_size = size;
-	memcpy(request->transport_buffer,result_descriptor,size);
-	usb_log_debug("sent desctiptor: %s\n",
-			usb_debug_str_buffer((uint8_t*)request->transport_buffer,size,size));
+	memcpy(request->data_buffer, result_descriptor, size);
 	if (del)
 		free(result_descriptor);
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -451,18 +581,19 @@
  * @return error code
  */
-static int process_get_configuration_request(rh_t *instance, 
-		usb_transfer_batch_t *request){
+static int process_get_configuration_request(rh_t *instance,
+	usb_transfer_batch_t *request) {
 	//set and get configuration requests do not have any meaning, only dummy
 	//values are returned
-	if(request->buffer_size != 1)
-		return EINVAL;
-	request->transport_buffer[0] = 1;
+	if (request->buffer_size != 1)
+		return EINVAL;
+	request->data_buffer[0] = 1;
 	request->transfered_size = 1;
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
  * process feature-enabling request on hub
- * 
+ *
  * @param instance root hub instance
  * @param feature feature selector
@@ -470,12 +601,15 @@
  */
 static int process_hub_feature_set_request(rh_t *instance,
-		uint16_t feature){
-	if(! ((1<<feature) & hub_set_feature_valid_mask))
-		return EINVAL;
+	uint16_t feature) {
+	if (!((1 << feature) & hub_set_feature_valid_mask))
+		return EINVAL;
+	if(feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER)
+		feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16;
 	instance->registers->rh_status =
-			(instance->registers->rh_status | (1<<feature))
-			& (~ hub_clear_feature_by_writing_one_mask);
-	return EOK;
-}
+		(instance->registers->rh_status | (1 << feature))
+		& (~hub_clear_feature_by_writing_one_mask);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -487,26 +621,25 @@
  */
 static int process_hub_feature_clear_request(rh_t *instance,
-		uint16_t feature){
-	if(! ((1<<feature) & hub_clear_feature_valid_mask))
+	uint16_t feature) {
+	if (!((1 << feature) & hub_clear_feature_valid_mask))
 		return EINVAL;
 	//is the feature cleared directly?
-	if ((1<<feature) & hub_set_feature_direct_mask){
+	if ((1 << feature) & hub_set_feature_direct_mask) {
 		instance->registers->rh_status =
-			(instance->registers->rh_status & (~(1<<feature)))
-			& (~ hub_clear_feature_by_writing_one_mask);
-	}else{//the feature is cleared by writing '1'
+			(instance->registers->rh_status & (~(1 << feature)))
+			& (~hub_clear_feature_by_writing_one_mask);
+	} else {//the feature is cleared by writing '1'
 		instance->registers->rh_status =
-				(instance->registers->rh_status
-				& (~ hub_clear_feature_by_writing_one_mask))
-				| (1<<feature);
-	}
-	return EOK;
-}
-
-
+			(instance->registers->rh_status
+			& (~hub_clear_feature_by_writing_one_mask))
+			| (1 << feature);
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 
 /**
  * process feature-enabling request on hub
- * 
+ *
  * @param instance root hub instance
  * @param feature feature selector
@@ -516,15 +649,16 @@
  */
 static int process_port_feature_set_request(rh_t *instance,
-		uint16_t feature, uint16_t port){
-	if(!((1<<feature) & port_set_feature_valid_mask))
-		return EINVAL;
-	if(port<1 || port>instance->port_count)
+	uint16_t feature, uint16_t port) {
+	if (!((1 << feature) & port_set_feature_valid_mask))
+		return EINVAL;
+	if (port < 1 || port > instance->port_count)
 		return EINVAL;
 	instance->registers->rh_port_status[port - 1] =
-			(instance->registers->rh_port_status[port - 1] | (1<<feature))
-			& (~port_clear_feature_valid_mask);
+		(instance->registers->rh_port_status[port - 1] | (1 << feature))
+		& (~port_clear_feature_valid_mask);
 	/// \TODO any error?
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -538,25 +672,25 @@
  */
 static int process_port_feature_clear_request(rh_t *instance,
-		uint16_t feature, uint16_t port){
-	if(!((1<<feature) & port_clear_feature_valid_mask))
-		return EINVAL;
-	if(port<1 || port>instance->port_count)
-		return EINVAL;
-	if(feature == USB_HUB_FEATURE_PORT_POWER)
+	uint16_t feature, uint16_t port) {
+	if (!((1 << feature) & port_clear_feature_valid_mask))
+		return EINVAL;
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	if (feature == USB_HUB_FEATURE_PORT_POWER)
 		feature = USB_HUB_FEATURE_PORT_LOW_SPEED;
-	if(feature == USB_HUB_FEATURE_PORT_SUSPEND)
+	if (feature == USB_HUB_FEATURE_PORT_SUSPEND)
 		feature = USB_HUB_FEATURE_PORT_OVER_CURRENT;
 	instance->registers->rh_port_status[port - 1] =
-			(instance->registers->rh_port_status[port - 1] 
-			& (~port_clear_feature_valid_mask))
-			| (1<<feature);
+		(instance->registers->rh_port_status[port - 1]
+		& (~port_clear_feature_valid_mask))
+		| (1 << feature);
 	/// \TODO any error?
 	return EOK;
 }
-
+/*----------------------------------------------------------------------------*/
 
 /**
  * register address to this device
- * 
+ *
  * @param instance root hub instance
  * @param address new address
@@ -564,8 +698,9 @@
  */
 static int process_address_set_request(rh_t *instance,
-		uint16_t address){
+	uint16_t address) {
 	instance->address = address;
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -579,16 +714,16 @@
  */
 static int process_request_with_output(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
-	if(setup_request->request == USB_DEVREQ_GET_STATUS){
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
+	if (setup_request->request == USB_DEVREQ_GET_STATUS) {
 		usb_log_debug("USB_DEVREQ_GET_STATUS\n");
 		return process_get_status_request(instance, request);
 	}
-	if(setup_request->request == USB_DEVREQ_GET_DESCRIPTOR){
+	if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) {
 		usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
 		return process_get_descriptor_request(instance, request);
 	}
-	if(setup_request->request == USB_DEVREQ_GET_CONFIGURATION){
+	if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) {
 		usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
 		return process_get_configuration_request(instance, request);
@@ -596,4 +731,5 @@
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -607,12 +743,12 @@
  */
 static int process_request_with_input(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
 	request->transfered_size = 0;
-	if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR){
+	if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) {
 		return ENOTSUP;
 	}
-	if(setup_request->request == USB_DEVREQ_SET_CONFIGURATION){
+	if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) {
 		//set and get configuration requests do not have any meaning,
 		//only dummy values are returned
@@ -621,4 +757,5 @@
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -632,46 +769,50 @@
  */
 static int process_request_without_data(rh_t *instance,
-		usb_transfer_batch_t *request){
+	usb_transfer_batch_t *request) {
 	usb_device_request_setup_packet_t * setup_request =
-			(usb_device_request_setup_packet_t*)request->setup_buffer;
+		(usb_device_request_setup_packet_t*) request->setup_buffer;
 	request->transfered_size = 0;
-	if(setup_request->request == USB_DEVREQ_CLEAR_FEATURE){
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){
+	if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) {
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
 			return process_hub_feature_clear_request(instance,
-					setup_request->value);
-		}
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){
+				setup_request->value);
+		}
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
 			return process_port_feature_clear_request(instance,
-					setup_request->value,
-					setup_request->index);
+				setup_request->value,
+				setup_request->index);
 		}
 		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
-				setup_request->request_type);
-		return EINVAL;
-	}
-	if(setup_request->request == USB_DEVREQ_SET_FEATURE){
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){
+			setup_request->request_type);
+		return EINVAL;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_FEATURE) {
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
 			return process_hub_feature_set_request(instance,
-					setup_request->value);
-		}
-		if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){
+				setup_request->value);
+		}
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
 			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
 			return process_port_feature_set_request(instance,
-					setup_request->value,
-					setup_request->index);
-		}
-		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",setup_request->request_type);
-		return EINVAL;
-	}
-	if(setup_request->request == USB_DEVREQ_SET_ADDRESS){
+				setup_request->value,
+				setup_request->index);
+		}
+		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
+			setup_request->request_type);
+		return EINVAL;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_ADDRESS) {
 		usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
-		return process_address_set_request(instance, setup_request->value);
-	}
-	usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",setup_request->request_type);
+		return process_address_set_request(instance,
+			setup_request->value);
+	}
+	usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",
+		setup_request->request_type);
 	return ENOTSUP;
 }
+/*----------------------------------------------------------------------------*/
 
 /**
@@ -693,83 +834,100 @@
  * @return error code
  */
-static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request){
+static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) {
+	if (!request->setup_buffer) {
+		usb_log_error("root hub received empty transaction?");
+		return EINVAL;
+	}
 	int opResult;
-	if (request->setup_buffer) {
-		if(sizeof(usb_device_request_setup_packet_t)>request->setup_size){
-			usb_log_error("setup packet too small\n");
-			return EINVAL;
-		}
-		usb_log_info("CTRL packet: %s.\n",
-			usb_debug_str_buffer((const uint8_t *)request->setup_buffer, 8, 8));
-		usb_device_request_setup_packet_t * setup_request =
-				(usb_device_request_setup_packet_t*)request->setup_buffer;
-		if(
-			setup_request->request == USB_DEVREQ_GET_STATUS
-			|| setup_request->request == USB_DEVREQ_GET_DESCRIPTOR
-			|| setup_request->request == USB_DEVREQ_GET_CONFIGURATION
-		){
+	if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) {
+		usb_log_error("setup packet too small\n");
+		return EINVAL;
+	}
+	usb_log_info("CTRL packet: %s.\n",
+		usb_debug_str_buffer(
+		(const uint8_t *) request->setup_buffer, 8, 8));
+	usb_device_request_setup_packet_t * setup_request =
+		(usb_device_request_setup_packet_t*)
+		request->setup_buffer;
+	switch (setup_request->request) {
+		case USB_DEVREQ_GET_STATUS:
+		case USB_DEVREQ_GET_DESCRIPTOR:
+		case USB_DEVREQ_GET_CONFIGURATION:
 			usb_log_debug("processing request with output\n");
-			opResult = process_request_with_output(instance,request);
-		}else if(
-			setup_request->request == USB_DEVREQ_CLEAR_FEATURE
-			|| setup_request->request == USB_DEVREQ_SET_FEATURE
-			|| setup_request->request == USB_DEVREQ_SET_ADDRESS
-		){
-			usb_log_debug("processing request without additional data\n");
-			opResult = process_request_without_data(instance,request);
-		}else if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR
-				|| setup_request->request == USB_DEVREQ_SET_CONFIGURATION
-		){
-			usb_log_debug("processing request with input\n");
-			opResult = process_request_with_input(instance,request);
-		}else{
-			usb_log_warning("received unsuported request: %d\n",
-					setup_request->request
-					);
+			opResult = process_request_with_output(
+				instance, request);
+			break;
+		case USB_DEVREQ_CLEAR_FEATURE:
+		case USB_DEVREQ_SET_FEATURE:
+		case USB_DEVREQ_SET_ADDRESS:
+			usb_log_debug("processing request without "
+				"additional data\n");
+			opResult = process_request_without_data(
+				instance, request);
+			break;
+		case USB_DEVREQ_SET_DESCRIPTOR:
+		case USB_DEVREQ_SET_CONFIGURATION:
+			usb_log_debug("processing request with "
+				"input\n");
+			opResult = process_request_with_input(
+				instance, request);
+			break;
+		default:
+			usb_log_warning("received unsuported request: "
+				"%d\n",
+				setup_request->request
+				);
 			opResult = ENOTSUP;
-		}
-	}else{
-		usb_log_error("root hub received empty transaction?");
-		opResult = EINVAL;
 	}
 	return opResult;
 }
-
-/**
- * process root hub request
- *
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-int rh_request(rh_t *instance, usb_transfer_batch_t *request)
-{
-	assert(instance);
-	assert(request);
-	int opResult;
-	if(request->transfer_type == USB_TRANSFER_CONTROL){
-		usb_log_info("Root hub got CONTROL packet\n");
-		opResult = process_ctrl_request(instance,request);
-	}else if(request->transfer_type == USB_TRANSFER_INTERRUPT){
-		usb_log_info("Root hub got INTERRUPT packet\n");
-		void * buffer;
-		create_interrupt_mask(instance, &buffer,
-			&(request->transfered_size));
-		memcpy(request->transport_buffer,buffer, request->transfered_size);
-		opResult = EOK;
-	}else{
-		opResult = EINVAL;
-	}
-	usb_transfer_batch_finish(request, opResult);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-
-void rh_interrupt(rh_t *instance)
-{
-	usb_log_info("Whoa whoa wait, I`m not supposed to receive any interrupts, am I?\n");
-	/* TODO: implement? */
-}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process hanging interrupt request
+ *
+ * If an interrupt transfer has been received and there was no change,
+ * the driver stores the transfer information and waits for change to occcur.
+ * This routine is called when that happens and it finalizes the interrupt
+ * transfer.
+ *
+ * @param instance hub instance
+ * @param request batch request to be processed
+ * @param change_buffer chages on hub
+ * @param buffer_size size of change buffer
+ *
+ * @return
+ */
+static int process_interrupt(rh_t *instance, usb_transfer_batch_t * request,
+    void * change_buffer, size_t buffe_size){
+	create_interrupt_mask(instance, &change_buffer,
+	    &(request->transfered_size));
+	memcpy(request->data_buffer, change_buffer,request->transfered_size);
+	instance->unfinished_interrupt_transfer = NULL;
+	usb_transfer_batch_finish_error(request, EOK);
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * return whether the buffer is full of zeros
+ *
+ * Convenience function.
+ * @param buffer
+ * @param size
+ * @return
+ */
+static bool is_zeros(void * buffer, size_t size){
+	if(!buffer) return true;
+	if(!size) return true;
+	size_t i;
+	for(i=0;i<size;++i){
+		if(((char*)buffer)[i])
+			return false;
+	}
+	return true;
+}
+
 /**
  * @}
Index: uspace/drv/ohci/root_hub.h
===================================================================
--- uspace/drv/ohci/root_hub.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/root_hub.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -50,13 +50,13 @@
 	/** usb address of the root hub */
 	usb_address_t address;
-	/** ddf device information */
-	ddf_dev_t *device;
 	/** hub port count */
 	int port_count;
 	/** hubs descriptors */
 	usb_device_descriptors_t descriptors;
+	/** interrupt transfer waiting for an actual interrupt to occur */
+	usb_transfer_batch_t * unfinished_interrupt_transfer;
 } rh_t;
 
-int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs);
+int rh_init(rh_t *instance, ohci_regs_t *regs);
 
 int rh_request(rh_t *instance, usb_transfer_batch_t *request);
Index: uspace/drv/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/ohci/utils/malloc32.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/ohci/utils/malloc32.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -37,8 +37,8 @@
 #include <assert.h>
 #include <malloc.h>
+#include <errno.h>
 #include <mem.h>
 #include <as.h>
 
-#define UHCI_STRCUTURES_ALIGNMENT 16
 #define UHCI_REQUIRED_PAGE_SIZE 4096
 
@@ -64,5 +64,5 @@
  */
 static inline void * malloc32(size_t size)
-	{ return memalign(UHCI_STRCUTURES_ALIGNMENT, size); }
+	{ return memalign(size, size); }
 /*----------------------------------------------------------------------------*/
 /** Physical mallocator simulator
Index: uspace/drv/uhci-hcd/batch.c
===================================================================
--- uspace/drv/uhci-hcd/batch.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/batch.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -30,5 +30,5 @@
  */
 /** @file
- * @brief UHCI driver USB transaction structure
+ * @brief UHCI driver USB transfer structure
  */
 #include <errno.h>
@@ -45,47 +45,48 @@
 #define DEFAULT_ERROR_COUNT 3
 
-typedef struct uhci_batch {
+typedef struct uhci_transfer_batch {
 	qh_t *qh;
 	td_t *tds;
-	size_t transfers;
-} uhci_batch_t;
+	void *device_buffer;
+	size_t td_count;
+} uhci_transfer_batch_t;
+/*----------------------------------------------------------------------------*/
+static void uhci_transfer_batch_dispose(void *uhci_batch)
+{
+	uhci_transfer_batch_t *instance = uhci_batch;
+	assert(instance);
+	free32(instance->device_buffer);
+	free(instance);
+}
+/*----------------------------------------------------------------------------*/
 
 static void batch_control(usb_transfer_batch_t *instance,
     usb_packet_id data_stage, usb_packet_id status_stage);
 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid);
-static void batch_call_in_and_dispose(usb_transfer_batch_t *instance);
-static void batch_call_out_and_dispose(usb_transfer_batch_t *instance);
-
 
 /** Allocate memory and initialize internal data structure.
  *
  * @param[in] fun DDF function to pass to callback.
- * @param[in] target Device and endpoint target of the transaction.
- * @param[in] transfer_type Interrupt, Control or Bulk.
- * @param[in] max_packet_size maximum allowed size of data transfers.
- * @param[in] speed Speed of the transaction.
+ * @param[in] ep Communication target
  * @param[in] buffer Data source/destination.
  * @param[in] size Size of the buffer.
  * @param[in] setup_buffer Setup data source (if not NULL)
  * @param[in] setup_size Size of setup_buffer (should be always 8)
- * @param[in] func_in function to call on inbound transaction completion
- * @param[in] func_out function to call on outbound transaction completion
+ * @param[in] func_in function to call on inbound transfer completion
+ * @param[in] func_out function to call on outbound transfer completion
  * @param[in] arg additional parameter to func_in or func_out
- * @param[in] ep Pointer to endpoint toggle management structure.
- * @return Valid pointer if all substructures were successfully created,
+ * @return Valid pointer if all structures were successfully created,
  * NULL otherwise.
  *
- * Determines the number of needed transfers (TDs). Prepares a transport buffer
- * (that is accessible by the hardware). Initializes parameters needed for the
- * transaction and callback.
- */
-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,
+ * Determines the number of needed transfer descriptors (TDs).
+ * Prepares a transport buffer (that is accessible by the hardware).
+ * Initializes parameters needed for the transfer and callback.
+ */
+usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
+    char *buffer, size_t buffer_size, 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, endpoint_t *ep
-    )
-{
+    usbhc_iface_transfer_out_callback_t func_out, void *arg)
+{
+	assert(ep);
 	assert(func_in == NULL || func_out == NULL);
 	assert(func_in != NULL || func_out != NULL);
@@ -94,54 +95,51 @@
 	if (ptr == NULL) { \
 		usb_log_error(message); \
-		if (instance) { \
-			batch_dispose(instance); \
+		if (uhci_data) { \
+			uhci_transfer_batch_dispose(uhci_data); \
 		} \
 		return NULL; \
 	} else (void)0
 
+	uhci_transfer_batch_t *uhci_data =
+	    malloc(sizeof(uhci_transfer_batch_t));
+	CHECK_NULL_DISPOSE_RETURN(uhci_data,
+	    "Failed to allocate UHCI batch.\n");
+	bzero(uhci_data, sizeof(uhci_transfer_batch_t));
+
+	uhci_data->td_count =
+	    (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
+	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
+		uhci_data->td_count += 2;
+	}
+
+	assert((sizeof(td_t) % 16) == 0);
+	const size_t total_size = (sizeof(td_t) * uhci_data->td_count)
+	    + sizeof(qh_t) + setup_size + buffer_size;
+	uhci_data->device_buffer = malloc32(total_size);
+	CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,
+	    "Failed to allocate UHCI buffer.\n");
+	bzero(uhci_data->device_buffer, total_size);
+
+	uhci_data->tds = uhci_data->device_buffer;
+	uhci_data->qh =
+	    (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));
+
+	qh_init(uhci_data->qh);
+	qh_set_element_td(uhci_data->qh, uhci_data->tds);
+
 	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
 	CHECK_NULL_DISPOSE_RETURN(instance,
 	    "Failed to allocate batch instance.\n");
-	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, ep, NULL);
-
-
-	uhci_batch_t *data = malloc(sizeof(uhci_batch_t));
-	CHECK_NULL_DISPOSE_RETURN(instance,
-	    "Failed to allocate batch instance.\n");
-	bzero(data, sizeof(uhci_batch_t));
-	instance->private_data = data;
-
-	data->transfers = (buffer_size + max_packet_size - 1) / max_packet_size;
-	if (transfer_type == USB_TRANSFER_CONTROL) {
-		data->transfers += 2;
-	}
-
-	data->tds = malloc32(sizeof(td_t) * data->transfers);
-	CHECK_NULL_DISPOSE_RETURN(
-	    data->tds, "Failed to allocate transfer descriptors.\n");
-	bzero(data->tds, sizeof(td_t) * data->transfers);
-
-	data->qh = malloc32(sizeof(qh_t));
-	CHECK_NULL_DISPOSE_RETURN(data->qh,
-	    "Failed to allocate batch queue head.\n");
-	qh_init(data->qh);
-	qh_set_element_td(data->qh, addr_to_phys(data->tds));
-
-	if (buffer_size > 0) {
-		instance->transport_buffer = malloc32(buffer_size);
-		CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
-		    "Failed to allocate device accessible buffer.\n");
-	}
-
-	if (setup_size > 0) {
-		instance->setup_buffer = malloc32(setup_size);
-		CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
-		    "Failed to allocate device accessible setup buffer.\n");
-		memcpy(instance->setup_buffer, setup_buffer, setup_size);
-	}
-
+	void *setup =
+	    uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)
+	    + sizeof(qh_t);
+	void *data_buffer = setup + setup_size;
+	usb_target_t target =
+	    { .address = ep->address, .endpoint = ep->endpoint };
+	usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size,
+	    setup, setup_size, func_in, func_out, arg, fun,
+	    uhci_data, uhci_transfer_batch_dispose);
+
+	memcpy(instance->setup_buffer, setup_buffer, setup_size);
 	usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
 	    instance, target.address, target.endpoint);
@@ -155,5 +153,5 @@
  *
  * Walk all TDs. Stop with false if there is an active one (it is to be
- * processed). Stop with true if an error is found. Return true if the last TS
+ * processed). Stop with true if an error is found. Return true if the last TD
  * is reached.
  */
@@ -161,12 +159,12 @@
 {
 	assert(instance);
-	uhci_batch_t *data = instance->private_data;
+	uhci_transfer_batch_t *data = instance->private_data;
 	assert(data);
 
 	usb_log_debug2("Batch(%p) checking %d transfer(s) for completion.\n",
-	    instance, data->transfers);
+	    instance, data->td_count);
 	instance->transfered_size = 0;
 	size_t i = 0;
-	for (;i < data->transfers; ++i) {
+	for (;i < data->td_count; ++i) {
 		if (td_is_active(&data->tds[i])) {
 			return false;
@@ -178,7 +176,8 @@
 			    instance, i, data->tds[i].status);
 			td_print_status(&data->tds[i]);
-			if (instance->ep != NULL)
-				endpoint_toggle_set(instance->ep,
-				    td_toggle(&data->tds[i]));
+
+			assert(instance->ep != NULL);
+			endpoint_toggle_set(instance->ep,
+			    td_toggle(&data->tds[i]));
 			if (i > 0)
 				goto substract_ret;
@@ -195,9 +194,9 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Prepares control write transaction.
- *
- * @param[in] instance Batch structure to use.
- *
- * Uses genercir control function with pids OUT and IN.
+/** Prepares control write transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control function with pids OUT and IN.
  */
 void batch_control_write(usb_transfer_batch_t *instance)
@@ -205,12 +204,11 @@
 	assert(instance);
 	/* We are data out, we are supposed to provide data */
-	memcpy(instance->transport_buffer, instance->buffer,
-	    instance->buffer_size);
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
 	batch_control(instance, USB_PID_OUT, USB_PID_IN);
-	instance->next_step = batch_call_out_and_dispose;
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
 	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepares control read transaction.
+/** Prepares control read transfer.
  *
  * @param[in] instance Batch structure to use.
@@ -222,46 +220,43 @@
 	assert(instance);
 	batch_control(instance, USB_PID_IN, USB_PID_OUT);
-	instance->next_step = batch_call_in_and_dispose;
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
 	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepare interrupt in transaction.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transaction with PID_IN.
+/** Prepare interrupt in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_IN.
  */
 void batch_interrupt_in(usb_transfer_batch_t *instance)
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_IN;
 	batch_data(instance, USB_PID_IN);
-	instance->next_step = batch_call_in_and_dispose;
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
 	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepare interrupt out transaction.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transaction with PID_OUT.
+/** Prepare interrupt out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_OUT.
  */
 void batch_interrupt_out(usb_transfer_batch_t *instance)
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_OUT;
 	/* We are data out, we are supposed to provide data */
-	memcpy(instance->transport_buffer, instance->buffer,
-	    instance->buffer_size);
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
 	batch_data(instance, USB_PID_OUT);
-	instance->next_step = batch_call_out_and_dispose;
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
 	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepare bulk in transaction.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transaction with PID_IN.
+/** Prepare bulk in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_IN.
  */
 void batch_bulk_in(usb_transfer_batch_t *instance)
@@ -269,33 +264,30 @@
 	assert(instance);
 	batch_data(instance, USB_PID_IN);
-	instance->direction = USB_DIRECTION_IN;
-	instance->next_step = batch_call_in_and_dispose;
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
 	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepare bulk out transaction.
- *
- * @param[in] instance Batch structure to use.
- *
- * Data transaction with PID_OUT.
+/** Prepare bulk out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_OUT.
  */
 void batch_bulk_out(usb_transfer_batch_t *instance)
 {
 	assert(instance);
-	instance->direction = USB_DIRECTION_OUT;
 	/* We are data out, we are supposed to provide data */
-	memcpy(instance->transport_buffer, instance->buffer,
-	    instance->buffer_size);
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
 	batch_data(instance, USB_PID_OUT);
-	instance->next_step = batch_call_out_and_dispose;
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
 	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepare generic data transaction
- *
- * @param[in] instance Batch structure to use.
- * @param[in] pid Pid to use for data transfers.
- *
- * Packets with alternating toggle bit and supplied pid value.
+/** Prepare generic data transfer
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] pid Pid to use for data transactions.
+ *
+ * Transactions with alternating toggle bit and supplied pid value.
  * The last transfer is marked with IOC flag.
  */
@@ -303,47 +295,46 @@
 {
 	assert(instance);
-	uhci_batch_t *data = instance->private_data;
+	uhci_transfer_batch_t *data = instance->private_data;
 	assert(data);
 
-	const bool low_speed = instance->speed == USB_SPEED_LOW;
+	const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
 	int toggle = endpoint_toggle_get(instance->ep);
 	assert(toggle == 0 || toggle == 1);
 
-	size_t transfer = 0;
+	size_t td = 0;
 	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
 	while (remain_size > 0) {
-		char *trans_data =
-		    instance->transport_buffer + instance->buffer_size
-		    - remain_size;
-
 		const size_t packet_size =
-		    (instance->max_packet_size > remain_size) ?
-		    remain_size : instance->max_packet_size;
-
-		td_t *next_transfer = (transfer + 1 < data->transfers)
-		    ? &data->tds[transfer + 1] : NULL;
-
-		assert(transfer < data->transfers);
+		    (instance->ep->max_packet_size > remain_size) ?
+		    remain_size : instance->ep->max_packet_size;
+
+		td_t *next_td = (td + 1 < data->td_count)
+		    ? &data->tds[td + 1] : NULL;
+
+
+		usb_target_t target =
+		    { instance->ep->address, instance->ep->endpoint };
+
+		assert(td < data->td_count);
+		td_init(
+		    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, target, pid, buffer, next_td);
+
+		++td;
+		toggle = 1 - toggle;
+		buffer += packet_size;
 		assert(packet_size <= remain_size);
-
-		td_init(
-		    &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size,
-		    toggle, false, low_speed, instance->target, pid, trans_data,
-		    next_transfer);
-
-
-		toggle = 1 - toggle;
 		remain_size -= packet_size;
-		++transfer;
 	}
-	td_set_ioc(&data->tds[transfer - 1]);
+	td_set_ioc(&data->tds[td - 1]);
 	endpoint_toggle_set(instance->ep, toggle);
 }
 /*----------------------------------------------------------------------------*/
-/** Prepare generic control transaction
- *
- * @param[in] instance Batch structure to use.
- * @param[in] data_stage Pid to use for data transfers.
- * @param[in] status_stage Pid to use for data transfers.
+/** Prepare generic control transfer
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data_stage Pid to use for data tds.
+ * @param[in] status_stage Pid to use for data tds.
  *
  * Setup stage with toggle 0 and USB_PID_SETUP.
@@ -356,37 +347,37 @@
 {
 	assert(instance);
-	uhci_batch_t *data = instance->private_data;
+	uhci_transfer_batch_t *data = instance->private_data;
 	assert(data);
-	assert(data->transfers >= 2);
-
-	const bool low_speed = instance->speed == USB_SPEED_LOW;
-	int toggle = 0;
+	assert(data->td_count >= 2);
+
+	const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
+	const usb_target_t target =
+	    { instance->ep->address, instance->ep->endpoint };
+
 	/* setup stage */
 	td_init(
-	    data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, toggle, false,
-	    low_speed, instance->target, USB_PID_SETUP, instance->setup_buffer,
+	    data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false,
+	    low_speed, target, USB_PID_SETUP, instance->setup_buffer,
 	    &data->tds[1]);
 
 	/* data stage */
-	size_t transfer = 1;
+	size_t td = 1;
+	unsigned toggle = 1;
 	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
 	while (remain_size > 0) {
-		char *control_data =
-		    instance->transport_buffer + instance->buffer_size
-		    - remain_size;
-
+		const size_t packet_size =
+		    (instance->ep->max_packet_size > remain_size) ?
+		    remain_size : instance->ep->max_packet_size;
+
+		td_init(
+		    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, target, data_stage,
+		    buffer, &data->tds[td + 1]);
+
+		++td;
 		toggle = 1 - toggle;
-
-		const size_t packet_size =
-		    (instance->max_packet_size > remain_size) ?
-		    remain_size : instance->max_packet_size;
-
-		td_init(
-		    &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size,
-		    toggle, false, low_speed, instance->target, data_stage,
-		    control_data, &data->tds[transfer + 1]);
-
-		++transfer;
-		assert(transfer < data->transfers);
+		buffer += packet_size;
+		assert(td < data->td_count);
 		assert(packet_size <= remain_size);
 		remain_size -= packet_size;
@@ -394,63 +385,26 @@
 
 	/* status stage */
-	assert(transfer == data->transfers - 1);
+	assert(td == data->td_count - 1);
 
 	td_init(
-	    &data->tds[transfer], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
-	    instance->target, status_stage, NULL, NULL);
-	td_set_ioc(&data->tds[transfer]);
+	    &data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
+	    target, status_stage, NULL, NULL);
+	td_set_ioc(&data->tds[td]);
 
 	usb_log_debug2("Control last TD status: %x.\n",
-	    data->tds[transfer].status);
-}
-/*----------------------------------------------------------------------------*/
+	    data->tds[td].status);
+}
+/*----------------------------------------------------------------------------*/
+/** Provides access to QH data structure.
+ * @param[in] instance Batch pointer to use.
+ * @return Pointer to the QH used by the batch.
+ */
 qh_t * batch_qh(usb_transfer_batch_t *instance)
 {
 	assert(instance);
-	uhci_batch_t *data = instance->private_data;
+	uhci_transfer_batch_t *data = instance->private_data;
 	assert(data);
 	return data->qh;
 }
-/*----------------------------------------------------------------------------*/
-/** Helper function calls callback and correctly disposes of batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-void batch_call_in_and_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_in(instance);
-	batch_dispose(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Helper function calls callback and correctly disposes of batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-void batch_call_out_and_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_out(instance);
-	batch_dispose(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Correctly dispose all used data structures.
- *
- * @param[in] instance Batch structure to use.
- */
-void batch_dispose(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	uhci_batch_t *data = instance->private_data;
-	assert(data);
-	usb_log_debug("Batch(%p) disposing.\n", instance);
-	/* free32 is NULL safe */
-	free32(data->tds);
-	free32(data->qh);
-	free32(instance->setup_buffer);
-	free32(instance->transport_buffer);
-	free(data);
-	free(instance);
-}
 /**
  * @}
Index: uspace/drv/uhci-hcd/batch.h
===================================================================
--- uspace/drv/uhci-hcd/batch.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/batch.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -30,5 +30,5 @@
  */
 /** @file
- * @brief UHCI driver USB transaction structure
+ * @brief UHCI driver USB tranfer helper functions
  */
 #ifndef DRV_UHCI_BATCH_H
@@ -44,18 +44,9 @@
 
 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,
-		endpoint_t *ep
-		);
+    void *arg);
 
 void batch_dispose(usb_transfer_batch_t *instance);
Index: uspace/drv/uhci-hcd/hc.c
===================================================================
--- uspace/drv/uhci-hcd/hc.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/hc.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -66,8 +66,4 @@
 static int hc_interrupt_emulator(void *arg);
 static int hc_debug_checker(void *arg);
-#if 0
-static bool usb_is_allowed(
-    bool low_speed, usb_transfer_type_t transfer, size_t size);
-#endif
 /*----------------------------------------------------------------------------*/
 /** Initialize UHCI hcd driver structure
@@ -89,9 +85,7 @@
 	int ret;
 
-#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
+#define CHECK_RET_RETURN(ret, message...) \
 	if (ret != EOK) { \
 		usb_log_error(message); \
-		if (instance->ddf_instance) \
-			ddf_fun_destroy(instance->ddf_instance); \
 		return ret; \
 	} else (void) 0
@@ -99,14 +93,11 @@
 	instance->hw_interrupts = interrupts;
 	instance->hw_failures = 0;
-
-	/* Setup UHCI function. */
-	instance->ddf_instance = fun;
 
 	/* allow access to hc control registers */
 	regs_t *io;
 	ret = pio_enable(regs, reg_size, (void**)&io);
-	CHECK_RET_DEST_FUN_RETURN(ret,
+	CHECK_RET_RETURN(ret,
 	    "Failed(%d) to gain access to registers at %p: %s.\n",
-	    ret, str_error(ret), io);
+	    ret, io, str_error(ret));
 	instance->registers = io;
 	usb_log_debug("Device registers at %p(%u) accessible.\n",
@@ -114,19 +105,15 @@
 
 	ret = hc_init_mem_structures(instance);
-	CHECK_RET_DEST_FUN_RETURN(ret,
-	    "Failed to initialize UHCI memory structures.\n");
+	CHECK_RET_RETURN(ret,
+	    "Failed(%d) to initialize UHCI memory structures: %s.\n",
+	    ret, str_error(ret));
 
 	hc_init_hw(instance);
 	if (!interrupts) {
-		instance->cleaner =
+		instance->interrupt_emulator =
 		    fibril_create(hc_interrupt_emulator, instance);
-		fibril_add_ready(instance->cleaner);
-	} else {
-		/* TODO: enable interrupts here */
-	}
-
-	instance->debug_checker =
-	    fibril_create(hc_debug_checker, instance);
-//	fibril_add_ready(instance->debug_checker);
+		fibril_add_ready(instance->interrupt_emulator);
+	}
+	(void)hc_debug_checker;
 
 	return EOK;
@@ -228,6 +215,6 @@
 	/* Set all frames to point to the first queue head */
 	const uint32_t queue =
-	  instance->transfers_interrupt.queue_head_pa
-	  | LINK_POINTER_QUEUE_HEAD_FLAG;
+	    LINK_POINTER_QH(addr_to_phys(
+	        instance->transfers_interrupt.queue_head));
 
 	unsigned i = 0;
@@ -236,11 +223,10 @@
 	}
 
-	/* Init device keeper*/
+	/* Init device keeper */
 	usb_device_keeper_init(&instance->manager);
 	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);
 
@@ -261,7 +247,10 @@
 {
 	assert(instance);
-#define CHECK_RET_CLEAR_RETURN(ret, message...) \
+#define SETUP_TRANSFER_LIST(type, name) \
+do { \
+	int ret = transfer_list_init(&instance->transfers_##type, name); \
 	if (ret != EOK) { \
-		usb_log_error(message); \
+		usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \
+		    ret, name, str_error(ret)); \
 		transfer_list_fini(&instance->transfers_bulk_full); \
 		transfer_list_fini(&instance->transfers_control_full); \
@@ -269,22 +258,13 @@
 		transfer_list_fini(&instance->transfers_interrupt); \
 		return ret; \
-	} else (void) 0
-
-	/* initialize TODO: check errors */
-	int ret;
-	ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
-
-	ret = transfer_list_init(
-	    &instance->transfers_control_full, "CONTROL_FULL");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
-
-	ret = transfer_list_init(
-	    &instance->transfers_control_slow, "CONTROL_SLOW");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
-
-	ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
-
+	} \
+} while (0)
+
+	SETUP_TRANSFER_LIST(bulk_full, "BULK FULL");
+	SETUP_TRANSFER_LIST(control_full, "CONTROL FULL");
+	SETUP_TRANSFER_LIST(control_slow, "CONTROL LOW");
+	SETUP_TRANSFER_LIST(interrupt, "INTERRUPT");
+#undef SETUP_TRANSFER_LIST
+	/* Connect lists into one schedule */
 	transfer_list_set_next(&instance->transfers_control_full,
 		&instance->transfers_bulk_full);
@@ -330,10 +310,6 @@
 
 	transfer_list_t *list =
-	    instance->transfers[batch->speed][batch->transfer_type];
+	    instance->transfers[batch->ep->speed][batch->ep->transfer_type];
 	assert(list);
-	if (batch->transfer_type == USB_TRANSFER_CONTROL) {
-		usb_device_keeper_use_control(
-		    &instance->manager, batch->target);
-	}
 	transfer_list_add_batch(list, batch);
 
@@ -355,7 +331,6 @@
 	assert(instance);
 //	status |= 1; //Uncomment to work around qemu hang
-	/* TODO: Resume interrupts are not supported */
 	/* Lower 2 bits are transaction error and transaction complete */
-	if (status & 0x3) {
+	if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
 		LIST_INITIALIZE(done);
 		transfer_list_remove_finished(
@@ -373,31 +348,11 @@
 			usb_transfer_batch_t *batch =
 			    list_get_instance(item, usb_transfer_batch_t, link);
-			switch (batch->transfer_type)
-			{
-			case USB_TRANSFER_CONTROL:
-				usb_device_keeper_release_control(
-				    &instance->manager, batch->target);
-				break;
-			case USB_TRANSFER_INTERRUPT:
-			case USB_TRANSFER_ISOCHRONOUS: {
-/*
-				int ret = bandwidth_free(&instance->bandwidth,
-				    batch->target.address,
-				    batch->target.endpoint,
-				    batch->direction);
-				if (ret != EOK)
-					usb_log_warning("Failed(%d) to free "
-					    "reserved bw: %s.\n", ret,
-					    str_error(ret));
-*/
-				}
-			default:
-				break;
-			}
-			batch->next_step(batch);
-		}
-	}
-	/* bits 4 and 5 indicate hc error */
-	if (status & 0x18) {
+			usb_transfer_batch_finish(batch);
+		}
+	}
+	/* Resume interrupts are not supported */
+
+	/* Bits 4 and 5 indicate hc error */
+	if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
 		usb_log_error("UHCI hardware failure!.\n");
 		++instance->hw_failures;
@@ -429,11 +384,11 @@
 
 	while (1) {
-		/* read and ack interrupts */
+		/* Readd and clear status register */
 		uint16_t status = pio_read_16(&instance->registers->usbsts);
-		pio_write_16(&instance->registers->usbsts, 0x1f);
+		pio_write_16(&instance->registers->usbsts, status);
 		if (status != 0)
 			usb_log_debug2("UHCI status: %x.\n", status);
 		hc_interrupt(instance, status);
-		async_usleep(UHCI_CLEANER_TIMEOUT);
+		async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
 	}
 	return EOK;
@@ -506,31 +461,4 @@
 #undef QH
 }
-/*----------------------------------------------------------------------------*/
-/** Check transfers for USB validity
- *
- * @param[in] low_speed Transfer speed.
- * @param[in] transfer Transer type
- * @param[in] size Size of data packets
- * @return True if transaction is allowed by USB specs, false otherwise
- */
-#if 0
-bool usb_is_allowed(
-    bool low_speed, usb_transfer_type_t transfer, size_t size)
-{
-	/* see USB specification chapter 5.5-5.8 for magic numbers used here */
-	switch(transfer)
-	{
-	case USB_TRANSFER_ISOCHRONOUS:
-		return (!low_speed && size < 1024);
-	case USB_TRANSFER_INTERRUPT:
-		return size <= (low_speed ? 8 : 64);
-	case USB_TRANSFER_CONTROL: /* device specifies its own max size */
-		return (size <= (low_speed ? 8 : 64));
-	case USB_TRANSFER_BULK: /* device specifies its own max size */
-		return (!low_speed && size <= 64);
-	}
-	return false;
-}
-#endif
 /**
  * @}
Index: uspace/drv/uhci-hcd/hc.h
===================================================================
--- uspace/drv/uhci-hcd/hc.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/hc.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -48,5 +48,7 @@
 #include "transfer_list.h"
 
+/** UHCI I/O registers layout */
 typedef struct uhci_regs {
+	/** Command register, controls HC behaviour */
 	uint16_t usbcmd;
 #define UHCI_CMD_MAX_PACKET (1 << 7)
@@ -59,4 +61,5 @@
 #define UHCI_CMD_RUN_STOP  (1 << 0)
 
+	/** Status register, 1 means interrupt is asserted (if enabled) */
 	uint16_t usbsts;
 #define UHCI_STATUS_HALTED (1 << 5)
@@ -67,4 +70,5 @@
 #define UHCI_STATUS_INTERRUPT (1 << 0)
 
+	/** Interrupt enabled registers */
 	uint16_t usbintr;
 #define UHCI_INTR_SHORT_PACKET (1 << 3)
@@ -73,37 +77,55 @@
 #define UHCI_INTR_CRC (1 << 0)
 
+	/** Register stores frame number used in SOF packet */
 	uint16_t frnum;
+
+	/** Pointer(physical) to the Frame List */
 	uint32_t flbaseadd;
+
+	/** SOF modification to match external timers */
 	uint8_t sofmod;
 } regs_t;
 
 #define UHCI_FRAME_LIST_COUNT 1024
-#define UHCI_CLEANER_TIMEOUT 10000
+#define UHCI_INT_EMULATOR_TIMEOUT 10000
 #define UHCI_DEBUGER_TIMEOUT 5000000
 #define UHCI_ALLOWED_HW_FAIL 5
 
+/* Main HC driver structure */
 typedef struct hc {
+	/** USB bus driver, devices and addresses */
 	usb_device_keeper_t manager;
+	/** USB bus driver, endpoints */
 	usb_endpoint_manager_t ep_manager;
 
+	/** Addresses of I/O registers */
 	regs_t *registers;
 
+	/** Frame List contains 1024 link pointers */
 	link_pointer_t *frame_list;
 
+	/** List and queue of interrupt transfers */
+	transfer_list_t transfers_interrupt;
+	/** List and queue of low speed control transfers */
+	transfer_list_t transfers_control_slow;
+	/** List and queue of full speed bulk transfers */
 	transfer_list_t transfers_bulk_full;
+	/** List and queue of full speed control transfers */
 	transfer_list_t transfers_control_full;
-	transfer_list_t transfers_control_slow;
-	transfer_list_t transfers_interrupt;
 
+	/** Pointer table to the above lists, helps during scheduling */
 	transfer_list_t *transfers[2][4];
 
+	/** Code to be executed in kernel interrupt handler */
 	irq_code_t interrupt_code;
 
-	fid_t cleaner;
-	fid_t debug_checker;
+	/** Fibril periodically checking status register*/
+	fid_t interrupt_emulator;
+
+	/** Indicator of hw interrupts availability */
 	bool hw_interrupts;
+
+	/** Number of hw failures detected. */
 	unsigned hw_failures;
-
-	ddf_fun_t *ddf_instance;
 } hc_t;
 
Index: uspace/drv/uhci-hcd/hw_struct/queue_head.h
===================================================================
--- uspace/drv/uhci-hcd/hw_struct/queue_head.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/hw_struct/queue_head.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -34,12 +34,15 @@
 #ifndef DRV_UHCI_QH_H
 #define DRV_UHCI_QH_H
-
-/* libc */
 #include <assert.h>
 
 #include "link_pointer.h"
+#include "transfer_descriptor.h"
+#include "utils/malloc32.h"
 
+/** This structure is defined in UHCI design guide p. 31 */
 typedef struct queue_head {
+	/** Pointer to the next entity (another QH or TD */
 	volatile link_pointer_t next;
+	/** Pointer to the contained entities (execution controlled by vertical flag*/
 	volatile link_pointer_t element;
 } __attribute__((packed)) qh_t;
@@ -64,11 +67,10 @@
  * @param[in] pa Physical address of the next queue head.
  *
- * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal
- * NULL.
+ * Adds proper flag. If the pointer is NULL, sets next to terminal NULL.
  */
-static inline void qh_set_next_qh(qh_t *instance, uint32_t pa)
+static inline void qh_set_next_qh(qh_t *instance, qh_t *next)
 {
-	/* Address is valid and not terminal */
-	if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
+	uint32_t pa = addr_to_phys(next);
+	if (pa) {
 		instance->next = LINK_POINTER_QH(pa);
 	} else {
@@ -80,30 +82,12 @@
  *
  * @param[in] instance qh_t structure to initialize.
- * @param[in] pa Physical address of the next queue head.
- *
- * Adds proper flag. If the pointer is NULL or terminal, sets element
- * to terminal NULL.
- */
-static inline void qh_set_element_qh(qh_t *instance, uint32_t pa)
-{
-	/* Address is valid and not terminal */
-	if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
-		instance->element = LINK_POINTER_QH(pa);
-	} else {
-		instance->element = LINK_POINTER_TERM;
-	}
-}
-/*----------------------------------------------------------------------------*/
-/** Set queue head element pointer
- *
- * @param[in] instance qh_t structure to initialize.
  * @param[in] pa Physical address of the TD structure.
  *
- * Adds proper flag. If the pointer is NULL or terminal, sets element
- * to terminal NULL.
+ * Adds proper flag. If the pointer is NULL, sets element to terminal NULL.
  */
-static inline void qh_set_element_td(qh_t *instance, uint32_t pa)
+static inline void qh_set_element_td(qh_t *instance, td_t *td)
 {
-	if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
+	uint32_t pa = addr_to_phys(td);
+	if (pa) {
 		instance->element = LINK_POINTER_TD(pa);
 	} else {
@@ -111,5 +95,4 @@
 	}
 }
-
 #endif
 /**
Index: uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -77,5 +77,6 @@
 
 	instance->status = 0
-	    | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
+	    | ((err_count & TD_STATUS_ERROR_COUNT_MASK)
+	        << TD_STATUS_ERROR_COUNT_POS)
 	    | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
 	    | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0)
@@ -89,6 +90,8 @@
 	    | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
 	    | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
-	    | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
-	    | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
+	    | ((target.address & TD_DEVICE_ADDRESS_MASK)
+	        << TD_DEVICE_ADDRESS_POS)
+	    | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK)
+	        << TD_DEVICE_ENDPOINT_POS)
 	    | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
 
@@ -114,5 +117,5 @@
 	assert(instance);
 
-	/* this is hc internal error it should never be reported */
+	/* This is hc internal error it should never be reported. */
 	if ((instance->status & TD_STATUS_ERROR_BIT_STUFF) != 0)
 		return EAGAIN;
@@ -123,18 +126,18 @@
 		return EBADCHECKSUM;
 
-	/* hc does not end transaction on these, it should never be reported */
+	/* HC does not end transactions on these, it should never be reported */
 	if ((instance->status & TD_STATUS_ERROR_NAK) != 0)
 		return EAGAIN;
 
-	/* buffer overrun or underrun */
+	/* Buffer overrun or underrun */
 	if ((instance->status & TD_STATUS_ERROR_BUFFER) != 0)
 		return ERANGE;
 
-	/* device babble is something serious */
+	/* Device babble is something serious */
 	if ((instance->status & TD_STATUS_ERROR_BABBLE) != 0)
 		return EIO;
 
-	/* stall might represent err count reaching zero or stall response from
-	 * the device, is err count reached zero, one of the above is reported*/
+	/* Stall might represent err count reaching zero or stall response from
+	 * the device. If err count reached zero, one of the above is reported*/
 	if ((instance->status & TD_STATUS_ERROR_STALLED) != 0)
 		return ESTALL;
Index: uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -40,48 +40,53 @@
 #include "link_pointer.h"
 
-/** UHCI Transfer Descriptor */
+/** Transfer Descriptor, defined in UHCI design guide p. 26 */
 typedef struct transfer_descriptor {
+	/** Pointer to the next entity (TD or QH) */
 	link_pointer_t next;
 
+	/** Status doubleword */
 	volatile uint32_t status;
 #define TD_STATUS_RESERVED_MASK 0xc000f800
-#define TD_STATUS_SPD_FLAG ( 1 << 29 )
-#define TD_STATUS_ERROR_COUNT_POS ( 27 )
-#define TD_STATUS_ERROR_COUNT_MASK ( 0x3 )
-#define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 )
-#define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 )
-#define TD_STATUS_IOC_FLAG ( 1 << 24 )
+#define TD_STATUS_SPD_FLAG         (1 << 29)
+#define TD_STATUS_ERROR_COUNT_POS 27
+#define TD_STATUS_ERROR_COUNT_MASK 0x3
+#define TD_STATUS_LOW_SPEED_FLAG   (1 << 26)
+#define TD_STATUS_ISOCHRONOUS_FLAG (1 << 25)
+#define TD_STATUS_IOC_FLAG         (1 << 24)
 
-#define TD_STATUS_ERROR_ACTIVE ( 1 << 23 )
-#define TD_STATUS_ERROR_STALLED ( 1 << 22 )
-#define TD_STATUS_ERROR_BUFFER ( 1 << 21 )
-#define TD_STATUS_ERROR_BABBLE ( 1 << 20 )
-#define TD_STATUS_ERROR_NAK ( 1 << 19 )
-#define TD_STATUS_ERROR_CRC ( 1 << 18 )
-#define TD_STATUS_ERROR_BIT_STUFF ( 1 << 17 )
-#define TD_STATUS_ERROR_RESERVED ( 1 << 16 )
+#define TD_STATUS_ERROR_ACTIVE    (1 << 23)
+#define TD_STATUS_ERROR_STALLED   (1 << 22)
+#define TD_STATUS_ERROR_BUFFER    (1 << 21)
+#define TD_STATUS_ERROR_BABBLE    (1 << 20)
+#define TD_STATUS_ERROR_NAK       (1 << 19)
+#define TD_STATUS_ERROR_CRC       (1 << 18)
+#define TD_STATUS_ERROR_BIT_STUFF (1 << 17)
+#define TD_STATUS_ERROR_RESERVED  (1 << 16)
 #define TD_STATUS_ERROR_POS 16
-#define TD_STATUS_ERROR_MASK ( 0xff )
+#define TD_STATUS_ERROR_MASK 0xff
 
 #define TD_STATUS_ACTLEN_POS 0
 #define TD_STATUS_ACTLEN_MASK 0x7ff
 
+	/* double word with USB device specific info */
 	volatile uint32_t device;
 #define TD_DEVICE_MAXLEN_POS 21
-#define TD_DEVICE_MAXLEN_MASK ( 0x7ff )
-#define TD_DEVICE_RESERVED_FLAG ( 1 << 20 )
-#define TD_DEVICE_DATA_TOGGLE_ONE_FLAG ( 1 << 19 )
+#define TD_DEVICE_MAXLEN_MASK 0x7ff
+#define TD_DEVICE_RESERVED_FLAG        (1 << 20)
+#define TD_DEVICE_DATA_TOGGLE_ONE_FLAG (1 << 19)
 #define TD_DEVICE_ENDPOINT_POS 15
-#define TD_DEVICE_ENDPOINT_MASK ( 0xf )
+#define TD_DEVICE_ENDPOINT_MASK 0xf
 #define TD_DEVICE_ADDRESS_POS 8
-#define TD_DEVICE_ADDRESS_MASK ( 0x7f )
+#define TD_DEVICE_ADDRESS_MASK 0x7f
 #define TD_DEVICE_PID_POS 0
-#define TD_DEVICE_PID_MASK ( 0xff )
+#define TD_DEVICE_PID_MASK 0xff
 
+	/** Pointer(physical) to the beginning of the transaction's buffer */
 	volatile uint32_t buffer_ptr;
 
-	/* there is 16 bytes of data available here, according to UHCI
-	 * Design guide, according to linux kernel the hardware does not care,
-	 * it just needs to be aligned, we don't use it anyway
+	/* According to UHCI design guide, there is 16 bytes of
+	 * data available here.
+	 * According to linux kernel the hardware does not care,
+	 * it just needs to be aligned. We don't use it anyway.
 	 */
 } __attribute__((packed)) td_t;
Index: uspace/drv/uhci-hcd/iface.c
===================================================================
--- uspace/drv/uhci-hcd/iface.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/iface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -41,53 +41,42 @@
 #include "hc.h"
 
-/** 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.
- */
-static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
-{
+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_t *hc = fun_to_hc(fun);
-	assert(hc);
-	usb_log_debug("Default address request with speed %d.\n", speed);
-	usb_device_keeper_reserve_default_address(&hc->manager, speed);
-	return EOK;
-#if 0
-	endpoint_t *ep = malloc(sizeof(endpoint_t));
-	if (ep == NULL)
+	*hc = fun_to_hc(fun);
+	assert(*hc);
+
+	size_t res_bw;
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    target.address, target.endpoint, name, bw, res_bw);
+		return ENOSPC;
+	}
+
+	*batch = batch_get(
+	        fun, ep, data, size, setup_data, setup_size, in, out, arg);
+	if (!*batch)
 		return ENOMEM;
-	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.
- */
-static int release_default_address(ddf_fun_t *fun)
-{
-	assert(fun);
-	hc_t *hc = fun_to_hc(fun);
-	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;
 }
@@ -151,5 +140,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)
@@ -157,33 +147,15 @@
 	hc_t *hc = fun_to_hc(fun);
 	assert(hc);
-	const usb_speed_t speed =
-	    usb_device_keeper_get_speed(&hc->manager, address);
-	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;
-	}
-
+	const size_t size = max_packet_size;
+	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
+	if (speed >= USB_SPEED_MAX) {
+		speed = ep_speed;
+	}
 	usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
 	    address, endpoint, usb_str_transfer_type(transfer_type),
 	    usb_str_speed(speed), direction, size, max_packet_size, interval);
 
-	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;
+	return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint,
+	    direction, transfer_type, speed, max_packet_size, size);
 }
 /*----------------------------------------------------------------------------*/
@@ -204,5 +176,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.
@@ -212,45 +183,17 @@
  */
 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_log_debug("Interrupt OUT %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	size_t res_bw;
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_OUT, &res_bw);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for INT OUT.\n",
-			target.address, target.endpoint);
-		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) INT IN needs %zu bw "
-		    "but only %zu is reserved.\n",
-		    target.address, target.endpoint, bw, res_bw);
-		return ENOENT;
-	}
-	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_INTERRUPT);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, NULL, callback, arg, ep);
-	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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -261,5 +204,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.
@@ -269,46 +211,17 @@
  */
 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_log_debug("Interrupt IN %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	size_t res_bw;
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_IN, &res_bw);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for INT IN.\n",
-		    target.address, target.endpoint);
-		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) INT IN needs %zu bw "
-		    "but only %zu bw is reserved.\n",
-		    target.address, target.endpoint, bw, res_bw);
-		return ENOENT;
-	}
-
-	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_INTERRUPT);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, callback, NULL, arg, ep);
-	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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -319,5 +232,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.
@@ -327,35 +239,17 @@
  */
 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_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_OUT, NULL);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for BULK OUT.\n",
-			target.address, target.endpoint);
-		return ENOENT;
-	}
-	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_BULK);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, NULL, callback, arg, ep);
-	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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -366,5 +260,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.
@@ -374,34 +267,17 @@
  */
 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_log_debug("Bulk IN %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
-
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_IN, NULL);
-	if (ep == NULL) {
-		usb_log_error("Endpoint(%d:%d) not registered for BULK IN.\n",
-			target.address, target.endpoint);
-		return ENOENT;
-	}
-	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_BULK);
-
-	usb_transfer_batch_t *batch =
-	    batch_get(fun, target, ep->transfer_type, ep->max_packet_size,
-	        ep->speed, data, size, NULL, 0, callback, NULL, arg, ep);
-	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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -412,5 +288,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).
@@ -422,35 +297,20 @@
  */
 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);
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_BOTH, NULL);
-	if (ep == NULL) {
-		usb_log_warning("Endpoint(%d:%d) not registered for CONTROL.\n",
-			target.address, target.endpoint);
-	}
-
-	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, ep);
-	if (!batch)
-		return ENOMEM;
-	usb_device_keeper_reset_if_need(&hc->manager, target, setup_data);
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
 	batch_control_write(batch);
-	const int ret = hc_schedule(hc, batch);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -461,5 +321,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).
@@ -471,31 +330,19 @@
  */
 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);
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_BOTH, NULL);
-	if (ep == NULL) {
-		usb_log_warning("Endpoint(%d:%d) not registered for CONTROL.\n",
-			target.address, target.endpoint);
-	}
-	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, ep);
-	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);
-	if (ret != EOK) {
-		batch_dispose(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
 	}
 	return ret;
@@ -503,6 +350,4 @@
 /*----------------------------------------------------------------------------*/
 usbhc_iface_t hc_iface = {
-	.reserve_default_address = reserve_default_address,
-	.release_default_address = release_default_address,
 	.request_address = request_address,
 	.bind_address = bind_address,
Index: uspace/drv/uhci-hcd/main.c
===================================================================
--- uspace/drv/uhci-hcd/main.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -39,5 +39,4 @@
 #include <usb/debug.h>
 
-#include "iface.h"
 #include "uhci.h"
 
@@ -62,6 +61,7 @@
 int uhci_add_device(ddf_dev_t *device)
 {
-	usb_log_debug("uhci_add_device() called\n");
+	usb_log_debug2("uhci_add_device() called\n");
 	assert(device);
+
 	uhci_t *uhci = malloc(sizeof(uhci_t));
 	if (uhci == NULL) {
@@ -72,11 +72,11 @@
 	int ret = uhci_init(uhci, device);
 	if (ret != EOK) {
-		usb_log_error("Failed to initialize UHCI driver: %s.\n",
-		    str_error(ret));
+		usb_log_error("Failed(%d) to initialize UHCI driver: %s.\n",
+		    ret, str_error(ret));
 		return ret;
 	}
 	device->driver_data = uhci;
 
-	usb_log_info("Controlling new UHCI device `%s'.\n", device->name);
+	usb_log_info("Controlling new UHCI device '%s'.\n", device->name);
 
 	return EOK;
@@ -85,5 +85,5 @@
 /** Initialize global driver structures (NONE).
  *
- * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argc Number of arguments in argv vector (ignored).
  * @param[in] argv Cmdline argument vector (ignored).
  * @return Error code.
@@ -94,6 +94,4 @@
 {
 	printf(NAME ": HelenOS UHCI driver.\n");
-
-	sleep(3); /* TODO: remove in final version */
 	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
 
Index: uspace/drv/uhci-hcd/pci.c
===================================================================
--- uspace/drv/uhci-hcd/pci.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/pci.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -44,5 +44,5 @@
 #include "pci.h"
 
-/** Get address of registers and IRQ for given device.
+/** Get I/O address of registers and IRQ for given device.
  *
  * @param[in] dev Device asking for the addresses.
@@ -53,18 +53,16 @@
  */
 int pci_get_my_registers(ddf_dev_t *dev,
-    uintptr_t *io_reg_address, size_t *io_reg_size,
-    int *irq_no)
+    uintptr_t *io_reg_address, size_t *io_reg_size, int *irq_no)
 {
 	assert(dev != NULL);
 
-	int parent_phone = devman_parent_device_connect(dev->handle,
-	    IPC_FLAG_BLOCKING);
+	int parent_phone =
+	    devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING);
 	if (parent_phone < 0) {
 		return parent_phone;
 	}
 
-	int rc;
 	hw_resource_list_t hw_resources;
-	rc = hw_res_get_resource_list(parent_phone, &hw_resources);
+	int rc = hw_res_get_resource_list(parent_phone, &hw_resources);
 	if (rc != EOK) {
 		goto leave;
@@ -95,4 +93,5 @@
 			    res->res.io_range.address, res->res.io_range.size);
 			io_found = true;
+			break;
 
 		default:
@@ -113,5 +112,4 @@
 leave:
 	async_hangup(parent_phone);
-
 	return rc;
 }
@@ -145,5 +143,5 @@
 	}
 
-	/* See UHCI design guide for these values,
+	/* See UHCI design guide for these values p.45,
 	 * write all WC bits in USB legacy register */
 	sysarg_t address = 0xc0;
Index: uspace/drv/uhci-hcd/root_hub.c
===================================================================
--- uspace/drv/uhci-hcd/root_hub.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/root_hub.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -55,10 +55,13 @@
 	int ret = asprintf(&match_str, "usb&uhci&root-hub");
 	if (ret < 0) {
-		usb_log_error("Failed to create root hub match string.\n");
-		return ENOMEM;
+		usb_log_error(
+		    "Failed(%d) to create root hub match string: %s.\n",
+		    ret, str_error(ret));
+		return ret;
 	}
 
 	ret = ddf_fun_add_match_id(fun, match_str, 100);
 	if (ret != EOK) {
+		free(match_str);
 		usb_log_error("Failed(%d) to add root hub match id: %s\n",
 		    ret, str_error(ret));
@@ -66,8 +69,8 @@
 	}
 
-	hw_resource_list_t *resource_list = &instance->resource_list;
-	resource_list->count = 1;
-	resource_list->resources = &instance->io_regs;
-	assert(resource_list->resources);
+	/* Initialize resource structure */
+	instance->resource_list.count = 1;
+	instance->resource_list.resources = &instance->io_regs;
+
 	instance->io_regs.type = IO_RANGE;
 	instance->io_regs.res.io_range.address = reg_addr;
Index: uspace/drv/uhci-hcd/root_hub.h
===================================================================
--- uspace/drv/uhci-hcd/root_hub.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/root_hub.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -39,6 +39,9 @@
 #include <ops/hw_res.h>
 
+/** DDF support structure for uhci-rhd driver, provides I/O resources */
 typedef struct rh {
+	/** List of resources available to the root hub. */
 	hw_resource_list_t resource_list;
+	/** The only resource in the above list */
 	hw_resource_t io_regs;
 } rh_t;
Index: uspace/drv/uhci-hcd/transfer_list.c
===================================================================
--- uspace/drv/uhci-hcd/transfer_list.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/transfer_list.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -57,7 +57,7 @@
 		return ENOMEM;
 	}
-	instance->queue_head_pa = addr_to_phys(instance->queue_head);
+	uint32_t queue_head_pa = addr_to_phys(instance->queue_head);
 	usb_log_debug2("Transfer list %s setup with QH: %p(%p).\n",
-	    name, instance->queue_head, instance->queue_head_pa);
+	    name, instance->queue_head, queue_head_pa);
 
 	qh_init(instance->queue_head);
@@ -67,4 +67,15 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Dispose transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ *
+ * Frees memory for internal qh_t structure.
+ */
+void transfer_list_fini(transfer_list_t *instance)
+{
+	assert(instance);
+	free32(instance->queue_head);
+}
 /** Set the next list in transfer list chain.
  *
@@ -81,13 +92,12 @@
 	if (!instance->queue_head)
 		return;
-	/* Set both queue_head.next to point to the follower */
-	qh_set_next_qh(instance->queue_head, next->queue_head_pa);
-}
-/*----------------------------------------------------------------------------*/
-/** Submit transfer batch to the list and queue.
+	/* Set queue_head.next to point to the follower */
+	qh_set_next_qh(instance->queue_head, next->queue_head);
+}
+/*----------------------------------------------------------------------------*/
+/** Add 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.
@@ -109,6 +119,6 @@
 	} else {
 		/* There is something scheduled */
-		usb_transfer_batch_t *last = list_get_instance(
-		    instance->batch_list.prev, usb_transfer_batch_t, link);
+		usb_transfer_batch_t *last =
+		    usb_transfer_batch_from_link(instance->batch_list.prev);
 		last_qh = batch_qh(last);
 	}
@@ -118,5 +128,5 @@
 	/* keep link */
 	batch_qh(batch)->next = last_qh->next;
-	qh_set_next_qh(last_qh, pa);
+	qh_set_next_qh(last_qh, batch_qh(batch));
 
 	asm volatile ("": : :"memory");
@@ -132,12 +142,8 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Check list for finished batches.
- *
- * @param[in] instance List to use.
- * @return Error code
- *
- * Creates a local list of finished batches and calls next_step on each and
- * every one. This is safer because next_step may theoretically access
- * this transfer list leading to the deadlock if its done inline.
+/** Add completed bantches to the provided list.
+ *
+ * @param[in] instance List to use.
+ * @param[in] done list to fill
  */
 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done)
@@ -151,8 +157,8 @@
 		link_t *next = current->next;
 		usb_transfer_batch_t *batch =
-		    list_get_instance(current, usb_transfer_batch_t, link);
+		    usb_transfer_batch_from_link(current);
 
 		if (batch_is_complete(batch)) {
-			/* Save for post-processing */
+			/* Save for processing */
 			transfer_list_remove_batch(instance, batch);
 			list_append(current, done);
@@ -161,8 +167,7 @@
 	}
 	fibril_mutex_unlock(&instance->guard);
-
-}
-/*----------------------------------------------------------------------------*/
-/** Walk the list and abort all batches.
+}
+/*----------------------------------------------------------------------------*/
+/** Walk the list and finish all batches with EINTR.
  *
  * @param[in] instance List to use.
@@ -174,7 +179,7 @@
 		link_t *current = instance->batch_list.next;
 		usb_transfer_batch_t *batch =
-		    list_get_instance(current, usb_transfer_batch_t, link);
+		    usb_transfer_batch_from_link(current);
 		transfer_list_remove_batch(instance, batch);
-		usb_transfer_batch_finish(batch, EIO);
+		usb_transfer_batch_finish_error(batch, EINTR);
 	}
 	fibril_mutex_unlock(&instance->guard);
@@ -185,5 +190,4 @@
  * @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.
@@ -202,24 +206,24 @@
 
 	const char *qpos = NULL;
+	qh_t *prev_qh = NULL;
 	/* Remove from the hardware queue */
 	if (instance->batch_list.next == &batch->link) {
 		/* I'm the first one here */
-		assert((instance->queue_head->next & LINK_POINTER_ADDRESS_MASK)
-		    == addr_to_phys(batch_qh(batch)));
-		instance->queue_head->next = batch_qh(batch)->next;
+		prev_qh = instance->queue_head;
 		qpos = "FIRST";
 	} else {
+		/* The thing before me is a batch too */
 		usb_transfer_batch_t *prev =
-		    list_get_instance(
-		        batch->link.prev, usb_transfer_batch_t, link);
-		assert((batch_qh(prev)->next & LINK_POINTER_ADDRESS_MASK)
-		    == addr_to_phys(batch_qh(batch)));
-		batch_qh(prev)->next = batch_qh(batch)->next;
+		    usb_transfer_batch_from_link(batch->link.prev);
+		prev_qh = batch_qh(prev);
 		qpos = "NOT FIRST";
 	}
+	assert((prev_qh->next & LINK_POINTER_ADDRESS_MASK)
+	    == addr_to_phys(batch_qh(batch)));
+	prev_qh->next = batch_qh(batch)->next;
 	asm volatile ("": : :"memory");
 	/* Remove from the batch list */
 	list_remove(&batch->link);
-	usb_log_debug("Batch(%p) removed (%s) from %s, next %x.\n",
+	usb_log_debug("Batch(%p) removed (%s) from %s, next: %x.\n",
 	    batch, qpos, instance->name, batch_qh(batch)->next);
 }
Index: uspace/drv/uhci-hcd/transfer_list.h
===================================================================
--- uspace/drv/uhci-hcd/transfer_list.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/transfer_list.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -39,35 +39,26 @@
 #include "batch.h"
 #include "hw_struct/queue_head.h"
-#include "utils/malloc32.h"
 
+/** Structure maintaining both hw queue and software list
+ * of currently executed transfers
+ */
 typedef struct transfer_list
 {
+	/** Guard against multiple add/remove races */
 	fibril_mutex_t guard;
+	/** UHCI hw structure represeting this queue */
 	qh_t *queue_head;
-	uint32_t queue_head_pa;
+	/** Assigned name, for nicer debug output */
 	const char *name;
+	/** List of all batches in this list */
 	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->queue_head);
-}
-
+void transfer_list_fini(transfer_list_t *instance);
 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_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/uhci-hcd/uhci.c
===================================================================
--- uspace/drv/uhci-hcd/uhci.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/uhci.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -44,9 +44,9 @@
 #include "pci.h"
 
-/** IRQ handling callback, identifies device
+/** IRQ handling callback, forward status from call to diver structure.
  *
  * @param[in] dev DDF instance of the device to use.
  * @param[in] iid (Unused).
- * @param[in] call Pointer to the call that represents interrupt.
+ * @param[in] call Pointer to the call from kernel.
  */
 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
@@ -61,7 +61,7 @@
 /** Get address of the device identified by handle.
  *
- * @param[in] dev DDF instance of the device to use.
- * @param[in] iid (Unused).
- * @param[in] call Pointer to the call that represents interrupt.
+ * @param[in] fun DDF instance of the function to use.
+ * @param[in] handle DDF handle of the driver seeking its USB address.
+ * @param[out] address Found address.
  */
 static int usb_iface_get_address(
@@ -69,5 +69,6 @@
 {
 	assert(fun);
-	usb_device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.manager;
+	usb_device_keeper_t *manager =
+	    &((uhci_t*)fun->dev->driver_data)->hc.manager;
 
 	usb_address_t addr = usb_device_keeper_find(manager, handle);
@@ -83,8 +84,8 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Gets handle of the respective hc (this or parent device).
- *
- * @param[in] root_hub_fun Root hub function seeking hc handle.
- * @param[out] handle Place to write the handle.
+/** Gets handle of the respective hc.
+ *
+ * @param[in] fun DDF function of uhci device.
+ * @param[out] handle Host cotnroller handle.
  * @return Error code.
  */
@@ -100,5 +101,5 @@
 }
 /*----------------------------------------------------------------------------*/
-/** This iface is generic for both RH and HC. */
+/** USB interface implementation used by RH */
 static usb_iface_t usb_iface = {
 	.get_hc_handle = usb_iface_get_hc_handle,
@@ -106,6 +107,6 @@
 };
 /*----------------------------------------------------------------------------*/
+/** Operations supported by the HC driver */
 static ddf_dev_ops_t hc_ops = {
-//	.interfaces[USB_DEV_IFACE] = &usb_iface,
 	.interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */
 };
@@ -122,4 +123,5 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Interface to provide the root hub driver with hw info */
 static hw_res_ops_t hw_res_iface = {
 	.get_resource_list = get_resource_list,
@@ -127,4 +129,5 @@
 };
 /*----------------------------------------------------------------------------*/
+/** RH function support for uhci-rhd */
 static ddf_dev_ops_t rh_ops = {
 	.interfaces[USB_DEV_IFACE] = &usb_iface,
@@ -132,5 +135,5 @@
 };
 /*----------------------------------------------------------------------------*/
-/** Initialize hc and rh ddf structures and their respective drivers.
+/** Initialize hc and rh DDF structures and their respective drivers.
  *
  * @param[in] instance UHCI structure to use.
@@ -138,6 +141,6 @@
  *
  * This function does all the preparatory work for hc and rh drivers:
- *  - gets device hw resources
- *  - disables UHCI legacy support
+ *  - gets device's hw resources
+ *  - disables UHCI legacy support (PCI config space)
  *  - asks for interrupt
  *  - registers interrupt handler
@@ -193,9 +196,11 @@
 	ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
 	CHECK_RET_DEST_FUN_RETURN(ret,
-	    "Failed(%d) to create HC function.\n", ret);
+	    "Failed(%d) to create HC function: %s.\n", ret, str_error(ret));
 
 	ret = hc_init(&instance->hc, instance->hc_fun,
 	    (void*)io_reg_base, io_reg_size, interrupts);
-	CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to init uhci-hcd: %s.\n", ret, str_error(ret));
+
 	instance->hc_fun->ops = &hc_ops;
 	instance->hc_fun->driver_data = &instance->hc;
@@ -221,15 +226,17 @@
 	    &instance->hc.interrupt_code);
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to register interrupt handler.\n", ret);
+	    "Failed(%d) to register interrupt handler: %s.\n",
+	    ret, str_error(ret));
 
 	instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh");
 	ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to create root hub function.\n", ret);
+	    "Failed(%d) to create root hub function: %s.\n",
+	    ret, str_error(ret));
 
 	ret = rh_init(&instance->rh, instance->rh_fun,
 	    (uintptr_t)instance->hc.registers + 0x10, 4);
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to setup UHCI root hub.\n", ret);
+	    "Failed(%d) to setup UHCI root hub: %s.\n", ret, str_error(ret));
 
 	instance->rh_fun->ops = &rh_ops;
@@ -237,5 +244,5 @@
 	ret = ddf_fun_bind(instance->rh_fun);
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to register UHCI root hub.\n", ret);
+	    "Failed(%d) to register UHCI root hub: %s.\n", ret, str_error(ret));
 
 	return EOK;
Index: uspace/drv/uhci-hcd/uhci.h
===================================================================
--- uspace/drv/uhci-hcd/uhci.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-hcd/uhci.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -41,14 +41,19 @@
 #include "root_hub.h"
 
+/** Structure representing both functions of UHCI hc, USB host controller
+ * and USB root hub */
 typedef struct uhci {
+	/** Pointer to DDF represenation of UHCI host controller */
 	ddf_fun_t *hc_fun;
+	/** Pointer to DDF represenation of UHCI root hub */
 	ddf_fun_t *rh_fun;
 
+	/** Internal driver's represenation of UHCI host controller */
 	hc_t hc;
+	/** Internal driver's represenation of UHCI root hub */
 	rh_t rh;
 } uhci_t;
 
 int uhci_init(uhci_t *instance, ddf_dev_t *device);
-
 #endif
 /**
Index: uspace/drv/uhci-rhd/port.c
===================================================================
--- uspace/drv/uhci-rhd/port.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-rhd/port.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -68,9 +68,8 @@
  * @return Error code. (Always EOK)
  */
-static inline void uhci_port_write_status(
-    uhci_port_t *port, port_status_t value)
-{
-	assert(port);
-	pio_write_16(port->address, value);
+static inline void uhci_port_write_status(uhci_port_t *port, port_status_t val)
+{
+	assert(port);
+	pio_write_16(port->address, val);
 }
 /*----------------------------------------------------------------------------*/
@@ -101,9 +100,9 @@
 	port->rh = rh;
 
-	int rc = usb_hc_connection_initialize_from_device(
-	    &port->hc_connection, rh);
-	if (rc != EOK) {
+	int ret =
+	    usb_hc_connection_initialize_from_device(&port->hc_connection, rh);
+	if (ret != EOK) {
 		usb_log_error("Failed to initialize connection to HC.");
-		return rc;
+		return ret;
 	}
 
@@ -238,5 +237,4 @@
 	/* Enable the port. */
 	uhci_port_set_enabled(port, true);
-
 	return EOK;
 }
@@ -271,5 +269,4 @@
 	usb_log_info("New device at port %u, address %d (handle %llu).\n",
 	    port->number, dev_addr, port->attached_device);
-
 	return EOK;
 }
@@ -313,4 +310,11 @@
 	/* Write new value. */
 	uhci_port_write_status(port, port_status);
+
+	/* Wait for port to become enabled */
+	do {
+		async_usleep(1000);
+		port_status = uhci_port_read_status(port);
+	} while ((port_status & STATUS_CONNECTED) &&
+	    !(port_status & STATUS_ENABLED));
 
 	usb_log_debug("%s: %sabled port.\n",
Index: uspace/drv/uhci-rhd/port.h
===================================================================
--- uspace/drv/uhci-rhd/port.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-rhd/port.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -54,4 +54,5 @@
 #define STATUS_SUSPEND   (1 << 12)
 
+/** UHCI port structure */
 typedef struct uhci_port
 {
Index: uspace/drv/uhci-rhd/root_hub.c
===================================================================
--- uspace/drv/uhci-rhd/root_hub.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-rhd/root_hub.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -33,4 +33,5 @@
  */
 #include <errno.h>
+#include <str_error.h>
 #include <ddi.h>
 #include <usb/debug.h>
@@ -43,5 +44,5 @@
  * @param[in] addr Address of I/O registers.
  * @param[in] size Size of available I/O space.
- * @param[in] rh Pointer to ddf instance of the root hub driver.
+ * @param[in] rh Pointer to DDF instance of the root hub driver.
  * @return Error code.
  */
@@ -58,6 +59,6 @@
 	if (ret < 0) {
 		usb_log_error(
-		    "Failed(%d) to gain access to port registers at %p\n",
-		    ret, regs);
+		    "Failed(%d) to gain access to port registers at %p: %s.\n",
+		    ret, regs, str_error(ret));
 		return ret;
 	}
@@ -66,7 +67,6 @@
 	unsigned i = 0;
 	for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
-		/* NOTE: mind pointer arithmetics here */
 		ret = uhci_port_init(
-		    &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);
+		    &instance->ports[i], &regs[i], i, ROOT_HUB_WAIT_USEC, rh);
 		if (ret != EOK) {
 			unsigned j = 0;
Index: uspace/drv/uhci-rhd/root_hub.h
===================================================================
--- uspace/drv/uhci-rhd/root_hub.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/uhci-rhd/root_hub.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -40,13 +40,14 @@
 
 #define UHCI_ROOT_HUB_PORT_COUNT 2
-#define ROOT_HUB_WAIT_USEC 5000000 /* 5 seconds */
+#define ROOT_HUB_WAIT_USEC 250000 /* 250 miliseconds */
 
+/** UHCI root hub drvier structure */
 typedef struct root_hub {
+	/** Ports provided by the hub */
 	uhci_port_t ports[UHCI_ROOT_HUB_PORT_COUNT];
-	devman_handle_t hc_handle;
 } uhci_root_hub_t;
 
 int uhci_root_hub_init(
-  uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh);
+    uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh);
 
 void uhci_root_hub_fini(uhci_root_hub_t *instance);
Index: uspace/drv/usbhid/Makefile
===================================================================
--- uspace/drv/usbhid/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2010-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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include -I.
+BINARY = usbhid
+
+STOLEN_LAYOUT_SOURCES = \
+        kbd/layout/us_qwerty.c \
+        kbd/layout/us_dvorak.c \
+        kbd/layout/cz.c
+
+SOURCES = \
+	main.c \
+	usbhid.c \
+	subdrivers.c \
+	kbd/conv.c \
+	kbd/kbddev.c \
+	kbd/kbdrepeat.c \
+	generic/hiddev.c \
+	mouse/mousedev.c \
+	lgtch-ultrax/lgtch-ultrax.c \
+	$(STOLEN_LAYOUT_SOURCES)
+
+EXTRA_CLEAN = $(STOLEN_LAYOUT_SOURCES)
+
+SRV_KBD = $(USPACE_PREFIX)/srv/hid/kbd
+
+include $(USPACE_PREFIX)/Makefile.common
+
+kbd/layout/%.c: $(SRV_KBD)/layout/%.c
+	ln -sfn ../../$< $@
Index: uspace/drv/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/usbhid/generic/hiddev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/generic/hiddev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+
+#include "hiddev.h"
+#include "usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.flags = 0
+};
+
+const char *HID_GENERIC_FUN_NAME = "hid";
+const char *HID_GENERIC_CLASS_NAME = "hid";
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, 
+    uint8_t *buffer, size_t buffer_size)
+{
+	usb_log_debug("usb_hid_polling_callback(%p, %p, %zu)\n",
+	    hid_dev, buffer, buffer_size);
+	usb_debug_str_buffer(buffer, buffer_size, 0);
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/usbhid/generic/hiddev.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/generic/hiddev.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID driver API.
+ */
+
+#ifndef USB_HID_HIDDDEV_H_
+#define USB_HID_HIDDDEV_H_
+
+#include <usb/devdrv.h>
+
+struct usb_hid_dev;
+
+usb_endpoint_description_t usb_hid_generic_poll_endpoint_description;
+
+const char *HID_GENERIC_FUN_NAME;
+const char *HID_GENERIC_CLASS_NAME;
+
+bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev,
+    uint8_t *buffer, size_t buffer_size);
+
+#endif // USB_HID_HIDDDEV_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd.h
===================================================================
--- uspace/drv/usbhid/kbd.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,5 @@
+/*
+ * Dummy file because of shared layout sources.
+ *
+ * Do not delete.
+ */
Index: uspace/drv/usbhid/kbd/conv.c
===================================================================
--- uspace/drv/usbhid/kbd/conv.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/conv.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB scancode parser.
+ */
+
+#include <io/keycode.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include "conv.h"
+
+/**
+ * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
+ * HelenOS key codes.
+ */
+static int scanmap_simple[255] = {
+
+//	[0x29] = KC_BACKTICK,
+
+//	[0x02] = KC_1,
+//	[0x03] = KC_2,
+	[0x04] = KC_A,
+	[0x05] = KC_B,
+	[0x06] = KC_C,
+	[0x07] = KC_D,
+	[0x08] = KC_E,
+	[0x09] = KC_F,
+	[0x0a] = KC_G,
+	[0x0b] = KC_H,
+	[0x0c] = KC_I,
+	[0x0d] = KC_J,
+	[0x0e] = KC_K,
+	[0x0f] = KC_L,
+	[0x10] = KC_M,
+	[0x11] = KC_N,
+	[0x12] = KC_O,
+	[0x13] = KC_P,
+	[0x14] = KC_Q,
+	[0x15] = KC_R,
+	[0x16] = KC_S,
+	[0x17] = KC_T,
+	[0x18] = KC_U,
+	[0x19] = KC_V,
+	[0x1a] = KC_W,
+	[0x1b] = KC_X,
+	[0x1c] = KC_Y,
+	[0x1d] = KC_Z,
+
+	[0x1e] = KC_1,
+	[0x1f] = KC_2,
+	[0x20] = KC_3,
+	[0x21] = KC_4,
+	[0x22] = KC_5,
+	[0x23] = KC_6,
+	[0x24] = KC_7,
+	[0x25] = KC_8,
+	[0x26] = KC_9,
+	[0x27] = KC_0,
+	
+	[0x28] = KC_ENTER,
+	[0x29] = KC_ESCAPE,
+	[0x2a] = KC_BACKSPACE,
+	[0x2b] = KC_TAB,
+	[0x2c] = KC_SPACE,
+
+	[0x2d] = KC_MINUS,  // same as DASH? (- or _)
+	[0x2e] = KC_EQUALS,
+	[0x2f] = KC_LBRACKET,
+	[0x30] = KC_RBRACKET,
+	[0x31] = KC_BACKSLASH,
+	//[0x32] = KC_,	// TODO: HASH??? maybe some as 0x31 - backslash
+	[0x33] = KC_SEMICOLON,
+	[0x34] = KC_QUOTE,  // same as APOSTROPHE? (')
+	[0x35] = KC_BACKTICK,  // same as GRAVE ACCENT?? (`)
+	[0x36] = KC_COMMA,
+	[0x37] = KC_PERIOD,
+	[0x38] = KC_SLASH,
+
+	[0x39] = KC_CAPS_LOCK,
+	
+	[0x3a] = KC_F1,
+	[0x3b] = KC_F2,
+	[0x3c] = KC_F3,
+	[0x3d] = KC_F4,
+	[0x3e] = KC_F5,
+	[0x3f] = KC_F6,
+	[0x40] = KC_F7,
+	[0x41] = KC_F8,
+	[0x42] = KC_F9,
+	[0x43] = KC_F10,
+	[0x44] = KC_F11,
+	[0x45] = KC_F12,
+	
+	[0x46] = KC_PRTSCR,
+	[0x47] = KC_SCROLL_LOCK,
+	[0x48] = KC_PAUSE,
+	[0x49] = KC_INSERT,
+	[0x4a] = KC_HOME,
+	[0x4b] = KC_PAGE_UP,
+	[0x4c] = KC_DELETE,
+	[0x4d] = KC_END,
+	[0x4e] = KC_PAGE_DOWN,
+	[0x4f] = KC_RIGHT,
+	[0x50] = KC_LEFT,
+	[0x51] = KC_DOWN,
+	[0x52] = KC_UP,
+	
+	//[0x64] = // some funny key
+	
+	[0xe0] = KC_LCTRL,
+	[0xe1] = KC_LSHIFT,
+	[0xe2] = KC_LALT,
+	//[0xe3] = KC_L	// TODO: left GUI
+	[0xe4] = KC_RCTRL,
+	[0xe5] = KC_RSHIFT,
+	[0xe6] = KC_RALT,
+	//[0xe7] = KC_R	// TODO: right GUI
+	
+	[0x53] = KC_NUM_LOCK,
+	[0x54] = KC_NSLASH,
+	[0x55] = KC_NTIMES,
+	[0x56] = KC_NMINUS,
+	[0x57] = KC_NPLUS,
+	[0x58] = KC_NENTER,
+	[0x59] = KC_N1,
+	[0x5a] = KC_N2,
+	[0x5b] = KC_N3,
+	[0x5c] = KC_N4,
+	[0x5d] = KC_N5,
+	[0x5e] = KC_N6,
+	[0x5f] = KC_N7,
+	[0x60] = KC_N8,
+	[0x61] = KC_N9,
+	[0x62] = KC_N0,
+	[0x63] = KC_NPERIOD
+	
+};
+
+/**
+ * Translate USB HID key codes (from HID Usage Tables) to generic key codes
+ * recognized by HelenOS.
+ *
+ * @param scancode USB HID key code (from HID Usage Tables).
+ * 
+ * @retval HelenOS key code corresponding to the given USB HID key code.
+ */
+unsigned int usbhid_parse_scancode(int scancode)
+{
+	unsigned int key;
+	int *map = scanmap_simple;
+	size_t map_length = sizeof(scanmap_simple) / sizeof(int);
+
+	if ((scancode < 0) || ((size_t) scancode >= map_length))
+		return -1;
+
+	key = map[scancode];
+	
+	return key;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/conv.h
===================================================================
--- uspace/drv/usbhid/kbd/conv.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/conv.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB scancode parser.
+ */
+
+#ifndef USB_HID_CONV_H_
+#define USB_HID_CONV_H_
+
+unsigned int usbhid_parse_scancode(int scancode);
+
+#endif /* USB_HID_CONV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/kbddev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,970 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard device structure and API.
+ */
+
+#include <errno.h>
+#include <str_error.h>
+#include <stdio.h>
+
+#include <io/keycode.h>
+#include <ipc/kbd.h>
+#include <async.h>
+#include <fibril.h>
+#include <fibril_synch.h>
+
+#include <usb/usb.h>
+#include <usb/dp.h>
+#include <usb/request.h>
+#include <usb/classes/hid.h>
+#include <usb/pipes.h>
+#include <usb/debug.h>
+#include <usb/classes/hidparser.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hidut.h>
+#include <usb/classes/hidreq.h>
+#include <usb/classes/hidreport.h>
+#include <usb/classes/hid/utled.h>
+
+#include <usb/devdrv.h>
+
+#include "kbddev.h"
+
+#include "layout.h"
+#include "conv.h"
+#include "kbdrepeat.h"
+
+#include "../usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+/** Default modifiers when the keyboard is initialized. */
+static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
+
+///** Boot protocol report size (key part). */
+//static const size_t BOOTP_REPORT_SIZE = 6;
+
+///** Boot protocol total report size. */
+//static const size_t BOOTP_BUFFER_SIZE = 8;
+
+///** Boot protocol output report size. */
+//static const size_t BOOTP_BUFFER_OUT_SIZE = 1;
+
+///** Boot protocol error key code. */
+//static const uint8_t BOOTP_ERROR_ROLLOVER = 1;
+static const uint8_t ERROR_ROLLOVER = 1;
+
+/** Default idle rate for keyboards. */
+static const uint8_t IDLE_RATE = 0;
+
+/** Delay before a pressed key starts auto-repeating. */
+static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
+
+/** Delay between two repeats of a pressed key when auto-repeating. */
+static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
+
+/*----------------------------------------------------------------------------*/
+
+/** Keyboard polling endpoint description for boot protocol class. */
+usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
+	.flags = 0
+};
+
+//static usb_endpoint_description_t hid_poll_endpoint_description = {
+//	.transfer_type = USB_TRANSFER_INTERRUPT,
+//	.direction = USB_DIRECTION_IN,
+//	.interface_class = USB_CLASS_HID,
+//	.flags = 0
+//};
+
+///* Array of endpoints expected on the device, NULL terminated. */
+//usb_endpoint_description_t 
+//    *usb_kbd_endpoints[USB_KBD_POLL_EP_COUNT + 1] = {
+//	&boot_poll_endpoint_description,
+//	&hid_poll_endpoint_description,
+//	NULL
+//};
+
+const char *HID_KBD_FUN_NAME = "keyboard";
+const char *HID_KBD_CLASS_NAME = "keyboard";
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE = 63
+};
+
+static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[
+    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE] = {
+        0x05, 0x01,  // Usage Page (Generic Desktop),
+        0x09, 0x06,  // Usage (Keyboard),
+        0xA1, 0x01,  // Collection (Application),
+        0x75, 0x01,  //   Report Size (1),
+        0x95, 0x08,  //   Report Count (8),       
+        0x05, 0x07,  //   Usage Page (Key Codes);
+        0x19, 0xE0,  //   Usage Minimum (224),
+        0x29, 0xE7,  //   Usage Maximum (231),
+        0x15, 0x00,  //   Logical Minimum (0),
+        0x25, 0x01,  //   Logical Maximum (1),
+        0x81, 0x02,  //   Input (Data, Variable, Absolute),   ; Modifier byte
+	0x95, 0x01,  //   Report Count (1),
+        0x75, 0x08,  //   Report Size (8),
+        0x81, 0x01,  //   Input (Constant),                   ; Reserved byte
+        0x95, 0x05,  //   Report Count (5),
+        0x75, 0x01,  //   Report Size (1),
+        0x05, 0x08,  //   Usage Page (Page# for LEDs),
+        0x19, 0x01,  //   Usage Minimum (1),
+        0x29, 0x05,  //   Usage Maxmimum (5),
+        0x91, 0x02,  //   Output (Data, Variable, Absolute),  ; LED report
+        0x95, 0x01,  //   Report Count (1),
+        0x75, 0x03,  //   Report Size (3),
+        0x91, 0x01,  //   Output (Constant),              ; LED report padding
+        0x95, 0x06,  //   Report Count (6),
+        0x75, 0x08,  //   Report Size (8),
+        0x15, 0x00,  //   Logical Minimum (0),
+        0x25, 0xff,  //   Logical Maximum (255),
+        0x05, 0x07,  //   Usage Page (Key Codes),
+        0x19, 0x00,  //   Usage Minimum (0),
+        0x29, 0xff,  //   Usage Maximum (255),
+        0x81, 0x00,  //   Input (Data, Array),            ; Key arrays (6 bytes)
+        0xC0           // End Collection
+
+};
+
+/*----------------------------------------------------------------------------*/
+
+typedef enum usb_kbd_flags {
+	USB_KBD_STATUS_UNINITIALIZED = 0,
+	USB_KBD_STATUS_INITIALIZED = 1,
+	USB_KBD_STATUS_TO_DESTROY = -1
+} usb_kbd_flags;
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
+    uint8_t report_id, void *arg);
+
+static const usb_hid_report_in_callbacks_t usb_kbd_parser_callbacks = {
+	.keyboard = usb_kbd_process_keycodes
+};
+
+/*----------------------------------------------------------------------------*/
+/* Keyboard layouts                                                           */
+/*----------------------------------------------------------------------------*/
+
+#define NUM_LAYOUTS 3
+
+/** Keyboard layout map. */
+static layout_op_t *layout[NUM_LAYOUTS] = {
+	&us_qwerty_op,
+	&us_dvorak_op,
+	&cz_op
+};
+
+static int active_layout = 0;
+
+/*----------------------------------------------------------------------------*/
+/* Modifier constants                                                         */
+/*----------------------------------------------------------------------------*/
+/** Mapping of USB modifier key codes to generic modifier key codes. */
+static const keycode_t usbhid_modifiers_keycodes[USB_HID_MOD_COUNT] = {
+	KC_LCTRL,         /* USB_HID_MOD_LCTRL */
+	KC_LSHIFT,        /* USB_HID_MOD_LSHIFT */
+	KC_LALT,          /* USB_HID_MOD_LALT */
+	0,                /* USB_HID_MOD_LGUI */
+	KC_RCTRL,         /* USB_HID_MOD_RCTRL */
+	KC_RSHIFT,        /* USB_HID_MOD_RSHIFT */
+	KC_RALT,          /* USB_HID_MOD_RALT */
+	0,                /* USB_HID_MOD_RGUI */
+};
+
+typedef enum usbhid_lock_code {
+	USB_KBD_LOCK_NUM = 0x53,
+	USB_KBD_LOCK_CAPS = 0x39,
+	USB_KBD_LOCK_SCROLL = 0x47,
+	USB_KBD_LOCK_COUNT = 3
+} usbhid_lock_code;
+
+static const usbhid_lock_code usbhid_lock_codes[USB_KBD_LOCK_COUNT] = {
+	USB_KBD_LOCK_NUM,
+	USB_KBD_LOCK_CAPS,
+	USB_KBD_LOCK_SCROLL
+};
+
+/*----------------------------------------------------------------------------*/
+/* IPC method handler                                                         */
+/*----------------------------------------------------------------------------*/
+
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+//ddf_dev_ops_t keyboard_ops = {
+//	.default_handler = default_connection_handler
+//};
+
+/** 
+ * Default handler for IPC methods not handled by DDF.
+ *
+ * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
+ * assumes the caller is the console and thus it stores IPC phone to it for 
+ * later use by the driver to notify about key events.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	if (hid_dev == NULL || hid_dev->data == NULL) {
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+	
+	assert(hid_dev != NULL);
+	assert(hid_dev->data != NULL);
+	usb_kbd_t *kbd_dev = (usb_kbd_t *)hid_dev->data;
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (kbd_dev->console_phone != -1) {
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		kbd_dev->console_phone = callback;
+		async_answer_0(icallid, EOK);
+		return;
+	}
+	
+	async_answer_0(icallid, EINVAL);
+}
+
+/*----------------------------------------------------------------------------*/
+/* Key processing functions                                                   */
+/*----------------------------------------------------------------------------*/
+/**
+ * Handles turning of LED lights on and off.
+ *
+ * In case of USB keyboards, the LEDs are handled in the driver, not in the 
+ * device. When there should be a change (lock key was pressed), the driver
+ * uses a Set_Report request sent to the device to set the state of the LEDs.
+ *
+ * This functions sets the LED lights according to current settings of modifiers
+ * kept in the keyboard device structure.
+ *
+ * @param kbd_dev Keyboard device structure.
+ */
+static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev) 
+{
+	if (kbd_dev->output_size == 0) {
+		return;
+	}
+	
+	unsigned i = 0;
+	
+	/* Reset the LED data. */
+	memset(kbd_dev->led_data, 0, kbd_dev->led_output_size * sizeof(int32_t));
+	
+	if ((kbd_dev->mods & KM_NUM_LOCK) && (i < kbd_dev->led_output_size)) {
+		kbd_dev->led_data[i++] = USB_HID_LED_NUM_LOCK;
+	}
+	
+	if ((kbd_dev->mods & KM_CAPS_LOCK) && (i < kbd_dev->led_output_size)) {
+		kbd_dev->led_data[i++] = USB_HID_LED_CAPS_LOCK;
+	}
+	
+	if ((kbd_dev->mods & KM_SCROLL_LOCK) 
+	    && (i < kbd_dev->led_output_size)) {
+		kbd_dev->led_data[i++] = USB_HID_LED_SCROLL_LOCK;
+	}
+
+	// TODO: COMPOSE and KANA
+	
+	usb_log_debug("Creating output report: %s\n", usb_debug_str_buffer ((uint8_t *)kbd_dev->led_data, kbd_dev->led_output_size * 4, 0));
+
+	usb_hid_report_output_set_data(hid_dev->parser, kbd_dev->led_path, 
+	                               USB_HID_PATH_COMPARE_END , kbd_dev->led_data, 
+	                               kbd_dev->led_output_size);
+	int rc = usb_hid_report_output_translate(hid_dev->parser, 0,
+	    kbd_dev->output_buffer, kbd_dev->output_size);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error translating LED output to output report"
+		    ".\n");
+		return;
+	}
+	
+	usb_log_debug("Output report buffer: %s\n", 
+	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size, 
+	        0));
+	
+	usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT, 
+	    kbd_dev->output_buffer, kbd_dev->output_size);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Processes key events.
+ *
+ * @note This function was copied from AT keyboard driver and modified to suit
+ *       USB keyboard.
+ *
+ * @note Lock keys are not sent to the console, as they are completely handled
+ *       in the driver. It may, however, be required later that the driver
+ *       sends also these keys to application (otherwise it cannot use those
+ *       keys at all).
+ * 
+ * @param kbd_dev Keyboard device structure.
+ * @param type Type of the event (press / release). Recognized values: 
+ *             KEY_PRESS, KEY_RELEASE
+ * @param key Key code of the key according to HID Usage Tables.
+ */
+void usb_kbd_push_ev(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, int type, 
+    unsigned int key)
+{
+	console_event_t ev;
+	unsigned mod_mask;
+
+	/*
+	 * These parts are copy-pasted from the AT keyboard driver.
+	 *
+	 * They definitely require some refactoring, but will keep it for later
+	 * when the console and keyboard system is changed in HelenOS.
+	 */
+	switch (key) {
+	case KC_LCTRL: mod_mask = KM_LCTRL; break;
+	case KC_RCTRL: mod_mask = KM_RCTRL; break;
+	case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
+	case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
+	case KC_LALT: mod_mask = KM_LALT; break;
+	case KC_RALT: mod_mask = KM_RALT; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KEY_PRESS)
+			kbd_dev->mods = kbd_dev->mods | mod_mask;
+		else
+			kbd_dev->mods = kbd_dev->mods & ~mod_mask;
+	}
+
+	switch (key) {
+	case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
+	case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
+	case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KEY_PRESS) {
+			/*
+			 * Only change lock state on transition from released
+			 * to pressed. This prevents autorepeat from messing
+			 * up the lock state.
+			 */
+			unsigned int locks_old = kbd_dev->lock_keys;
+			
+			kbd_dev->mods = 
+			    kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
+			kbd_dev->lock_keys = kbd_dev->lock_keys | mod_mask;
+
+			/* Update keyboard lock indicator lights. */
+			if (kbd_dev->lock_keys != locks_old 
+			    && hid_dev != NULL) { // ugly hack
+				usb_kbd_set_led(hid_dev, kbd_dev);
+			}
+		} else {
+			kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
+		}
+	}
+
+	if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
+		// do not send anything to the console, this is our business
+		return;
+	}
+	
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F1) {
+		active_layout = 0;
+		layout[active_layout]->reset();
+		return;
+	}
+
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F2) {
+		active_layout = 1;
+		layout[active_layout]->reset();
+		return;
+	}
+
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F3) {
+		active_layout = 2;
+		layout[active_layout]->reset();
+		return;
+	}
+	
+	ev.type = type;
+	ev.key = key;
+	ev.mods = kbd_dev->mods;
+
+	ev.c = layout[active_layout]->parse_ev(&ev);
+
+	usb_log_debug2("Sending key %d to the console\n", ev.key);
+	if (kbd_dev->console_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+	
+	async_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key, 
+	    ev.mods, ev.c);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline int usb_kbd_is_lock(unsigned int key_code) 
+{
+	return (key_code == KC_NUM_LOCK
+	    || key_code == KC_SCROLL_LOCK
+	    || key_code == KC_CAPS_LOCK);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Checks if some keys were pressed or released and generates key events.
+ *
+ * An event is created only when key is pressed or released. Besides handling
+ * the events (usb_kbd_push_ev()), the auto-repeat fibril is notified about
+ * key presses and releases (see usb_kbd_repeat_start() and 
+ * usb_kbd_repeat_stop()).
+ *
+ * @param kbd_dev Keyboard device structure.
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ *
+ * @sa usb_kbd_push_ev(), usb_kbd_repeat_start(), usb_kbd_repeat_stop()
+ */
+static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev, 
+    usb_kbd_t *kbd_dev, const uint8_t *key_codes, size_t count)
+{
+	unsigned int key;
+	unsigned int i, j;
+	
+	/*
+	 * First of all, check if the kbd have reported phantom state.
+	 *
+	 * As there is no way to distinguish keys from modifiers, we do not have
+	 * a way to check that 'all keys report Error Rollover'. We thus check
+	 * if there is at least one such error and in such case we ignore the
+	 * whole input report.
+	 */
+	i = 0;
+	while (i < count && key_codes[i] != ERROR_ROLLOVER) {
+		++i;
+	}
+	if (i != count) {
+		usb_log_debug("Phantom state occured.\n");
+		// phantom state, do nothing
+		return;
+	}
+	
+	/* TODO: quite dummy right now, think of better implementation */
+	assert(count == kbd_dev->key_count);
+	
+	/*
+	 * 1) Key releases
+	 */
+	for (j = 0; j < count; ++j) {
+		// try to find the old key in the new key list
+		i = 0;
+		while (i < kbd_dev->key_count
+		    && key_codes[i] != kbd_dev->keys[j]) {
+			++i;
+		}
+		
+		if (i == count) {
+			// not found, i.e. the key was released
+			key = usbhid_parse_scancode(kbd_dev->keys[j]);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_stop(kbd_dev, key);
+			}
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_RELEASE, key);
+			usb_log_debug2("Key released: %d\n", key);
+		} else {
+			// found, nothing happens
+		}
+	}
+	
+	/*
+	 * 1) Key presses
+	 */
+	for (i = 0; i < kbd_dev->key_count; ++i) {
+		// try to find the new key in the old key list
+		j = 0;
+		while (j < count && kbd_dev->keys[j] != key_codes[i]) { 
+			++j;
+		}
+		
+		if (j == count) {
+			// not found, i.e. new key pressed
+			key = usbhid_parse_scancode(key_codes[i]);
+			usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
+			    key_codes[i]);
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, 
+			    key);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_start(kbd_dev, key);
+			}
+		} else {
+			// found, nothing happens
+		}
+	}
+	
+	memcpy(kbd_dev->keys, key_codes, count);
+
+	usb_log_debug("New stored keycodes: %s\n", 
+	    usb_debug_str_buffer(kbd_dev->keys, kbd_dev->key_count, 0));
+}
+
+/*----------------------------------------------------------------------------*/
+/* Callbacks for parser                                                       */
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback function for the HID report parser.
+ *
+ * This function is called by the HID report parser with the parsed report.
+ * The parsed report is used to check if any events occured (key was pressed or
+ * released, modifier was pressed or released).
+ *
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ * @param report_id
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @sa usb_kbd_check_key_changes(), usb_kbd_check_modifier_changes()
+ */
+static void usb_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
+    uint8_t report_id, void *arg)
+{
+	if (arg == NULL) {
+		usb_log_warning("Missing argument in callback "
+		    "usbhid_process_keycodes().\n");
+		return;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	if (hid_dev->data == NULL) {
+		usb_log_warning("Missing KBD device structure in callback.\n");
+		return;
+	}
+	
+	usb_kbd_t *kbd_dev = (usb_kbd_t *)hid_dev->data;
+
+	usb_log_debug("Got keys from parser (report id: %u): %s\n", 
+	    report_id, usb_debug_str_buffer(key_codes, count, 0));
+	
+	if (count != kbd_dev->key_count) {
+		usb_log_warning("Number of received keycodes (%d) differs from"
+		    " expected number (%d).\n", count, kbd_dev->key_count);
+		return;
+	}
+	
+	///usb_kbd_check_modifier_changes(kbd_dev, key_codes, count);
+	usb_kbd_check_key_changes(hid_dev, kbd_dev, key_codes, count);
+}
+
+/*----------------------------------------------------------------------------*/
+/* General kbd functions                                                      */
+/*----------------------------------------------------------------------------*/
+/**
+ * Processes data received from the device in form of report.
+ *
+ * This function uses the HID report parser to translate the data received from
+ * the device into generic USB HID key codes and into generic modifiers bitmap.
+ * The parser then calls the given callback (usb_kbd_process_keycodes()).
+ *
+ * @note Currently, only the boot protocol is supported.
+ *
+ * @param kbd_dev Keyboard device structure (must be initialized).
+ * @param buffer Data from the keyboard (i.e. the report).
+ * @param actual_size Size of the data from keyboard (report size) in bytes.
+ *
+ * @sa usb_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report(),
+ *     usb_hid_parse_report().
+ */
+static void usb_kbd_process_data(usb_hid_dev_t *hid_dev,
+                                 uint8_t *buffer, size_t actual_size)
+{
+	assert(hid_dev->parser != NULL);
+
+	usb_log_debug("Calling usb_hid_parse_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
+	
+//	int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
+//	    callbacks, kbd_dev);
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	//usb_hid_report_path_set_report_id(path, 0);
+	
+	int rc = usb_hid_parse_report(hid_dev->parser, buffer, actual_size);	
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(hid_dev->parser, 
+	                    NULL, path, USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+						USB_HID_REPORT_TYPE_INPUT);
+	
+	while(field != NULL) {
+		usb_log_debug("FIELD (%X) - VALUE(%X) USAGE(%X)\n", field, field->value, field->usage);
+		field = usb_hid_report_get_sibling(hid_dev->parser, field, path, 
+		                                   USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		                                   USB_HID_REPORT_TYPE_INPUT);
+	}
+		
+	
+	usb_hid_report_path_free(path);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error in usb_hid_boot_keyboard_input_report():"
+		    "%s\n", str_error(rc));
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/* HID/KBD structure manipulation                                             */
+/*----------------------------------------------------------------------------*/
+
+static void usb_kbd_mark_unusable(usb_kbd_t *kbd_dev)
+{
+	kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Creates a new USB/HID keyboard structure.
+ *
+ * The structure returned by this function is not initialized. Use 
+ * usb_kbd_init() to initialize it prior to polling.
+ *
+ * @return New uninitialized structure for representing a USB/HID keyboard or
+ *         NULL if not successful (memory error).
+ */
+static usb_kbd_t *usb_kbd_new(void)
+{
+	usb_kbd_t *kbd_dev = 
+	    (usb_kbd_t *)calloc(1, sizeof(usb_kbd_t));
+
+	if (kbd_dev == NULL) {
+		usb_log_fatal("No memory!\n");
+		return NULL;
+	}
+	
+	kbd_dev->console_phone = -1;
+	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
+	
+	return kbd_dev;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions                                                              */
+/*----------------------------------------------------------------------------*/
+/**
+ * Initialization of the USB/HID keyboard structure.
+ *
+ * This functions initializes required structures from the device's descriptors.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ *
+ * @param kbd_dev Keyboard device structure to be initialized.
+ * @param dev DDF device structure of the keyboard.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if some parameter is not given.
+ * @return Other value inherited from function usbhid_dev_init().
+ */
+int usb_kbd_init(usb_hid_dev_t *hid_dev)
+{
+	usb_log_debug("Initializing HID/KBD structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init keyboard structure: no structure"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	/*
+	 * TODO: make more general
+	 */
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	
+	usb_hid_report_path_set_report_id(path, 0);
+	
+	kbd_dev->key_count = usb_hid_report_input_length(
+	    hid_dev->parser, path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
+	usb_hid_report_path_free(path);
+	
+	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
+	
+	kbd_dev->keys = (uint8_t *)calloc(kbd_dev->key_count, sizeof(uint8_t));
+	
+	if (kbd_dev->keys == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Output report
+	 */
+	kbd_dev->output_size = 0;
+	kbd_dev->output_buffer = usb_hid_report_output(hid_dev->parser, 
+	    &kbd_dev->output_size, 0x00);
+	if (kbd_dev->output_buffer == NULL) {
+		usb_log_warning("Error creating output report buffer.\n");
+		free(kbd_dev->keys);
+		return ENOMEM;  /* TODO: other error code */
+	}
+	
+	usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
+	
+	kbd_dev->led_path = usb_hid_report_path();
+	usb_hid_report_path_append_item(
+	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
+	
+	kbd_dev->led_output_size = usb_hid_report_output_size(hid_dev->parser, 
+	    kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
+	
+	usb_log_debug("Output report size (in items): %zu\n", 
+	    kbd_dev->led_output_size);
+	
+	kbd_dev->led_data = (int32_t *)calloc(
+	    kbd_dev->led_output_size, sizeof(int32_t));
+	
+	if (kbd_dev->led_data == NULL) {
+		usb_log_warning("Error creating buffer for LED output report."
+		    "\n");
+		free(kbd_dev->keys);
+		usb_hid_report_output_free(kbd_dev->output_buffer);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Modifiers and locks
+	 */	
+	kbd_dev->modifiers = 0;
+	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
+	kbd_dev->lock_keys = 0;
+	
+	/*
+	 * Autorepeat
+	 */	
+	kbd_dev->repeat.key_new = 0;
+	kbd_dev->repeat.key_repeated = 0;
+	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
+	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
+	
+	kbd_dev->repeat_mtx = (fibril_mutex_t *)(
+	    malloc(sizeof(fibril_mutex_t)));
+	if (kbd_dev->repeat_mtx == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev->keys);
+		usb_hid_report_output_free(kbd_dev->output_buffer);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	fibril_mutex_initialize(kbd_dev->repeat_mtx);
+	
+	// save the KBD device structure into the HID device structure
+	hid_dev->data = kbd_dev;
+	
+	// set handler for incoming calls
+	hid_dev->ops.default_handler = default_connection_handler;
+	
+	/*
+	 * Set LEDs according to initial setup.
+	 * Set Idle rate
+	 */
+	usb_kbd_set_led(hid_dev, kbd_dev);
+	
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, IDLE_RATE);
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+	
+	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
+	usb_log_debug("HID/KBD device structure initialized.\n");
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, uint8_t *buffer,
+     size_t buffer_size)
+{
+	if (hid_dev == NULL || buffer == NULL) {
+		// do not continue polling (???)
+		return false;
+	}
+	
+	// TODO: add return value from this function
+	usb_kbd_process_data(hid_dev, buffer, buffer_size);
+	
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Properly destroys the USB/HID keyboard structure.
+ *
+ * @param kbd_dev Pointer to the structure to be destroyed.
+ */
+void usb_kbd_free(usb_kbd_t **kbd_dev)
+{
+	if (kbd_dev == NULL || *kbd_dev == NULL) {
+		return;
+	}
+	
+	// hangup phone to the console
+	async_hangup((*kbd_dev)->console_phone);
+	
+	if ((*kbd_dev)->repeat_mtx != NULL) {
+		/* TODO: replace by some check and wait */
+		assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
+		free((*kbd_dev)->repeat_mtx);
+	}
+	
+	// free the output buffer
+	usb_hid_report_output_free((*kbd_dev)->output_buffer);
+
+	free(*kbd_dev);
+	*kbd_dev = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_kbd_deinit(usb_hid_dev_t *hid_dev)
+{
+	if (hid_dev == NULL) {
+		return;
+	}
+	
+	if (hid_dev->data != NULL) {
+		usb_kbd_t *kbd_dev = (usb_kbd_t *)hid_dev->data;
+		if (usb_kbd_is_initialized(kbd_dev)) {
+			usb_kbd_mark_unusable(kbd_dev);
+		} else {
+			usb_kbd_free(&kbd_dev);
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	int rc = usb_hid_parse_report_descriptor(hid_dev->parser, 
+	    USB_KBD_BOOT_REPORT_DESCRIPTOR, 
+	    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
+	
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/kbddev.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard device structure and API.
+ */
+
+#ifndef USB_HID_KBDDEV_H_
+#define USB_HID_KBDDEV_H_
+
+#include <stdint.h>
+
+#include <fibril_synch.h>
+
+#include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/pipes.h>
+#include <usb/devdrv.h>
+
+#include "kbdrepeat.h"
+
+struct usb_hid_dev;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * USB/HID keyboard device type.
+ *
+ * Holds a reference to generic USB/HID device structure and keyboard-specific
+ * data, such as currently pressed keys, modifiers and lock keys.
+ *
+ * Also holds a IPC phone to the console (since there is now no other way to 
+ * communicate with it).
+ *
+ * @note Storing active lock keys in this structure results in their setting
+ *       being device-specific.
+ */
+typedef struct usb_kbd_t {
+	/** Currently pressed keys (not translated to key codes). */
+	uint8_t *keys;
+	/** Count of stored keys (i.e. number of keys in the report). */
+	size_t key_count;
+	/** Currently pressed modifiers (bitmap). */
+	uint8_t modifiers;
+	
+	/** Currently active modifiers including locks. Sent to the console. */
+	unsigned mods;
+	
+	/** Currently active lock keys. */
+	unsigned lock_keys;
+	
+	/** IPC phone to the console device (for sending key events). */
+	int console_phone;
+	
+	/** Information for auto-repeat of keys. */
+	usb_kbd_repeat_t repeat;
+	
+	/** Mutex for accessing the information about auto-repeat. */
+	fibril_mutex_t *repeat_mtx;
+	
+	uint8_t *output_buffer;
+	
+	size_t output_size;
+	
+	size_t led_output_size;
+	
+	usb_hid_report_path_t *led_path;
+	
+	int32_t *led_data;
+	
+	/** State of the structure (for checking before use). 
+	 * 
+	 * 0 - not initialized
+	 * 1 - initialized
+	 * -1 - ready for destroying
+	 */
+	int initialized;
+} usb_kbd_t;
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
+
+const char *HID_KBD_FUN_NAME;
+const char *HID_KBD_CLASS_NAME;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_init(struct usb_hid_dev *hid_dev);
+
+bool usb_kbd_polling_callback(struct usb_hid_dev *hid_dev, uint8_t *buffer,
+    size_t buffer_size);
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev);
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev);
+
+void usb_kbd_free(usb_kbd_t **kbd_dev);
+
+void usb_kbd_push_ev(struct usb_hid_dev *hid_dev, usb_kbd_t *kbd_dev,
+    int type, unsigned int key);
+
+void usb_kbd_deinit(struct usb_hid_dev *hid_dev);
+
+int usb_kbd_set_boot_protocol(struct usb_hid_dev *hid_dev);
+
+#endif /* USB_HID_KBDDEV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbdrepeat.c
===================================================================
--- uspace/drv/usbhid/kbd/kbdrepeat.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/kbdrepeat.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#include <fibril_synch.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+
+#include "kbdrepeat.h"
+#include "kbddev.h"
+
+
+/** Delay between auto-repeat state checks when no key is being repeated. */
+static unsigned int CHECK_DELAY = 10000;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Main loop handling the auto-repeat of keys.
+ *
+ * This functions periodically checks if there is some key to be auto-repeated.
+ *
+ * If a new key is to be repeated, it uses the delay before first repeat stored
+ * in the keyboard structure to wait until the key has to start repeating.
+ *
+ * If the same key is still pressed, it uses the delay between repeats stored
+ * in the keyboard structure to wait until the key should be repeated.
+ * 
+ * If the currently repeated key is not pressed any more (
+ * usb_kbd_repeat_stop() was called), it stops repeating it and starts 
+ * checking again.
+ *
+ * @note For accessing the keyboard device auto-repeat information a fibril
+ *       mutex (repeat_mtx) from the @a kbd structure is used.
+ * 
+ * @param kbd Keyboard device structure.
+ */
+static void usb_kbd_repeat_loop(usb_kbd_t *kbd)
+{
+	unsigned int delay = 0;
+	
+	usb_log_debug("Starting autorepeat loop.\n");
+
+	while (true) {
+		// check if the kbd structure is usable
+		if (!usb_kbd_is_initialized(kbd)) {
+			if (usb_kbd_is_ready_to_destroy(kbd)) {
+				usb_kbd_free(&kbd);
+				assert(kbd == NULL);
+			}
+			return;
+		}
+		
+		fibril_mutex_lock(kbd->repeat_mtx);
+
+		if (kbd->repeat.key_new > 0) {
+			if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
+				usb_log_debug2("Repeating key: %u.\n", 
+				    kbd->repeat.key_repeated);
+				// ugly hack with the NULL
+				usb_kbd_push_ev(NULL, kbd, KEY_PRESS, 
+				    kbd->repeat.key_repeated);
+				delay = kbd->repeat.delay_between;
+			} else {
+				usb_log_debug("New key to repeat: %u.\n", 
+				    kbd->repeat.key_new);
+				kbd->repeat.key_repeated = kbd->repeat.key_new;
+				delay = kbd->repeat.delay_before;
+			}
+		} else {
+			if (kbd->repeat.key_repeated > 0) {
+				usb_log_debug("Stopping to repeat key: %u.\n", 
+				    kbd->repeat.key_repeated);
+				kbd->repeat.key_repeated = 0;
+			}
+			delay = CHECK_DELAY;
+		}
+		fibril_mutex_unlock(kbd->repeat_mtx);
+		
+		async_usleep(delay);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Main routine to be executed by a fibril for handling auto-repeat.
+ *
+ * Starts the loop for checking changes in auto-repeat.
+ * 
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @retval EOK if the routine has finished.
+ * @retval EINVAL if no argument is supplied.
+ */
+int usb_kbd_repeat_fibril(void *arg)
+{
+	usb_log_debug("Autorepeat fibril spawned.\n");
+	
+	if (arg == NULL) {
+		usb_log_error("No device!\n");
+		return EINVAL;
+	}
+	
+	usb_kbd_t *kbd = (usb_kbd_t *)arg;
+	
+	usb_kbd_repeat_loop(kbd);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Start repeating particular key.
+ *
+ * @note Only one key is repeated at any time, so calling this function 
+ *       effectively cancels auto-repeat of the current repeated key (if any)
+ *       and 'schedules' another key for auto-repeat.
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to start repeating.
+ */
+void usb_kbd_repeat_start(usb_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(kbd->repeat_mtx);
+	kbd->repeat.key_new = key;
+	fibril_mutex_unlock(kbd->repeat_mtx);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Stop repeating particular key.
+ *
+ * @note Only one key is repeated at any time, but this function may be called
+ *       even with key that is not currently repeated (in that case nothing 
+ *       happens).
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to stop repeating.
+ */
+void usb_kbd_repeat_stop(usb_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(kbd->repeat_mtx);
+	if (key == kbd->repeat.key_new) {
+		kbd->repeat.key_new = 0;
+	}
+	fibril_mutex_unlock(kbd->repeat_mtx);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbdrepeat.h
===================================================================
--- uspace/drv/usbhid/kbd/kbdrepeat.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/kbdrepeat.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#ifndef USB_HID_KBDREPEAT_H_
+#define USB_HID_KBDREPEAT_H_
+
+struct usb_kbd_t;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Structure for keeping information needed for auto-repeat of keys.
+ */
+typedef struct {
+	/** Last pressed key. */
+	unsigned int key_new;
+	/** Key to be repeated. */
+	unsigned int key_repeated;
+	/** Delay before first repeat in microseconds. */
+	unsigned int delay_before;
+	/** Delay between repeats in microseconds. */
+	unsigned int delay_between;
+} usb_kbd_repeat_t;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_repeat_fibril(void *arg);
+
+void usb_kbd_repeat_start(struct usb_kbd_t *kbd, unsigned int key);
+
+void usb_kbd_repeat_stop(struct usb_kbd_t *kbd, unsigned int key);
+
+#endif /* USB_HID_KBDREPEAT_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/layout.h
===================================================================
--- uspace/drv/usbhid/kbd/layout.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/layout.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,1 @@
+../layout.h
Index: uspace/drv/usbhid/kbd/main.c
===================================================================
--- uspace/drv/usbhid/kbd/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/kbd/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB KBD driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/devdrv.h>
+
+#include "kbddev.h"
+#include "kbdrepeat.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbkbd"
+
+/**
+ * Function for adding a new device of type USB/HID/keyboard.
+ *
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ * @note Currently supports only boot-protocol keyboards.
+ *
+ * @param dev Device to add.
+ *
+ * @retval EOK if successful.
+ * @retval ENOMEM if there
+ * @return Other error code inherited from one of functions usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ *
+ * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
+ */
+static int usb_kbd_try_add_device(usb_device_t *dev)
+{
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *kbd_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
+	    "keyboard");
+	if (kbd_fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID KBD device...\n");
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		ddf_fun_destroy(kbd_fun);
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	int rc = usb_kbd_init(kbd_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID KBD device.\n");
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID KBD device structure initialized.\n");
+	
+	/*
+	 * Store the initialized keyboard device and keyboard ops
+	 * to the DDF function.
+	 */
+	kbd_fun->driver_data = kbd_dev;
+	kbd_fun->ops = &keyboard_ops;
+
+	rc = ddf_fun_bind(kbd_fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'keyboard': %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	/*
+	 * Create new fibril for handling this keyboard
+	 */
+	//fid_t fid = fibril_create(usb_kbd_fibril, kbd_dev);
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   USB_KBD_POLL_EP_NO,
+	   /* Callback when data arrives. */
+	   usb_kbd_polling_callback,
+	   /* How much data to request. */
+	   dev->pipes[USB_KBD_POLL_EP_NO].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_kbd_polling_ended_callback,
+	   /* Custom argument. */
+	   kbd_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+	//fibril_add_ready(fid);
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+
+	(void)keyboard_ops;
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ *
+ * @retval EOK if successful. 
+ * @retval EREFUSED if the device is not supported.
+ */
+static int usb_kbd_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_kbd_add_device()\n");
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add USB KBD device: endpoint not "
+		    "found.\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_kbd_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add KBD device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("Keyboard `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_kbd_driver_ops = {
+        .add_device = usb_kbd_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_kbd_driver = {
+        .name = NAME,
+        .ops = &usb_kbd_driver_ops,
+        .endpoints = usb_kbd_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB KBD driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return usb_driver_main(&usb_kbd_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/layout.h
===================================================================
--- uspace/drv/usbhid/layout.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/layout.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Lubos Slovak 
+ * (copied from /uspace/srv/hid/kbd/include/layout.h)
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * Keyboard layout.
+ */
+
+#ifndef USB_HID_LAYOUT_H_
+#define USB_HID_LAYOUT_H_
+
+#include <sys/types.h>
+#include <io/console.h>
+
+typedef struct {
+	void (*reset)(void);
+	wchar_t (*parse_ev)(console_event_t *);
+} layout_op_t;
+
+extern layout_op_t us_qwerty_op;
+extern layout_op_t us_dvorak_op;
+extern layout_op_t cz_op;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.c
===================================================================
--- uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak, 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB Logitech UltraX Keyboard sample driver.
+ */
+
+
+#include "lgtch-ultrax.h"
+#include "../usbhid.h"
+
+#include <usb/classes/hidparser.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#define NAME "lgtch-ultrax"
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count,
+    uint8_t report_id, void *arg);
+
+static const usb_hid_report_in_callbacks_t usb_lgtch_parser_callbacks = {
+	.keyboard = usb_lgtch_process_keycodes
+};
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count,
+    uint8_t report_id, void *arg)
+{
+	// TODO: checks
+	
+	usb_log_debug(NAME " Got keys from parser (report id: %u): %s\n", 
+	    report_id, usb_debug_str_buffer(key_codes, count, 0));
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_lgtch_polling_callback(struct usb_hid_dev *hid_dev, 
+    uint8_t *buffer, size_t buffer_size)
+{
+	// TODO: checks
+	
+	usb_log_debug(NAME " usb_lgtch_polling_callback(%p, %p, %zu)\n",
+	    hid_dev, buffer, buffer_size);
+
+	usb_log_debug(NAME " Calling usb_hid_parse_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, buffer_size, 0));
+	
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, 0xc, 0);
+	usb_hid_report_path_set_report_id(path, 0);
+	
+	int rc = usb_hid_parse_report(hid_dev->parser, buffer, buffer_size);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(hid_dev->parser, NULL, path, USB_HID_PATH_COMPARE_END , USB_HID_REPORT_TYPE_INPUT);
+	while(field != NULL) {
+		usb_log_debug("KEY VALUE(%X) USAGE(%X)\n", field->value, field->usage);
+	}
+	
+
+	usb_hid_report_path_free(path);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error in usb_hid_boot_keyboard_input_report():"
+		    "%s\n", str_error(rc));
+	}
+	
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.h
===================================================================
--- uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB Logitech UltraX Keyboard sample driver.
+ */
+
+#ifndef USB_HID_LGTCH_ULTRAX_H_
+#define USB_HID_LGTCH_ULTRAX_H_
+
+#include <usb/devdrv.h>
+
+struct usb_hid_dev;
+//struct usb_hid_subdriver_mapping;
+
+/*----------------------------------------------------------------------------*/
+
+//extern struct usb_hid_subdriver_mapping usb_lgtch_mapping;
+
+/*----------------------------------------------------------------------------*/
+
+//int usb_lgtch_init(struct usb_hid_dev *hid_dev);
+
+bool usb_lgtch_polling_callback(struct usb_hid_dev *hid_dev, uint8_t *buffer,
+    size_t buffer_size);
+
+/*----------------------------------------------------------------------------*/
+
+#endif // USB_HID_LGTCH_ULTRAX_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB HID driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/devdrv.h>
+#include <usb/devpoll.h>
+
+#include "usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbhid"
+
+/**
+ * Function for adding a new device of type USB/HID/keyboard.
+ *
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ * @note Currently supports only boot-protocol keyboards.
+ *
+ * @param dev Device to add.
+ *
+ * @retval EOK if successful.
+ * @retval ENOMEM if there
+ * @return Other error code inherited from one of functions usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ */
+static int usb_hid_try_add_device(usb_device_t *dev)
+{
+	assert(dev != NULL);
+	
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID device...\n");
+	
+	usb_hid_dev_t *hid_dev = usb_hid_new();
+	if (hid_dev == NULL) {
+		usb_log_error("Error while creating USB/HID device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	int rc = usb_hid_init(hid_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID device.\n");
+		usb_hid_free(&hid_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID device structure initialized.\n");
+	
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *hid_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
+	    usb_hid_get_function_name(hid_dev));
+	if (hid_fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		usb_hid_free(&hid_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Store the initialized HID device and HID ops
+	 * to the DDF function.
+	 */
+	hid_fun->ops = &hid_dev->ops;
+	hid_fun->driver_data = hid_dev;   // TODO: maybe change to hid_dev->data
+
+	rc = ddf_fun_bind(hid_fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(hid_fun);
+		usb_hid_free(&hid_dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_class(hid_fun, usb_hid_get_class_name(hid_dev));
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'hid': %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(hid_fun);
+		usb_hid_free(&hid_dev);
+		return rc;
+	}
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   hid_dev->poll_pipe_index,
+	   /* Callback when data arrives. */
+	   usb_hid_polling_callback,
+	   /* How much data to request. */
+	   dev->pipes[hid_dev->poll_pipe_index].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_hid_polling_ended_callback,
+	   /* Custom argument. */
+	   hid_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ *
+ * @retval EOK if successful. 
+ * @retval EREFUSED if the device is not supported.
+ */
+static int usb_hid_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_hid_add_device()\n");
+	
+	if (dev == NULL) {
+		usb_log_warning("Wrong parameter given for add_device().\n");
+		return EINVAL;
+	}
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported HID device.\n");
+		usb_log_error("Failed to add HID device: endpoints not found."
+		    "\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_hid_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported HID device.\n");
+		usb_log_error("Failed to add HID device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("HID device `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_hid_driver_ops = {
+        .add_device = usb_hid_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_hid_driver = {
+        .name = NAME,
+        .ops = &usb_hid_driver_ops,
+        .endpoints = usb_hid_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB HID driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return usb_driver_main(&usb_hid_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/usbhid/mouse/mousedev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/mouse/mousedev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak, 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB Mouse driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hid.h>
+#include <usb/classes/hidreq.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ipc/mouse.h>
+
+#include "mousedev.h"
+#include "../usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_MOUSE,
+	.flags = 0
+};
+
+const char *HID_MOUSE_FUN_NAME = "mouse";
+const char *HID_MOUSE_CLASS_NAME = "mouse";
+
+/** Default idle rate for mouses. */
+static const uint8_t IDLE_RATE = 0;
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63
+};
+
+static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[
+    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = {
+	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
+	0x09, 0x02,                    // USAGE (Mouse)
+	0xa1, 0x01,                    // COLLECTION (Application)
+	0x09, 0x01,                    //   USAGE (Pointer)
+	0xa1, 0x00,                    //   COLLECTION (Physical)
+	0x95, 0x03,                    //     REPORT_COUNT (3)
+	0x75, 0x01,                    //     REPORT_SIZE (1)
+	0x05, 0x09,                    //     USAGE_PAGE (Button)
+	0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
+	0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
+	0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
+	0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
+	0x81, 0x02,                    //     INPUT (Data,Var,Abs)
+	0x95, 0x01,                    //     REPORT_COUNT (1)
+	0x75, 0x05,                    //     REPORT_SIZE (5)
+	0x81, 0x01,                    //     INPUT (Cnst)
+	0x75, 0x08,                    //     REPORT_SIZE (8)
+	0x95, 0x02,                    //     REPORT_COUNT (2)
+	0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
+	0x09, 0x30,                    //     USAGE (X)
+	0x09, 0x31,                    //     USAGE (Y)
+	0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
+	0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
+	0x81, 0x06,                    //     INPUT (Data,Var,Rel)
+	0xc0,                          //   END_COLLECTION
+	0xc0                           // END_COLLECTION
+};
+
+/*----------------------------------------------------------------------------*/
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	if (hid_dev == NULL || hid_dev->data == NULL) {
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+	
+	assert(hid_dev != NULL);
+	assert(hid_dev->data != NULL);
+	usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
+	
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (mouse_dev->console_phone != -1) {
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		mouse_dev->console_phone = callback;
+		usb_log_debug("Console phone to mouse set ok (%d).\n", callback);
+		async_answer_0(icallid, EOK);
+		return;
+	}
+
+	async_answer_0(icallid, EINVAL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static usb_mouse_t *usb_mouse_new(void)
+{
+	usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t));
+	if (mouse == NULL) {
+		return NULL;
+	}
+	mouse->console_phone = -1;
+	
+	return mouse;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_mouse_free(usb_mouse_t **mouse_dev)
+{
+	assert(mouse_dev != NULL && *mouse_dev != NULL);
+	
+	// hangup phone to the console
+	if ((*mouse_dev)->console_phone >= 0) {
+		async_hangup((*mouse_dev)->console_phone);
+	}
+	
+	free(*mouse_dev);
+	*mouse_dev = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_mouse_process_boot_report(usb_mouse_t *mouse_dev,
+    uint8_t *buffer, size_t buffer_size)
+{
+	usb_log_debug2("got buffer: %s.\n",
+	    usb_debug_str_buffer(buffer, buffer_size, 0));
+
+	uint8_t butt = buffer[0];
+	char str_buttons[4] = {
+		butt & 1 ? '#' : '.',
+		butt & 2 ? '#' : '.',
+		butt & 4 ? '#' : '.',
+		0
+	};
+
+	int shift_x = ((int) buffer[1]) - 127;
+	int shift_y = ((int) buffer[2]) - 127;
+	int wheel = ((int) buffer[3]) - 127;
+
+	if (buffer[1] == 0) {
+		shift_x = 0;
+	}
+	if (buffer[2] == 0) {
+		shift_y = 0;
+	}
+	if (buffer[3] == 0) {
+		wheel = 0;
+	}
+	
+	if (mouse_dev->console_phone >= 0) {
+		usb_log_debug("Console phone: %d\n", mouse_dev->console_phone);
+		if ((shift_x != 0) || (shift_y != 0)) {
+			/* FIXME: guessed for QEMU */
+			async_req_2_0(mouse_dev->console_phone,
+			    MEVENT_MOVE,
+			    - shift_x / 10,  - shift_y / 10);
+		} else {
+			usb_log_error("No move reported\n");
+		}
+		if (butt) {
+			/* FIXME: proper button clicking. */
+			async_req_2_0(mouse_dev->console_phone,
+			    MEVENT_BUTTON, 1, 1);
+			async_req_2_0(mouse_dev->console_phone,
+			    MEVENT_BUTTON, 1, 0);
+		}
+	} else {
+		usb_log_error("No console phone in mouse!!\n");
+	}
+
+	usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
+	    str_buttons, shift_x, shift_y, wheel);
+
+	/* Guess. */
+	//async_usleep(1000);
+	// no sleep right now
+
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_mouse_init(usb_hid_dev_t *hid_dev)
+{
+	usb_log_debug("Initializing HID/Mouse structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init keyboard structure: no structure"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	usb_mouse_t *mouse_dev = usb_mouse_new();
+	if (mouse_dev == NULL) {
+		usb_log_error("Error while creating USB/HID Mouse device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	// save the Mouse device structure into the HID device structure
+	hid_dev->data = mouse_dev;
+	
+	// set handler for incoming calls
+	hid_dev->ops.default_handler = default_connection_handler;
+	
+	// TODO: how to know if the device supports the request???
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, IDLE_RATE);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, uint8_t *buffer,
+     size_t buffer_size)
+{
+	usb_log_debug("usb_mouse_polling_callback()\n");
+	usb_debug_str_buffer(buffer, buffer_size, 0);
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Missing argument to the mouse polling callback."
+		    "\n");
+		return false;
+	}
+	
+	if (hid_dev->data == NULL) {
+		usb_log_error("Wrong argument to the mouse polling callback."
+		    "\n");
+		return false;
+	}
+	usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
+	
+	return usb_mouse_process_boot_report(mouse_dev, buffer, buffer_size);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_mouse_deinit(usb_hid_dev_t *hid_dev)
+{
+	usb_mouse_free((usb_mouse_t **)&hid_dev->data);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	int rc = usb_hid_parse_report_descriptor(hid_dev->parser, 
+	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR, 
+	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
+	
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/usbhid/mouse/mousedev.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/mouse/mousedev.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB Mouse driver API.
+ */
+
+#ifndef USB_HID_MOUSEDEV_H_
+#define USB_HID_MOUSEDEV_H_
+
+#include <usb/devdrv.h>
+
+struct usb_hid_dev;
+
+/*----------------------------------------------------------------------------*/
+
+/** Container for USB mouse device. */
+typedef struct {
+	///** Polling interval in microseconds. */
+	//suseconds_t poll_interval_us;
+	/** IPC phone to console (consumer). */
+	int console_phone;
+} usb_mouse_t;
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
+
+const char *HID_MOUSE_FUN_NAME;
+const char *HID_MOUSE_CLASS_NAME;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_mouse_init(struct usb_hid_dev *hid_dev);
+
+bool usb_mouse_polling_callback(struct usb_hid_dev *hid_dev, uint8_t *buffer,
+    size_t buffer_size);
+
+void usb_mouse_deinit(struct usb_hid_dev *hid_dev);
+
+int usb_mouse_set_boot_protocol(struct usb_hid_dev *hid_dev);
+
+/*----------------------------------------------------------------------------*/
+
+#endif // USB_HID_MOUSEDEV_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/subdrivers.c
===================================================================
--- uspace/drv/usbhid/subdrivers.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/subdrivers.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID subdriver mappings.
+ */
+
+#include "subdrivers.h"
+#include "usb/classes/hidut.h"
+
+#include "lgtch-ultrax/lgtch-ultrax.h"
+
+static usb_hid_subdriver_usage_t path_kbd[] = {
+	{USB_HIDUT_PAGE_KEYBOARD, 0}, 
+	{0, 0}
+};
+
+static usb_hid_subdriver_usage_t lgtch_path[] = {
+	{0xc, 0},
+	{0, 0}
+};
+
+const usb_hid_subdriver_mapping_t usb_hid_subdrivers[] = {
+	{
+		path_kbd,
+		-1,
+		USB_HID_PATH_COMPARE_END 
+		| USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		0,
+		0,
+		{
+			.init = usb_kbd_init,
+			.deinit = usb_kbd_deinit,
+			.poll = usb_kbd_polling_callback,
+			.poll_end = NULL
+		},
+		
+	},
+	{
+		lgtch_path,
+		1,
+		USB_HID_PATH_COMPARE_END 
+		| USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		0x046d,
+		0xc30e,
+		{
+			.init = NULL,
+			.deinit = NULL,
+			.poll = usb_lgtch_polling_callback,
+			.poll_end = NULL
+		}
+	},
+	{NULL, -1, 0, 0, 0, {NULL, NULL, NULL, NULL}}
+};
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/subdrivers.h
===================================================================
--- uspace/drv/usbhid/subdrivers.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/subdrivers.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID subdriver mappings.
+ */
+
+#ifndef USB_HID_SUBDRIVERS_H_
+#define USB_HID_SUBDRIVERS_H_
+
+#include "usbhid.h"
+#include "kbd/kbddev.h"
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct usb_hid_subdriver_usage {
+	int usage_page;
+	int usage;
+} usb_hid_subdriver_usage_t;
+
+/*----------------------------------------------------------------------------*/
+
+/* TODO: This mapping must contain some other information to get the proper
+ *       interface.
+ */
+typedef struct usb_hid_subdriver_mapping {
+	const usb_hid_subdriver_usage_t *usage_path;
+	int report_id;
+	int compare;
+	uint16_t vendor_id;
+	uint16_t product_id;
+	usb_hid_subdriver_t subdriver;
+} usb_hid_subdriver_mapping_t;
+
+/*----------------------------------------------------------------------------*/
+
+extern const usb_hid_subdriver_mapping_t usb_hid_subdrivers[];
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* USB_HID_SUBDRIVERS_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.c
===================================================================
--- uspace/drv/usbhid/usbhid.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/usbhid.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <usb/classes/hidreport.h>
+#include <usb/classes/hidreq.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include "usbhid.h"
+
+#include "kbd/kbddev.h"
+#include "generic/hiddev.h"
+#include "mouse/mousedev.h"
+#include "subdrivers.h"
+
+/*----------------------------------------------------------------------------*/
+
+/* Array of endpoints expected on the device, NULL terminated. */
+usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
+	&usb_hid_kbd_poll_endpoint_description,
+	&usb_hid_mouse_poll_endpoint_description,
+	&usb_hid_generic_poll_endpoint_description,
+	NULL
+};
+
+static const int USB_HID_MAX_SUBDRIVERS = 10;
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	// set the init callback
+	hid_dev->subdrivers[0].init = usb_kbd_init;
+	
+	// set the polling callback
+	hid_dev->subdrivers[0].poll = usb_kbd_polling_callback;
+	
+	// set the polling ended callback
+	hid_dev->subdrivers[0].poll_end = NULL;
+	
+	// set the deinit callback
+	hid_dev->subdrivers[0].deinit = usb_kbd_deinit;
+	
+	// set subdriver count
+	hid_dev->subdriver_count = 1;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	// set the init callback
+	hid_dev->subdrivers[0].init = usb_mouse_init;
+	
+	// set the polling callback
+	hid_dev->subdrivers[0].poll = usb_mouse_polling_callback;
+	
+	// set the polling ended callback
+	hid_dev->subdrivers[0].poll_end = NULL;
+	
+	// set the deinit callback
+	hid_dev->subdrivers[0].deinit = usb_mouse_deinit;
+	
+	// set subdriver count
+	hid_dev->subdriver_count = 1;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	// set the init callback
+	hid_dev->subdrivers[0].init = NULL;
+	
+	// set the polling callback
+	hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
+	
+	// set the polling ended callback
+	hid_dev->subdrivers[0].poll_end = NULL;
+	
+	// set the deinit callback
+	hid_dev->subdrivers[0].deinit = NULL;
+	
+	// set subdriver count
+	hid_dev->subdriver_count = 1;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev, 
+    const usb_hid_subdriver_mapping_t *mapping)
+{
+	return false;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev, 
+    const usb_hid_subdriver_mapping_t *mapping)
+{
+	assert(hid_dev != NULL);
+	assert(mapping != NULL);
+	
+	usb_hid_report_path_t *usage_path = usb_hid_report_path();
+	if (usage_path == NULL) {
+		usb_log_debug("Failed to create usage path.\n");
+		return false;
+	}
+	int i = 0;
+	while (mapping->usage_path[i].usage != 0 
+	    || mapping->usage_path[i].usage_page != 0) {
+		if (usb_hid_report_path_append_item(usage_path, 
+		    mapping->usage_path[i].usage_page, 
+		    mapping->usage_path[i].usage) != EOK) {
+			usb_log_debug("Failed to append to usage path.\n");
+			usb_hid_report_path_free(usage_path);
+			return false;
+		}
+		++i;
+	}
+	
+	if (mapping->report_id >= 0) {
+		usb_hid_report_path_set_report_id(usage_path, 
+		    mapping->report_id);
+	}
+	
+	assert(hid_dev->parser != NULL);
+	
+	usb_log_debug("Compare flags: %d\n", mapping->compare);
+	size_t size = usb_hid_report_input_length(hid_dev->parser, usage_path, 
+	    mapping->compare);
+	usb_log_debug("Size of the input report: %d\n", size);
+	
+	usb_hid_report_path_free(usage_path);
+	
+	return (size > 0);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev, 
+    const usb_hid_subdriver_t **subdrivers, int count)
+{
+	int i;
+	
+	if (count <= 0) {
+		hid_dev->subdriver_count = 0;
+		hid_dev->subdrivers = NULL;
+		return EOK;
+	}
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(count * 
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	for (i = 0; i < count; ++i) {
+		hid_dev->subdrivers[i].init = subdrivers[i]->init;
+		hid_dev->subdrivers[i].deinit = subdrivers[i]->deinit;
+		hid_dev->subdrivers[i].poll = subdrivers[i]->poll;
+		hid_dev->subdrivers[i].poll_end = subdrivers[i]->poll_end;
+	}
+	
+	hid_dev->subdriver_count = count;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+	
+	const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
+	
+	int i = 0, count = 0;
+	const usb_hid_subdriver_mapping_t *mapping = &usb_hid_subdrivers[i];
+
+	bool ids_matched;
+	bool matched;
+	
+	while (count < USB_HID_MAX_SUBDRIVERS &&
+	    (mapping->usage_path != NULL
+	    || mapping->vendor_id != 0 || mapping->product_id != 0)) {
+		// check the vendor & product ID
+		if (mapping->vendor_id != 0 && mapping->product_id == 0) {
+			usb_log_warning("Missing Product ID for Vendor ID %u\n",
+			    mapping->vendor_id);
+			return EINVAL;
+		}
+		if (mapping->product_id != 0 && mapping->vendor_id == 0) {
+			usb_log_warning("Missing Vendor ID for Product ID %u\n",
+			    mapping->product_id);
+			return EINVAL;
+		}
+		
+		ids_matched = false;
+		matched = false;
+		
+		if (mapping->vendor_id != 0) {
+			assert(mapping->product_id != 0);
+			usb_log_debug("Comparing device against vendor ID %u"
+			    " and product ID %u.\n", mapping->vendor_id,
+			    mapping->product_id);
+			if (usb_hid_ids_match(hid_dev, mapping)) {
+				usb_log_debug("IDs matched.\n");
+				ids_matched = true;
+			}
+		}
+		
+		if (mapping->usage_path != NULL) {
+			usb_log_debug("Comparing device against usage path.\n");
+			if (usb_hid_path_matches(hid_dev, mapping)) {
+				// does not matter if IDs were matched
+				matched = true;
+			}
+		} else {
+			// matched only if IDs were matched and there is no path
+			matched = ids_matched;
+		}
+		
+		if (matched) {
+			subdrivers[count++] = &mapping->subdriver;
+		}
+		
+		mapping = &usb_hid_subdrivers[++i];
+	}
+	
+	// we have all subdrivers determined, save them into the hid device
+	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	assert(hid_dev != NULL && dev != NULL);
+	
+	int rc = EOK;
+	
+	if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
+		usb_log_debug("Found keyboard endpoint.\n");
+		// save the pipe index
+		hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
+	} else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
+		usb_log_debug("Found mouse endpoint.\n");
+		// save the pipe index
+		hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
+	} else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
+		usb_log_debug("Found generic HID endpoint.\n");
+		// save the pipe index
+		hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
+	} else {
+		usb_log_error("None of supported endpoints found - probably"
+		    " not a supported device.\n");
+		rc = ENOTSUP;
+	}
+	
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+usb_hid_dev_t *usb_hid_new(void)
+{
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
+	    sizeof(usb_hid_dev_t));
+	
+	if (hid_dev == NULL) {
+		usb_log_fatal("No memory!\n");
+		return NULL;
+	}
+	
+	hid_dev->parser = (usb_hid_report_t *)(malloc(sizeof(
+	    usb_hid_report_t)));
+	if (hid_dev->parser == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(hid_dev);
+		return NULL;
+	}
+	
+	hid_dev->poll_pipe_index = -1;
+	
+	return hid_dev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	int rc, i;
+	
+	usb_log_debug("Initializing HID structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init HID structure: no structure given"
+		    ".\n");
+		return EINVAL;
+	}
+	
+	if (dev == NULL) {
+		usb_log_error("Failed to init HID structure: no USB device"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	/* The USB device should already be initialized, save it in structure */
+	hid_dev->usb_dev = dev;
+	
+	rc = usb_hid_check_pipes(hid_dev, dev);
+	if (rc != EOK) {
+		//usb_hid_free(&hid_dev);
+		return rc;
+	}
+		
+	/* Get the report descriptor and parse it. */
+	rc = usb_hid_process_report_descriptor(hid_dev->usb_dev, 
+	    hid_dev->parser);
+	
+	bool fallback = false;
+	
+	if (rc == EOK) {
+		// try to find subdrivers that may want to handle this device
+		rc = usb_hid_find_subdrivers(hid_dev);
+		if (rc != EOK || hid_dev->subdriver_count == 0) {
+			// try to fall back to the boot protocol if available
+			usb_log_info("No subdrivers found to handle this"
+			    " device.\n");
+			fallback = true;
+			assert(hid_dev->subdrivers == NULL);
+			assert(hid_dev->subdriver_count == 0);
+		}
+	} else {
+		usb_log_error("Failed to parse Report descriptor.\n");
+		// try to fall back to the boot protocol if available
+		fallback = true;
+	}
+	
+	// TODO: remove the mouse hack
+	if (hid_dev->poll_pipe_index == USB_HID_MOUSE_POLL_EP_NO ||
+	    fallback) {
+		// fall back to boot protocol
+		switch (hid_dev->poll_pipe_index) {
+		case USB_HID_KBD_POLL_EP_NO:
+			usb_log_info("Falling back to kbd boot protocol.\n");
+			rc = usb_kbd_set_boot_protocol(hid_dev);
+			if (rc == EOK) {
+				rc = usb_hid_set_boot_kbd_subdriver(hid_dev);
+			}
+			break;
+		case USB_HID_MOUSE_POLL_EP_NO:
+			usb_log_info("Falling back to mouse boot protocol.\n");
+			rc = usb_mouse_set_boot_protocol(hid_dev);
+			if (rc == EOK) {
+				rc = usb_hid_set_boot_mouse_subdriver(hid_dev);
+			}
+			break;
+		default:
+			assert(hid_dev->poll_pipe_index 
+			    == USB_HID_GENERIC_POLL_EP_NO);
+			
+			/* TODO: this has no meaning if the report descriptor
+			         is not parsed */
+			usb_log_info("Falling back to generic HID driver.\n");
+			rc = usb_hid_set_generic_hid_subdriver(hid_dev);
+		}
+	}
+	
+	if (rc != EOK) {
+		usb_log_error("No subdriver for handling this device could be"
+		    " initialized: %s.\n", str_error(rc));
+		usb_log_debug("Subdriver count: %d\n", 
+		    hid_dev->subdriver_count);
+		//usb_hid_free(&hid_dev);
+	} else {
+		bool ok = false;
+		
+		usb_log_debug("Subdriver count: %d\n", 
+		    hid_dev->subdriver_count);
+		
+		for (i = 0; i < hid_dev->subdriver_count; ++i) {
+			if (hid_dev->subdrivers[i].init != NULL) {
+				usb_log_debug("Initializing subdriver %d.\n",i);
+				rc = hid_dev->subdrivers[i].init(hid_dev);
+				if (rc != EOK) {
+					usb_log_warning("Failed to initialize"
+					    " HID subdriver structure.\n");
+				} else {
+					// at least one subdriver initialized
+					ok = true;
+				}
+			} else {
+				ok = true;
+			}
+		}
+		
+		rc = (ok) ? EOK : -1;	// what error to report
+	}
+	
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
+    size_t buffer_size, void *arg)
+{
+	int i;
+	
+	if (dev == NULL || arg == NULL || buffer == NULL) {
+		usb_log_error("Missing arguments to polling callback.\n");
+		return false;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	bool cont = false;
+	
+	// continue if at least one of the subdrivers want to continue
+	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll != NULL
+		    && hid_dev->subdrivers[i].poll(hid_dev, buffer, 
+		    buffer_size)) {
+			cont = true;
+		}
+	}
+	
+	return cont;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
+     void *arg)
+{
+	int i; 
+	
+	if (dev == NULL || arg == NULL) {
+		return;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll_end != NULL) {
+			hid_dev->subdrivers[i].poll_end(hid_dev, reason);
+		}
+	}
+	
+	usb_hid_free(&hid_dev);
+}
+
+/*----------------------------------------------------------------------------*/
+
+const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev)
+{
+	switch (hid_dev->poll_pipe_index) {
+	case USB_HID_KBD_POLL_EP_NO:
+		return HID_KBD_FUN_NAME;
+		break;
+	case USB_HID_MOUSE_POLL_EP_NO:
+		return HID_MOUSE_FUN_NAME;
+		break;
+	default:
+		return HID_GENERIC_FUN_NAME;
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev)
+{
+	// this means that only boot protocol keyboards will be connected
+	// to the console; there is probably no better way to do this
+	
+	switch (hid_dev->poll_pipe_index) {
+	case USB_HID_KBD_POLL_EP_NO:
+		return HID_KBD_CLASS_NAME;
+		break;
+	case USB_HID_MOUSE_POLL_EP_NO:
+		return HID_MOUSE_CLASS_NAME;
+		break;
+	default:
+		return HID_GENERIC_CLASS_NAME;
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_free(usb_hid_dev_t **hid_dev)
+{
+	int i;
+	
+	if (hid_dev == NULL || *hid_dev == NULL) {
+		return;
+	}
+	
+	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
+	    (*hid_dev)->subdrivers, (*hid_dev)->subdriver_count);
+	
+	assert((*hid_dev)->subdrivers != NULL 
+	    || (*hid_dev)->subdriver_count == 0);
+	
+	for (i = 0; i < (*hid_dev)->subdriver_count; ++i) {
+		if ((*hid_dev)->subdrivers[i].deinit != NULL) {
+			(*hid_dev)->subdrivers[i].deinit(*hid_dev);
+		}
+	}
+	
+	// free the subdrivers info
+	if ((*hid_dev)->subdrivers != NULL) {
+		free((*hid_dev)->subdrivers);
+	}
+
+	// destroy the parser
+	if ((*hid_dev)->parser != NULL) {
+		usb_hid_free_report((*hid_dev)->parser);
+	}
+
+	if ((*hid_dev)->report_desc != NULL) {
+		free((*hid_dev)->report_desc);
+	}
+
+	free(*hid_dev);
+	*hid_dev = NULL;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.h
===================================================================
--- uspace/drv/usbhid/usbhid.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/usbhid.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID driver API.
+ */
+
+#ifndef USB_HID_USBHID_H_
+#define USB_HID_USBHID_H_
+
+#include <stdint.h>
+
+#include <usb/classes/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/pipes.h>
+#include <usb/devdrv.h>
+#include <usb/classes/hid.h>
+
+struct usb_hid_dev;
+
+typedef int (*usb_hid_driver_init_t)(struct usb_hid_dev *);
+typedef void (*usb_hid_driver_deinit_t)(struct usb_hid_dev *);
+typedef bool (*usb_hid_driver_poll)(struct usb_hid_dev *, uint8_t *, size_t);
+typedef int (*usb_hid_driver_poll_ended)(struct usb_hid_dev *, bool reason);
+
+// TODO: add function and class name??
+typedef struct usb_hid_subdriver {	
+	/** Function to be called when initializing HID device. */
+	usb_hid_driver_init_t init;
+	/** Function to be called when destroying the HID device structure. */
+	usb_hid_driver_deinit_t deinit;
+	/** Function to be called when data arrives from the device. */
+	usb_hid_driver_poll poll;
+	/** Function to be called when polling ends. */
+	usb_hid_driver_poll_ended poll_end;
+} usb_hid_subdriver_t;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Structure for holding general HID device data.
+ */
+typedef struct usb_hid_dev {
+	/** Structure holding generic USB device information. */
+	usb_device_t *usb_dev;
+	
+	/** @todo What is this actually? */
+	ddf_dev_ops_t ops;
+	
+	/** Index of the polling pipe in usb_hid_endpoints array. */
+	int poll_pipe_index;
+	
+	/** Subdrivers. */
+	usb_hid_subdriver_t *subdrivers;
+	
+	/** Number of subdrivers. */
+	int subdriver_count;
+	
+	/** Report descriptor. */
+	uint8_t *report_desc;
+
+	/** Report descriptor size. */
+	size_t report_desc_size;
+	
+	/** HID Report parser. */
+	usb_hid_report_t *parser;
+	
+	/** Arbitrary data (e.g. a special structure for handling keyboard). */
+	void *data;
+} usb_hid_dev_t;
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_HID_KBD_POLL_EP_NO = 0,
+	USB_HID_MOUSE_POLL_EP_NO = 1,
+	USB_HID_GENERIC_POLL_EP_NO = 2,
+	USB_HID_POLL_EP_COUNT = 3
+};
+
+usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1];
+
+/*----------------------------------------------------------------------------*/
+
+usb_hid_dev_t *usb_hid_new(void);
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
+    size_t buffer_size, void *arg);
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
+     void *arg);
+
+const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev);
+
+const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev);
+
+void usb_hid_free(usb_hid_dev_t **hid_dev);
+
+#endif /* USB_HID_USBHID_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.ma
===================================================================
--- uspace/drv/usbhid/usbhid.ma	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbhid/usbhid.ma	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,3 @@
+100 usb&interface&class=HID&subclass=0x01&protocol=0x01
+1000 usb&interface&class=HID&subclass=0x01&protocol=0x02
+100 usb&interface&class=HID
Index: uspace/drv/usbhub/Makefile
===================================================================
--- uspace/drv/usbhub/Makefile	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -34,7 +34,7 @@
 SOURCES = \
 	main.c \
-	ports.c \
 	utils.c \
-	usbhub.c
+	usbhub.c \
+	ports.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbhub/port_status.h
===================================================================
--- uspace/drv/usbhub/port_status.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/port_status.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -49,4 +49,14 @@
 
 /**
+ * structure holding hub status and changes flags.
+ * should not be accessed directly, use supplied getter/setter methods.
+ *
+ * For more information refer to table 11.16.2.5 in
+ * "Universal Serial Bus Specification Revision 1.1"
+ *
+ */
+typedef uint32_t usb_hub_status_t;
+
+/**
  * set values in request to be it a port status request
  * @param request
@@ -54,6 +64,6 @@
  */
 static inline void usb_hub_set_port_status_request(
-usb_device_request_setup_packet_t * request, uint16_t port
-){
+	usb_device_request_setup_packet_t * request, uint16_t port
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS;
@@ -63,4 +73,18 @@
 }
 
+/**
+ * set values in request to be it a port status request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_hub_status_request(
+	usb_device_request_setup_packet_t * request
+	) {
+	request->index = 0;
+	request->request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS;
+	request->request = USB_HUB_REQUEST_GET_STATUS;
+	request->value = 0;
+	request->length = 4;
+}
 
 /**
@@ -70,12 +94,11 @@
  */
 static inline usb_device_request_setup_packet_t *
-usb_hub_create_port_status_request(uint16_t port){
+usb_hub_create_port_status_request(uint16_t port) {
 	usb_device_request_setup_packet_t * result =
-		usb_new(usb_device_request_setup_packet_t);
-	usb_hub_set_port_status_request(result,port);
+		malloc(sizeof(usb_device_request_setup_packet_t));
+	usb_hub_set_port_status_request(result, port);
 	return result;
 }
 
-
 /**
  * set the device request to be a port feature enable request
@@ -85,7 +108,7 @@
  */
 static inline void usb_hub_set_enable_port_feature_request(
-usb_device_request_setup_packet_t * request, uint16_t port,
-		uint16_t feature_selector
-){
+	usb_device_request_setup_packet_t * request, uint16_t port,
+	uint16_t feature_selector
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -102,7 +125,7 @@
  */
 static inline void usb_hub_set_disable_port_feature_request(
-usb_device_request_setup_packet_t * request, uint16_t port,
-		uint16_t feature_selector
-){
+	usb_device_request_setup_packet_t * request, uint16_t port,
+	uint16_t feature_selector
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -118,6 +141,6 @@
  */
 static inline void usb_hub_set_enable_port_request(
-usb_device_request_setup_packet_t * request, uint16_t port
-){
+	usb_device_request_setup_packet_t * request, uint16_t port
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -133,8 +156,8 @@
  */
 static inline usb_device_request_setup_packet_t *
-usb_hub_create_enable_port_request(uint16_t port){
+usb_hub_create_enable_port_request(uint16_t port) {
 	usb_device_request_setup_packet_t * result =
-		usb_new(usb_device_request_setup_packet_t);
-	usb_hub_set_enable_port_request(result,port);
+		malloc(sizeof(usb_device_request_setup_packet_t));
+	usb_hub_set_enable_port_request(result, port);
 	return result;
 }
@@ -146,6 +169,6 @@
  */
 static inline void usb_hub_set_disable_port_request(
-usb_device_request_setup_packet_t * request, uint16_t port
-){
+	usb_device_request_setup_packet_t * request, uint16_t port
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -161,8 +184,8 @@
  */
 static inline usb_device_request_setup_packet_t *
-usb_hub_create_disable_port_request(uint16_t port){
+usb_hub_create_disable_port_request(uint16_t port) {
 	usb_device_request_setup_packet_t * result =
-		usb_new(usb_device_request_setup_packet_t);
-	usb_hub_set_disable_port_request(result,port);
+		malloc(sizeof(usb_device_request_setup_packet_t));
+	usb_hub_set_disable_port_request(result, port);
 	return result;
 }
@@ -174,6 +197,6 @@
  */
 static inline void usb_hub_set_reset_port_request(
-usb_device_request_setup_packet_t * request, uint16_t port
-){
+	usb_device_request_setup_packet_t * request, uint16_t port
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -189,8 +212,8 @@
  */
 static inline usb_device_request_setup_packet_t *
-usb_hub_create_reset_port_request(uint16_t port){
+usb_hub_create_reset_port_request(uint16_t port) {
 	usb_device_request_setup_packet_t * result =
-		usb_new(usb_device_request_setup_packet_t);
-	usb_hub_set_reset_port_request(result,port);
+		malloc(sizeof(usb_device_request_setup_packet_t));
+	usb_hub_set_reset_port_request(result, port);
 	return result;
 }
@@ -202,6 +225,6 @@
  */
 static inline void usb_hub_set_power_port_request(
-usb_device_request_setup_packet_t * request, uint16_t port
-){
+	usb_device_request_setup_packet_t * request, uint16_t port
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -217,6 +240,6 @@
  */
 static inline void usb_hub_unset_power_port_request(
-usb_device_request_setup_packet_t * request, uint16_t port
-){
+	usb_device_request_setup_packet_t * request, uint16_t port
+	) {
 	request->index = port;
 	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
@@ -226,146 +249,433 @@
 }
 
-
-/** get i`th bit of port status */
-static inline bool usb_port_get_bit(usb_port_status_t * status, int idx)
-{
-	return (((*status)>>(idx))%2);
-}
-
-/** set i`th bit of port status */
-static inline void usb_port_set_bit(
-	usb_port_status_t * status, int idx, bool value)
-{
-	(*status) = value?
-		               ((*status)|(1<<(idx))):
-		               ((*status)&(~(1<<(idx))));
-}
-
-//device connnected on port
-static inline bool usb_port_dev_connected(usb_port_status_t * status){
-	return usb_port_get_bit(status,0);
-}
-
-static inline void usb_port_set_dev_connected(usb_port_status_t * status,bool connected){
-	usb_port_set_bit(status,0,connected);
+/**
+ * get i`th bit of port status
+ * 
+ * @param status
+ * @param idx
+ * @return
+ */
+static inline bool usb_port_is_status(usb_port_status_t status, int idx) {
+	return (status&(1 << idx))!=0;
+}
+
+/**
+ * set i`th bit of port status
+ * 
+ * @param status
+ * @param idx
+ * @param value
+ */
+static inline void usb_port_status_set_bit(
+	usb_port_status_t * status, int idx, bool value) {
+	(*status) = value ?
+		((*status) | (1 << (idx))) :
+		((*status)&(~(1 << (idx))));
+}
+
+/**
+ * get i`th bit of hub status
+ * 
+ * @param status
+ * @param idx
+ * @return
+ */
+static inline bool usb_hub_is_status(usb_hub_status_t status, int idx) {
+	return (status&(1 << idx))!=0;
+}
+
+/**
+ * set i`th bit of hub status
+ * 
+ * @param status
+ * @param idx
+ * @param value
+ */
+static inline void usb_hub_status_set_bit(
+	usb_hub_status_t * status, int idx, bool value) {
+	(*status) = value ?
+		((*status) | (1 << (idx))) :
+		((*status)&(~(1 << (idx))));
+}
+
+
+#if 0
+/**
+ * connection status geter for port status
+ * 
+ * @param status
+ * @return true if there is something connected
+ */
+static inline bool usb_port_dev_connected(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 0);
+}
+
+/**
+ * set device connected bit in port status
+ *
+ * @param status
+ * @param connected value of the bit
+ */
+static inline void usb_port_set_dev_connected(usb_port_status_t * status, bool connected) {
+	usb_port_set_bit(status, 0, connected);
 }
 
 //port enabled
-static inline bool usb_port_enabled(usb_port_status_t * status){
-	return usb_port_get_bit(status,1);
-}
-
-static inline void usb_port_set_enabled(usb_port_status_t * status,bool enabled){
-	usb_port_set_bit(status,1,enabled);
+
+/**
+ * port enabled getter for port status
+ * 
+ * @param status
+ * @return true if the port is enabled
+ */
+static inline bool usb_port_enabled(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 1);
+}
+
+/**
+ * set port enabled bit in port status
+ *
+ * @param status
+ * @param enabled value of the bit
+ */
+static inline void usb_port_set_enabled(usb_port_status_t * status, bool enabled) {
+	usb_port_set_bit(status, 1, enabled);
 }
 
 //port suspended
-static inline bool usb_port_suspended(usb_port_status_t * status){
-	return usb_port_get_bit(status,2);
-}
-
-static inline void usb_port_set_suspended(usb_port_status_t * status,bool suspended){
-	usb_port_set_bit(status,2,suspended);
+/**
+ * port suspended getter for port status
+ *
+ * @param status
+ * @return true if port is suspended
+ */
+static inline bool usb_port_suspended(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 2);
+}
+
+/**
+ * set port suspended bit in port status
+ *
+ * @param status
+ * @param suspended value of the bit
+ */
+static inline void usb_port_set_suspended(usb_port_status_t * status, bool suspended) {
+	usb_port_set_bit(status, 2, suspended);
 }
 
 //over currect
-static inline bool usb_port_over_current(usb_port_status_t * status){
-	return usb_port_get_bit(status,3);
-}
-
-static inline void usb_port_set_over_current(usb_port_status_t * status,bool value){
-	usb_port_set_bit(status,3,value);
+/**
+ * over current condition indicator getter for port status
+ *
+ * @param status
+ * @return true if there is opver-current condition on the hub
+ */
+static inline bool usb_port_over_current(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 3);
+}
+
+/**
+ * set over current indicator bit in port status
+ *
+ * @param status
+ * @param value value of the bit
+ */
+static inline void usb_port_set_over_current(usb_port_status_t * status, bool value) {
+	usb_port_set_bit(status, 3, value);
 }
 
 //port reset
-static inline bool usb_port_reset(usb_port_status_t * status){
-	return usb_port_get_bit(status,4);
-}
-
-static inline void usb_port_set_reset(usb_port_status_t * status,bool value){
-	usb_port_set_bit(status,4,value);
+/**
+ * port reset indicator getter for port status
+ * 
+ * @param status
+ * @return true if port is reset
+ */
+static inline bool usb_port_reset(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 4);
+}
+
+/**
+ * set port reset bit in port status
+ *
+ * @param status
+ * @param value value of the bit
+ */
+static inline void usb_port_set_reset(usb_port_status_t * status, bool value) {
+	usb_port_set_bit(status, 4, value);
 }
 
 //powered
-static inline bool usb_port_powered(usb_port_status_t * status){
-	return usb_port_get_bit(status,8);
-}
-
-static inline void usb_port_set_powered(usb_port_status_t * status,bool powered){
-	usb_port_set_bit(status,8,powered);
-}
+/**
+ * power state getter for port status
+ *
+ * @param status
+ * @return true if port is powered
+ */
+static inline bool usb_port_powered(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 8);
+}
+
+/**
+ * set port powered bit in port status
+ *
+ * @param status
+ * @param powered value of the bit
+ */
+static inline void usb_port_set_powered(usb_port_status_t * status, bool powered) {
+	usb_port_set_bit(status, 8, powered);
+}
+
+#endif
 
 //low speed device attached
-static inline bool usb_port_low_speed(usb_port_status_t * status){
-	return usb_port_get_bit(status,9);
-}
-
-static inline void usb_port_set_low_speed(usb_port_status_t * status,bool low_speed){
-	usb_port_set_bit(status,9,low_speed);
-}
-
-//low speed device attached
-static inline bool usb_port_high_speed(usb_port_status_t * status){
-	return usb_port_get_bit(status,10);
-}
-
-static inline void usb_port_set_high_speed(usb_port_status_t * status,bool high_speed){
-	usb_port_set_bit(status,10,high_speed);
-}
-
-static inline usb_speed_t usb_port_speed(usb_port_status_t * status){
-	if(usb_port_low_speed(status))
+/**
+ * low speed device on the port indicator
+ * 
+ * @param status
+ * @return true if low speed device is attached
+ */
+static inline bool usb_port_low_speed(usb_port_status_t status) {
+	return usb_port_is_status(status, 9);
+}
+
+/**
+ * set low speed device connected bit in port status
+ * 
+ * @param status
+ * @param low_speed value of the bit
+ */
+static inline void usb_port_set_low_speed(usb_port_status_t * status, bool low_speed) {
+	usb_port_status_set_bit(status, 9, low_speed);
+}
+
+//high speed device attached
+/**
+ * high speed device on the port indicator
+ *
+ * @param status
+ * @return true if high speed device is on port
+ */
+static inline bool usb_port_high_speed(usb_port_status_t status) {
+	return usb_port_is_status(status, 10);
+}
+
+/**
+ * set high speed device bit in port status
+ *
+ * @param status
+ * @param high_speed value of the bit
+ */
+static inline void usb_port_set_high_speed(usb_port_status_t * status, bool high_speed) {
+	usb_port_status_set_bit(status, 10, high_speed);
+}
+
+/**
+ * speed getter for port status
+ *
+ * @param status
+ * @return speed of usb device (for more see usb specification)
+ */
+static inline usb_speed_t usb_port_speed(usb_port_status_t status) {
+	if (usb_port_low_speed(status))
 		return USB_SPEED_LOW;
-	if(usb_port_high_speed(status))
+	if (usb_port_high_speed(status))
 		return USB_SPEED_HIGH;
 	return USB_SPEED_FULL;
 }
 
-
+#if 0
 //connect change
-static inline bool usb_port_connect_change(usb_port_status_t * status){
-	return usb_port_get_bit(status,16);
-}
-
-static inline void usb_port_set_connect_change(usb_port_status_t * status,bool change){
-	usb_port_set_bit(status,16,change);
+/**
+ * port connect change indicator
+ *
+ * @param status
+ * @return true if connection has changed
+ */
+static inline bool usb_port_connect_change(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 16);
+}
+
+/**
+ * set connection change bit in port status
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_port_set_connect_change(usb_port_status_t * status, bool change) {
+	usb_port_set_bit(status, 16, change);
 }
 
 //port enable change
-static inline bool usb_port_enabled_change(usb_port_status_t * status){
-	return usb_port_get_bit(status,17);
-}
-
-static inline void usb_port_set_enabled_change(usb_port_status_t * status,bool change){
-	usb_port_set_bit(status,17,change);
+/**
+ * port enable change for port status
+ *
+ * @param status
+ * @return true if the port has been enabled/disabled
+ */
+static inline bool usb_port_enabled_change(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 17);
+}
+
+/**
+ * set port enable change bit in port status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_port_set_enabled_change(usb_port_status_t * status, bool change) {
+	usb_port_set_bit(status, 17, change);
 }
 
 //suspend change
-static inline bool usb_port_suspend_change(usb_port_status_t * status){
-	return usb_port_get_bit(status,18);
-}
-
-static inline void usb_port_set_suspend_change(usb_port_status_t * status,bool change){
-	usb_port_set_bit(status,18,change);
+/**
+ * port suspend change for port status
+ * 
+ * @param status
+ * @return ture if suspend status has changed
+ */
+static inline bool usb_port_suspend_change(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 18);
+}
+
+/**
+ * set port suspend change bit in port status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_port_set_suspend_change(usb_port_status_t * status, bool change) {
+	usb_port_set_bit(status, 18, change);
 }
 
 //over current change
-static inline bool usb_port_overcurrent_change(usb_port_status_t * status){
-	return usb_port_get_bit(status,19);
-}
-
-static inline void usb_port_set_overcurrent_change(usb_port_status_t * status,bool change){
-	usb_port_set_bit(status,19,change);
+/**
+ * over current change indicator
+ * 
+ * @param status
+ * @return true if over-current condition on port has changed
+ */
+static inline bool usb_port_overcurrent_change(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 19);
+}
+
+/**
+ * set port over current change bit in port status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_port_set_overcurrent_change(usb_port_status_t * status, bool change) {
+	usb_port_set_bit(status, 19, change);
 }
 
 //reset change
-static inline bool usb_port_reset_completed(usb_port_status_t * status){
-	return usb_port_get_bit(status,20);
-}
-
-static inline void usb_port_set_reset_completed(usb_port_status_t * status,bool completed){
-	usb_port_set_bit(status,20,completed);
-}
-
+/**
+ * port reset change indicator
+ * @param status
+ * @return true if port has been reset
+ */
+static inline bool usb_port_reset_completed(usb_port_status_t * status) {
+	return usb_port_get_bit(status, 20);
+}
+
+/**
+ * set port reset completed bit in port status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_port_set_reset_completed(usb_port_status_t * status, bool completed) {
+	usb_port_set_bit(status, 20, completed);
+}
+
+//local power status
+/**
+ * local power lost indicator for hub status
+ * 
+ * @param status
+ * @return true if hub is not powered
+ */
+static inline bool usb_hub_local_power_lost(usb_hub_status_t * status) {
+	return usb_hub_get_bit(status, 0);
+}
+
+/**
+ * set hub power lost bit in hub status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_hub_set_local_power_lost(usb_port_status_t * status,
+	bool power_lost) {
+	usb_hub_set_bit(status, 0, power_lost);
+}
+
+//over current ocndition
+/**
+ * hub over-current indicator
+ *
+ * @param status
+ * @return true if over-current condition occurred on hub
+ */
+static inline bool usb_hub_over_current(usb_hub_status_t * status) {
+	return usb_hub_get_bit(status, 1);
+}
+
+/**
+ * set hub over current bit in hub status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_hub_set_over_current(usb_port_status_t * status,
+	bool over_current) {
+	usb_hub_set_bit(status, 1, over_current);
+}
+
+//local power change
+/**
+ * hub power change indicator
+ *
+ * @param status
+ * @return true if local power status has been changed - power has been
+ * dropped or re-established
+ */
+static inline bool usb_hub_local_power_change(usb_hub_status_t * status) {
+	return usb_hub_get_bit(status, 16);
+}
+
+/**
+ * set hub power change bit in hub status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_hub_set_local_power_change(usb_port_status_t * status,
+	bool change) {
+	usb_hub_set_bit(status, 16, change);
+}
+
+//local power status
+/**
+ * hub over-current condition change indicator
+ *
+ * @param status
+ * @return true if over-current condition has changed
+ */
+static inline bool usb_hub_over_current_change(usb_hub_status_t * status) {
+	return usb_hub_get_bit(status, 17);
+}
+
+/**
+ * set hub over current change bit in hub status
+ *
+ * @param status
+ * @param change value of the bit
+ */
+static inline void usb_hub_set_over_current_change(usb_port_status_t * status,
+	bool change) {
+	usb_hub_set_bit(status, 17, change);
+}
+#endif
 
 
Index: uspace/drv/usbhub/ports.c
===================================================================
--- uspace/drv/usbhub/ports.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/ports.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -33,10 +33,224 @@
  * Hub ports functions.
  */
-#include "port_status.h"
-#include <inttypes.h>
+
+#include <bool.h>
 #include <errno.h>
 #include <str_error.h>
-#include <usb/request.h>
+#include <inttypes.h>
+#include <fibril_synch.h>
+
 #include <usb/debug.h>
+
+#include "ports.h"
+#include "usbhub.h"
+#include "usbhub_private.h"
+#include "port_status.h"
+
+
+/** Information for fibril for device discovery. */
+struct add_device_phase1 {
+	usb_hub_info_t *hub;
+	size_t port;
+	usb_speed_t speed;
+};
+
+static void usb_hub_removed_device(
+	usb_hub_info_t * hub, uint16_t port);
+
+static void usb_hub_port_reset_completed(usb_hub_info_t * hub,
+	uint16_t port, uint32_t status);
+
+static void usb_hub_port_over_current(usb_hub_info_t * hub,
+	uint16_t port, uint32_t status);
+
+static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
+    usb_port_status_t *status);
+
+static int enable_port_callback(int port_no, void *arg);
+
+static int add_device_phase1_worker_fibril(void *arg);
+
+static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
+    usb_speed_t speed);
+
+/**
+ * Process interrupts on given hub port
+ *
+ * Accepts connection, over current and port reset change.
+ * @param hub hub representation
+ * @param port port number, starting from 1
+ */
+void usb_hub_process_interrupt(usb_hub_info_t * hub,
+	uint16_t port) {
+	usb_log_debug("interrupt at port %d\n", port);
+	//determine type of change
+	//usb_pipe_t *pipe = hub->control_pipe;
+
+	int opResult;
+
+	usb_port_status_t status;
+	opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status);
+	if (opResult != EOK) {
+		usb_log_error("Failed to get port %zu status: %s.\n",
+		    port, str_error(opResult));
+		return;
+	}
+	//connection change
+	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_CONNECTION)) {
+		bool device_connected = usb_port_is_status(status,
+		    USB_HUB_FEATURE_PORT_CONNECTION);
+		usb_log_debug("Connection change on port %zu: %s.\n", port,
+		    device_connected ? "device attached" : "device removed");
+
+		if (device_connected) {
+			opResult = create_add_device_fibril(hub, port,
+			    usb_port_speed(status));
+			if (opResult != EOK) {
+				usb_log_error(
+				    "Cannot handle change on port %zu: %s.\n",
+				    str_error(opResult));
+			}
+		} else {
+			usb_hub_removed_device(hub, port);
+		}
+	}
+	//over current
+	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) {
+		//check if it was not auto-resolved
+		usb_log_debug("overcurrent change on port\n");
+		usb_hub_port_over_current(hub, port, status);
+	}
+	//port reset
+	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_RESET)) {
+		usb_hub_port_reset_completed(hub, port, status);
+	}
+	usb_log_debug("status x%x : %d\n ", status, status);
+
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_C_PORT_CONNECTION,false);
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_PORT_RESET,false);
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_C_PORT_RESET,false);
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT,false);
+	/// \TODO what about port power change?
+	if (status >> 16) {
+		usb_log_info("there was unsupported change on port %d: %X\n",
+			port, status);
+
+	}
+}
+
+
+/**
+ * routine called when a device on port has been removed
+ *
+ * If the device on port had default address, it releases default address.
+ * Otherwise does not do anything, because DDF does not allow to remove device
+ * from it`s device tree.
+ * @param hub hub representation
+ * @param port port number, starting from 1
+ */
+static void usb_hub_removed_device(
+	usb_hub_info_t * hub, uint16_t port) {
+
+	int opResult = usb_hub_clear_port_feature(hub->control_pipe,
+		port, USB_HUB_FEATURE_C_PORT_CONNECTION);
+	if (opResult != EOK) {
+		usb_log_warning("could not clear port-change-connection flag\n");
+	}
+	/** \TODO remove device from device manager - not yet implemented in
+	 * devide manager
+	 */
+
+	//close address
+	//if (hub->attached_devs[port].address != 0) {
+	if(hub->ports[port].attached_device.address >= 0){
+		/*uncomment this code to use it when DDF allows device removal
+		opResult = usb_hc_unregister_device(
+			&hub->connection,
+			hub->attached_devs[port].address);
+		if(opResult != EOK) {
+			dprintf(USB_LOG_LEVEL_WARNING, "could not release "
+				"address of "
+			    "removed device: %d", opResult);
+		}
+		hub->attached_devs[port].address = 0;
+		hub->attached_devs[port].handle = 0;
+		 */
+	} else {
+		// TODO: is this really reason to print a warning?
+		usb_log_warning("Device removed before being registered.\n");
+
+		/*
+		 * Device was removed before port reset completed.
+		 * We will announce a failed port reset to unblock the
+		 * port reset callback from new device wrapper.
+		 */
+		usb_hub_port_t *the_port = hub->ports + port;
+		fibril_mutex_lock(&the_port->reset_mutex);
+		the_port->reset_completed = true;
+		the_port->reset_okay = false;
+		fibril_condvar_broadcast(&the_port->reset_cv);
+		fibril_mutex_unlock(&the_port->reset_mutex);
+	}
+}
+
+
+/**
+ * Process port reset change
+ *
+ * After this change port should be enabled, unless some problem occured.
+ * This functions triggers second phase of enabling new device.
+ * @param hub
+ * @param port
+ * @param status
+ */
+static void usb_hub_port_reset_completed(usb_hub_info_t * hub,
+	uint16_t port, uint32_t status){
+	usb_log_debug("Port %zu reset complete.\n", port);
+	if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) {
+		/* Finalize device adding. */
+		usb_hub_port_t *the_port = hub->ports + port;
+		fibril_mutex_lock(&the_port->reset_mutex);
+		the_port->reset_completed = true;
+		the_port->reset_okay = true;
+		fibril_condvar_broadcast(&the_port->reset_cv);
+		fibril_mutex_unlock(&the_port->reset_mutex);
+	} else {
+		usb_log_warning(
+		    "Port %zu reset complete but port not enabled.\n",
+		    port);
+	}
+}
+
+/**
+ * Process over current condition on port.
+ *
+ * Turn off the power on the port.
+ *
+ * @param hub hub representation
+ * @param port port number, starting from 1
+ */
+static void usb_hub_port_over_current(usb_hub_info_t * hub,
+	uint16_t port, uint32_t status) {
+	int opResult;
+	if(usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)){
+		opResult = usb_hub_clear_port_feature(hub->control_pipe,
+			port, USB_HUB_FEATURE_PORT_POWER);
+		if (opResult != EOK) {
+			usb_log_error("cannot power off port %d;  %d\n",
+				port, opResult);
+		}
+	}else{
+		opResult = usb_hub_set_port_feature(hub->control_pipe,
+			port, USB_HUB_FEATURE_PORT_POWER);
+		if (opResult != EOK) {
+			usb_log_error("cannot power on port %d;  %d\n",
+				port, opResult);
+		}
+	}
+}
 
 /** Retrieve port status.
@@ -73,11 +287,4 @@
 }
 
-/** Information for fibril for device discovery. */
-struct add_device_phase1 {
-	usb_hub_info_t *hub;
-	size_t port;
-	usb_speed_t speed;
-};
-
 /** Callback for enabling a specific port.
  *
@@ -91,5 +298,5 @@
 static int enable_port_callback(int port_no, void *arg)
 {
-	usb_hub_info_t *hub = (usb_hub_info_t *) arg;
+	usb_hub_info_t *hub = arg;
 	int rc;
 	usb_device_request_setup_packet_t request;
@@ -122,5 +329,9 @@
 	}
 
-	return EOK;
+	if (my_port->reset_okay) {
+		return EOK;
+	} else {
+		return ESTALL;
+	}
 }
 
@@ -156,5 +367,5 @@
 	data->hub->ports[data->port].attached_device.address = new_address;
 
-	usb_log_info("Detected new device on `%s' (port %zu), " \
+	usb_log_info("Detected new device on `%s' (port %zu), "
 	    "address %d (handle %" PRIun ").\n",
 	    data->hub->usb_device->ddf_dev->name, data->port,
@@ -166,4 +377,5 @@
 	return EOK;
 }
+
 
 /** Start device adding when connection change is detected.
@@ -176,5 +388,5 @@
  * @return Error code.
  */
-static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port,
+static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
     usb_speed_t speed)
 {
@@ -213,118 +425,4 @@
 }
 
-/** Process change on a single port.
- *
- * @param hub Hub to which the port belongs.
- * @param port Port index (starting at 1).
- */
-static void process_port_change(usb_hub_info_t *hub, size_t port)
-{
-	int rc;
-
-	usb_port_status_t port_status;
-
-	rc = get_port_status(&hub->usb_device->ctrl_pipe, port, &port_status);
-	if (rc != EOK) {
-		usb_log_error("Failed to get port %zu status: %s.\n",
-		    port, str_error(rc));
-		return;
-	}
-
-	/*
-	 * Check exact nature of the change.
-	 */
-	usb_log_debug("Port %zu change status: %x.\n", port,
-	    (unsigned int) port_status);
-
-	if (usb_port_connect_change(&port_status)) {
-		bool device_connected = usb_port_dev_connected(&port_status);
-		usb_log_debug("Connection change on port %zu: %s.\n", port,
-		    device_connected ? "device attached" : "device removed");
-
-		if (device_connected) {
-			rc = add_device_phase1_new_fibril(hub, port,
-			    usb_port_speed(&port_status));
-			if (rc != EOK) {
-				usb_log_error(
-				    "Cannot handle change on port %zu: %s.\n",
-				    str_error(rc));
-			}
-		} else {
-			usb_hub_removed_device(hub, port);
-		}
-	}
-
-	if (usb_port_overcurrent_change(&port_status)) {
-		if (usb_port_over_current(&port_status)) {
-			usb_log_warning("Overcurrent on port %zu.\n", port);
-			usb_hub_over_current(hub, port);
-		} else {
-			usb_log_debug("Overcurrent on port %zu autoresolved.\n",
-			    port);
-		}
-	}
-
-	if (usb_port_reset_completed(&port_status)) {
-		usb_log_debug("Port %zu reset complete.\n", port);
-		if (usb_port_enabled(&port_status)) {
-			/* Finalize device adding. */
-			usb_hub_port_t *the_port = hub->ports + port;
-			fibril_mutex_lock(&the_port->reset_mutex);
-			the_port->reset_completed = true;
-			fibril_condvar_broadcast(&the_port->reset_cv);
-			fibril_mutex_unlock(&the_port->reset_mutex);
-		} else {
-			usb_log_warning(
-			    "Port %zu reset complete but port not enabled.\n",
-			    port);
-		}
-	}
-
-	usb_port_set_connect_change(&port_status, false);
-	usb_port_set_reset(&port_status, false);
-	usb_port_set_reset_completed(&port_status, false);
-	usb_port_set_dev_connected(&port_status, false);
-	if (port_status >> 16) {
-		usb_log_warning("Unsupported change on port %zu: %x.\n",
-		    port, (unsigned int) port_status);
-	}
-}
-
-
-/** Callback for polling hub for port changes.
- *
- * @param dev Device where the change occured.
- * @param change_bitmap Bitmap of changed ports.
- * @param change_bitmap_size Size of the bitmap in bytes.
- * @param arg Custom argument, points to @c usb_hub_info_t.
- * @return Whether to continue polling.
- */
-bool hub_port_changes_callback(usb_device_t *dev,
-    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg)
-{
-	usb_hub_info_t *hub = (usb_hub_info_t *) arg;
-
-	/* FIXME: check that we received enough bytes. */
-	if (change_bitmap_size == 0) {
-		goto leave;
-	}
-
-	size_t port;
-	for (port = 1; port < hub->port_count + 1; port++) {
-		bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
-		if (change) {
-			process_port_change(hub, port);
-		}
-	}
-
-
-leave:
-	/* FIXME: proper interval. */
-	async_usleep(1000 * 1000 * 10 );
-
-	return true;
-}
-
-
 /**
  * @}
Index: uspace/drv/usbhub/ports.h
===================================================================
--- uspace/drv/usbhub/ports.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/ports.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -36,13 +36,8 @@
 #define DRV_USBHUB_PORTS_H
 
-#include <ipc/devman.h>
-#include <usb/usb.h>
-#include <ddf/driver.h>
-#include <fibril_synch.h>
-
+#include <usb/devdrv.h>
 #include <usb/hub.h>
 
-#include <usb/pipes.h>
-#include <usb/devdrv.h>
+typedef struct usb_hub_info_t usb_hub_info_t;
 
 /** Information about single port on a hub. */
@@ -56,4 +51,6 @@
 	 */
 	bool reset_completed;
+	/** Whether to announce the port reset as successful. */
+	bool reset_okay;
 
 	/** Information about attached device. */
@@ -72,5 +69,8 @@
 }
 
-bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, void *);
+
+void usb_hub_process_interrupt(usb_hub_info_t * hub,
+	uint16_t port);
+
 
 
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/usbhub.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -37,4 +37,5 @@
 #include <errno.h>
 #include <str_error.h>
+#include <inttypes.h>
 
 #include <usb_iface.h>
@@ -44,4 +45,5 @@
 #include <usb/request.h>
 #include <usb/classes/hub.h>
+#include <usb/devpoll.h>
 #include <stdio.h>
 
@@ -53,11 +55,134 @@
 #include "usb/classes/classes.h"
 
-static int usb_hub_trigger_connecting_non_removable_devices(
-		usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
-
+
+static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev);
+
+static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info);
+
+static int usb_hub_set_configuration(usb_hub_info_t * hub_info);
+
+static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info);
+
+static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
+    usb_hub_status_t status);
+
+static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
+    usb_hub_status_t status);
+
+static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info);
+
+
+/// \TODO malloc checking
 
 //*********************************************
 //
 //  hub driver code, initialization
+//
+//*********************************************
+
+/**
+ * Initialize hub device driver fibril
+ *
+ * Creates hub representation and fibril that periodically checks hub`s status.
+ * Hub representation is passed to the fibril.
+ * @param usb_dev generic usb device information
+ * @return error code
+ */
+int usb_hub_add_device(usb_device_t * usb_dev) {
+	if (!usb_dev) return EINVAL;
+	usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
+	//create hc connection
+	usb_log_debug("Initializing USB wire abstraction.\n");
+	int opResult = usb_hc_connection_initialize_from_device(
+	    &hub_info->connection,
+	    hub_info->usb_device->ddf_dev);
+	if (opResult != EOK) {
+		usb_log_error("could not initialize connection to device, "
+		    "errno %d\n",
+		    opResult);
+		free(hub_info);
+		return opResult;
+	}
+
+	//usb_pipe_start_session(hub_info->control_pipe);
+	//set hub configuration
+	opResult = usb_hub_set_configuration(hub_info);
+	if (opResult != EOK) {
+		usb_log_error("could not set hub configuration, errno %d\n",
+		    opResult);
+		free(hub_info);
+		return opResult;
+	}
+	//get port count and create attached_devs
+	opResult = usb_hub_process_hub_specific_info(hub_info);
+	if (opResult != EOK) {
+		usb_log_error("could process hub specific info, errno %d\n",
+		    opResult);
+		free(hub_info);
+		return opResult;
+	}
+	//usb_pipe_end_session(hub_info->control_pipe);
+
+
+	usb_log_debug("Creating 'hub' function in DDF.\n");
+	ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
+	    fun_exposed, "hub");
+	assert(hub_fun != NULL);
+	hub_fun->ops = NULL;
+
+	opResult = ddf_fun_bind(hub_fun);
+	assert(opResult == EOK);
+	opResult = ddf_fun_add_to_class(hub_fun, "hub");
+	assert(opResult == EOK);
+
+	opResult = usb_hub_start_hub_fibril(hub_info);
+	if(opResult!=EOK)
+		free(hub_info);
+	return opResult;
+}
+
+
+/** Callback for polling hub for changes.
+ *
+ * @param dev Device where the change occured.
+ * @param change_bitmap Bitmap of changed ports.
+ * @param change_bitmap_size Size of the bitmap in bytes.
+ * @param arg Custom argument, points to @c usb_hub_info_t.
+ * @return Whether to continue polling.
+ */
+bool hub_port_changes_callback(usb_device_t *dev,
+    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) {
+	usb_log_debug("hub_port_changes_callback\n");
+	usb_hub_info_t *hub = (usb_hub_info_t *) arg;
+
+	/* FIXME: check that we received enough bytes. */
+	if (change_bitmap_size == 0) {
+		goto leave;
+	}
+
+	bool change;
+	change = ((uint8_t*) change_bitmap)[0] & 1;
+	if (change) {
+		usb_hub_process_global_interrupt(hub);
+	}
+
+	size_t port;
+	for (port = 1; port < hub->port_count + 1; port++) {
+		bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
+		if (change) {
+			usb_hub_process_interrupt(hub, port);
+		}
+	}
+leave:
+	/* FIXME: proper interval. */
+	async_usleep(1000 * 1000 * 10);
+
+	return true;
+}
+
+
+//*********************************************
+//
+//  support functions
 //
 //*********************************************
@@ -71,6 +196,6 @@
  */
 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
-	usb_hub_info_t * result = usb_new(usb_hub_info_t);
-	if(!result) return NULL;
+	usb_hub_info_t * result = malloc(sizeof(usb_hub_info_t));
+	if (!result) return NULL;
 	result->usb_device = usb_dev;
 	result->status_change_pipe = usb_dev->pipes[0].pipe;
@@ -90,53 +215,76 @@
  * @return error code
  */
-static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info){
+static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {
 	// get hub descriptor
 	usb_log_debug("creating serialized descriptor\n");
-	void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
+	//void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
+	uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];
 	usb_hub_descriptor_t * descriptor;
-
-	/* this was one fix of some bug, should not be needed anymore
-	 * these lines allow to reset hub once more, it can be used as
-	 * brute-force initialization for non-removable devices
-	int opResult = usb_request_set_configuration(&result->endpoints.control, 1);
-	if(opResult!=EOK){
-		usb_log_error("could not set default configuration, errno %d",opResult);
-		return opResult;
-	}
-	 */
+	int opResult;
+
 	size_t received_size;
-	int opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,
-			USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
-			USB_DESCTYPE_HUB,
-			0, 0, serialized_descriptor,
-			USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
-
-	if (opResult != EOK) {
-		usb_log_error("failed when receiving hub descriptor, badcode = %d\n",
-				opResult);
+	opResult = usb_request_get_descriptor(hub_info->control_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
+	    USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
+
+	if (opResult != EOK) {
+		usb_log_error("failed when receiving hub descriptor, "
+		    "badcode = %d\n",
+		    opResult);
 		free(serialized_descriptor);
 		return opResult;
 	}
 	usb_log_debug2("deserializing descriptor\n");
-	descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
-	if(descriptor==NULL){
+	descriptor = usb_create_deserialized_hub_desriptor(
+	    serialized_descriptor);
+	if (descriptor == NULL) {
 		usb_log_warning("could not deserialize descriptor \n");
-		return opResult;
-	}
-	usb_log_debug("setting port count to %d\n",descriptor->ports_count);
+		return ENOMEM;
+	}
+	usb_log_debug("setting port count to %d\n", descriptor->ports_count);
 	hub_info->port_count = descriptor->ports_count;
-	hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1));
+	/// \TODO this is not semantically correct
+	bool is_power_switched =
+	    ((descriptor->hub_characteristics & 1) ==0);
+	bool has_individual_port_powering =
+	    ((descriptor->hub_characteristics & 1) !=0);
+	hub_info->ports = malloc(
+	    sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
 	size_t port;
 	for (port = 0; port < hub_info->port_count + 1; port++) {
 		usb_hub_port_init(&hub_info->ports[port]);
 	}
-	//handle non-removable devices
-	usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);
+	if(is_power_switched){
+		usb_log_debug("is_power_switched\n");
+		if(has_individual_port_powering){
+			usb_log_debug("has_individual_port_powering\n");
+			for (port = 0; port < hub_info->port_count; port++) {
+				opResult = usb_hub_set_port_feature(hub_info->control_pipe,
+				    port+1, USB_HUB_FEATURE_PORT_POWER);
+				if (opResult != EOK) {
+					usb_log_error("cannot power on port %d;  %d\n",
+					    port+1, opResult);
+				}
+			}
+		}else{
+			usb_log_debug("!has_individual_port_powering\n");
+			opResult = usb_hub_set_feature(hub_info->control_pipe,
+			    USB_HUB_FEATURE_C_HUB_LOCAL_POWER);
+			if (opResult != EOK) {
+				usb_log_error("cannot power hub;  %d\n",
+				  opResult);
+			}
+		}
+	}else{
+		usb_log_debug("!is_power_switched\n");
+	}
 	usb_log_debug2("freeing data\n");
-	free(serialized_descriptor);
-	free(descriptor->devices_removable);
+	//free(serialized_descriptor);
+	//free(descriptor->devices_removable);
 	free(descriptor);
 	return EOK;
 }
+
 /**
  * Set configuration of hub
@@ -147,5 +295,5 @@
  * @return error code
  */
-static int usb_hub_set_configuration(usb_hub_info_t * hub_info){
+static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {
 	//device descriptor
 	usb_standard_device_descriptor_t *std_descriptor
@@ -153,5 +301,5 @@
 	usb_log_debug("hub has %d configurations\n",
 	    std_descriptor->configuration_count);
-	if(std_descriptor->configuration_count<1){
+	if (std_descriptor->configuration_count < 1) {
 		usb_log_error("there are no configurations available\n");
 		return EINVAL;
@@ -173,5 +321,5 @@
 	}
 	usb_log_debug("\tused configuration %d\n",
-			config_descriptor->configuration_number);
+	    config_descriptor->configuration_number);
 
 	return EOK;
@@ -179,56 +327,13 @@
 
 /**
- * Initialize hub device driver fibril
- *
- * Creates hub representation and fibril that periodically checks hub`s status.
- * Hub representation is passed to the fibril.
- * @param usb_dev generic usb device information
- * @return error code
- */
-int usb_hub_add_device(usb_device_t * usb_dev){
-	if(!usb_dev) return EINVAL;
-	usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
-	//create hc connection
-	usb_log_debug("Initializing USB wire abstraction.\n");
-	int opResult = usb_hc_connection_initialize_from_device(
-			&hub_info->connection,
-			hub_info->usb_device->ddf_dev);
-	if(opResult != EOK){
-		usb_log_error("could not initialize connection to device, errno %d\n",
-				opResult);
-		free(hub_info);
-		return opResult;
-	}
-	
-	usb_pipe_start_session(hub_info->control_pipe);
-	//set hub configuration
-	opResult = usb_hub_set_configuration(hub_info);
-	if(opResult!=EOK){
-		usb_log_error("could not set hub configuration, errno %d\n",opResult);
-		free(hub_info);
-		return opResult;
-	}
-	//get port count and create attached_devs
-	opResult = usb_hub_process_hub_specific_info(hub_info);
-	if(opResult!=EOK){
-		usb_log_error("could not set hub configuration, errno %d\n",opResult);
-		free(hub_info);
-		return opResult;
-	}
-	usb_pipe_end_session(hub_info->control_pipe);
-
-
-	/// \TODO what is this?
-	usb_log_debug("Creating `hub' function.\n");
-	ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
-			fun_exposed, "hub");
-	assert(hub_fun != NULL);
-	hub_fun->ops = NULL;
-
-	int rc = ddf_fun_bind(hub_fun);
-	assert(rc == EOK);
-	rc = ddf_fun_add_to_class(hub_fun, "hub");
-	assert(rc == EOK);
-
+ * create and start fibril with hub control loop
+ *
+ * Before the fibril is started, the control pipe and host controller
+ * connection of the hub is open.
+ *
+ * @param hub_info hub representing structure
+ * @return error code
+ */
+static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info){
 	/*
 	 * The processing will require opened control pipe and connection
@@ -239,20 +344,14 @@
 	 * auto destruction, this could work better.
 	 */
-	rc = usb_pipe_start_session(&usb_dev->ctrl_pipe);
+	int rc = usb_hc_connection_open(&hub_info->connection);
 	if (rc != EOK) {
-		usb_log_error("Failed to start session on control pipe: %s.\n",
-		    str_error(rc));
-		goto leave;
-	}
-	rc = usb_hc_connection_open(&hub_info->connection);
-	if (rc != EOK) {
-		usb_pipe_end_session(&usb_dev->ctrl_pipe);
+		//usb_pipe_end_session(hub_info->control_pipe);
 		usb_log_error("Failed to open connection to HC: %s.\n",
 		    str_error(rc));
-		goto leave;
+		return rc;
 	}
 
 	rc = usb_device_auto_poll(hub_info->usb_device, 0,
-	    hub_port_changes_callback, ((hub_info->port_count+1) / 8) + 1,
+	    hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
 	    NULL, hub_info);
 	if (rc != EOK) {
@@ -266,197 +365,119 @@
 	    hub_info->usb_device->ddf_dev->name, hub_info->port_count);
 	return EOK;
-
-leave:
-	free(hub_info);
-
-	return rc;
-}
-
-
-//*********************************************
-//
-//  hub driver code, main loop and port handling
-//
-//*********************************************
-
-/**
- * triggers actions to connect non0removable devices
- *
- * This will trigger operations leading to activated non-removable device.
- * Control pipe of the hub must be open fo communication.
- * @param hub hub representation
- * @param descriptor usb hub descriptor
- * @return error code
- */
-static int usb_hub_trigger_connecting_non_removable_devices(usb_hub_info_t * hub,
-		usb_hub_descriptor_t * descriptor)
-{
-	usb_log_info("attaching non-removable devices(if any)\n");
+}
+
+//*********************************************
+//
+//  change handling functions
+//
+//*********************************************
+
+
+/**
+ * process hub over current change
+ *
+ * This means either to power off the hub or power it on.
+ * @param hub_info hub instance
+ * @param status hub status bitmask
+ * @return error code
+ */
+static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
+    usb_hub_status_t status) {
+	int opResult;
+	if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_OVER_CURRENT)){
+		opResult = usb_hub_clear_feature(hub_info->control_pipe,
+		    USB_HUB_FEATURE_HUB_LOCAL_POWER);
+		if (opResult != EOK) {
+			usb_log_error("cannot power off hub: %d\n",
+			    opResult);
+		}
+	} else {
+		opResult = usb_hub_set_feature(hub_info->control_pipe,
+		    USB_HUB_FEATURE_HUB_LOCAL_POWER);
+		if (opResult != EOK) {
+			usb_log_error("cannot power on hub: %d\n",
+			    opResult);
+		}
+	}
+	return opResult;
+}
+
+/**
+ * process hub power change
+ *
+ * If the power has been lost, reestablish it.
+ * If it was reestablished, re-power all ports.
+ * @param hub_info hub instance
+ * @param status hub status bitmask
+ * @return error code
+ */
+static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
+    usb_hub_status_t status) {
+	int opResult;
+	if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_LOCAL_POWER)) {
+		//restart power on hub
+		opResult = usb_hub_set_feature(hub_info->control_pipe,
+		    USB_HUB_FEATURE_HUB_LOCAL_POWER);
+		if (opResult != EOK) {
+			usb_log_error("cannot power on hub: %d\n",
+			    opResult);
+		}
+	} else {//power reestablished on hub- restart ports
+		size_t port;
+		for (port = 0; port < hub_info->port_count; ++port) {
+			opResult = usb_hub_set_port_feature(
+			    hub_info->control_pipe,
+			    port, USB_HUB_FEATURE_PORT_POWER);
+			if (opResult != EOK) {
+				usb_log_error("cannot power on port %d;  %d\n",
+				    port, opResult);
+			}
+		}
+	}
+	return opResult;
+}
+
+/**
+ * process hub interrupts
+ *
+ * The change can be either in the over-current condition or
+ * local-power lost condition.
+ * @param hub_info hub instance
+ */
+static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info) {
+	usb_log_debug("global interrupt on a hub\n");
+	usb_pipe_t *pipe = hub_info->control_pipe;
+	int opResult;
+
+	usb_port_status_t status;
+	size_t rcvd_size;
 	usb_device_request_setup_packet_t request;
-	int opResult;
-	size_t rcvd_size;
-	usb_port_status_t status;
-	uint8_t * non_removable_dev_bitmap = descriptor->devices_removable;
-	int port;
-	for(port=1;port<=descriptor->ports_count;++port){
-		bool is_non_removable =
-				((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
-		if(is_non_removable){
-			usb_log_debug("non-removable device on port %d\n",port);
-			usb_hub_set_port_status_request(&request, port);
-			opResult = usb_pipe_control_read(
-					hub->control_pipe,
-					&request, sizeof(usb_device_request_setup_packet_t),
-					&status, 4, &rcvd_size
-					);
-			if (opResult != EOK) {
-				usb_log_error("could not get port status of port %d errno:%d\n",
-						port, opResult);
-				return opResult;
-			}
-			//set the status change bit, so it will be noticed in driver loop
-			if(usb_port_dev_connected(&status)){
-				usb_hub_set_disable_port_feature_request(&request, port,
-						USB_HUB_FEATURE_PORT_CONNECTION);
-				opResult = usb_pipe_control_read(
-						hub->control_pipe,
-						&request, sizeof(usb_device_request_setup_packet_t),
-						&status, 4, &rcvd_size
-						);
-				if (opResult != EOK) {
-					usb_log_warning(
-							"could not clear port connection on port %d errno:%d\n",
-							port, opResult);
-				}
-				usb_log_debug("cleared port connection\n");
-				usb_hub_set_enable_port_feature_request(&request, port,
-						USB_HUB_FEATURE_PORT_ENABLE);
-				opResult = usb_pipe_control_read(
-						hub->control_pipe,
-						&request, sizeof(usb_device_request_setup_packet_t),
-						&status, 4, &rcvd_size
-						);
-				if (opResult != EOK) {
-					usb_log_warning(
-							"could not set port enabled on port %d errno:%d\n",
-							port, opResult);
-				}
-				usb_log_debug("port set to enabled - should lead to connection change\n");
-			}
-		}
-	}
-	/// \TODO this is just a debug code
-	for(port=1;port<=descriptor->ports_count;++port){
-		bool is_non_removable =
-				((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
-		if(is_non_removable){
-			usb_log_debug("port %d is non-removable\n",port);
-			usb_port_status_t status;
-			size_t rcvd_size;
-			usb_device_request_setup_packet_t request;
-			//int opResult;
-			usb_hub_set_port_status_request(&request, port);
-			//endpoint 0
-			opResult = usb_pipe_control_read(
-					hub->control_pipe,
-					&request, sizeof(usb_device_request_setup_packet_t),
-					&status, 4, &rcvd_size
-					);
-			if (opResult != EOK) {
-				usb_log_error("could not get port status %d\n",opResult);
-			}
-			if (rcvd_size != sizeof (usb_port_status_t)) {
-				usb_log_error("received status has incorrect size\n");
-			}
-			//something connected/disconnected
-			if (usb_port_connect_change(&status)) {
-				usb_log_debug("some connection changed\n");
-			}
-			usb_log_debug("status: %s\n",usb_debug_str_buffer(
-					(uint8_t *)&status,4,4));
-		}
-	}
-	return EOK;
-}
-
-
-/**
- * release default address used by given hub
- *
- * Also unsets hub->is_default_address_used. Convenience wrapper function.
- * @note hub->connection MUST be open for communication
- * @param hub hub representation
- * @return error code
- */
-static int usb_hub_release_default_address(usb_hub_info_t * hub){
-	int opResult = usb_hc_release_default_address(&hub->connection);
-	if(opResult!=EOK){
-		usb_log_error("could not release default address, errno %d\n",opResult);
-		return opResult;
-	}
-	hub->is_default_address_used = false;
-	return EOK;
-}
-
-/**
- * routine called when a device on port has been removed
- *
- * If the device on port had default address, it releases default address.
- * Otherwise does not do anything, because DDF does not allow to remove device
- * from it`s device tree.
- * @param hub hub representation
- * @param port port number, starting from 1
- */
-void usb_hub_removed_device(
-    usb_hub_info_t * hub,uint16_t port) {
-
-	int opResult = usb_hub_clear_port_feature(hub->control_pipe,
-				port, USB_HUB_FEATURE_C_PORT_CONNECTION);
-	if(opResult != EOK){
-		usb_log_warning("could not clear port-change-connection flag\n");
-	}
-	/** \TODO remove device from device manager - not yet implemented in
-	 * devide manager
-	 */
-	
-	//close address
-	if(hub->ports[port].attached_device.address >= 0){
-		/*uncomment this code to use it when DDF allows device removal
-		opResult = usb_hc_unregister_device(
-				&hub->connection, hub->attached_devs[port].address);
-		if(opResult != EOK) {
-			dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \
-			    "removed device: %d", opResult);
-		}
-		hub->attached_devs[port].address = 0;
-		hub->attached_devs[port].handle = 0;
-		 */
-	}else{
-		usb_log_warning("this is strange, disconnected device had no address\n");
-		//device was disconnected before it`s port was reset - return default address
-		usb_hub_release_default_address(hub);
-	}
-}
-
-
-/**
- * Process over current condition on port.
- * 
- * Turn off the power on the port.
- *
- * @param hub hub representation
- * @param port port number, starting from 1
- */
-void usb_hub_over_current( usb_hub_info_t * hub,
-		uint16_t port){
-	int opResult;
-	opResult = usb_hub_clear_port_feature(hub->control_pipe,
-	    port, USB_HUB_FEATURE_PORT_POWER);
-	if(opResult!=EOK){
-		usb_log_error("cannot power off port %d;  %d\n",
-				port, opResult);
-	}
-}
-
+	//int opResult;
+	usb_hub_set_hub_status_request(&request);
+	//endpoint 0
+
+	opResult = usb_pipe_control_read(
+	    pipe,
+	    &request, sizeof (usb_device_request_setup_packet_t),
+	    &status, 4, &rcvd_size
+	    );
+	if (opResult != EOK) {
+		usb_log_error("could not get hub status\n");
+		return;
+	}
+	if (rcvd_size != sizeof (usb_port_status_t)) {
+		usb_log_error("received status has incorrect size\n");
+		return;
+	}
+	//port reset
+	if (
+	    usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) {
+		usb_process_hub_over_current(hub_info, status);
+	}
+	if (
+	    usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) {
+		usb_process_hub_power_change(hub_info, status);
+	}
+}
 
 /**
Index: uspace/drv/usbhub/usbhub.h
===================================================================
--- uspace/drv/usbhub/usbhub.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/usbhub.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -37,13 +37,15 @@
 
 #include <ipc/devman.h>
-#include <usb/usb.h>
 #include <ddf/driver.h>
 
-#define NAME "usbhub"
-
 #include <usb/hub.h>
+#include <usb/classes/hub.h>
 
 #include <usb/pipes.h>
 #include <usb/devdrv.h>
+
+#include <fibril_synch.h>
+
+#define NAME "usbhub"
 
 #include "ports.h"
@@ -52,11 +54,11 @@
 
 /** Information about attached hub. */
-typedef struct {
+struct usb_hub_info_t{
 	/** Number of ports. */
 	size_t port_count;
 
-	/** Ports. */
+	/** attached device handles, for each port one */
 	usb_hub_port_t *ports;
-	
+
 	/** connection to hcd */
 	usb_hc_connection_t connection;
@@ -87,24 +89,12 @@
 	/** generic usb device data*/
 	usb_device_t * usb_device;
-} usb_hub_info_t;
+};
 
-/**
- * function running the hub-controlling loop.
- * @param hub_info_param hub info pointer
- */
-int usb_hub_control_loop(void * hub_info_param);
-
-/**
- * Check changes on specified hub
- * @param hub_info_param pointer to usb_hub_info_t structure
- * @return error code if there is problem when initializing communication with
- * hub, EOK otherwise
- */
-int usb_hub_check_hub_changes(usb_hub_info_t * hub_info_param);
-
-void usb_hub_removed_device(usb_hub_info_t *, uint16_t);
-void usb_hub_over_current(usb_hub_info_t *, uint16_t);
+//int usb_hub_control_loop(void * hub_info_param);
 
 int usb_hub_add_device(usb_device_t * usb_dev);
+
+bool hub_port_changes_callback(usb_device_t *dev,
+    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg);
 
 #endif
Index: uspace/drv/usbhub/usbhub_private.h
===================================================================
--- uspace/drv/usbhub/usbhub_private.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/usbhub_private.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -54,16 +54,6 @@
 //
 //************
-#define usb_new(type) (type*)malloc(sizeof(type))
 
 
-/**
- * Create hub structure instance
- *
- * Set the address and port count information most importantly.
- *
- * @param device
- * @param hc host controller phone
- * @return
- */
 usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device);
 
@@ -110,21 +100,81 @@
 
 /**
- * create uint8_t array with serialized descriptor
+ * Clear feature on hub port.
  *
- * @param descriptor
- * @return newly created serializd descriptor pointer
+ * @param hc Host controller telephone
+ * @param address Hub address
+ * @param port_index Port
+ * @param feature Feature selector
+ * @return Operation result
  */
-void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor);
+static inline int usb_hub_set_port_feature(usb_pipe_t *pipe,
+    int port_index,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
+		.request = USB_DEVREQ_SET_FEATURE,
+		.length = 0,
+		.index = port_index
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof(clear_request), NULL, 0);
+}
+
 
 /**
- * create deserialized desriptor structure out of serialized descriptor
+ * Clear feature on hub port.
  *
- * The serialized descriptor must be proper usb hub descriptor,
- * otherwise an eerror might occur.
+ * @param pipe pipe to hub control endpoint
+ * @param feature Feature selector
+ * @return Operation result
+ */
+static inline int usb_hub_clear_feature(usb_pipe_t *pipe,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
+		.request = USB_DEVREQ_CLEAR_FEATURE,
+		.length = 0,
+		.index = 0
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof(clear_request), NULL, 0);
+}
+
+/**
+ * Clear feature on hub port.
  *
- * @param sdescriptor serialized descriptor
- * @return newly created deserialized descriptor pointer
+ * @param pipe pipe to hub control endpoint
+ * @param feature Feature selector
+ * @return Operation result
  */
-usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * sdescriptor);
+static inline int usb_hub_set_feature(usb_pipe_t *pipe,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
+		.request = USB_DEVREQ_SET_FEATURE,
+		.length = 0,
+		.index = 0
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof(clear_request), NULL, 0);
+}
+
+
+void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t * descriptor);
+
+void usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor,
+    void * serialized_descriptor);
+
+usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
+    void * serialized_descriptor);
+
+void usb_deserialize_hub_desriptor(void * serialized_descriptor,
+    usb_hub_descriptor_t * descriptor);
 
 
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbhub/utils.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -56,60 +56,107 @@
 //hub descriptor utils
 
-void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
+/**
+ * create uint8_t array with serialized descriptor
+ *
+ * @param descriptor
+ * @return newly created serializd descriptor pointer
+ */
+void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t * descriptor) {
 	//base size
 	size_t size = 7;
 	//variable size according to port count
-	size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
+	size_t var_size = (descriptor->ports_count+7)/8;
 	size += 2 * var_size;
-	uint8_t * result = (uint8_t*) malloc(size);
+	uint8_t * result = malloc(size);
 	//size
-	result[0] = size;
+	if(result)
+		usb_serialize_hub_descriptor(descriptor,result);
+	return result;
+}
+
+/**
+ * serialize descriptor into given buffer
+ *
+ * The buffer size is not checked.
+ * @param descriptor
+ * @param serialized_descriptor
+ */
+void usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor,
+    void * serialized_descriptor) {
+	//base size
+	uint8_t * sdescriptor = serialized_descriptor;
+	size_t size = 7;
+	//variable size according to port count
+	size_t var_size = (descriptor->ports_count+7)/8;
+	size += 2 * var_size;
+	//size
+	sdescriptor[0] = size;
 	//descriptor type
-	result[1] = USB_DESCTYPE_HUB;
-	result[2] = descriptor->ports_count;
+	sdescriptor[1] = USB_DESCTYPE_HUB;
+	sdescriptor[2] = descriptor->ports_count;
 	/// @fixme handling of endianness??
-	result[3] = descriptor->hub_characteristics / 256;
-	result[4] = descriptor->hub_characteristics % 256;
-	result[5] = descriptor->pwr_on_2_good_time;
-	result[6] = descriptor->current_requirement;
+	sdescriptor[3] = descriptor->hub_characteristics / 256;
+	sdescriptor[4] = descriptor->hub_characteristics % 256;
+	sdescriptor[5] = descriptor->pwr_on_2_good_time;
+	sdescriptor[6] = descriptor->current_requirement;
 
 	size_t i;
 	for (i = 0; i < var_size; ++i) {
-		result[7 + i] = descriptor->devices_removable[i];
+		sdescriptor[7 + i] = descriptor->devices_removable[i];
 	}
 	for (i = 0; i < var_size; ++i) {
-		result[7 + var_size + i] = 255;
+		sdescriptor[7 + var_size + i] = 255;
 	}
+}
+
+
+/**
+ * create deserialized desriptor structure out of serialized descriptor
+ *
+ * The serialized descriptor must be proper usb hub descriptor,
+ * otherwise an eerror might occur.
+ *
+ * @param sdescriptor serialized descriptor
+ * @return newly created deserialized descriptor pointer
+ */
+usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
+void * serialized_descriptor) {
+	uint8_t * sdescriptor = serialized_descriptor;
+
+	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
+		usb_log_warning("trying to deserialize wrong descriptor %x\n",
+		    sdescriptor[1]);
+		return NULL;
+	}
+
+	usb_hub_descriptor_t * result = malloc(sizeof(usb_hub_descriptor_t));
+	if(result)
+		usb_deserialize_hub_desriptor(serialized_descriptor,result);
 	return result;
 }
 
-usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
-	uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
-
-	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
-		usb_log_warning("trying to deserialize wrong descriptor %x\n",sdescriptor[1]);
-		return NULL;
-	}
-
-	usb_hub_descriptor_t * result = usb_new(usb_hub_descriptor_t);
-	
-
-	result->ports_count = sdescriptor[2];
+/**
+ * deserialize descriptor into given pointer
+ * 
+ * @param serialized_descriptor
+ * @param descriptor
+ * @return
+ */
+void usb_deserialize_hub_desriptor(
+void * serialized_descriptor, usb_hub_descriptor_t * descriptor) {
+	uint8_t * sdescriptor = serialized_descriptor;
+	descriptor->ports_count = sdescriptor[2];
 	/// @fixme handling of endianness??
-	result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
-	result->pwr_on_2_good_time = sdescriptor[5];
-	result->current_requirement = sdescriptor[6];
-	size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0)
-			? 1 : 0);
-	result->devices_removable = (uint8_t*) malloc(var_size);
+	descriptor->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
+	descriptor->pwr_on_2_good_time = sdescriptor[5];
+	descriptor->current_requirement = sdescriptor[6];
+	size_t var_size = (descriptor->ports_count+7) / 8;
+	//descriptor->devices_removable = (uint8_t*) malloc(var_size);
 
 	size_t i;
 	for (i = 0; i < var_size; ++i) {
-		result->devices_removable[i] = sdescriptor[7 + i];
+		descriptor->devices_removable[i] = sdescriptor[7 + i];
 	}
-	return result;
 }
-
-
 
 /**
Index: uspace/drv/usbkbd/kbddev.c
===================================================================
--- uspace/drv/usbkbd/kbddev.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbkbd/kbddev.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -268,4 +268,8 @@
 static void usb_kbd_set_led(usb_kbd_t *kbd_dev) 
 {
+	if (kbd_dev->output_size == 0) {
+		return;
+	}
+
 	unsigned i = 0;
 	
@@ -544,5 +548,5 @@
  *                  according to HID Usage Tables.
  * @param count Number of key codes in report (size of the report).
- * @param modifiers Bitmap of modifiers (Ctrl, Alt, Shift, GUI).
+ * @param report_id
  * @param arg User-specified argument. Expects pointer to the keyboard device
  *            structure representing the keyboard.
@@ -551,5 +555,5 @@
  */
 static void usb_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
-    uint8_t modifiers, void *arg)
+    uint8_t report_id, void *arg)
 {
 	if (arg == NULL) {
@@ -562,5 +566,5 @@
 	assert(kbd_dev != NULL);
 
-	usb_log_debug("Got keys from parser (report id: %d): %s\n", modifiers, 
+	usb_log_debug("Got keys from parser (report id: %d): %s\n", report_id, 
 	    usb_debug_str_buffer(key_codes, count, 0));
 	
@@ -763,4 +767,7 @@
 	usb_hid_report_path_t *path = usb_hid_report_path();
 	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	
+	usb_hid_report_path_set_report_id(path, 0);
+	
 	kbd_dev->key_count = usb_hid_report_input_length(
 	    kbd_dev->parser, path, USB_HID_PATH_COMPARE_END);
@@ -796,5 +803,6 @@
 	
 	kbd_dev->led_output_size = usb_hid_report_output_size(kbd_dev->parser, 
-	    kbd_dev->led_path, USB_HID_PATH_COMPARE_END);
+	    kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
 	
 	usb_log_debug("Output report size (in items): %zu\n", 
Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbkbd/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -33,5 +33,5 @@
 /**
  * @file
- * Main routines of USB HID driver.
+ * Main routines of USB KBD driver.
  */
 
@@ -42,4 +42,5 @@
 
 #include <usb/devdrv.h>
+#include <usb/devpoll.h>
 
 #include "kbddev.h"
@@ -75,5 +76,5 @@
  * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
  */
-static int usbhid_try_add_device(usb_device_t *dev)
+static int usb_kbd_try_add_device(usb_device_t *dev)
 {
 	/* Create the function exposed under /dev/devices. */
@@ -105,5 +106,5 @@
 		usb_kbd_free(&kbd_dev);
 		return rc;
-	}	
+	}
 	
 	usb_log_debug("USB/HID KBD device structure initialized.\n");
@@ -195,20 +196,20 @@
  * @retval EREFUSED if the device is not supported.
  */
-static int usbhid_add_device(usb_device_t *dev)
+static int usb_kbd_add_device(usb_device_t *dev)
 {
-	usb_log_debug("usbhid_add_device()\n");
+	usb_log_debug("usb_kbd_add_device()\n");
 	
 	if (dev->interface_no < 0) {
 		usb_log_warning("Device is not a supported keyboard.\n");
-		usb_log_error("Failed to add HID device: endpoint not found."
-		    "\n");
+		usb_log_error("Failed to add USB KBD device: endpoint not "
+		    "found.\n");
 		return ENOTSUP;
 	}
 	
-	int rc = usbhid_try_add_device(dev);
+	int rc = usb_kbd_try_add_device(dev);
 	
 	if (rc != EOK) {
 		usb_log_warning("Device is not a supported keyboard.\n");
-		usb_log_error("Failed to add HID device: %s.\n",
+		usb_log_error("Failed to add KBD device: %s.\n",
 		    str_error(rc));
 		return rc;
@@ -224,13 +225,13 @@
 /* Currently, the framework supports only device adding. Once the framework
  * supports unplug, more callbacks will be added. */
-static usb_driver_ops_t usbhid_driver_ops = {
-        .add_device = usbhid_add_device,
+static usb_driver_ops_t usb_kbd_driver_ops = {
+        .add_device = usb_kbd_add_device,
 };
 
 
 /* The driver itself. */
-static usb_driver_t usbhid_driver = {
+static usb_driver_t usb_kbd_driver = {
         .name = NAME,
-        .ops = &usbhid_driver_ops,
+        .ops = &usb_kbd_driver_ops,
         .endpoints = usb_kbd_endpoints
 };
@@ -238,24 +239,11 @@
 /*----------------------------------------------------------------------------*/
 
-//static driver_ops_t kbd_driver_ops = {
-//	.add_device = usbhid_add_device,
-//};
-
-///*----------------------------------------------------------------------------*/
-
-//static driver_t kbd_driver = {
-//	.name = NAME,
-//	.driver_ops = &kbd_driver_ops
-//};
-
-/*----------------------------------------------------------------------------*/
-
 int main(int argc, char *argv[])
 {
-	printf(NAME ": HelenOS USB HID driver.\n");
+	printf(NAME ": HelenOS USB KBD driver.\n");
 
 	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
 
-	return usb_driver_main(&usbhid_driver);
+	return usb_driver_main(&usb_kbd_driver);
 }
 
Index: uspace/drv/usbkbd/usbkbd.ma
===================================================================
--- uspace/drv/usbkbd/usbkbd.ma	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbkbd/usbkbd.ma	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -1,2 +1,1 @@
-100 usb&interface&class=HID&subclass=0x01&protocol=0x01
-10 usb&interface&class=HID
+10 usb&interface&class=HID&subclass=0x01&protocol=0x01
Index: uspace/drv/usbmast/Makefile
===================================================================
--- uspace/drv/usbmast/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include
+BINARY = usbmast
+
+SOURCES = \
+	main.c \
+	mast.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmast/cmds.h
===================================================================
--- uspace/drv/usbmast/cmds.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/cmds.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,85 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef USB_USBMAST_CMDS_H_
+#define USB_USBMAST_CMDS_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint32_t dCBWSignature;
+	uint32_t dCBWTag;
+	uint32_t dCBWDataTransferLength;
+	uint8_t bmCBWFlags;
+	uint8_t bCBWLUN;
+	uint8_t bCBWBLength;
+	uint8_t CBWCB[16];
+} __attribute__((packed)) usb_massstor_cbw_t;
+
+typedef struct {
+	uint32_t dCSWSignature;
+	uint32_t dCSWTag;
+	uint32_t dCSWDataResidue;
+	uint8_t dCSWStatus;
+} __attribute__((packed)) usb_massstor_csw_t;
+
+static inline void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
+    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
+    uint8_t lun, uint8_t cmd_len, uint8_t *cmd)
+{
+	cbw->dCBWSignature = uint32_host2usb(0x43425355);
+	cbw->dCBWTag = tag;
+	cbw->dCBWDataTransferLength = transfer_length;
+
+	cbw->bmCBWFlags = 0;
+	if (dir == USB_DIRECTION_IN) {
+		cbw->bmCBWFlags |= (1 << 7);
+	}
+
+	/* Only lowest 4 bits. */
+	cbw->bCBWLUN = lun & 0x0F;
+
+	/* Only lowest 5 bits. */
+	cbw->bCBWBLength = cmd_len & 0x1F;
+
+	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/main.c
===================================================================
--- uspace/drv/usbmast/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,196 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB mass storage driver.
+ */
+#include <usb/devdrv.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/massstor.h>
+#include <errno.h>
+#include <str_error.h>
+#include "cmds.h"
+#include "scsi.h"
+#include "mast.h"
+
+#define NAME "usbmast"
+
+#define BULK_IN_EP 0
+#define BULK_OUT_EP 1
+
+#define GET_BULK_IN(dev) ((dev)->pipes[BULK_IN_EP].pipe)
+#define GET_BULK_OUT(dev) ((dev)->pipes[BULK_OUT_EP].pipe)
+
+static usb_endpoint_description_t bulk_in_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+static usb_endpoint_description_t bulk_out_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_OUT,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+
+usb_endpoint_description_t *mast_endpoints[] = {
+	&bulk_in_ep,
+	&bulk_out_ep,
+	NULL
+};
+
+#define BITS_GET_MASK(type, bitcount) (((type)(1 << (bitcount)))-1)
+#define BITS_GET_MID_MASK(type, bitcount, offset) \
+	((type)( BITS_GET_MASK(type, (bitcount) + (offset)) - BITS_GET_MASK(type, bitcount) ))
+#define BITS_GET(type, number, bitcount, offset) \
+	((type)( (number) & (BITS_GET_MID_MASK(type, bitcount, offset)) ) >> (offset))
+
+#define INQUIRY_RESPONSE_LENGTH 35
+
+static void try_inquiry(usb_device_t *dev)
+{
+	scsi_cmd_inquiry_t inquiry = {
+		.op_code = 0x12,
+		.lun_evpd = 0,
+		.page_code = 0,
+		.alloc_length = INQUIRY_RESPONSE_LENGTH,
+		.ctrl = 0
+	};
+	size_t response_len;
+	uint8_t response[INQUIRY_RESPONSE_LENGTH];
+
+	int rc;
+
+	rc = usb_massstor_data_in(GET_BULK_IN(dev), GET_BULK_OUT(dev),
+	    0xDEADBEEF, 0, (uint8_t *) &inquiry, sizeof(inquiry),
+	    response, INQUIRY_RESPONSE_LENGTH, &response_len);
+
+	if (rc != EOK) {
+		usb_log_error("Failed to probe device %s using %s: %s.\n",
+		   dev->ddf_dev->name, "SCSI:INQUIRY", str_error(rc));
+		return;
+	}
+
+	if (response_len < 8) {
+		usb_log_error("The SCSI response is too short.\n");
+		return;
+	}
+
+	/*
+	 * This is an ugly part of the code. We will parse the returned
+	 * data by hand and try to get as many useful data as possible.
+	 */
+	int device_type = BITS_GET(uint8_t, response[0], 5, 0);
+	int removable = BITS_GET(uint8_t, response[1], 1, 7);
+
+	usb_log_info("SCSI information for device `%s':\n", dev->ddf_dev->name);
+	usb_log_info("  - peripheral device type: %d\n", device_type);
+	usb_log_info("  - removable: %s\n", removable ? "yes" : "no");
+
+	if (response_len < 32) {
+		return;
+	}
+
+	char dev_vendor[9];
+	str_ncpy(dev_vendor, 9, (const char *) &response[8], 8);
+	usb_log_info("  - vendor: '%s'\n", dev_vendor);
+
+	char dev_product[9];
+	str_ncpy(dev_product, 9, (const char *) &response[16], 8);
+	usb_log_info("  - product: '%s'\n", dev_vendor);
+}
+
+/** Callback when new device is attached and recognized as a mass storage.
+ *
+ * @param dev Representation of a the USB device.
+ * @return Error code.
+ */
+static int usbmast_add_device(usb_device_t *dev)
+{
+	int rc;
+	const char *fun_name = "ctl";
+
+	ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
+	    fun_name);
+	if (ctl_fun == NULL) {
+		usb_log_error("Failed to create control function.\n");
+		return ENOMEM;
+	}
+	rc = ddf_fun_bind(ctl_fun);
+	if (rc != EOK) {
+		usb_log_error("Failed to bind control function: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	usb_log_info("Pretending to control mass storage `%s'.\n",
+	    dev->ddf_dev->name);
+	usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_IN_EP].pipe->endpoint_no,
+	    (size_t) dev->pipes[BULK_IN_EP].descriptor->max_packet_size);
+	usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_OUT_EP].pipe->endpoint_no,
+	    (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
+
+	try_inquiry(dev);
+
+	return EOK;
+}
+
+/** USB mass storage driver ops. */
+static usb_driver_ops_t usbmast_driver_ops = {
+	.add_device = usbmast_add_device,
+};
+
+/** USB mass storage driver. */
+static usb_driver_t usbmast_driver = {
+	.name = NAME,
+	.ops = &usbmast_driver_ops,
+	.endpoints = mast_endpoints
+};
+
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&usbmast_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/mast.c
===================================================================
--- uspace/drv/usbmast/mast.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/mast.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,139 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Generic functions for USB mass storage (implementation).
+ */
+#include "mast.h"
+#include "cmds.h"
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+
+bool usb_mast_verbose = true;
+
+#define MASTLOG(format, ...) \
+	do { \
+		if (usb_mast_verbose) { \
+			usb_log_debug("USB cl08: " format, ##__VA_ARGS__); \
+		} \
+	} while (false)
+
+/** Request data from mass storage device.
+ *
+ * @param bulk_in_pipe Bulk in pipe to the device.
+ * @param bulk_out_pipe Bulk out pipe to the device.
+ * @param tag Command block wrapper tag (automatically compared with answer).
+ * @param lun LUN index.
+ * @param cmd SCSI command buffer (in SCSI endianness).
+ * @param cmd_size Length of SCSI command @p cmd in bytes.
+ * @param in_buffer Buffer where to store the answer (CSW is not returned).
+ * @param in_buffer_size Size of the buffer (size of the request to the device).
+ * @param received_size Number of actually received bytes.
+ * @return Error code.
+ */
+int usb_massstor_data_in(usb_pipe_t *bulk_in_pipe, usb_pipe_t *bulk_out_pipe,
+    uint32_t tag, uint8_t lun, void *cmd, size_t cmd_size,
+    void *in_buffer, size_t in_buffer_size, size_t *received_size)
+{
+	int rc;
+	size_t act_size;
+
+	/* Prepare CBW - command block wrapper */
+	usb_massstor_cbw_t cbw;
+	usb_massstor_cbw_prepare(&cbw, tag, in_buffer_size,
+	    USB_DIRECTION_IN, lun, cmd_size, cmd);
+
+	/* First, send the CBW. */
+	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
+	MASTLOG("CBW '%s' sent: %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Try to retrieve the data from the device. */
+	act_size = 0;
+	rc = usb_pipe_read(bulk_in_pipe, in_buffer, in_buffer_size, &act_size);
+	MASTLOG("Received %zuB (%s): %s.\n", act_size,
+	    usb_debug_str_buffer((uint8_t *) in_buffer, act_size, 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Read CSW. */
+	usb_massstor_csw_t csw;
+	size_t csw_size;
+	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
+	MASTLOG("CSW '%s' received (%zuB): %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+	if (csw_size != sizeof(csw)) {
+		return ERANGE;
+	}
+
+	if (csw.dCSWTag != tag) {
+		return EBADCHECKSUM;
+	}
+
+	/*
+	 * Determine the actual return value from the CSW.
+	 */
+	if (csw.dCSWStatus != 0) {
+		// FIXME: better error code
+		// FIXME: distinguish 0x01 and 0x02
+		return EXDEV;
+	}
+
+	size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
+	if (residue > in_buffer_size) {
+		return ERANGE;
+	}
+	if (act_size != in_buffer_size - residue) {
+		return ERANGE;
+	}
+	if (received_size != NULL) {
+		*received_size = in_buffer_size - residue;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/mast.h
===================================================================
--- uspace/drv/usbmast/mast.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/mast.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,50 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * Generic functions for USB mass storage.
+ */
+
+#ifndef USB_USBMAST_MAST_H_
+#define USB_USBMAST_MAST_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/pipes.h>
+
+int usb_massstor_data_in(usb_pipe_t *, usb_pipe_t *, uint32_t, uint8_t,
+    void *, size_t, void *, size_t, size_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/scsi.h
===================================================================
--- uspace/drv/usbmast/scsi.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/scsi.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,54 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * SCSI related structures.
+ */
+
+#ifndef USB_USBMAST_SCSI_H_
+#define USB_USBMAST_SCSI_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint8_t op_code;
+	uint8_t lun_evpd;
+	uint8_t page_code;
+	uint16_t alloc_length;
+	uint8_t ctrl;
+} __attribute__((packed)) scsi_cmd_inquiry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/usbmast.ma
===================================================================
--- uspace/drv/usbmast/usbmast.ma	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/drv/usbmast/usbmast.ma	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,1 @@
+50 usb&interface&class=mass-storage&subclass=0x06&protocol=0x50
Index: uspace/drv/usbmid/main.c
===================================================================
--- uspace/drv/usbmid/main.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbmid/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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/usbmouse/main.c
===================================================================
--- uspace/drv/usbmouse/main.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/usbmouse/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -36,4 +36,5 @@
 #include "mouse.h"
 #include <usb/debug.h>
+#include <usb/devpoll.h>
 #include <errno.h>
 #include <str_error.h>
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/drv/vhc/connhost.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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,
@@ -328,16 +324,4 @@
 }
 
-static int reserve_default_address(ddf_fun_t *fun, usb_speed_t ignored)
-{
-	usb_address_keeping_reserve_default(&addresses);
-	return EOK;
-}
-
-static int release_default_address(ddf_fun_t *fun)
-{
-	usb_address_keeping_release_default(&addresses);
-	return EOK;
-}
-
 static int request_address(ddf_fun_t *fun, usb_speed_t ignored,
     usb_address_t *address)
@@ -392,6 +376,4 @@
 
 usbhc_iface_t vhc_iface = {
-	.reserve_default_address = reserve_default_address,
-	.release_default_address = release_default_address,
 	.request_address = request_address,
 	.bind_address = bind_address,
Index: uspace/lib/c/arch/mips32/include/atomic.h
===================================================================
--- uspace/lib/c/arch/mips32/include/atomic.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/c/arch/mips32/include/atomic.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -70,5 +70,4 @@
 		"	sc %0, %1\n"
 		"	beq %0, %4, 1b\n"	/* if the atomic operation failed, try again */
-		/*	nop	*/		/* nop is inserted automatically by compiler */
 		"	nop\n"
 		: "=&r" (tmp),
Index: uspace/lib/c/generic/adt/measured_strings.c
===================================================================
--- uspace/lib/c/generic/adt/measured_strings.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/c/generic/adt/measured_strings.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -74,5 +74,5 @@
 	new->length = length;
 	new->value = ((uint8_t *) new) + sizeof(measured_string_t);
-	// append terminating zero explicitly - to be safe
+	/* Append terminating zero explicitly - to be safe */
 	memcpy(new->value, string, new->length);
 	new->value[new->length] = '\0';
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/c/generic/async.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -1586,12 +1586,14 @@
  * @param dst     Address of the beginning of the destination buffer.
  * @param size    Size of the destination buffer.
+ * @param flags   Flags to control the data transfer.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int async_data_read_start(int phoneid, void *dst, size_t size)
-{
-	return async_req_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
-	    (sysarg_t) size);
+int
+async_data_read_start_generic(int phoneid, void *dst, size_t size, int flags)
+{
+	return async_req_3_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
+	    (sysarg_t) size, (sysarg_t) flags);
 }
 
@@ -1683,12 +1685,15 @@
  * @param src     Address of the beginning of the source buffer.
  * @param size    Size of the source buffer.
+ * @param flags   Flags to control the data transfer.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int async_data_write_start(int phoneid, const void *src, size_t size)
-{
-	return async_req_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
-	    (sysarg_t) size);
+int
+async_data_write_start_generic(int phoneid, const void *src, size_t size,
+    int flags)
+{
+	return async_req_3_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
+	    (sysarg_t) size, (sysarg_t) flags);
 }
 
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -378,5 +378,6 @@
 	
 	req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer);
-	rc = async_data_read_start(vfs_phone, (void *)buf, nbyte);
+	rc = async_data_read_start_generic(vfs_phone, (void *) buf, nbyte,
+	    IPC_XF_RESTRICT);
 	if (rc != EOK) {
 		vfs_exchange_end(vfs_phone);
@@ -407,5 +408,6 @@
 	
 	req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
-	rc = async_data_write_start(vfs_phone, (void *)buf, nbyte);
+	rc = async_data_write_start_generic(vfs_phone, (void *) buf, nbyte,
+	    IPC_XF_RESTRICT);
 	if (rc != EOK) {
 		vfs_exchange_end(vfs_phone);
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/c/include/async.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -341,5 +341,8 @@
 
 extern aid_t async_data_read(int, void *, size_t, ipc_call_t *);
-extern int async_data_read_start(int, void *, size_t);
+#define async_data_read_start(p, buf, len) \
+	async_data_read_start_generic((p), (buf), (len), IPC_XF_NONE)
+
+extern int async_data_read_start_generic(int, void *, size_t, int);
 extern bool async_data_read_receive(ipc_callid_t *, size_t *);
 extern int async_data_read_finalize(ipc_callid_t, const void *, size_t);
@@ -380,5 +383,8 @@
 	    (arg4), (answer))
 
-extern int async_data_write_start(int, const void *, size_t);
+#define async_data_write_start(p, buf, len) \
+	async_data_write_start_generic((p), (buf), (len), IPC_XF_NONE)
+
+extern int async_data_write_start_generic(int, const void *, size_t, int);
 extern bool async_data_write_receive(ipc_callid_t *, size_t *);
 extern int async_data_write_finalize(ipc_callid_t, void *, size_t);
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -45,4 +45,6 @@
 	/** Interface provided by USB host controller. */
 	USBHC_DEV_IFACE,
+	/** Interface provided by USB HID devices. */
+	USBHID_DEV_IFACE,
 
 	DEV_IFACE_MAX
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/drv/generic/dev_iface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -43,4 +43,5 @@
 #include "remote_usb.h"
 #include "remote_usbhc.h"
+#include "remote_usbhid.h"
 #include "remote_pci.h"
 
@@ -51,5 +52,6 @@
 		&remote_pci_iface,
 		&remote_usb_iface,
-		&remote_usbhc_iface
+		&remote_usbhc_iface,
+		&remote_usbhid_iface
 	}
 };
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/drv/generic/driver.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -47,4 +47,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <str_error.h>
 #include <ctype.h>
 #include <errno.h>
@@ -402,5 +403,5 @@
 			    get_remote_method(rem_iface, iface_method_idx);
 			if (iface_method_ptr == NULL) {
-				// the interface has not such method
+				/* The interface has not such method */
 				printf("%s: driver_connection_gen error - "
 				    "invalid interface method.", driver->name);
@@ -655,4 +656,6 @@
 int ddf_driver_main(driver_t *drv)
 {
+	int rc;
+
 	/*
 	 * Remember the driver structure - driver_ops will be called by generic
@@ -668,9 +671,21 @@
 	
 	/*
-	 * Register driver by device manager with generic handler for incoming
-	 * connections.
+	 * Register driver with device manager using generic handler for
+	 * incoming connections.
 	 */
-	devman_driver_register(driver->name, driver_connection);
-	
+	rc = devman_driver_register(driver->name, driver_connection);
+	if (rc != EOK) {
+		printf("Error: Failed to register driver with device manager "
+		    "(%s).\n", (rc == EEXISTS) ? "driver already started" :
+		    str_error(rc));
+		
+		return 1;
+	}
+	
+	/* Return success from the task since server has started. */
+	rc = task_retval(0);
+	if (rc != EOK)
+		return 1;
+
 	async_manager();
 	
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -50,6 +50,4 @@
 static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
@@ -61,7 +59,4 @@
 /** Remote USB host controller interface operations. */
 static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
-	remote_usbhc_reserve_default_address,
-	remote_usbhc_release_default_address,
-
 	remote_usbhc_request_address,
 	remote_usbhc_bind_address,
@@ -129,36 +124,4 @@
 }
 
-void remote_usbhc_reserve_default_address(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-
-	if (!usb_iface->reserve_default_address) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-	
-	usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
-	
-	int rc = usb_iface->reserve_default_address(fun, speed);
-
-	async_answer_0(callid, rc);
-}
-
-void remote_usbhc_release_default_address(ddf_fun_t *fun, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-
-	if (!usb_iface->release_default_address) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	int rc = usb_iface->release_default_address(fun);
-
-	async_answer_0(callid, rc);
-}
-
 void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
@@ -270,5 +233,4 @@
 	}
 
-	size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
 	usb_target_t target = {
 		.address = DEV_IPC_GET_ARG1(*call),
@@ -300,5 +262,5 @@
 	trans->size = len;
 
-	rc = transfer_func(fun, target, max_packet_size,
+	rc = transfer_func(fun, target,
 	    buffer, len,
 	    callback_out, trans);
@@ -326,5 +288,4 @@
 	}
 
-	size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
 	usb_target_t target = {
 		.address = DEV_IPC_GET_ARG1(*call),
@@ -348,5 +309,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 +375,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 +410,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 +437,4 @@
 		.endpoint = DEV_IPC_GET_ARG2(*call)
 	};
-	size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
 
 	int rc;
@@ -515,5 +474,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 +496,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/generic/remote_usbhid.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhid.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/drv/generic/remote_usbhid.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2010-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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "usbhid_iface.h"
+#include "ddf/driver.h"
+
+static void remote_usbhid_get_event_length(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhid_get_event(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+// static void remote_usbhid_(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB HID interface operations. */
+static remote_iface_func_ptr_t remote_usbhid_iface_ops [] = {
+	remote_usbhid_get_event_length,
+	remote_usbhid_get_event
+};
+
+/** Remote USB HID interface structure.
+ */
+remote_iface_t remote_usbhid_iface = {
+	.method_count = sizeof(remote_usbhid_iface_ops) /
+	    sizeof(remote_usbhid_iface_ops[0]),
+	.methods = remote_usbhid_iface_ops
+};
+
+usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+
+void remote_usbhid_get_event_length(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
+
+	if (!hid_iface->get_event_length) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int len = hid_iface->get_event_length(fun);
+	if (len == 0) {
+		len = EEMPTY;
+	}
+	if (len < 0) {
+		async_answer_0(callid, len);
+	} else {
+		async_answer_1(callid, EOK, len);
+	}
+}
+
+void remote_usbhid_get_event(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
+
+	if (!hid_iface->get_event) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	unsigned int flags = DEV_IPC_GET_ARG1(*call);
+
+	size_t len;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &len)) {
+		async_answer_0(callid, EPARTY);
+		return;
+	}
+	/* Check that length is even number. Truncate otherwise. */
+	if ((len % 2) == 1) {
+		len--;
+	}
+	if (len == 0) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_0(callid, EINVAL);
+	}
+
+	int rc;
+
+	size_t items = len / 2;
+	uint16_t *usage_pages_and_usages = malloc(sizeof(uint16_t) * len);
+	if (usage_pages_and_usages == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+	}
+
+	size_t act_items;
+	int rc = hid_iface->get_event(fun, usage_pages_and_usages,
+	    usage_pages_and_usages + items, items, &act_items, flags);
+	if (rc != EOK) {
+		free(usage_pages_and_usages);
+		async_answer_0(data_callid, rc);
+		async_answer_0(callid, rc);
+	}
+	if (act_items >= items) {
+		/* This shall not happen. */
+		// FIXME: how about an assert here?
+		act_items = items;
+	}
+
+	async_data_read_finalize(data_callid, usage_pages_and_usages,
+	    act_items * 2 * sizeof(uint16_t));
+
+	free(usage_pages_and_usages);
+
+	async_answer_0(callid, EOK);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_usbhid.h
===================================================================
--- uspace/lib/drv/include/remote_usbhid.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/drv/include/remote_usbhid.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,44 @@
+/*
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_USBHID_H_
+#define LIBDRV_REMOTE_USBHID_H_
+
+remote_iface_t remote_usbhid_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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
@@ -85,19 +84,4 @@
  */
 typedef enum {
-	/** Reserve usage of default address.
-	 * This call informs the host controller that the caller will be
-	 * using default USB address. It is duty of the HC driver to ensure
-	 * that only single entity will have it reserved.
-	 * The address is returned via IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS.
-	 * The caller can start using the address after receiving EOK
-	 * answer.
-	 */
-	IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS,
-
-	/** Release usage of default address.
-	 * @see IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS
-	 */
-	IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS,
-
 	/** Asks for address assignment by host controller.
 	 * Answer:
@@ -169,9 +153,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 +189,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 +197,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 +209,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 +222,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/drv/include/usbhid_iface.h
===================================================================
--- uspace/lib/drv/include/usbhid_iface.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/drv/include/usbhid_iface.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libdrv
+ * @{
+ */
+/** @file
+ * USB HID interface definition.
+ */
+
+#ifndef LIBDRV_USBHID_IFACE_H_
+#define LIBDRV_USBHID_IFACE_H_
+
+#include "ddf/driver.h"
+#include <usb/usb.h>
+
+/** IPC methods for USB HID device interface. */
+typedef enum {
+	/** Get number of events reported in single burst.
+	 * Parameters: none
+	 * Answer:
+	 * - EOK (expected always as long as device support USB HID interface)
+	 * Parameters of the answer:
+	 * - number of items
+	 */
+	IPC_M_USBHID_GET_EVENT_LENGTH,
+	/** Get single event from the HID device.
+	 * The word single refers to set of individual events that were
+	 * available at particular point in time.
+	 * Parameters:
+	 * - flags
+	 * The call is followed by data read expecting two concatenated
+	 * arrays.
+	 * Answer:
+	 * - EOK - events returned
+	 * - EAGAIN - no event ready (only in non-blocking mode)
+	 *
+	 * It is okay if the client requests less data. Extra data must
+	 * be truncated by the driver.
+	 */
+	IPC_M_USBHID_GET_EVENT
+} usbhid_iface_funcs_t;
+
+/** USB HID interface flag - return immediately if no data are available. */
+#define USBHID_IFACE_FLAG_NON_BLOCKING (1 << 0)
+
+/** USB HID device communication interface. */
+typedef struct {
+	/** Get number of items in the event.
+	 *
+	 * @param[in] fun DDF function answering the request.
+	 * @return Number of events or error code.
+	 */
+	int (*get_event_length)(ddf_fun_t *fun);
+
+	/** Get single event from the HID device.
+	 *
+	 * @param[in] fun DDF function answering the request.
+	 * @param[out] usage_page Array of usage pages and usages.
+	 * @param[out] usage Array of data (1:1 with @p usage).
+	 * @param[in] size Size of @p usage and @p data arrays.
+	 * @param[out] act_size Actual number of returned events.
+	 * @param[in] flags Flags (see USBHID_IFACE_FLAG_*).
+	 * @return Error code.
+	 */
+	int (*get_event)(ddf_fun_t *fun,
+	    uint16_t *usage_page, uint16_t *usage, size_t size, size_t *act_size,
+	    unsigned int flags);
+} usbhid_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/net/generic/generic.c
===================================================================
--- uspace/lib/net/generic/generic.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/generic/generic.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -106,5 +106,5 @@
 		return EBADMEM;
 
-	// request the address
+	/* Request the address */
 	message_id = async_send_1(phone, (sysarg_t) message,
 	    (sysarg_t) device_id, NULL);
@@ -112,7 +112,7 @@
 	async_wait_for(message_id, &result);
 
-	// if not successful
+	/* If not successful */
 	if ((string == EOK) && (result != EOK)) {
-		// clear the data
+		/* Clear the data */
 		free(*address);
 		free(*data);
@@ -242,5 +242,5 @@
 		return EBADMEM;
 
-	// request the translation
+	/* Request the translation */
 	message_id = async_send_3(phone, (sysarg_t) message,
 	    (sysarg_t) device_id, (sysarg_t) count, (sysarg_t) service, NULL);
@@ -249,7 +249,7 @@
 	async_wait_for(message_id, &result);
 
-	// if not successful
+	/* If not successful */
 	if ((string == EOK) && (result != EOK)) {
-		// clear the data
+		/* Clear the data */
 		free(*translation);
 		free(*data);
Index: uspace/lib/net/generic/net_checksum.c
===================================================================
--- uspace/lib/net/generic/net_checksum.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/generic/net_checksum.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -52,5 +52,5 @@
 uint16_t compact_checksum(uint32_t sum)
 {
-	// shorten to the 16 bits
+	/* Shorten to the 16 bits */
 	while (sum >> 16)
 		sum = (sum & 0xffff) + (sum >> 16);
@@ -72,9 +72,9 @@
 	size_t index;
 
-	// sum all the 16 bit fields
+	/* Sum all the 16 bit fields */
 	for (index = 0; index + 1 < length; index += 2)
 		seed += (data[index] << 8) + data[index + 1];
 
-	// last odd byte with zero padding
+	/* Last odd byte with zero padding */
 	if (index + 1 == length)
 		seed += data[index] << 8;
@@ -94,39 +94,39 @@
 	size_t index;
 
-	// process full bytes
+	/* Process full bytes */
 	while (length >= 8) {
-		// add the data
+		/* Add the data */
 		seed ^= (*data) << 24;
 		
-		// for each added bit
+		/* For each added bit */
 		for (index = 0; index < 8; ++index) {
-			// if the first bit is set
+			/* If the first bit is set */
 			if (seed & 0x80000000) {
-				// shift and divide the checksum
+				/* Shift and divide the checksum */
 				seed = (seed << 1) ^ ((uint32_t) CRC_DIVIDER_BE);
 			} else {
-				// shift otherwise
+				/* Shift otherwise */
 				seed <<= 1;
 			}
 		}
 		
-		// move to the next byte
+		/* Move to the next byte */
 		++data;
 		length -= 8;
 	}
 
-	// process the odd bits
+	/* Process the odd bits */
 	if (length > 0) {
-		// add the data with zero padding
+		/* Add the data with zero padding */
 		seed ^= ((*data) & (0xff << (8 - length))) << 24;
 		
-		// for each added bit
+		/* For each added bit */
 		for (index = 0; index < length; ++index) {
-			// if the first bit is set
+			/* If the first bit is set */
 			if (seed & 0x80000000) {
-				// shift and divide the checksum
+				/* Shift and divide the checksum */
 				seed = (seed << 1) ^ ((uint32_t) CRC_DIVIDER_BE);
 			} else {
-				// shift otherwise
+				/* Shift otherwise */
 				seed <<= 1;
 			}
@@ -148,38 +148,38 @@
 	size_t index;
 
-	// process full bytes
+	/* Process full bytes */
 	while (length >= 8) {
-		// add the data
+		/* Add the data */
 		seed ^= (*data);
 		
-		// for each added bit
+		/* For each added bit */
 		for (index = 0; index < 8; ++index) {
-			// if the last bit is set
+			/* If the last bit is set */
 			if (seed & 1) {
-				// shift and divide the checksum
+				/* Shift and divide the checksum */
 				seed = (seed >> 1) ^ ((uint32_t) CRC_DIVIDER_LE);
 			} else {
-				// shift otherwise
+				/* Shift otherwise */
 				seed >>= 1;
 			}
 		}
 		
-		// move to the next byte
+		/* Move to the next byte */
 		++data;
 		length -= 8;
 	}
 
-	// process the odd bits
+	/* Process the odd bits */
 	if (length > 0) {
-		// add the data with zero padding
+		/* Add the data with zero padding */
 		seed ^= (*data) >> (8 - length);
 		
 		for (index = 0; index < length; ++index) {
-			// if the last bit is set
+			/* If the last bit is set */
 			if (seed & 1) {
-				// shift and divide the checksum
+				/* Shift and divide the checksum */
 				seed = (seed >> 1) ^ ((uint32_t) CRC_DIVIDER_LE);
 			} else {
-				// shift otherwise
+				/* Shift otherwise */
 				seed >>= 1;
 			}
@@ -198,5 +198,5 @@
 uint16_t flip_checksum(uint16_t checksum)
 {
-	// flip, zero is returned as 0xFFFF (not flipped)
+	/* Flip, zero is returned as 0xFFFF (not flipped) */
 	checksum = ~checksum;
 	return checksum ? checksum : IP_CHECKSUM_ZERO;
@@ -216,5 +216,5 @@
 uint16_t ip_checksum(uint8_t *data, size_t length)
 {
-	// compute, compact and flip the data checksum
+	/* Compute, compact and flip the data checksum */
 	return flip_checksum(compact_checksum(compute_checksum(0, data,
 	    length)));
Index: uspace/lib/net/generic/packet_client.c
===================================================================
--- uspace/lib/net/generic/packet_client.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/generic/packet_client.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -267,5 +267,5 @@
 		return NULL;
 
-	// get a new packet
+	/* Get a new packet */
 	copy = packet_get_4_remote(phone, PACKET_DATA_LENGTH(packet),
 	    PACKET_MAX_ADDRESS_LENGTH(packet), packet->max_prefix,
@@ -274,10 +274,10 @@
 		return NULL;
 
-	// get addresses
+	/* Get addresses */
 	addrlen = packet_get_addr(packet, &src, &dest);
-	// copy data
+	/* Copy data */
 	if ((packet_copy_data(copy, packet_get_data(packet),
 	    PACKET_DATA_LENGTH(packet)) == EOK) &&
-	    // copy addresses if present
+	    /* Copy addresses if present */
 	    ((addrlen <= 0) ||
 	    (packet_set_addr(copy, src, dest, addrlen) == EOK))) {
Index: uspace/lib/net/il/ip_client.c
===================================================================
--- uspace/lib/net/il/ip_client.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/il/ip_client.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -124,5 +124,6 @@
 
 	// TODO IPv6
-/*	case AF_INET6:
+#if 0
+	case AF_INET6:
 		if (addrlen != sizeof(struct sockaddr_in6))
 			return EINVAL;
@@ -130,5 +131,5 @@
 		address_in6 = (struct sockaddr_in6 *) addr;
 		return EOK;
-*/
+#endif
 
 	default:
@@ -159,6 +160,8 @@
 	size_t padding;
 
-	// compute the padding if IP options are set
-	// multiple of 4 bytes
+	/*
+	 * Compute the padding if IP options are set
+	 * multiple of 4 bytes
+	 */
 	padding =  ipopt_length % 4;
 	if (padding) {
@@ -167,14 +170,14 @@
 	}
 
-	// prefix the header
+	/* Prefix the header */
 	data = (uint8_t *) packet_prefix(packet, sizeof(ip_header_t) + padding);
 	if (!data)
 		return ENOMEM;
 
-	// add the padding
+	/* Add the padding */
 	while (padding--)
 		data[sizeof(ip_header_t) + padding] = IPOPT_NOOP;
 
-	// set the header
+	/* Set the header */
 	header = (ip_header_t *) data;
 	header->header_length = IP_COMPUTE_HEADER_LENGTH(sizeof(ip_header_t) +
Index: uspace/lib/net/tl/icmp_client.c
===================================================================
--- uspace/lib/net/tl/icmp_client.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/tl/icmp_client.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -81,5 +81,5 @@
 		*mtu = header->un.frag.mtu;
 
-	// remove debug dump
+	/* Remove debug dump */
 #ifdef CONFIG_DEBUG
 	printf("ICMP error %d (%d) in packet %d\n", header->type, header->code,
Index: uspace/lib/net/tl/socket_core.c
===================================================================
--- uspace/lib/net/tl/socket_core.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/tl/socket_core.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -91,11 +91,11 @@
 	int packet_id;
 
-	// if bound
+	/* If bound */
 	if (socket->port) {
-		// release the port
+		/* Release the port */
 		socket_port_release(global_sockets, socket);
 	}
 	
-	// release all received packets
+	/* Release all received packets */
 	while ((packet_id = dyn_fifo_pop(&socket->received)) >= 0)
 		pq_release_remote(packet_phone, packet_id);
@@ -166,5 +166,5 @@
 	int rc;
 
-	// create a wrapper
+	/* Create a wrapper */
 	socket_ref = malloc(sizeof(*socket_ref));
 	if (!socket_ref)
@@ -172,5 +172,5 @@
 
 	*socket_ref = socket;
-	// add the wrapper
+	/* Add the wrapper */
 	rc = socket_port_map_add(&socket_port->map, key, key_length,
 	    socket_ref);
@@ -206,5 +206,5 @@
 	int rc;
 
-	// create a wrapper
+	/* Create a wrapper */
 	socket_port = malloc(sizeof(*socket_port));
 	if (!socket_port)
@@ -221,5 +221,5 @@
 		goto fail;
 	
-	// register the incomming port
+	/* Register the incoming port */
 	rc = socket_ports_add(global_sockets, port, socket_port);
 	if (rc < 0)
@@ -277,25 +277,25 @@
 		
 		address_in = (struct sockaddr_in *) addr;
-		// find the socket
+		/* Find the socket */
 		socket = socket_cores_find(local_sockets, socket_id);
 		if (!socket)
 			return ENOTSOCK;
 		
-		// bind a free port?
+		/* Bind a free port? */
 		if (address_in->sin_port <= 0)
 			return socket_bind_free_port(global_sockets, socket,
 			     free_ports_start, free_ports_end, last_used_port);
 		
-		// try to find the port
+		/* Try to find the port */
 		socket_port = socket_ports_find(global_sockets,
 		    ntohs(address_in->sin_port));
 		if (socket_port) {
-			// already used
+			/* Already used */
 			return EADDRINUSE;
 		}
 		
-		// if bound
+		/* If bound */
 		if (socket->port) {
-			// release the port
+			/* Release the port */
 			socket_port_release(global_sockets, socket);
 		}
@@ -333,5 +333,5 @@
 	int index;
 
-	// from the last used one
+	/* From the last used one */
 	index = last_used_port;
 	
@@ -339,18 +339,18 @@
 		++index;
 		
-		// til the range end
+		/* Till the range end */
 		if (index >= free_ports_end) {
-			// start from the range beginning
+			/* Start from the range beginning */
 			index = free_ports_start - 1;
 			do {
 				++index;
-				// til the last used one
+				/* Till the last used one */
 				if (index >= last_used_port) {
-					// none found
+					/* None found */
 					return ENOTCONN;
 				}
 			} while (socket_ports_find(global_sockets, index));
 			
-			// found, break immediately
+			/* Found, break immediately */
 			break;
 		}
@@ -376,5 +376,7 @@
 
 	count = 0;
-//	socket_id = socket_globals.last_id;
+#if 0
+	socket_id = socket_globals.last_id;
+#endif
 	do {
 		if (count < SOCKET_ID_TRIES) {
@@ -384,12 +386,14 @@
 			socket_id = 1;
 			++count;
-		// only this branch for last_id
+		/* Only this branch for last_id */
 		} else {
 			if (socket_id < INT_MAX) {
 				++ socket_id;
-/*			} else if(socket_globals.last_id) {
-*				socket_globals.last_id = 0;
-*				socket_id = 1;
-*/			} else {
+#if 0
+			} else if(socket_globals.last_id) {
+				socket_globals.last_id = 0;
+				socket_id = 1;
+#endif
+			} else {
 				return ELIMIT;
 			}
@@ -425,5 +429,5 @@
 		return EINVAL;
 	
-	// store the socket
+	/* Store the socket */
 	if (*socket_id <= 0) {
 		positive = (*socket_id == 0);
@@ -441,5 +445,5 @@
 		return ENOMEM;
 	
-	// initialize
+	/* Initialize */
 	socket->phone = app_phone;
 	socket->port = -1;
@@ -493,10 +497,10 @@
 	int accepted_id;
 
-	// find the socket
+	/* Find the socket */
 	socket = socket_cores_find(local_sockets, socket_id);
 	if (!socket)
 		return ENOTSOCK;
 	
-	// destroy all accepted sockets
+	/* Destroy all accepted sockets */
 	while ((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0)
 		socket_destroy(packet_phone, accepted_id, local_sockets,
@@ -535,13 +539,13 @@
 	next_packet = pq_next(packet);
 	if (!next_packet) {
-		// write all if only one fragment
+		/* Write all if only one fragment */
 		rc = data_reply(packet_get_data(packet),
 		    packet_get_data_length(packet));
 		if (rc != EOK)
 			return rc;
-		// store the total length
+		/* Store the total length */
 		*length = packet_get_data_length(packet);
 	} else {
-		// count the packet fragments
+		/* Count the packet fragments */
 		fragments = 1;
 		next_packet = pq_next(packet);
@@ -549,5 +553,5 @@
 			++fragments;
 		
-		// compute and store the fragment lengths
+		/* Compute and store the fragment lengths */
 		lengths = (size_t *) malloc(sizeof(size_t) * fragments +
 		    sizeof(size_t));
@@ -565,5 +569,5 @@
 		}
 		
-		// write the fragment lengths
+		/* Write the fragment lengths */
 		rc = data_reply(lengths, sizeof(int) * (fragments + 1));
 		if (rc != EOK) {
@@ -573,5 +577,5 @@
 		next_packet = packet;
 		
-		// write the fragments
+		/* Write the fragments */
 		for (index = 0; index < fragments; ++index) {
 			rc = data_reply(packet_get_data(next_packet),
@@ -584,5 +588,5 @@
 		}
 		
-		// store the total length
+		/* Store the total length */
 		*length = lengths[fragments];
 		free(lengths);
@@ -636,8 +640,8 @@
 		return;
 	
-	// find ports
+	/* Find ports */
 	socket_port = socket_ports_find(global_sockets, socket->port);
 	if (socket_port) {
-		// find the socket
+		/* Find the socket */
 		socket_ref = socket_port_map_find(&socket_port->map,
 		    socket->key, socket->key_length);
@@ -646,13 +650,13 @@
 			--socket_port->count;
 			
-			// release if empty
+			/* Release if empty */
 			if (socket_port->count <= 0) {
-				// destroy the map
+				/* Destroy the map */
 				socket_port_map_destroy(&socket_port->map, free);
-				// release the port
+				/* Release the port */
 				socket_ports_exclude(global_sockets,
 				    socket->port, free);
 			} else {
-				// remove
+				/* Remove */
 				socket_port_map_exclude(&socket_port->map,
 				    socket->key, socket->key_length, free);
@@ -685,10 +689,10 @@
 	int rc;
 
-	// find ports
+	/* Find ports */
 	socket_port = socket_ports_find(global_sockets, port);
 	if (!socket_port)
 		return ENOENT;
 	
-	// add the socket
+	/* Add the socket */
 	rc = socket_port_add_core(socket_port, socket, key, key_length);
 	if (rc != EOK)
Index: uspace/lib/net/tl/tl_common.c
===================================================================
--- uspace/lib/net/tl/tl_common.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/net/tl/tl_common.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -255,5 +255,5 @@
 	int length;
 
-	// detach the first packet and release the others
+	/* Detach the first packet and release the others */
 	next = pq_detach(packet);
 	if (next)
@@ -262,6 +262,8 @@
 	length = packet_get_addr(packet, &src, NULL);
 	if ((length > 0) && (!error) && (icmp_phone >= 0) &&
-	    // set both addresses to the source one (avoids the source address
-	    // deletion before setting the destination one)
+	    /*
+	     * Set both addresses to the source one (avoids the source address
+	     * deletion before setting the destination one)
+	     */
 	    (packet_set_addr(packet, src, src, (size_t) length) == EOK)) {
 		return EOK;
@@ -299,9 +301,9 @@
 		return EINVAL;
 
-	// get the data length
+	/* Get the data length */
 	if (!async_data_write_receive(&callid, &length))
 		return EINVAL;
 
-	// get a new packet
+	/* Get a new packet */
 	*packet = packet_get_4_remote(packet_phone, length, dimension->addr_len,
 	    prefix + dimension->prefix, dimension->suffix);
@@ -309,5 +311,5 @@
 		return ENOMEM;
 
-	// allocate space in the packet
+	/* Allocate space in the packet */
 	data = packet_suffix(*packet, length);
 	if (!data) {
@@ -316,5 +318,5 @@
 	}
 
-	// read the data into the packet
+	/* Read the data into the packet */
 	rc = async_data_write_finalize(callid, data, length);
 	if (rc != EOK) {
@@ -323,5 +325,5 @@
 	}
 	
-	// set the packet destination address
+	/* Set the packet destination address */
 	rc = packet_set_addr(*packet, NULL, (uint8_t *) addr, addrlen);
 	if (rc != EOK) {
Index: uspace/lib/packet/generic/packet_server.c
===================================================================
--- uspace/lib/packet/generic/packet_server.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/packet/generic/packet_server.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -112,9 +112,9 @@
     size_t max_content, size_t max_suffix)
 {
-	// clear the packet content
+	/* Clear the packet content */
 	bzero(((void *) packet) + sizeof(packet_t),
 	    packet->length - sizeof(packet_t));
 	
-	// clear the packet header
+	/* Clear the packet header */
 	packet->order = 0;
 	packet->metric = 0;
@@ -151,5 +151,5 @@
 	assert(fibril_mutex_is_locked(&ps_globals.lock));
 
-	// already locked
+	/* Already locked */
 	packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
 	    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
Index: uspace/lib/softint/generic/multiplication.c
===================================================================
--- uspace/lib/softint/generic/multiplication.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/softint/generic/multiplication.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -109,5 +109,5 @@
 	 * result does not fit in signed one */
 	if (SOFTINT_CHECK_OF && ((t2 < t1) || (t2 & (1ull << 63)))) {
-		// error, overflow
+		/* Error, overflow */
 		return (neg ? INT64_MIN : INT64_MAX);
 	}
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/Makefile	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -34,4 +34,5 @@
 SOURCES = \
 	src/addrkeep.c \
+	src/altiface.c \
 	src/class.c \
 	src/ddfiface.c \
@@ -41,6 +42,8 @@
 	src/dp.c \
 	src/dump.c \
+	src/hidiface.c \
 	src/hidparser.c \
 	src/hub.c \
+	src/pipepriv.c \
 	src/pipes.c \
 	src/pipesinit.c \
Index: uspace/lib/usb/include/usb/classes/hid/iface.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hid/iface.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/include/usb/classes/hid/iface.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,47 @@
+/*
+ * 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
+ * Client functions for accessing USB HID interface.
+ */
+#ifndef LIBUSB_CLASSES_HID_IFACE_H_
+#define LIBUSB_CLASSES_HID_IFACE_H_
+
+#include <sys/types.h>
+
+int usbhid_dev_get_event_length(int);
+int usbhid_dev_get_event(int, uint16_t *, uint16_t *, size_t, size_t *,
+    unsigned int);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hidparser.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidparser.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/classes/hidparser.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -317,4 +317,5 @@
 usb_hid_report_path_t *usb_hid_report_path_clone(usb_hid_report_path_t *usage_path);
 
+usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, usb_hid_report_type_t type);
 
 /*
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -43,4 +43,6 @@
  */
 typedef enum {
+	USB_HUB_FEATURE_HUB_LOCAL_POWER = 0,
+	USB_HUB_FEATURE_HUB_OVER_CURRENT = 1,
 	USB_HUB_FEATURE_C_HUB_LOCAL_POWER = 0,
 	USB_HUB_FEATURE_C_HUB_OVER_CURRENT = 1,
@@ -59,4 +61,5 @@
 	/* USB_HUB_FEATURE_ = , */
 } usb_hub_class_feature_t;
+
 
 /** Header of standard hub descriptor without the "variadic" part. */
@@ -149,5 +152,5 @@
             maximum of 255 ports).
      */
-    uint8_t * devices_removable;
+    uint8_t devices_removable[32];
 
     /**
Index: uspace/lib/usb/include/usb/classes/massstor.h
===================================================================
--- uspace/lib/usb/include/usb/classes/massstor.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/include/usb/classes/massstor.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,68 @@
+/*
+ * 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
+ * USB mass storage related functions and constants.
+ */
+#ifndef LIBUSB_CLASS_MASSSTOR_H_
+#define LIBUSB_CLASS_MASSSTOR_H_
+
+#include <sys/types.h>
+
+/** USB mass storage subclasses. */
+typedef enum {
+	USB_MASSSTOR_SUBCLASS_RBC = 0x01,
+	/** Also known as MMC-5. */
+	USB_MASSSTOR_SUBCLASS_ATAPI = 0x02,
+	USB_MASSSTOR_SUBCLASS_UFI = 0x04,
+	USB_MASSSTOR_SUBCLASS_SCSI = 0x06,
+	USB_MASSSTOR_SUBCLASS_LSDFS = 0x07,
+	USB_MASSSTOR_SUBCLASS_IEEE1667 = 0x08,
+	USB_MASSSTOR_SUBCLASS_VENDOR = 0xFF
+} usb_massstor_subclass_t;
+
+/** USB mass storage interface protocols. */
+typedef enum {
+	/** CBI transport with command completion interrupt. */
+	USB_MASSSTOR_PROTOCOL_CBI_CC = 0x00,
+	/** CBI transport with no command completion interrupt. */
+	USB_MASSSTOR_PROTOCOL_CBI = 0x01,
+	/** Bulk only transport. */
+	USB_MASSSTOR_PROTOCOL_BBB = 0x50,
+	/** USB attached SCSI. */
+	USB_MASSSTOR_PROTOCOL_UAS = 0x62,
+	USB_MASSSTOR_PROTOCOL_VENDOR = 0xFF
+} usb_massstor_protocol_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/devdrv.h
===================================================================
--- uspace/lib/usb/include/usb/devdrv.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/devdrv.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -162,10 +162,14 @@
     usb_endpoint_description_t **);
 
-typedef bool (*usb_polling_callback_t)(usb_device_t *,
-    uint8_t *, size_t, void *);
-typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, 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);
+int usb_device_create(ddf_dev_t *, usb_endpoint_description_t **, usb_device_t **, const char **);
 
-int usb_device_auto_poll(usb_device_t *, size_t,
-    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
+size_t usb_interface_count_alternates(uint8_t *, size_t, uint8_t);
+int usb_alternate_interfaces_create(uint8_t *, size_t, int,
+    usb_alternate_interfaces_t **);
 
 #endif
Index: uspace/lib/usb/include/usb/devpoll.h
===================================================================
--- uspace/lib/usb/include/usb/devpoll.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/include/usb/devpoll.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,99 @@
+/*
+ * 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
+ * USB device polling functions.
+ */
+#ifndef LIBUSB_DEVPOLL_H_
+#define LIBUSB_DEVPOLL_H_
+
+#include <usb/devdrv.h>
+#include <time.h>
+
+typedef struct {
+	/** Level of debugging messages from auto polling.
+	 * 0 - nothing
+	 * 1 - inform about errors and polling start/end
+	 * 2 - also dump every retrieved buffer
+	 */
+	int debug;
+	/** Maximum number of consecutive errors before polling termination. */
+	size_t max_failures;
+	/** Delay between poll requests in milliseconds.
+	 * Set to negative value to use value from endpoint descriptor.
+	 */
+	int delay;
+	/** Whether to automatically try to clear the HALT feature after
+	 * the endpoint stalls.
+	 */
+	bool auto_clear_halt;
+	/** Callback when data arrives.
+	 *
+	 * @param dev Device that was polled.
+	 * @param data Data buffer (in USB endianness).
+	 * @param data_size Size of the @p data buffer in bytes.
+	 * @param arg Custom argument.
+	 * @return Whether to continue in polling.
+	 */
+	bool (*on_data)(usb_device_t *dev, uint8_t *data, size_t data_size,
+	    void *arg);
+	/** Callback when polling is terminated.
+	 *
+	 * @param dev Device where the polling was terminated.
+	 * @param due_to_errors Whether polling stopped due to several failures.
+	 * @param arg Custom argument.
+	 */
+	void (*on_polling_end)(usb_device_t *dev, bool due_to_errors,
+	    void *arg);
+	/** Callback when error occurs.
+	 *
+	 * @param dev Device where error occurred.
+	 * @param err_code Error code (as returned from usb_pipe_read).
+	 * @param arg Custom argument.
+	 * @return Whether to continue in polling.
+	 */
+	bool (*on_error)(usb_device_t *dev, int err_code, void *arg);
+} usb_device_auto_polling_t;
+
+int usb_device_auto_polling(usb_device_t *, size_t, usb_device_auto_polling_t *,
+    size_t, void *);
+
+typedef bool (*usb_polling_callback_t)(usb_device_t *,
+    uint8_t *, size_t, void *);
+typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);
+
+int usb_device_auto_poll(usb_device_t *, size_t,
+    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/host/batch.h
===================================================================
--- uspace/lib/usb/include/usb/host/batch.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/host/batch.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -43,34 +43,27 @@
 typedef struct usb_transfer_batch usb_transfer_batch_t;
 struct usb_transfer_batch {
+	endpoint_t *ep;
 	link_t link;
-	usb_target_t target;
-	usb_transfer_type_t transfer_type;
-	usb_speed_t speed;
-	usb_direction_t direction;
 	usbhc_iface_transfer_in_callback_t callback_in;
 	usbhc_iface_transfer_out_callback_t callback_out;
+	void *arg;
 	char *buffer;
-	char *transport_buffer;
+	char *data_buffer;
 	size_t buffer_size;
 	char *setup_buffer;
 	size_t setup_size;
-	size_t max_packet_size;
 	size_t transfered_size;
 	void (*next_step)(usb_transfer_batch_t *);
 	int error;
 	ddf_fun_t *fun;
-	void *arg;
-	endpoint_t *ep;
 	void *private_data;
+	void (*private_data_dtor)(void *p_data);
 };
 
 void usb_transfer_batch_init(
     usb_transfer_batch_t *instance,
-    usb_target_t target,
-    usb_transfer_type_t transfer_type,
-    usb_speed_t speed,
-    size_t max_packet_size,
+    endpoint_t *ep,
     char *buffer,
-    char *transport_buffer,
+    char *data_buffer,
     size_t buffer_size,
     char *setup_buffer,
@@ -80,7 +73,20 @@
     void *arg,
     ddf_fun_t *fun,
-		endpoint_t *ep,
-    void *private_data
+    void *private_data,
+    void (*private_data_dtor)(void *p_data)
 );
+
+void usb_transfer_batch_call_in_and_dispose(usb_transfer_batch_t *instance);
+void usb_transfer_batch_call_out_and_dispose(usb_transfer_batch_t *instance);
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance);
+void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);
+
+static inline void usb_transfer_batch_finish_error(
+    usb_transfer_batch_t *instance, int error)
+{
+	assert(instance);
+	instance->error = error;
+	usb_transfer_batch_finish(instance);
+}
 
 static inline usb_transfer_batch_t *usb_transfer_batch_from_link(link_t *l)
@@ -90,8 +96,4 @@
 }
 
-void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
-void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance, int error);
-
 #endif
 /**
Index: uspace/lib/usb/include/usb/host/device_keeper.h
===================================================================
--- uspace/lib/usb/include/usb/host/device_keeper.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/host/device_keeper.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -54,6 +54,4 @@
 	usb_speed_t speed;
 	bool occupied;
-	link_t endpoints;
-	uint16_t control_used;
 	devman_handle_t handle;
 };
@@ -65,20 +63,8 @@
 	struct usb_device_info devices[USB_ADDRESS_COUNT];
 	fibril_mutex_t guard;
-	fibril_condvar_t change;
 	usb_address_t last_address;
 } usb_device_keeper_t;
 
 void usb_device_keeper_init(usb_device_keeper_t *instance);
-
-void usb_device_keeper_add_ep(
-    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep);
-
-void usb_device_keeper_reserve_default_address(
-    usb_device_keeper_t *instance, usb_speed_t speed);
-
-void usb_device_keeper_release_default_address(usb_device_keeper_t *instance);
-
-void usb_device_keeper_reset_if_need(usb_device_keeper_t *instance,
-    usb_target_t target, const uint8_t *setup_data);
 
 usb_address_t device_keeper_get_free_address(usb_device_keeper_t *instance,
@@ -96,11 +82,4 @@
 usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
     usb_address_t address);
-
-void usb_device_keeper_use_control(usb_device_keeper_t *instance,
-    usb_target_t target);
-
-void usb_device_keeper_release_control(usb_device_keeper_t *instance,
-    usb_target_t target);
-
 #endif
 /**
Index: uspace/lib/usb/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usb/include/usb/host/endpoint.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/host/endpoint.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -39,4 +39,6 @@
 #include <bool.h>
 #include <adt/list.h>
+#include <fibril_synch.h>
+
 #include <usb/usb.h>
 
@@ -48,7 +50,13 @@
 	usb_speed_t speed;
 	size_t max_packet_size;
-	bool active;
 	unsigned toggle:1;
-	link_t same_device_eps;
+	fibril_mutex_t guard;
+	fibril_condvar_t avail;
+	volatile bool active;
+	struct {
+		void *data;
+		int (*toggle_get)(void *);
+		void (*toggle_set)(void *, int);
+	} hc_data;
 } endpoint_t;
 
@@ -59,12 +67,18 @@
 void endpoint_destroy(endpoint_t *instance);
 
+void endpoint_set_hc_data(endpoint_t *instance,
+    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int));
+
+void endpoint_clear_hc_data(endpoint_t *instance);
+
+void endpoint_use(endpoint_t *instance);
+
+void endpoint_release(endpoint_t *instance);
+
 int endpoint_toggle_get(endpoint_t *instance);
 
 void endpoint_toggle_set(endpoint_t *instance, int toggle);
 
-void endpoint_toggle_reset(link_t *ep);
-
-void endpoint_toggle_reset_filtered(link_t *ep, usb_endpoint_t epn);
-
+void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target);
 #endif
 /**
Index: uspace/lib/usb/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usb/include/usb/host/usb_endpoint_manager.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/host/usb_endpoint_manager.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -66,9 +66,4 @@
     endpoint_t *ep, size_t data_size);
 
-int usb_endpoint_manager_register_ep_wait(usb_endpoint_manager_t *instance,
-    usb_address_t address, usb_endpoint_t ep, usb_direction_t direction,
-    void *data, void (*data_remove_callback)(void* data, void* arg), void *arg,
-    size_t bw);
-
 int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
     usb_address_t address, usb_endpoint_t ep, usb_direction_t direction);
@@ -78,4 +73,30 @@
     size_t *bw);
 
+void usb_endpoint_manager_reset_if_need(
+    usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
+
+static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
+    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
+    size_t data_size)
+{
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+
+	int ret = endpoint_init(ep, address, endpoint, direction, type, speed,
+	    max_packet_size);
+	if (ret != EOK) {
+		free(ep);
+		return ret;
+	}
+
+	ret = usb_endpoint_manager_register_ep(instance, ep, data_size);
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+		return ret;
+	}
+	return EOK;
+}
 #endif
 /**
Index: uspace/lib/usb/include/usb/hub.h
===================================================================
--- uspace/lib/usb/include/usb/hub.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/hub.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -59,7 +59,4 @@
 } usb_hc_attached_device_t;
 
-int usb_hc_reserve_default_address(usb_hc_connection_t *, usb_speed_t);
-int usb_hc_release_default_address(usb_hc_connection_t *);
-
 usb_address_t usb_hc_request_address(usb_hc_connection_t *, usb_speed_t);
 int usb_hc_register_device(usb_hc_connection_t *,
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/pipes.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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,21 @@
 	/** 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;
+
+	/** Whether to automatically reset halt on the endpoint.
+	 * Valid only for control endpoint zero.
+	 */
+	bool auto_reset_halt;
 } usb_pipe_t;
 
@@ -134,4 +158,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 +166,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/request.h
===================================================================
--- uspace/lib/usb/include/usb/request.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/request.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -50,4 +50,10 @@
 /** USB endpoint status - endpoint is halted (stalled). */
 #define USB_ENDPOINT_STATUS_HALTED ((uint16_t)(1 << 0))
+
+/** USB feature selector - endpoint halt (stall). */
+#define USB_FEATURE_SELECTOR_ENDPOINT_HALT (0)
+
+/** USB feature selector - device remote wake-up. */
+#define USB_FEATURE_SELECTOR_REMOTE_WAKEUP (1)
 
 /** Standard device request. */
@@ -135,4 +141,6 @@
     char **);
 
+int usb_request_clear_endpoint_halt(usb_pipe_t *, uint16_t);
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/include/usb/usb.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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/altiface.c
===================================================================
--- uspace/lib/usb/src/altiface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/src/altiface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,181 @@
+/*
+ * 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
+ * Handling alternate interface settings.
+ */
+#include <usb/devdrv.h>
+#include <usb/request.h>
+#include <usb/debug.h>
+#include <usb/dp.h>
+#include <errno.h>
+#include <str_error.h>
+#include <assert.h>
+
+/** Count number of alternate settings of a interface.
+ *
+ * @param config_descr Full configuration descriptor.
+ * @param config_descr_size Size of @p config_descr in bytes.
+ * @param interface_no Interface number.
+ * @return Number of alternate interfaces for @p interface_no interface.
+ */
+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
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = config_descr,
+		.size = config_descr_size,
+		.arg = NULL
+	};
+
+	size_t alternate_count = 0;
+
+	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, config_descr);
+	while (iface_ptr != NULL) {
+		usb_standard_interface_descriptor_t *iface
+		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
+			if (iface->interface_number == interface_no) {
+				alternate_count++;
+			}
+		}
+		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    config_descr, iface_ptr);
+	}
+
+	return alternate_count;
+}
+
+/** Create alternate interface representation structure.
+ *
+ * @param[in] config_descr Configuration descriptor.
+ * @param[in] config_descr_size Size of configuration descriptor.
+ * @param[in] interface_number Interface number.
+ * @param[out] alternates_ptr Where to store pointer to allocated structure.
+ * @return Error code.
+ */
+int usb_alternate_interfaces_create(uint8_t *config_descr,
+    size_t config_descr_size, int interface_number,
+    usb_alternate_interfaces_t **alternates_ptr)
+{
+	assert(alternates_ptr != NULL);
+	assert(config_descr != NULL);
+	assert(config_descr_size > 0);
+
+	if (interface_number < 0) {
+		alternates_ptr = NULL;
+		return EOK;
+	}
+
+	usb_alternate_interfaces_t *alternates
+	    = malloc(sizeof(usb_alternate_interfaces_t));
+
+	if (alternates == NULL) {
+		return ENOMEM;
+	}
+
+	alternates->alternative_count
+	    = usb_interface_count_alternates(config_descr, config_descr_size,
+	    interface_number);
+
+	if (alternates->alternative_count == 0) {
+		free(alternates);
+		return ENOENT;
+	}
+
+	alternates->alternatives = malloc(alternates->alternative_count
+	    * sizeof(usb_alternate_interface_descriptors_t));
+	if (alternates->alternatives == NULL) {
+		free(alternates);
+		return ENOMEM;
+	}
+
+	alternates->current = 0;
+
+	usb_dp_parser_t dp_parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = config_descr,
+		.size = config_descr_size,
+		.arg = NULL
+	};
+
+	usb_alternate_interface_descriptors_t *cur_alt_iface
+	    = &alternates->alternatives[0];
+
+	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, dp_data.data);
+	while (iface_ptr != NULL) {
+		usb_standard_interface_descriptor_t *iface
+		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
+		    || (iface->interface_number != interface_number)) {
+			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
+			    &dp_data,
+			    dp_data.data, iface_ptr);
+			continue;
+		}
+
+		cur_alt_iface->interface = iface;
+		cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
+
+		/* Find next interface to count size of nested descriptors. */
+		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    dp_data.data, iface_ptr);
+		if (iface_ptr == NULL) {
+			uint8_t *next = dp_data.data + dp_data.size;
+			cur_alt_iface->nested_descriptors_size
+			    = next - cur_alt_iface->nested_descriptors;
+		} else {
+			cur_alt_iface->nested_descriptors_size
+			    = iface_ptr - cur_alt_iface->nested_descriptors;
+		}
+
+		cur_alt_iface++;
+	}
+
+	*alternates_ptr = alternates;
+
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/devdrv.c
===================================================================
--- uspace/lib/usb/src/devdrv.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/devdrv.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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,300 +98,26 @@
  */
 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) {
+    usb_device_t *dev, int alternate_setting)
+{
+	if (endpoints == NULL) {
+		dev->pipes = NULL;
+		dev->pipes_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_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);
-	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;
-
-	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;
-}
-
-/** Initialize all endpoint pipes.
- *
- * @param drv The driver.
- * @param dev The device to be initialized.
- * @return Error code.
- */
-static int initialize_pipes(usb_device_t *dev)
-{
-	int rc;
-
-	rc = usb_device_connection_initialize_from_device(&dev->wire,
-	    dev->ddf_dev);
-	if (rc != EOK) {
-		usb_log_error(
-		    "Failed initializing connection on device `%s'. %s.\n",
-		    dev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
-	    &dev->wire);
-	if (rc != EOK) {
-		usb_log_error("Failed to initialize default control pipe " \
-		    "on device `%s': %s.\n",
-		    dev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	rc = usb_pipe_probe_default_control(&dev->ctrl_pipe);
-	if (rc != EOK) {
-		usb_log_error(
-		    "Probing default control pipe on device `%s' failed: %s.\n",
-		    dev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	/* Get our interface. */
-	dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
-
-	/*
-	 * For further actions, we need open session on default control pipe.
-	 */
-	rc = usb_pipe_start_session(&dev->ctrl_pipe);
-	if (rc != EOK) {
-		usb_log_error("Failed to start an IPC session: %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",
-		    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);
-
-	/* Rollback actions. */
-	if (rc != EOK) {
-		if (dev->descriptors.configuration != NULL) {
-			free(dev->descriptors.configuration);
-		}
-	}
-
-	return rc;
-}
-
-/** Count number of alternate settings of a interface.
- *
- * @param config_descr Full configuration descriptor.
- * @param config_descr_size Size of @p config_descr in bytes.
- * @param interface_no Interface number.
- * @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)
-{
-	assert(config_descr != NULL);
-	usb_dp_parser_t dp_parser = {
-		.nesting = usb_dp_standard_descriptor_nesting
-	};
-	usb_dp_parser_data_t dp_data = {
-		.data = config_descr,
-		.size = config_descr_size,
-		.arg = NULL
-	};
-
-	size_t alternate_count = 0;
-
-	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, config_descr);
-	while (iface_ptr != NULL) {
-		usb_standard_interface_descriptor_t *iface
-		    = (usb_standard_interface_descriptor_t *) iface_ptr;
-		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
-			if (iface->interface_number == interface_no) {
-				alternate_count++;
-			}
-		}
-		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
-		    config_descr, iface_ptr);
-	}
-
-	return alternate_count;
-}
-
-/** Initialize structures related to alternate interfaces.
- *
- * @param dev Device where alternate settings shall be initialized.
- * @return Error code.
- */
-static int initialize_alternate_interfaces(usb_device_t *dev)
-{
-	if (dev->interface_no < 0) {
-		dev->alternate_interfaces = NULL;
-		return EOK;
-	}
-
-	usb_alternate_interfaces_t *alternates
-	    = malloc(sizeof(usb_alternate_interfaces_t));
-
-	if (alternates == NULL) {
-		return ENOMEM;
-	}
-
-	alternates->alternative_count
-	    = count_alternate_interfaces(dev->descriptors.configuration,
-	    dev->descriptors.configuration_size, dev->interface_no);
-
-	if (alternates->alternative_count == 0) {
-		free(alternates);
-		return ENOENT;
-	}
-
-	alternates->alternatives = malloc(alternates->alternative_count
-	    * sizeof(usb_alternate_interface_descriptors_t));
-	if (alternates->alternatives == NULL) {
-		free(alternates);
-		return ENOMEM;
-	}
-
-	alternates->current = 0;
-
-	usb_dp_parser_t dp_parser = {
-		.nesting = usb_dp_standard_descriptor_nesting
-	};
-	usb_dp_parser_data_t dp_data = {
-		.data = dev->descriptors.configuration,
-		.size = dev->descriptors.configuration_size,
-		.arg = NULL
-	};
-
-	usb_alternate_interface_descriptors_t *cur_alt_iface
-	    = &alternates->alternatives[0];
-
-	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, dp_data.data);
-	while (iface_ptr != NULL) {
-		usb_standard_interface_descriptor_t *iface
-		    = (usb_standard_interface_descriptor_t *) iface_ptr;
-		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
-		    || (iface->interface_number != dev->interface_no)) {
-			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
-			    &dp_data,
-			    dp_data.data, iface_ptr);
-			continue;
-		}
-
-		cur_alt_iface->interface = iface;
-		cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
-
-		/* Find next interface to count size of nested descriptors. */
-		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
-		    dp_data.data, iface_ptr);
-		if (iface_ptr == NULL) {
-			uint8_t *next = dp_data.data + dp_data.size;
-			cur_alt_iface->nested_descriptors_size
-			    = next - cur_alt_iface->nested_descriptors;
-		} else {
-			cur_alt_iface->nested_descriptors_size
-			    = iface_ptr - cur_alt_iface->nested_descriptors;
-		}
-
-		cur_alt_iface++;
-	}
-
-	dev->alternate_interfaces = alternates;
+	    dev->interface_no, alternate_setting,
+	    &pipes, &pipes_count);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	dev->pipes = pipes;
+	dev->pipes_count = pipes_count;
 
 	return EOK;
@@ -423,27 +139,12 @@
 	int rc;
 
-	usb_device_t *dev = malloc(sizeof(usb_device_t));
-	if (dev == NULL) {
-		usb_log_error("Out of memory when adding device `%s'.\n",
-		    gen_dev->name);
-		return ENOMEM;
-	}
-
-
-	dev->ddf_dev = gen_dev;
-	dev->ddf_dev->driver_data = dev;
-	dev->driver_data = NULL;
-	dev->descriptors.configuration = NULL;
-
-	dev->pipes_count = 0;
-	dev->pipes = NULL;
-
-	rc = initialize_pipes(dev);
-	if (rc != EOK) {
-		free(dev);
-		return rc;
-	}
-
-	(void) initialize_alternate_interfaces(dev);
+	usb_device_t *dev = NULL;
+	const char *err_msg = NULL;
+	rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);
+	if (rc != EOK) {
+		usb_log_error("USB device `%s' creation failed (%s): %s.\n",
+		    gen_dev->name, err_msg, str_error(rc));
+		return rc;
+	}
 
 	return driver->ops->add_device(dev);
@@ -457,36 +158,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;
@@ -505,4 +180,11 @@
  * with usb_pipe_initialize_from_configuration().
  *
+ * @warning This is a wrapper function that does several operations that
+ * can fail and that cannot be rollbacked easily. That means that a failure
+ * during the SET_INTERFACE request would result in having a device with
+ * no pipes at all (except the default control one). That is because the old
+ * pipes needs to be unregistered at HC first and the new ones could not
+ * be created.
+ *
  * @param dev USB device.
  * @param alternate_setting Alternate setting to choose.
@@ -519,6 +201,4 @@
 	int rc;
 
-	/* TODO: more transactional behavior. */
-
 	/* Destroy existing pipes. */
 	rc = destroy_current_pipes(dev);
@@ -535,7 +215,323 @@
 
 	/* 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 endpoint pipe.
+ * @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);
+
+	descriptors->configuration = NULL;
+
+	int rc;
+
+	/* It is worth to start a long transfer. */
+	rc = usb_pipe_start_long_transfer(ctrl_pipe);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Get the device descriptor. */
+	rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	/* Get the full configuration descriptor. */
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    ctrl_pipe, 0, (void **) &descriptors->configuration,
+	    &descriptors->configuration_size);
+
+leave:
+	usb_pipe_end_long_transfer(ctrl_pipe);
+
+	return rc;
+}
+
+/** 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;
+}
+
+/** Initialize control pipe in a device.
+ *
+ * @param dev USB device in question.
+ * @param errmsg Where to store error context.
+ * @return
+ */
+static int init_wire_and_ctrl_pipe(usb_device_t *dev, const char **errmsg)
+{
+	int rc;
+
+	rc = usb_device_connection_initialize_from_device(&dev->wire,
+	    dev->ddf_dev);
+	if (rc != EOK) {
+		*errmsg = "device connection initialization";
+		return rc;
+	}
+
+	rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
+	    &dev->wire);
+	if (rc != EOK) {
+		*errmsg = "default control pipe initialization";
+		return rc;
+	}
+
+	return EOK;
+}
+
+
+/** Create new instance of USB device.
+ *
+ * @param[in] ddf_dev Generic DDF device backing the USB one.
+ * @param[in] endpoints NULL terminated array of endpoints (NULL for none).
+ * @param[out] dev_ptr Where to store pointer to the new device.
+ * @param[out] errstr_ptr Where to store description of context
+ *	(in case error occurs).
+ * @return Error code.
+ */
+int usb_device_create(ddf_dev_t *ddf_dev,
+    usb_endpoint_description_t **endpoints,
+    usb_device_t **dev_ptr, const char **errstr_ptr)
+{
+	assert(dev_ptr != NULL);
+	assert(ddf_dev != NULL);
+
+	int rc;
+
+	usb_device_t *dev = malloc(sizeof(usb_device_t));
+	if (dev == NULL) {
+		*errstr_ptr = "structure allocation";
+		return ENOMEM;
+	}
+
+	// FIXME: proper deallocation in case of errors
+
+	dev->ddf_dev = ddf_dev;
+	dev->driver_data = NULL;
+	dev->descriptors.configuration = NULL;
+	dev->alternate_interfaces = NULL;
+
+	dev->pipes_count = 0;
+	dev->pipes = NULL;
+
+	/* Initialize backing wire and control pipe. */
+	rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Get our interface. */
+	dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
+
+	/* Retrieve standard descriptors. */
+	rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
+	    &dev->descriptors);
+	if (rc != EOK) {
+		*errstr_ptr = "descriptor retrieval";
+		return rc;
+	}
+
+	/* Create alternate interfaces. */
+	rc = usb_alternate_interfaces_create(dev->descriptors.configuration,
+	    dev->descriptors.configuration_size, dev->interface_no,
+	    &dev->alternate_interfaces);
+	if (rc != EOK) {
+		/* We will try to silently ignore this. */
+		dev->alternate_interfaces = NULL;
+	}
+
+	rc = initialize_other_pipes(endpoints, dev, 0);
+	if (rc != EOK) {
+		*errstr_ptr = "pipes initialization";
+		return rc;
+	}
+
+	*errstr_ptr = NULL;
+	*dev_ptr = dev;
+
+	return EOK;
 }
 
Index: uspace/lib/usb/src/devpoll.c
===================================================================
--- uspace/lib/usb/src/devpoll.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/devpoll.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -33,7 +33,8 @@
  * USB device driver framework - automatic interrupt polling.
  */
-#include <usb/devdrv.h>
+#include <usb/devpoll.h>
 #include <usb/request.h>
 #include <usb/debug.h>
+#include <usb/classes/classes.h>
 #include <errno.h>
 #include <str_error.h>
@@ -45,8 +46,14 @@
 /** Data needed for polling. */
 typedef struct {
+	int debug;
+	size_t max_failures;
+	useconds_t delay;
+	bool auto_clear_halt;
+	bool (*on_data)(usb_device_t *, uint8_t *, size_t, void *);
+	void (*on_polling_end)(usb_device_t *, bool, void *);
+	bool (*on_error)(usb_device_t *, int, void *);
+
 	usb_device_t *dev;
 	size_t pipe_index;
-	usb_polling_callback_t callback;
-	usb_polling_terminted_callback_t terminated_callback;
 	size_t request_size;
 	uint8_t *buffer;
@@ -54,4 +61,5 @@
 } polling_data_t;
 
+
 /** Polling fibril.
  *
@@ -66,14 +74,22 @@
 	usb_pipe_t *pipe
 	    = polling_data->dev->pipes[polling_data->pipe_index].pipe;
+	
+	if (polling_data->debug > 0) {
+		usb_endpoint_mapping_t *mapping
+		    = &polling_data->dev->pipes[polling_data->pipe_index];
+		usb_log_debug("Poll0x%x: started polling of `%s' - " \
+		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
+		    polling_data,
+		    polling_data->dev->ddf_dev->name,
+		    (int) mapping->interface->interface_number,
+		    usb_str_class(mapping->interface->interface_class),
+		    (int) mapping->interface->interface_subclass,
+		    (int) mapping->interface->interface_protocol,
+		    polling_data->request_size, pipe->max_packet_size);
+	}
 
 	size_t failed_attempts = 0;
-	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
+	while (failed_attempts <= polling_data->max_failures) {
 		int rc;
-
-		rc = usb_pipe_start_session(pipe);
-		if (rc != EOK) {
-			failed_attempts++;
-			continue;
-		}
 
 		size_t actual_size;
@@ -81,8 +97,40 @@
 		    polling_data->request_size, &actual_size);
 
-		/* Quit the session regardless of errors. */
-		usb_pipe_end_session(pipe);
+		if (polling_data->debug > 1) {
+			if (rc == EOK) {
+				usb_log_debug(
+				    "Poll0x%x: received: '%s' (%zuB).\n",
+				    polling_data,
+				    usb_debug_str_buffer(polling_data->buffer,
+				        actual_size, 16),
+				    actual_size);
+			} else {
+				usb_log_debug(
+				    "Poll0x%x: polling failed: %s.\n",
+				    polling_data, str_error(rc));
+			}
+		}
+
+		/* If the pipe stalled, we can try to reset the stall. */
+		if ((rc == ESTALL) && (polling_data->auto_clear_halt)) {
+			/*
+			 * We ignore error here as this is usually a futile
+			 * attempt anyway.
+			 */
+			usb_request_clear_endpoint_halt(
+			    &polling_data->dev->ctrl_pipe,
+			    pipe->endpoint_no);
+		}
 
 		if (rc != EOK) {
+			if (polling_data->on_error != NULL) {
+				bool cont = polling_data->on_error(
+				    polling_data->dev, rc,
+				    polling_data->custom_arg);
+				if (!cont) {
+					failed_attempts
+					    = polling_data->max_failures;
+				}
+			}
 			failed_attempts++;
 			continue;
@@ -90,5 +138,5 @@
 
 		/* We have the data, execute the callback now. */
-		bool carry_on = polling_data->callback(polling_data->dev,
+		bool carry_on = polling_data->on_data(polling_data->dev,
 		    polling_data->buffer, actual_size,
 		    polling_data->custom_arg);
@@ -101,15 +149,26 @@
 		/* Reset as something might be only a temporary problem. */
 		failed_attempts = 0;
-	}
-
-	if (failed_attempts > 0) {
-		usb_log_error(
-		    "Polling of device `%s' terminated: recurring failures.\n",
-		    polling_data->dev->ddf_dev->name);
-	}
-
-	if (polling_data->terminated_callback != NULL) {
-		polling_data->terminated_callback(polling_data->dev,
+
+		/* Take a rest before next request. */
+		async_usleep(polling_data->delay);
+	}
+
+	if (polling_data->on_polling_end != NULL) {
+		polling_data->on_polling_end(polling_data->dev,
 		    failed_attempts > 0, polling_data->custom_arg);
+	}
+
+	if (polling_data->debug > 0) {
+		if (failed_attempts > 0) {
+			usb_log_error(
+			    "Polling of device `%s' terminated: %s.\n",
+			    polling_data->dev->ddf_dev->name,
+			    "recurring failures");
+		} else {
+			usb_log_debug(
+			    "Polling of device `%s' terminated by user.\n",
+			    polling_data->dev->ddf_dev->name
+			);
+		}
 	}
 
@@ -154,4 +213,61 @@
 	}
 
+	usb_device_auto_polling_t *auto_polling
+	    = malloc(sizeof(usb_device_auto_polling_t));
+	if (auto_polling == NULL) {
+		return ENOMEM;
+	}
+
+	auto_polling->debug = 1;
+	auto_polling->auto_clear_halt = true;
+	auto_polling->delay = 0;
+	auto_polling->max_failures = MAX_FAILED_ATTEMPTS;
+	auto_polling->on_data = callback;
+	auto_polling->on_polling_end = terminated_callback;
+	auto_polling->on_error = NULL;
+
+	int rc = usb_device_auto_polling(dev, pipe_index, auto_polling,
+	   request_size, arg);
+
+	free(auto_polling);
+
+	return rc;
+}
+
+/** Start automatic device polling over interrupt in pipe.
+ *
+ * The polling settings is copied thus it is okay to destroy the structure
+ * after this function returns.
+ *
+ * @warning There is no guarantee when the request to the device
+ * will be sent for the first time (it is possible that this
+ * first request would be executed prior to return from this function).
+ *
+ * @param dev Device to be periodically polled.
+ * @param pipe_index Index of the endpoint pipe used for polling.
+ * @param polling Polling settings.
+ * @param request_size How many bytes to ask for in each request.
+ * @param arg Custom argument (passed as is to the callbacks).
+ * @return Error code.
+ * @retval EOK New fibril polling the device was already started.
+ */
+int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
+    usb_device_auto_polling_t *polling,
+    size_t request_size, void *arg)
+{
+	if (dev == NULL) {
+		return EBADMEM;
+	}
+	if (pipe_index >= dev->pipes_count) {
+		return EINVAL;
+	}
+	if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
+	    || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
+		return EINVAL;
+	}
+	if ((polling == NULL) || (polling->on_data == NULL)) {
+		return EBADMEM;
+	}
+
 	polling_data_t *polling_data = malloc(sizeof(polling_data_t));
 	if (polling_data == NULL) {
@@ -159,16 +275,28 @@
 	}
 
-	/* Allocate now to prevent immediate failure in the polling fibril. */
-	polling_data->buffer = malloc(request_size);
+	/* Fill-in the data. */
+	polling_data->buffer = malloc(sizeof(request_size));
 	if (polling_data->buffer == NULL) {
 		free(polling_data);
 		return ENOMEM;
 	}
+	polling_data->request_size = request_size;
 	polling_data->dev = dev;
 	polling_data->pipe_index = pipe_index;
-	polling_data->callback = callback;
-	polling_data->terminated_callback = terminated_callback;
-	polling_data->request_size = request_size;
 	polling_data->custom_arg = arg;
+
+	polling_data->debug = polling->debug;
+	polling_data->max_failures = polling->max_failures;
+	if (polling->delay >= 0) {
+		polling_data->delay = (useconds_t) polling->delay;
+	} else {
+		polling_data->delay = (useconds_t) dev->pipes[pipe_index]
+		    .descriptor->poll_interval;
+	}
+	polling_data->auto_clear_halt = polling->auto_clear_halt;
+
+	polling_data->on_data = polling->on_data;
+	polling_data->on_polling_end = polling->on_polling_end;
+	polling_data->on_error = polling->on_error;
 
 	fid_t fibril = fibril_create(polling_fibril, polling_data);
@@ -176,10 +304,9 @@
 		free(polling_data->buffer);
 		free(polling_data);
-		/* FIXME: better error code. */
 		return ENOMEM;
 	}
 	fibril_add_ready(fibril);
 
-	/* The allocated buffer etc. will be freed by the fibril. */
+	/* Fibril launched. That fibril will free the allocated data. */
 
 	return EOK;
Index: uspace/lib/usb/src/hidiface.c
===================================================================
--- uspace/lib/usb/src/hidiface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/src/hidiface.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -0,0 +1,146 @@
+/*
+ * 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
+ * Client functions for accessing USB HID interface (implementation).
+ */
+#include <dev_iface.h>
+#include <usbhid_iface.h>
+#include <usb/classes/hid/iface.h>
+#include <errno.h>
+#include <str_error.h>
+#include <async.h>
+#include <assert.h>
+
+/** Ask for event array length.
+ *
+ * @param dev_phone Opened phone to DDF device providing USB HID interface.
+ * @return Number of usages returned or negative error code.
+ */
+int usbhid_dev_get_event_length(int dev_phone)
+{
+	if (dev_phone < 0) {
+		return EINVAL;
+	}
+
+	sysarg_t len;
+	int rc = async_req_1_1(dev_phone, DEV_IFACE_ID(USBHID_DEV_IFACE),
+	    IPC_M_USBHID_GET_EVENT_LENGTH, &len);
+	if (rc == EOK) {
+		return (int) len;
+	} else {
+		return rc;
+	}
+}
+
+/** Request for next event from HID device.
+ *
+ * @param[in] dev_phone Opened phone to DDF device providing USB HID interface.
+ * @param[out] usage_pages Where to store usage pages.
+ * @param[out] usages Where to store usages (actual data).
+ * @param[in] usage_count Length of @p usage_pages and @p usages buffer
+ *	(in items, not bytes).
+ * @param[out] actual_usage_count Number of usages actually returned by the
+ *	device driver.
+ * @param[in] flags Flags (see USBHID_IFACE_FLAG_*).
+ * @return Error code.
+ */
+int usbhid_dev_get_event(int dev_phone, uint16_t *usage_pages, uint16_t *usages,
+    size_t usage_count, size_t *actual_usage_count, unsigned int flags)
+{
+	if (dev_phone < 0) {
+		return EINVAL;
+	}
+	if ((usage_pages == NULL) || (usages == NULL)) {
+		return ENOMEM;
+	}
+	if (usage_count == 0) {
+		return EINVAL;
+	}
+
+	size_t buffer_size = sizeof(uint16_t) * usage_count * 2;
+	uint16_t *buffer = malloc(buffer_size);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+
+	aid_t opening_request = async_send_2(dev_phone,
+	    DEV_IFACE_ID(USBHID_DEV_IFACE), IPC_M_USBHID_GET_EVENT,
+	    flags, NULL);
+	if (opening_request == 0) {
+		free(buffer);
+		return ENOMEM;
+	}
+
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(dev_phone, buffer, buffer_size,
+	    &data_request_call);
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		free(buffer);
+		return ENOMEM;
+	}
+
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	size_t actual_size = IPC_GET_ARG2(data_request_call);
+	size_t items = actual_size / 2;
+
+	/* Copy the individual items. */
+	memcpy(usage_pages, buffer, items * sizeof(uint16_t));
+	memcpy(usages, buffer + items, items * sizeof(uint16_t));
+
+	if (actual_usage_count != NULL) {
+		*actual_usage_count = items;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/hidparser.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -877,5 +877,4 @@
 
 	offset = item->offset + (j * item->size);
-	
 	// FIXME
 	if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
@@ -1352,9 +1351,11 @@
 
 		field = list_get_instance(field_it, usb_hid_report_field_t, link);
-		usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
-		if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK) {
-			ret++;
-		}
-		usb_hid_report_remove_last_item (field->collection_path);
+		if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0){
+			usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
+			if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK) {
+				ret++;
+			}
+			usb_hid_report_remove_last_item (field->collection_path);
+		}
 		
 		field_it = field_it->next;
@@ -1536,24 +1537,4 @@
 
 /**
- * Clones given report item structure and returns the new one
- *
- * @param item Report item structure to clone
- * @return Clonned item
- */
-usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item)
-{
-	usb_hid_report_item_t *new_report_item;
-	
-	if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
-		return NULL;
-	}					
-	memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
-	link_initialize(&(new_report_item->link));
-
-	return new_report_item;
-}
-
-
-/**
  *
  *
@@ -1604,4 +1585,55 @@
 }
 
+
+usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item)
+{
+	usb_hid_report_item_t *new_report_item;
+	
+	if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
+		return NULL;
+	}					
+	memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
+	link_initialize(&(new_report_item->link));
+
+	return new_report_item;
+}
+
+
+usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, 
+							usb_hid_report_field_t *field, 
+                            usb_hid_report_path_t *path, int flags, 
+                            usb_hid_report_type_t type)
+{
+	usb_hid_report_description_t *report_des = usb_hid_report_find_description (report, path->report_id, type);
+	link_t *field_it;
+	
+	if(report_des == NULL){
+		return NULL;
+	}
+
+	if(field == NULL){
+		// vezmu prvni co mathuje podle path!!
+		field_it = report_des->report_items.next;
+	}
+	else {
+		field_it = field->link.next;
+	}
+
+	while(field_it != &report_des->report_items) {
+		field = list_get_instance(field_it, usb_hid_report_field_t, link);
+			
+		usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
+		if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK){
+			usb_hid_report_remove_last_item (field->collection_path);
+			usb_log_debug("....OK\n");
+			return field;
+		}
+		usb_hid_report_remove_last_item (field->collection_path);
+
+		field_it = field_it->next;
+	}
+
+	return NULL;
+}
 /**
  * @}
Index: uspace/lib/usb/src/hidreport.c
===================================================================
--- uspace/lib/usb/src/hidreport.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/hidreport.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -80,4 +80,5 @@
 		d = usb_dp_get_sibling_descriptor(&parser, &parser_data, 
 		    dev->descriptors.configuration, d);
+		++i;
 	}
 	
@@ -118,14 +119,4 @@
 	uint16_t length =  hid_desc->report_desc_info.length;
 	size_t actual_size = 0;
-	
-	/*
-	 * Start session for the control transfer.
-	 */
-	int sess_rc = usb_pipe_start_session(&dev->ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
 
 	/*
@@ -161,16 +152,4 @@
 		    "%u)\n", actual_size, length);
 		return EINVAL;
-	}
-	
-	/*
-	 * End session for the control transfer.
-	 */
-	sess_rc = usb_pipe_end_session(&dev->ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to end a session: %s.\n",
-		    str_error(sess_rc));
-		free(*report_desc);
-		*report_desc = NULL;
-		return sess_rc;
 	}
 	
Index: uspace/lib/usb/src/hidreq.c
===================================================================
--- uspace/lib/usb/src/hidreq.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/hidreq.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -56,7 +56,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_set_report(usb_pipe_t *ctrl_pipe, int iface_no,
@@ -79,12 +77,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 	
 	uint16_t value = 0;
@@ -97,16 +88,8 @@
 	    USB_HIDREQ_SET_REPORT, value, iface_no, buffer, buf_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -123,7 +106,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_set_protocol(usb_pipe_t *ctrl_pipe, int iface_no,
@@ -146,12 +127,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	usb_log_debug("Sending Set_Protocol request to the device ("
@@ -162,16 +136,8 @@
 	    USB_HIDREQ_SET_PROTOCOL, protocol, iface_no, NULL, 0);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -189,7 +155,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_set_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t duration)
@@ -211,12 +175,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	usb_log_debug("Sending Set_Idle request to the device ("
@@ -229,16 +186,8 @@
 	    USB_HIDREQ_SET_IDLE, value, iface_no, NULL, 0);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -259,7 +208,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_get_report(usb_pipe_t *ctrl_pipe, int iface_no, 
@@ -283,12 +230,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	uint16_t value = 0;
@@ -302,16 +242,8 @@
 	    actual_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -328,7 +260,5 @@
  * @retval EOK if successful.
  * @retval EINVAL if no HID device is given.
- * @return Other value inherited from one of functions 
- *         usb_pipe_start_session(), usb_pipe_end_session(),
- *         usb_control_request_set().
+ * @return Other value inherited from function usb_control_request_set().
  */
 int usbhid_req_get_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 
@@ -351,12 +281,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;	
 
 	usb_log_debug("Sending Get_Protocol request to the device ("
@@ -370,16 +293,8 @@
 	    USB_HIDREQ_GET_PROTOCOL, 0, iface_no, buffer, 1, &actual_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
@@ -427,12 +342,5 @@
 	 */
 	
-	int rc, sess_rc;
-	
-	sess_rc = usb_pipe_start_session(ctrl_pipe);
-	if (sess_rc != EOK) {
-		usb_log_warning("Failed to start a session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
+	int rc;
 
 	usb_log_debug("Sending Get_Idle request to the device ("
@@ -448,16 +356,8 @@
 	    &actual_size);
 
-	sess_rc = usb_pipe_end_session(ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
 	}
 	
Index: uspace/lib/usb/src/host/batch.c
===================================================================
--- uspace/lib/usb/src/host/batch.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/host/batch.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -39,12 +39,12 @@
 #include <usb/host/batch.h>
 
+void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
+void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
+
 void usb_transfer_batch_init(
     usb_transfer_batch_t *instance,
-    usb_target_t target,
-    usb_transfer_type_t transfer_type,
-    usb_speed_t speed,
-    size_t max_packet_size,
+    endpoint_t *ep,
     char *buffer,
-    char *transport_buffer,
+    char *data_buffer,
     size_t buffer_size,
     char *setup_buffer,
@@ -54,29 +54,48 @@
     void *arg,
     ddf_fun_t *fun,
-		endpoint_t *ep,
-    void *private_data
+    void *private_data,
+    void (*private_data_dtor)(void *p_data)
     )
 {
 	assert(instance);
 	link_initialize(&instance->link);
-	instance->target = target;
-	instance->transfer_type = transfer_type;
-	instance->speed = speed;
-	instance->direction = USB_DIRECTION_BOTH;
+	instance->ep = ep;
 	instance->callback_in = func_in;
 	instance->callback_out = func_out;
 	instance->arg = arg;
 	instance->buffer = buffer;
-	instance->transport_buffer = transport_buffer;
+	instance->data_buffer = data_buffer;
 	instance->buffer_size = buffer_size;
 	instance->setup_buffer = setup_buffer;
 	instance->setup_size = setup_size;
-	instance->max_packet_size = max_packet_size;
 	instance->fun = fun;
 	instance->private_data = private_data;
+	instance->private_data_dtor = private_data_dtor;
 	instance->transfered_size = 0;
 	instance->next_step = NULL;
 	instance->error = EOK;
-	instance->ep = ep;
+	endpoint_use(instance->ep);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function, calls callback and correctly destroys batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_call_in_and_dispose(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_transfer_batch_call_in(instance);
+	usb_transfer_batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function calls callback and correctly destroys batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_call_out_and_dispose(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_transfer_batch_call_out(instance);
+	usb_transfer_batch_dispose(instance);
 }
 /*----------------------------------------------------------------------------*/
@@ -86,8 +105,9 @@
  *
  */
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance, int error)
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance)
 {
 	assert(instance);
-	instance->error = error;
+	assert(instance->ep);
+	endpoint_release(instance->ep);
 	instance->next_step(instance);
 }
@@ -103,16 +123,14 @@
 	assert(instance);
 	assert(instance->callback_in);
+	assert(instance->ep);
 
 	/* We are data in, we need data */
-	memcpy(instance->buffer, instance->transport_buffer,
-	    instance->buffer_size);
+	memcpy(instance->buffer, instance->data_buffer, instance->buffer_size);
 
 	usb_log_debug("Batch %p done (T%d.%d, %s %s in, %zuB): %s (%d).\n",
-	    instance,
-	    instance->target.address, instance->target.endpoint,
-	    usb_str_speed(instance->speed),
-	    usb_str_transfer_type_short(instance->transfer_type),
-	    instance->transfered_size,
-	    str_error(instance->error), instance->error);
+	    instance, instance->ep->address, instance->ep->endpoint,
+	    usb_str_speed(instance->ep->speed),
+	    usb_str_transfer_type_short(instance->ep->transfer_type),
+	    instance->transfered_size, str_error(instance->error), instance->error);
 
 	instance->callback_in(instance->fun, instance->error,
@@ -130,8 +148,7 @@
 
 	usb_log_debug("Batch %p done (T%d.%d, %s %s out): %s (%d).\n",
-	    instance,
-	    instance->target.address, instance->target.endpoint,
-	    usb_str_speed(instance->speed),
-	    usb_str_transfer_type_short(instance->transfer_type),
+	    instance, instance->ep->address, instance->ep->endpoint,
+	    usb_str_speed(instance->ep->speed),
+	    usb_str_transfer_type_short(instance->ep->transfer_type),
 	    str_error(instance->error), instance->error);
 
@@ -139,4 +156,19 @@
 	    instance->error, instance->arg);
 }
+/*----------------------------------------------------------------------------*/
+/** Correctly dispose all used data structures.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_dispose(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_log_debug("Batch(%p) disposing.\n", instance);
+	if (instance->private_data) {
+		assert(instance->private_data_dtor);
+		instance->private_data_dtor(instance->private_data);
+	}
+	free(instance);
+}
 /**
  * @}
Index: uspace/lib/usb/src/host/device_keeper.c
===================================================================
--- uspace/lib/usb/src/host/device_keeper.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/host/device_keeper.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -48,113 +48,15 @@
 {
 	assert(instance);
-	fibril_mutex_initialize(&instance->guard);
-	fibril_condvar_initialize(&instance->change);
-	instance->last_address = 0;
 	unsigned i = 0;
 	for (; i < USB_ADDRESS_COUNT; ++i) {
 		instance->devices[i].occupied = false;
-		instance->devices[i].control_used = 0;
 		instance->devices[i].handle = 0;
-		list_initialize(&instance->devices[i].endpoints);
+		instance->devices[i].speed = USB_SPEED_MAX;
 	}
-}
-/*----------------------------------------------------------------------------*/
-void usb_device_keeper_add_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_append(&ep->same_device_eps, &instance->devices[address].endpoints);
-	fibril_mutex_unlock(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-/** Attempt to obtain address 0, blocks.
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] speed Speed of the device requesting default address.
- */
-void usb_device_keeper_reserve_default_address(
-    usb_device_keeper_t *instance, usb_speed_t speed)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	while (instance->devices[USB_ADDRESS_DEFAULT].occupied) {
-		fibril_condvar_wait(&instance->change, &instance->guard);
-	}
-	instance->devices[USB_ADDRESS_DEFAULT].occupied = true;
-	instance->devices[USB_ADDRESS_DEFAULT].speed = speed;
-	fibril_mutex_unlock(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-/** Attempt to obtain address 0, blocks.
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] speed Speed of the device requesting default address.
- */
-void usb_device_keeper_release_default_address(usb_device_keeper_t *instance)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	instance->devices[USB_ADDRESS_DEFAULT].occupied = false;
-	fibril_mutex_unlock(&instance->guard);
-	fibril_condvar_signal(&instance->change);
-}
-/*----------------------------------------------------------------------------*/
-/** Check setup packet data for signs of toggle reset.
- *
- * @param[in] instance Device keeper structure to use.
- * @param[in] target Device to receive setup packet.
- * @param[in] data Setup packet data.
- *
- * Really ugly one.
- */
-void usb_device_keeper_reset_if_need(
-    usb_device_keeper_t *instance, usb_target_t target, const uint8_t *data)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	if (target.endpoint > 15 || target.endpoint < 0
-	    || target.address >= USB_ADDRESS_COUNT || target.address < 0
-	    || !instance->devices[target.address].occupied) {
-		fibril_mutex_unlock(&instance->guard);
-		usb_log_error("Invalid data when checking for toggle reset.\n");
-		return;
-	}
-
-	switch (data[1])
-	{
-	case 0x01: /*clear feature*/
-		/* recipient is endpoint, value is zero (ENDPOINT_STALL) */
-		if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
-			link_t *current =
-			    instance->devices[target.address].endpoints.next;
-			while (current !=
-			   &instance->devices[target.address].endpoints)
-			{
-			/* endpoint number is < 16, thus first byte is enough */
-				endpoint_toggle_reset_filtered(
-				    current, data[4]);
-				current = current->next;
-			}
-		}
-	break;
-
-	case 0x9: /* set configuration */
-	case 0x11: /* set interface */
-		/* target must be device */
-		if ((data[0] & 0xf) == 0) {
-			link_t *current =
-			    instance->devices[target.address].endpoints.next;
-			while (current !=
-			   &instance->devices[target.address].endpoints)
-			{
-				endpoint_toggle_reset(current);
-				current = current->next;
-			}
-		}
-	break;
-	}
-	fibril_mutex_unlock(&instance->guard);
+	// TODO: is this hack enough?
+	// (it is needed to allow smooth registration at default address)
+	instance->devices[0].occupied = true;
+	instance->last_address = 0;
+	fibril_mutex_initialize(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
@@ -184,7 +86,9 @@
 	assert(new_address != USB_ADDRESS_DEFAULT);
 	assert(instance->devices[new_address].occupied == false);
+
 	instance->devices[new_address].occupied = true;
 	instance->devices[new_address].speed = speed;
 	instance->last_address = new_address;
+
 	fibril_mutex_unlock(&instance->guard);
 	return new_address;
@@ -202,7 +106,9 @@
 	assert(instance);
 	fibril_mutex_lock(&instance->guard);
+
 	assert(address > 0);
 	assert(address <= USB11_ADDRESS_MAX);
 	assert(instance->devices[address].occupied);
+
 	instance->devices[address].handle = handle;
 	fibril_mutex_unlock(&instance->guard);
@@ -223,4 +129,5 @@
 	fibril_mutex_lock(&instance->guard);
 	assert(instance->devices[address].occupied);
+
 	instance->devices[address].occupied = false;
 	fibril_mutex_unlock(&instance->guard);
@@ -241,4 +148,5 @@
 	while (address <= USB11_ADDRESS_MAX) {
 		if (instance->devices[address].handle == handle) {
+			assert(instance->devices[address].occupied);
 			fibril_mutex_unlock(&instance->guard);
 			return address;
@@ -262,30 +170,6 @@
 	assert(address >= 0);
 	assert(address <= USB11_ADDRESS_MAX);
+
 	return instance->devices[address].speed;
-}
-/*----------------------------------------------------------------------------*/
-void usb_device_keeper_use_control(
-    usb_device_keeper_t *instance, usb_target_t target)
-{
-	assert(instance);
-	const uint16_t ep = 1 << target.endpoint;
-	fibril_mutex_lock(&instance->guard);
-	while (instance->devices[target.address].control_used & ep) {
-		fibril_condvar_wait(&instance->change, &instance->guard);
-	}
-	instance->devices[target.address].control_used |= ep;
-	fibril_mutex_unlock(&instance->guard);
-}
-/*----------------------------------------------------------------------------*/
-void usb_device_keeper_release_control(
-    usb_device_keeper_t *instance, usb_target_t target)
-{
-	assert(instance);
-	const uint16_t ep = 1 << target.endpoint;
-	fibril_mutex_lock(&instance->guard);
-	assert((instance->devices[target.address].control_used & ep) != 0);
-	instance->devices[target.address].control_used &= ~ep;
-	fibril_mutex_unlock(&instance->guard);
-	fibril_condvar_signal(&instance->change);
 }
 /**
Index: uspace/lib/usb/src/host/endpoint.c
===================================================================
--- uspace/lib/usb/src/host/endpoint.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/host/endpoint.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -34,4 +34,5 @@
  */
 
+#include <assert.h>
 #include <errno.h>
 #include <usb/host/endpoint.h>
@@ -49,5 +50,8 @@
 	instance->max_packet_size = max_packet_size;
 	instance->toggle = 0;
-	link_initialize(&instance->same_device_eps);
+	instance->active = false;
+	fibril_mutex_initialize(&instance->guard);
+	fibril_condvar_initialize(&instance->avail);
+	endpoint_clear_hc_data(instance);
 	return EOK;
 }
@@ -56,6 +60,42 @@
 {
 	assert(instance);
-	list_remove(&instance->same_device_eps);
+	assert(!instance->active);
 	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_set_hc_data(endpoint_t *instance,
+    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int))
+{
+	assert(instance);
+	instance->hc_data.data = data;
+	instance->hc_data.toggle_get = toggle_get;
+	instance->hc_data.toggle_set = toggle_set;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_clear_hc_data(endpoint_t *instance)
+{
+	assert(instance);
+	instance->hc_data.data = NULL;
+	instance->hc_data.toggle_get = NULL;
+	instance->hc_data.toggle_set = NULL;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_use(endpoint_t *instance)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	while (instance->active)
+		fibril_condvar_wait(&instance->avail, &instance->guard);
+	instance->active = true;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_release(endpoint_t *instance)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	instance->active = false;
+	fibril_mutex_unlock(&instance->guard);
+	fibril_condvar_signal(&instance->avail);
 }
 /*----------------------------------------------------------------------------*/
@@ -63,4 +103,7 @@
 {
 	assert(instance);
+	if (instance->hc_data.toggle_get)
+		instance->toggle =
+		    instance->hc_data.toggle_get(instance->hc_data.data);
 	return (int)instance->toggle;
 }
@@ -70,22 +113,15 @@
 	assert(instance);
 	assert(toggle == 0 || toggle == 1);
+	if (instance->hc_data.toggle_set)
+		instance->hc_data.toggle_set(instance->hc_data.data, toggle);
 	instance->toggle = toggle;
 }
 /*----------------------------------------------------------------------------*/
-void endpoint_toggle_reset(link_t *ep)
+void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target)
 {
-	endpoint_t *instance =
-	    list_get_instance(ep, endpoint_t, same_device_eps);
 	assert(instance);
-	instance->toggle = 0;
-}
-/*----------------------------------------------------------------------------*/
-void endpoint_toggle_reset_filtered(link_t *ep, usb_endpoint_t epn)
-{
-	endpoint_t *instance =
-	    list_get_instance(ep, endpoint_t, same_device_eps);
-	assert(instance);
-	if (instance->endpoint == epn)
-		instance->toggle = 0;
+	if (instance->address == target.address &&
+	    (instance->endpoint == target.endpoint || target.endpoint == 0))
+		endpoint_toggle_set(instance, 0);
 }
 /**
Index: uspace/lib/usb/src/host/usb_endpoint_manager.c
===================================================================
--- uspace/lib/usb/src/host/usb_endpoint_manager.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/host/usb_endpoint_manager.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -31,4 +31,5 @@
 #include <errno.h>
 
+#include <usb/debug.h>
 #include <usb/host/usb_endpoint_manager.h>
 
@@ -80,4 +81,12 @@
 	endpoint_destroy(node->ep);
 	free(node);
+}
+/*----------------------------------------------------------------------------*/
+static void node_toggle_reset_filtered(link_t *item, void *arg)
+{
+	assert(item);
+	node_t *node = hash_table_get_instance(item, node_t, link);
+	usb_target_t *target = arg;
+	endpoint_toggle_reset_filtered(node->ep, *target);
 }
 /*----------------------------------------------------------------------------*/
@@ -202,4 +211,7 @@
 
 	node_t *node = hash_table_get_instance(item, node_t, link);
+	if (node->ep->active)
+		return EBUSY;
+
 	instance->free_bw += node->bw;
 	hash_table_remove(&instance->ep_table, key, MAX_KEYS);
@@ -230,2 +242,50 @@
 	return node->ep;
 }
+/*----------------------------------------------------------------------------*/
+/** Check setup packet data for signs of toggle reset.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] target Device to receive setup packet.
+ * @param[in] data Setup packet data.
+ *
+ * Really ugly one.
+ */
+void usb_endpoint_manager_reset_if_need(
+    usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data)
+{
+	assert(instance);
+	if (target.endpoint > 15 || target.endpoint < 0
+	    || target.address >= USB11_ADDRESS_MAX || target.address < 0) {
+		usb_log_error("Invalid data when checking for toggle reset.\n");
+		return;
+	}
+
+	switch (data[1])
+	{
+	case 0x01: /*clear feature*/
+		/* recipient is endpoint, value is zero (ENDPOINT_STALL) */
+		if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
+			/* endpoint number is < 16, thus first byte is enough */
+			usb_target_t reset_target =
+			    { .address = target.address, data[4] };
+			fibril_mutex_lock(&instance->guard);
+			hash_table_apply(&instance->ep_table,
+			    node_toggle_reset_filtered, &reset_target);
+			fibril_mutex_unlock(&instance->guard);
+		}
+	break;
+
+	case 0x9: /* set configuration */
+	case 0x11: /* set interface */
+		/* target must be device */
+		if ((data[0] & 0xf) == 0) {
+			usb_target_t reset_target =
+			    { .address = target.address, 0 };
+			fibril_mutex_lock(&instance->guard);
+			hash_table_apply(&instance->ep_table,
+			    node_toggle_reset_filtered, &reset_target);
+			fibril_mutex_unlock(&instance->guard);
+		}
+	break;
+	}
+}
Index: uspace/lib/usb/src/hub.c
===================================================================
--- uspace/lib/usb/src/hub.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/hub.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -40,4 +40,10 @@
 #include <errno.h>
 #include <assert.h>
+#include <usb/debug.h>
+
+/** How much time to wait between attempts to register endpoint 0:0.
+ * The value is based on typical value for port reset + some overhead.
+ */
+#define ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC (1000 * (10 + 2))
 
 /** Check that HC connection is alright.
@@ -53,35 +59,4 @@
 	} while (false)
 
-
-/** Tell host controller to reserve default address.
- *
- * @param connection Opened connection to host controller.
- * @param speed Speed of the device that will respond on the default address.
- * @return Error code.
- */
-int usb_hc_reserve_default_address(usb_hc_connection_t *connection,
-    usb_speed_t speed)
-{
-	CHECK_CONNECTION(connection);
-
-	return async_req_2_0(connection->hc_phone,
-	    DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS, speed);
-}
-
-/** Tell host controller to release default address.
- *
- * @param connection Opened connection to host controller.
- * @return Error code.
- */
-int usb_hc_release_default_address(usb_hc_connection_t *connection)
-{
-	CHECK_CONNECTION(connection);
-
-	return async_req_1_0(connection->hc_phone,
-	    DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
-}
-
 /** Ask host controller for free address assignment.
  *
@@ -178,6 +153,11 @@
  * error codes than those listed as return codes by this function itself).
  *
+ * The @p connection representing connection with host controller does not
+ * need to be started.
+ * This function duplicates the connection to allow simultaneous calls of
+ * this function (i.e. from different fibrils).
+ *
  * @param[in] parent Parent device (i.e. the hub device).
- * @param[in] connection Opened connection to host controller.
+ * @param[in] connection Connection to host controller.
  * @param[in] dev_speed New device speed.
  * @param[in] enable_port Function for enabling signaling through the port the
@@ -206,43 +186,40 @@
     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
 {
-	CHECK_CONNECTION(connection);
+	assert(connection != NULL);
+	// FIXME: this is awful, we are accessing directly the structure.
+	usb_hc_connection_t hc_conn = {
+		.hc_handle = connection->hc_handle,
+		.hc_phone = -1
+	};
+
+	int rc;
+
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
 
 	/*
 	 * Request new address.
 	 */
-	usb_address_t dev_addr = usb_hc_request_address(connection, dev_speed);
+	usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
 	if (dev_addr < 0) {
+		usb_hc_connection_close(&hc_conn);
 		return EADDRNOTAVAIL;
 	}
 
-	int rc;
-
-	/*
-	 * Reserve the default address.
-	 */
-	rc = usb_hc_reserve_default_address(connection, 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;
 	rc = usb_device_connection_initialize_on_default_address(&dev_conn,
-	    connection);
+	    &hc_conn);
 	if (rc != EOK) {
 		rc = ENOTCONN;
-		goto leave_release_default_address;
+		goto leave_release_free_address;
 	}
 
@@ -252,54 +229,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(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
+		}
+	} 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_register(&ctrl_pipe, 0, connection);
-	if (rc != EOK) {
-		rc = EREFUSED;
+	rc = usb_pipe_probe_default_control(&ctrl_pipe);
+	if (rc != EOK) {
+		rc = ESTALL;
 		goto leave_release_default_address;
 	}
-	rc = usb_pipe_probe_default_control(&ctrl_pipe);
-	if (rc != EOK) {
-		rc = ENOTCONN;
+
+	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
+	if (rc != EOK) {
+		rc = ESTALL;
 		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, connection);
-	if (rc != EOK) {
-		rc = EREFUSED;
-		goto leave_unregister_endpoint;
-	}
-
-	/*
-	 * Release the original endpoint.
-	 */
-	unregister_control_endpoint_on_default_address(connection);
-
-	/*
-	 * Once the address is changed, we can return the default address.
-	 */
-	usb_hc_release_default_address(connection);
-
+	/*
+	 * 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) {
+		goto leave_release_free_address;
+	}
 
 	/*
@@ -316,6 +289,4 @@
 	}
 
-
-
 	/*
 	 * And now inform the host controller about the handle.
@@ -325,5 +296,5 @@
 		.handle = child_handle
 	};
-	rc = usb_hc_register_device(connection, &new_device);
+	rc = usb_hc_register_device(&hc_conn, &new_device);
 	if (rc != EOK) {
 		rc = EDESTADDRREQ;
@@ -349,16 +320,11 @@
 	 * Completely ignoring errors here.
 	 */
-
-leave_stop_session:
-	usb_pipe_end_session(&ctrl_pipe);
-
-leave_unregister_endpoint:
-	usb_pipe_unregister(&ctrl_pipe, connection);
-
 leave_release_default_address:
-	usb_hc_release_default_address(connection);
+	usb_pipe_unregister(&ctrl_pipe, &hc_conn);
 
 leave_release_free_address:
-	usb_hc_unregister_device(connection, dev_addr);
+	usb_hc_unregister_device(&hc_conn, dev_addr);
+
+	usb_hc_connection_close(&hc_conn);
 
 	return rc;
Index: uspace/lib/usb/src/pipepriv.c
===================================================================
--- uspace/lib/usb/src/pipepriv.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/src/pipepriv.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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 e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
+++ uspace/lib/usb/src/pipepriv.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/pipes.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/pipesinit.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -356,10 +356,14 @@
 	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;
+	pipe->auto_reset_halt = false;
 
 	return EOK;
@@ -382,4 +386,6 @@
 	    0, USB_TRANSFER_CONTROL, CTRL_PIPE_MIN_PACKET_SIZE,
 	    USB_DIRECTION_BOTH);
+
+	pipe->auto_reset_halt = true;
 
 	return rc;
@@ -413,10 +419,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 +440,5 @@
 		}
 	}
-	usb_pipe_end_session(pipe);
+	usb_pipe_end_long_transfer(pipe);
 	if (rc != EOK) {
 		return rc;
@@ -461,4 +462,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 +490,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 ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/pipesio.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -49,4 +49,6 @@
 #include <assert.h>
 #include <usbhc_iface.h>
+#include <usb/request.h>
+#include "pipepriv.h"
 
 /** Request an in transfer, no checking of input parameters.
@@ -78,13 +80,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 +101,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 +157,9 @@
 
 	if (buffer == NULL) {
-			return EINVAL;
+		return EINVAL;
 	}
 
 	if (size == 0) {
 		return EINVAL;
-	}
-
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
 	}
 
@@ -165,8 +172,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 +226,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 +245,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 +286,4 @@
 	}
 
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
-	}
-
 	if (pipe->direction != USB_DIRECTION_OUT) {
 		return EBADF;
@@ -272,7 +294,35 @@
 	}
 
-	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;
+}
+
+/** Try to clear endpoint halt of default control pipe.
+ *
+ * @param pipe Pipe for control endpoint zero.
+ */
+static void clear_self_endpoint_halt(usb_pipe_t *pipe)
+{
+	assert(pipe != NULL);
+
+	if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
+		return;
+	}
+
+
+	/* Prevent indefinite recursion. */
+	pipe->auto_reset_halt = false;
+	usb_request_clear_endpoint_halt(pipe, 0);
+	pipe->auto_reset_halt = true;
 }
 
@@ -293,11 +343,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 +363,5 @@
 	    setup_buffer, setup_buffer_size);
 	if (rc != EOK) {
+		pipe_end_transaction(pipe);
 		async_wait_for(opening_request, NULL);
 		return rc;
@@ -322,4 +375,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 +440,4 @@
 	}
 
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
-	}
-
 	if ((pipe->direction != USB_DIRECTION_BOTH)
 	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
@@ -388,8 +445,21 @@
 	}
 
+	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);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
+	pipe_drop_ref(pipe);
 
 	if (rc != EOK) {
@@ -418,14 +488,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 +510,5 @@
 	    setup_buffer, setup_buffer_size);
 	if (rc != EOK) {
+		pipe_end_transaction(pipe);
 		async_wait_for(opening_request, NULL);
 		return rc;
@@ -447,8 +521,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 +572,4 @@
 	}
 
-	if (!usb_pipe_is_session_started(pipe)) {
-		return EBADF;
-	}
-
 	if ((pipe->direction != USB_DIRECTION_BOTH)
 	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
@@ -500,6 +577,19 @@
 	}
 
-	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);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
+	pipe_drop_ref(pipe);
 
 	return rc;
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/recognise.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -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;
Index: uspace/lib/usb/src/request.c
===================================================================
--- uspace/lib/usb/src/request.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/lib/usb/src/request.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -871,4 +871,18 @@
 }
 
+/** Clear halt bit of an endpoint pipe (after pipe stall).
+ *
+ * @param pipe Control pipe.
+ * @param ep_index Endpoint index (in native endianness).
+ * @return Error code.
+ */
+int usb_request_clear_endpoint_halt(usb_pipe_t *pipe, uint16_t ep_index)
+{
+	return usb_request_clear_feature(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_ENDPOINT,
+	    uint16_host2usb(USB_FEATURE_SELECTOR_ENDPOINT_HALT),
+	    uint16_host2usb(ep_index));
+}
+
 /**
  * @}
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -372,4 +372,5 @@
 	uint16_t w;
 	uint8_t c;
+	uint16_t bc;
 	size_t pos, len;
 	int rc;
@@ -387,11 +388,24 @@
 	} else if (rc == EIO) {
 		/*
-		 * There is something, but not a register device.
-		 * It could be a packet device.
+		 * There is something, but not a register device. Check to see
+		 * whether the IDENTIFY command left the packet signature in
+		 * the registers in case this is a packet device.
+		 *
+		 * According to the ATA specification, the LBA low and
+		 * interrupt reason registers should be set to 0x01. However,
+		 * there are many devices that do not follow this and only set
+		 * the byte count registers. So, only check these.
 		 */
-		rc = identify_pkt_dev(disk_id, &idata);
-		if (rc == EOK) {
-			/* We have a packet device. */
-			d->dev_type = ata_pkt_dev;
+		bc = ((uint16_t)pio_read_8(&cmd->cylinder_high) << 8) |
+		    pio_read_8(&cmd->cylinder_low);
+
+		if (bc == PDEV_SIGNATURE_BC) {
+			rc = identify_pkt_dev(disk_id, &idata);
+			if (rc == EOK) {
+				/* We have a packet device. */
+				d->dev_type = ata_pkt_dev;
+			} else {
+				return EIO;
+			}
 		} else {
 			/* Nope. Something's there, but not recognized. */
@@ -403,5 +417,4 @@
 	}
 
-	printf("device caps: 0x%04x\n", idata.caps);
 	if (d->dev_type == ata_pkt_dev) {
 		/* Packet device */
@@ -566,8 +579,9 @@
 
 	/*
-	 * This is where we would most likely expect a non-existing device to
-	 * show up by not setting SR_DRDY.
+	 * Do not wait for DRDY to be set in case this is a packet device.
+	 * We determine whether the device is present by waiting for DRQ to be
+	 * set after issuing the command.
 	 */
-	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
 		return ETIMEOUT;
 
@@ -577,15 +591,20 @@
 		return ETIMEOUT;
 
+	/*
+	 * If ERR is set, this may be a packet device, so return EIO to cause
+	 * the caller to check for one.
+	 */
+	if ((status & SR_ERR) != 0) {
+		return EIO;
+	}
+
+	if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
+		return ETIMEOUT;
+
 	/* Read data from the disk buffer. */
 
-	if ((status & SR_DRQ) != 0) {
-		for (i = 0; i < identify_data_size / 2; i++) {
-			data = pio_read_16(&cmd->data_port);
-			((uint16_t *) buf)[i] = data;
-		}
-	}
-
-	if ((status & SR_ERR) != 0) {
-		return EIO;
+	for (i = 0; i < identify_data_size / 2; i++) {
+		data = pio_read_16(&cmd->data_port);
+		((uint16_t *) buf)[i] = data;
 	}
 
Index: uspace/srv/bd/ata_bd/ata_hw.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_hw.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/bd/ata_bd/ata_hw.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -293,4 +293,12 @@
 };
 
+enum ata_pdev_signature {
+	/**
+	 * Signature put by a packet device in byte count register
+	 * in response to Identify command.
+	 */
+	PDEV_SIGNATURE_BC	= 0xEB14
+};
+
 #endif
 
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/devman/devman.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -555,17 +555,4 @@
 }
 
-/** Remember the driver's phone.
- *
- * @param driver	The driver.
- * @param phone		The phone to the driver.
- */
-void set_driver_phone(driver_t *driver, sysarg_t phone)
-{
-	fibril_mutex_lock(&driver->driver_mutex);
-	assert(driver->state == DRIVER_STARTING);
-	driver->phone = phone;
-	fibril_mutex_unlock(&driver->driver_mutex);
-}
-
 /** Notify driver about the devices to which it was assigned.
  *
@@ -685,4 +672,5 @@
 	list_initialize(&drv->devices);
 	fibril_mutex_initialize(&drv->driver_mutex);
+	drv->phone = -1;
 }
 
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/devman/devman.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -88,5 +88,5 @@
 	
 	/** Phone asociated with this driver. */
-	sysarg_t phone;
+	int phone;
 	/** Name of the device driver. */
 	char *name;
@@ -316,5 +316,4 @@
 
 extern driver_t *find_driver(driver_list_t *, const char *);
-extern void set_driver_phone(driver_t *, sysarg_t);
 extern void initialize_running_driver(driver_t *, dev_tree_t *);
 
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/devman/main.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -95,5 +95,4 @@
 	/* Find driver structure. */
 	driver = find_driver(&drivers_list, drv_name);
-	
 	if (driver == NULL) {
 		log_msg(LVL_ERROR, "No driver named `%s' was found.", drv_name);
@@ -107,4 +106,30 @@
 	drv_name = NULL;
 	
+	fibril_mutex_lock(&driver->driver_mutex);
+	
+	if (driver->phone >= 0) {
+		/* We already have a connection to the driver. */
+		log_msg(LVL_ERROR, "Driver '%s' already started.\n",
+		    driver->name);
+		fibril_mutex_unlock(&driver->driver_mutex);
+		async_answer_0(iid, EEXISTS);
+		return NULL;
+	}
+	
+	switch (driver->state) {
+	case DRIVER_NOT_STARTED:
+		/* Somebody started the driver manually. */
+		log_msg(LVL_NOTE, "Driver '%s' started manually.\n",
+		    driver->name);
+		driver->state = DRIVER_STARTING;
+		break;
+	case DRIVER_STARTING:
+		/* The expected case */
+		break;
+	case DRIVER_RUNNING:
+		/* Should not happen since we do not have a connected phone */
+		assert(false);
+	}
+	
 	/* Create connection to the driver. */
 	log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
@@ -113,4 +138,5 @@
 	ipc_callid_t callid = async_get_call(&call);
 	if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
+		fibril_mutex_unlock(&driver->driver_mutex);
 		async_answer_0(callid, ENOTSUP);
 		async_answer_0(iid, ENOTSUP);
@@ -119,5 +145,7 @@
 	
 	/* Remember driver's phone. */
-	set_driver_phone(driver, IPC_GET_ARG5(call));
+	driver->phone = IPC_GET_ARG5(call);
+	
+	fibril_mutex_unlock(&driver->driver_mutex);
 	
 	log_msg(LVL_NOTE, 
@@ -579,5 +607,5 @@
 		method = DRIVER_CLIENT;
 	
-	if (driver->phone <= 0) {
+	if (driver->phone < 0) {
 		log_msg(LVL_ERROR, 
 		    "Could not forward to driver `%s' (phone is %d).",
@@ -619,5 +647,5 @@
 	dev = fun->dev;
 	
-	if (dev->state != DEVICE_USABLE || dev->drv->phone <= 0) {
+	if (dev->state != DEVICE_USABLE || dev->drv->phone < 0) {
 		async_answer_0(iid, EINVAL);
 		return;
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/fs/fat/fat_ops.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -722,6 +722,6 @@
 		    (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
 			memset(d, 0, sizeof(fat_dentry_t));
-			str_cpy((char *) d->name, 8, FAT_NAME_DOT);
-			str_cpy((char *) d->ext, 3, FAT_EXT_PAD);
+			memcpy(d->name, FAT_NAME_DOT, FAT_NAME_LEN);
+			memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
 			d->attr = FAT_ATTR_SUBDIR;
 			d->firstc = host2uint16_t_le(childp->firstc);
@@ -732,6 +732,6 @@
 		    (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
 			memset(d, 0, sizeof(fat_dentry_t));
-			str_cpy((char *) d->name, 8, FAT_NAME_DOT_DOT);
-			str_cpy((char *) d->ext, 3, FAT_EXT_PAD);
+			memcpy(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN);
+			memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
 			d->attr = FAT_ATTR_SUBDIR;
 			d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/net/il/ip/ip.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -176,5 +176,5 @@
 	socklen_t addrlen;
 
-	// detach the first packet and release the others
+	/* Detach the first packet and release the others */
 	next = pq_detach(packet);
 	if (next)
@@ -185,5 +185,5 @@
 			return ENOMEM;
 
-		// get header
+		/* Get header */
 		header = (ip_header_t *) packet_get_data(packet);
 		if (!header)
@@ -192,13 +192,13 @@
 	}
 
-	// only for the first fragment
+	/* Only for the first fragment */
 	if (IP_FRAGMENT_OFFSET(header))
 		return EINVAL;
 
-	// not for the ICMP protocol
+	/* Not for the ICMP protocol */
 	if (header->protocol == IPPROTO_ICMP)
 		return EPERM;
 
-	// set the destination address
+	/* Set the destination address */
 	switch (header->version) {
 	case IPVERSION:
@@ -351,5 +351,5 @@
 	configuration = &names[0];
 
-	// get configuration
+	/* Get configuration */
 	rc = net_get_device_conf_req(ip_globals.net_phone, ip_netif->device_id,
 	    &configuration, count, &data);
@@ -419,5 +419,5 @@
 	}
 
-	// binds the netif service which also initializes the device
+	/* Bind netif service which also initializes the device */
 	ip_netif->phone = nil_bind_service(ip_netif->service,
 	    (sysarg_t) ip_netif->device_id, SERVICE_IP,
@@ -429,5 +429,5 @@
 	}
 
-	// has to be after the device netif module initialization
+	/* Has to be after the device netif module initialization */
 	if (ip_netif->arp) {
 		if (route) {
@@ -445,5 +445,5 @@
 	}
 
-	// get packet dimensions
+	/* Get packet dimensions */
 	rc = nil_packet_size_req(ip_netif->phone, ip_netif->device_id,
 	    &ip_netif->packet_dimension);
@@ -463,5 +463,5 @@
 	
 	if (gateway.s_addr) {
-		// the default gateway
+		/* The default gateway */
 		ip_globals.gateway.address.s_addr = 0;
 		ip_globals.gateway.netmask.s_addr = 0;
@@ -512,5 +512,5 @@
 		ip_netif->arp->usage++;
 
-	// print the settings
+	/* Print the settings */
 	printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
 	    NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
@@ -587,5 +587,5 @@
 	ip_netif_t *netif;
 
-	// start with the last netif - the newest one
+	/* Start with the last netif - the newest one */
 	index = ip_netifs_count(&ip_globals.netifs) - 1;
 	while (index >= 0) {
@@ -629,18 +629,18 @@
 	size_t length;
 
-	// copy first itself
+	/* Copy first itself */
 	memcpy(last, first, sizeof(ip_header_t));
 	length = sizeof(ip_header_t);
 	next = sizeof(ip_header_t);
 
-	// process all ip options
+	/* Process all IP options */
 	while (next < first->header_length) {
 		option = (ip_option_t *) (((uint8_t *) first) + next);
-		// skip end or noop
+		/* Skip end or noop */
 		if ((option->type == IPOPT_END) ||
 		    (option->type == IPOPT_NOOP)) {
 			next++;
 		} else {
-			// copy if told so or skip
+			/* Copy if told so or skip */
 			if (IPOPT_COPIED(option->type)) {
 				memcpy(((uint8_t *) last) + length,
@@ -648,10 +648,10 @@
 				length += option->length;
 			}
-			// next option
+			/* Next option */
 			next += option->length;
 		}
 	}
 
-	// align 4 byte boundary
+	/* Align 4 byte boundary */
 	if (length % 4) {
 		bzero(((uint8_t *) last) + length, 4 - (length % 4));
@@ -789,5 +789,5 @@
 
 	header->total_length = htons(length);
-	// unnecessary for all protocols
+	/* Unnecessary for all protocols */
 	header->header_checksum = IP_HEADER_CHECKSUM(header);
 
@@ -916,14 +916,14 @@
 		return ENOMEM;
 
-	// get header
+	/* Get header */
 	header = (ip_header_t *) packet_get_data(packet);
 	if (!header)
 		return EINVAL;
 
-	// fragmentation forbidden?
+	/* Fragmentation forbidden? */
 	if(header->flags & IPFLAG_DONT_FRAGMENT)
 		return EPERM;
 
-	// create the last fragment
+	/* Create the last fragment */
 	new_packet = packet_get_4_remote(ip_globals.net_phone, prefix, length,
 	    suffix, ((addrlen > addr_len) ? addrlen : addr_len));
@@ -931,5 +931,5 @@
 		return ENOMEM;
 
-	// allocate as much as originally
+	/* Allocate as much as originally */
 	last_header = (ip_header_t *) packet_suffix(new_packet,
 	    IP_HEADER_LENGTH(header));
@@ -939,5 +939,5 @@
 	ip_create_last_header(last_header, header);
 
-	// trim the unused space
+	/* Trim the unused space */
 	rc = packet_trim(new_packet, 0,
 	    IP_HEADER_LENGTH(header) - IP_HEADER_LENGTH(last_header));
@@ -945,5 +945,5 @@
 		return ip_release_and_return(packet, rc);
 
-	// biggest multiple of 8 lower than content
+	/* Greatest multiple of 8 lower than content */
 	// TODO even fragmentation?
 	length = length & ~0x7;
@@ -957,8 +957,8 @@
 		return ip_release_and_return(packet, rc);
 
-	// mark the first as fragmented
+	/* Mark the first as fragmented */
 	header->flags |= IPFLAG_MORE_FRAGMENTS;
 
-	// create middle framgents
+	/* Create middle fragments */
 	while (IP_TOTAL_LENGTH(header) > length) {
 		new_packet = packet_get_4_remote(ip_globals.net_phone, prefix,
@@ -981,5 +981,5 @@
 	}
 
-	// finish the first fragment
+	/* Finish the first fragment */
 	header->header_checksum = IP_HEADER_CHECKSUM(header);
 
@@ -1012,5 +1012,5 @@
 
 	next = packet;
-	// check all packets
+	/* Check all packets */
 	while (next) {
 		length = packet_get_data_length(next);
@@ -1021,5 +1021,5 @@
 		}
 
-		// too long
+		/* Too long */
 		result = ip_fragment_packet(next, content, prefix,
 		    suffix, addr_len);
@@ -1027,13 +1027,13 @@
 			new_packet = pq_detach(next);
 			if (next == packet) {
-				// the new first packet of the queue
+				/* The new first packet of the queue */
 				packet = new_packet;
 			}
-			// fragmentation needed?
+			/* Fragmentation needed? */
 			if (result == EPERM) {
 				phone = ip_prepare_icmp_and_get_phone(
 				    error, next, NULL);
 				if (phone >= 0) {
-					// fragmentation necessary ICMP
+					/* Fragmentation necessary ICMP */
 					icmp_destination_unreachable_msg(phone,
 					    ICMP_FRAG_NEEDED, content, next);
@@ -1080,5 +1080,5 @@
 	int rc;
 
-	// get destination hardware address
+	/* Get destination hardware address */
 	if (netif->arp && (route->address.s_addr != dest.s_addr)) {
 		destination.value = route->gateway.s_addr ?
@@ -1102,5 +1102,5 @@
 			    NULL);
 			if (phone >= 0) {
-				// unreachable ICMP if no routing
+				/* Unreachable ICMP if no routing */
 				icmp_destination_unreachable_msg(phone,
 				    ICMP_HOST_UNREACH, 0, packet);
@@ -1148,6 +1148,8 @@
 	int rc;
 
-	// addresses in the host byte order
-	// should be the next hop address or the target destination address
+	/*
+	 * Addresses in the host byte order
+	 * Should be the next hop address or the target destination address
+	 */
 	addrlen = packet_get_addr(packet, NULL, (uint8_t **) &addr);
 	if (addrlen < 0)
@@ -1174,5 +1176,5 @@
 	fibril_rwlock_read_lock(&ip_globals.netifs_lock);
 
-	// device specified?
+	/* Device specified? */
 	if (device_id > 0) {
 		netif = ip_netifs_find(&ip_globals.netifs, device_id);
@@ -1190,5 +1192,5 @@
 		phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
 		if (phone >= 0) {
-			// unreachable ICMP if no routing
+			/* Unreachable ICMP if no routing */
 			icmp_destination_unreachable_msg(phone,
 			    ICMP_NET_UNREACH, 0, packet);
@@ -1198,6 +1200,8 @@
 
 	if (error) {
-		// do not send for broadcast, anycast packets or network
-		// broadcast
+		/*
+		 * Do not send for broadcast, anycast packets or network
+		 * broadcast.
+		 */
 		if (!dest->s_addr || !(~dest->s_addr) ||
 		    !(~((dest->s_addr & ~route->netmask.s_addr) |
@@ -1208,8 +1212,8 @@
 	}
 	
-	// if the local host is the destination
+	/* If the local host is the destination */
 	if ((route->address.s_addr == dest->s_addr) &&
 	    (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
-		// find the loopback device to deliver
+		/* Find the loopback device to deliver */
 		dest->s_addr = IPV4_LOCALHOST_ADDRESS;
 		route = ip_find_route(*dest);
@@ -1220,5 +1224,5 @@
 			    NULL);
 			if (phone >= 0) {
-				// unreachable ICMP if no routing
+				/* Unreachable ICMP if no routing */
 				icmp_destination_unreachable_msg(phone,
 				    ICMP_HOST_UNREACH, 0, packet);
@@ -1252,5 +1256,5 @@
 
 	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-	// find the device
+	/* Find the device */
 	netif = ip_netifs_find(&ip_globals.netifs, device_id);
 	if (!netif) {
@@ -1344,5 +1348,5 @@
 		return ip_release_and_return(packet, rc);
 
-	// trim padding if present
+	/* Trim padding if present */
 	if (!error &&
 	    (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))) {
@@ -1360,5 +1364,5 @@
 		phone = ip_prepare_icmp_and_get_phone(error, packet, header);
 		if (phone >= 0) {
-			// unreachable ICMP
+			/* Unreachable ICMP */
 			icmp_destination_unreachable_msg(phone,
 			    ICMP_PROT_UNREACH, 0, packet);
@@ -1417,10 +1421,10 @@
 		return ip_release_and_return(packet, ENOMEM);
 
-	// checksum
+	/* Checksum */
 	if ((header->header_checksum) &&
 	    (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)) {
 		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
 		if (phone >= 0) {
-			// checksum error ICMP
+			/* Checksum error ICMP */
 			icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER,
 			    ((size_t) ((void *) &header->header_checksum)) -
@@ -1433,5 +1437,5 @@
 		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
 		if (phone >= 0) {
-			// ttl exceeded ICMP
+			/* TTL exceeded ICMP */
 			icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
 		}
@@ -1439,8 +1443,8 @@
 	}
 	
-	// process ipopt and get destination
+	/* Process ipopt and get destination */
 	dest = ip_get_destination(header);
 
-	// set the addrination address
+	/* Set the destination address */
 	switch (header->version) {
 	case IPVERSION:
@@ -1464,5 +1468,5 @@
 		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
 		if (phone >= 0) {
-			// unreachable ICMP
+			/* Unreachable ICMP */
 			icmp_destination_unreachable_msg(phone,
 			    ICMP_HOST_UNREACH, 0, packet);
@@ -1472,5 +1476,5 @@
 
 	if (route->address.s_addr == dest.s_addr) {
-		// local delivery
+		/* Local delivery */
 		return ip_deliver_local(device_id, packet, header, 0);
 	}
@@ -1484,5 +1488,5 @@
 	phone = ip_prepare_icmp_and_get_phone(0, packet, header);
 	if (phone >= 0) {
-		// unreachable ICMP if no routing
+		/* Unreachable ICMP if no routing */
 		icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0,
 		    packet);
@@ -1770,8 +1774,8 @@
 		header = (ip_header_t *)(data + offset);
 
-		// destination host unreachable?
+		/* Destination host unreachable? */
 		if ((type != ICMP_DEST_UNREACH) ||
 		    (code != ICMP_HOST_UNREACH)) {
-		    	// no, something else
+			/* No, something else */
 			break;
 		}
@@ -1787,8 +1791,8 @@
 		route = ip_routes_get_index(&netif->routes, 0);
 
-		// from the same network?
+		/* From the same network? */
 		if (route && ((route->address.s_addr & route->netmask.s_addr) ==
 		    (header->destination_address & route->netmask.s_addr))) {
-			// clear the ARP mapping if any
+			/* Clear the ARP mapping if any */
 			address.value = (uint8_t *) &header->destination_address;
 			address.length = sizeof(header->destination_address);
@@ -1844,8 +1848,8 @@
 	fibril_rwlock_read_lock(&ip_globals.lock);
 	route = ip_find_route(*dest);
-	// if the local host is the destination
+	/* If the local host is the destination */
 	if (route && (route->address.s_addr == dest->s_addr) &&
 	    (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
-		// find the loopback device to deliver
+		/* Find the loopback device to deliver */
 		dest->s_addr = IPV4_LOCALHOST_ADDRESS;
 		route = ip_find_route(*dest);
Index: uspace/srv/net/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/net/nil/eth/eth.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -531,5 +531,5 @@
 			    proto->service);
 		} else {
-			// drop invalid/unknown
+			/* Drop invalid/unknown */
 			pq_release_remote(eth_globals.net_phone,
 			    packet_get_id(packet));
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -299,7 +299,8 @@
 		return tcp_release_and_return(packet, NO_DATA);
 
-//      printf("header len %d, port %d \n", TCP_HEADER_LENGTH(header),
-//	    ntohs(header->destination_port));
-
+#if 0
+	printf("header len %d, port %d \n", TCP_HEADER_LENGTH(header),
+	    ntohs(header->destination_port));
+#endif
 	result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
 	if (result <= 0)
@@ -1062,5 +1063,5 @@
 	tcp_process_acknowledgement(socket, socket_data, header);
 
-	socket_data->next_incoming = ntohl(header->sequence_number);	// + 1;
+	socket_data->next_incoming = ntohl(header->sequence_number); /* + 1; */
 	pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
 	socket_data->state = TCP_SOCKET_ESTABLISHED;
Index: uspace/srv/net/tl/tcp/tcp.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp.h	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/net/tl/tcp/tcp.h	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -190,7 +190,4 @@
 	int backlog;
 	
-//	/** Segment size. */
-//	size_t segment_size;
-
 	/**
 	 * Parent listening socket identifier.
Index: uspace/srv/net/tl/udp/udp.c
===================================================================
--- uspace/srv/net/tl/udp/udp.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/net/tl/udp/udp.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -499,5 +499,9 @@
 	device_id_t device_id;
 	packet_dimension_t *packet_dimension;
+	size_t size;
 	int rc;
+
+	/* In case of error, do not update the data fragment size. */
+	*data_fragment_size = 0;
 	
 	rc = tl_get_address_port(addr, addrlen, &dest_port);
@@ -539,4 +543,14 @@
 		packet_dimension = &udp_globals.packet_dimension;
 //	}
+
+	/*
+	 * Update the data fragment size based on what the lower layers can
+	 * handle without fragmentation, but not more than the maximum allowed
+	 * for UDP.
+	 */
+	size = MAX_UDP_FRAGMENT_SIZE;
+	if (packet_dimension->content < size)
+	    size = packet_dimension->content;
+	*data_fragment_size = size;
 
 	/* Read the first packet fragment */
@@ -740,5 +754,5 @@
 	int socket_id;
 	size_t addrlen;
-	size_t size = 0;
+	size_t size;
 	ipc_call_t answer;
 	size_t answer_count;
@@ -786,13 +800,12 @@
 				break;
 			
+			size = MAX_UDP_FRAGMENT_SIZE;
 			if (tl_get_ip_packet_dimension(udp_globals.ip_phone,
 			    &udp_globals.dimensions, DEVICE_INVALID_ID,
 			    &packet_dimension) == EOK) {
-				SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
-				    packet_dimension->content);
+				if (packet_dimension->content < size)
+					size = packet_dimension->content;
 			}
-
-//			SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
-//			    MAX_UDP_FRAGMENT_SIZE);
+			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
 			SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
 			answer_count = 3;
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision ef354b6778a2049a1546b354af20cf92410bf74c)
+++ uspace/srv/vfs/vfs_file.c	(revision e50cd7f06f4f69de26916ce998bb262dbcd8bec0)
@@ -258,7 +258,9 @@
 	if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
 		vfs_file_t *file = FILES[fd];
-		vfs_file_addref(file);
-		fibril_mutex_unlock(&VFS_DATA->lock);
-		return file;
+		if (file != NULL) {
+			vfs_file_addref(file);
+			fibril_mutex_unlock(&VFS_DATA->lock);
+			return file;
+		}
 	}
 	fibril_mutex_unlock(&VFS_DATA->lock);
