Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision 8240dc5a6bfbb4e3c8ad048993eac2db271476f1)
+++ uspace/lib/c/generic/devman.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -230,8 +230,8 @@
 	
 	if (flags & IPC_FLAG_BLOCKING) {
-		phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
+		phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
 		    DEVMAN_CONNECT_TO_DEVICE, handle);
 	} else {
-		phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
+		phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
 		    DEVMAN_CONNECT_TO_DEVICE, handle);
 	}
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 8240dc5a6bfbb4e3c8ad048993eac2db271476f1)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -38,4 +38,8 @@
 	HW_RES_DEV_IFACE = 0,	
 	CHAR_DEV_IFACE,
+
+	/** Interface provided by USB host controller. */
+	USBHC_DEV_IFACE,
+
 	// TODO add more interfaces
 	DEV_IFACE_MAX
@@ -50,4 +54,14 @@
 	DEV_IFACE_ID(DEV_FIRST_CUSTOM_METHOD_IDX)
 
+/*
+ * The first argument is actually method (as the "real" method is used
+ * for indexing into interfaces.
+ */
+
+#define DEV_IPC_GET_ARG1(call) IPC_GET_ARG2((call))
+#define DEV_IPC_GET_ARG2(call) IPC_GET_ARG3((call))
+#define DEV_IPC_GET_ARG3(call) IPC_GET_ARG4((call))
+#define DEV_IPC_GET_ARG4(call) IPC_GET_ARG5((call))
+
 
 #endif
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 8240dc5a6bfbb4e3c8ad048993eac2db271476f1)
+++ uspace/lib/drv/Makefile	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -29,5 +29,5 @@
 
 USPACE_PREFIX = ../..
-EXTRA_CFLAGS = -Iinclude
+EXTRA_CFLAGS = -Iinclude -I$(LIBUSB_PREFIX)/include
 LIBRARY = libdrv
 
@@ -36,4 +36,5 @@
 	generic/dev_iface.c \
 	generic/remote_res.c \
+	generic/remote_usbhc.c \
 	generic/remote_char.c
 
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 8240dc5a6bfbb4e3c8ad048993eac2db271476f1)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -39,9 +39,11 @@
 #include "remote_res.h"
 #include "remote_char.h"
+#include "remote_usbhc.h"
 
 static iface_dipatch_table_t remote_ifaces = {
 	.ifaces = {
 		&remote_res_iface,
-		&remote_char_iface
+		&remote_char_iface,
+		&remote_usbhc_iface
 	}
 };
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 8240dc5a6bfbb4e3c8ad048993eac2db271476f1)
+++ uspace/lib/drv/generic/driver.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -390,5 +390,6 @@
  */
 int child_device_register_wrapper(device_t *parent, const char *child_name,
-    const char *child_match_id, int child_match_score)
+    const char *child_match_id, int child_match_score,
+    devman_handle_t *child_handle)
 {
 	device_t *child = NULL;
@@ -418,4 +419,7 @@
 		goto failure;
 
+	if (child_handle != NULL) {
+		*child_handle = child->handle;
+	}
 	return EOK;
 
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,502 @@
+/*
+ * 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
+ */
+
+#include <ipc/ipc.h>
+#include <async.h>
+#include <errno.h>
+
+#include "usbhc_iface.h"
+#include "driver.h"
+
+#define USB_MAX_PAYLOAD_SIZE 1020
+
+static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_get_buffer(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_write_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_release_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+//static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB interface operations. */
+static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
+	remote_usbhc_get_address,
+
+	remote_usbhc_get_buffer,
+
+	remote_usbhc_reserve_default_address,
+	remote_usbhc_release_default_address,
+
+	remote_usbhc_request_address,
+	remote_usbhc_bind_address,
+	remote_usbhc_release_address,
+
+	remote_usbhc_interrupt_out,
+	remote_usbhc_interrupt_in,
+
+	remote_usbhc_control_write_setup,
+	remote_usbhc_control_write_data,
+	remote_usbhc_control_write_status,
+
+	remote_usbhc_control_read_setup,
+	remote_usbhc_control_read_data,
+	remote_usbhc_control_read_status
+};
+
+/** Remote USB interface structure.
+ */
+remote_iface_t remote_usbhc_iface = {
+	.method_count = sizeof(remote_usbhc_iface_ops) /
+	    sizeof(remote_usbhc_iface_ops[0]),
+	.methods = remote_usbhc_iface_ops
+};
+
+typedef struct {
+	ipc_callid_t caller;
+	void *buffer;
+	size_t size;
+} async_transaction_t;
+
+void remote_usbhc_get_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->tell_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
+
+	usb_address_t address;
+	int rc = usb_iface->tell_address(device, handle, &address);
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+	} else {
+		ipc_answer_1(callid, EOK, address);
+	}
+}
+
+void remote_usbhc_get_buffer(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	sysarg_t buffer_hash = DEV_IPC_GET_ARG1(*call);
+	async_transaction_t * trans = (async_transaction_t *)buffer_hash;
+	if (trans == NULL) {
+		ipc_answer_0(callid, ENOENT);
+		return;
+	}
+	if (trans->buffer == NULL) {
+		ipc_answer_0(callid, EINVAL);
+		free(trans);
+		return;
+	}
+
+	ipc_callid_t cid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&cid, &accepted_size)) {
+		ipc_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (accepted_size > trans->size) {
+		accepted_size = trans->size;
+	}
+	async_data_read_finalize(cid, trans->buffer, accepted_size);
+
+	ipc_answer_1(callid, EOK, accepted_size);
+
+	free(trans->buffer);
+	free(trans);
+}
+
+void remote_usbhc_reserve_default_address(device_t *device, 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) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int rc = usb_iface->reserve_default_address(device);
+
+	ipc_answer_0(callid, rc);
+}
+
+void remote_usbhc_release_default_address(device_t *device, 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) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int rc = usb_iface->release_default_address(device);
+
+	ipc_answer_0(callid, rc);
+}
+
+void remote_usbhc_request_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->request_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address;
+	int rc = usb_iface->request_address(device, &address);
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+	} else {
+		ipc_answer_1(callid, EOK, (sysarg_t) address);
+	}
+}
+
+void remote_usbhc_bind_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->bind_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
+
+	int rc = usb_iface->bind_address(device, address, handle);
+
+	ipc_answer_0(callid, rc);
+}
+
+void remote_usbhc_release_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->release_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+
+	int rc = usb_iface->release_address(device, address);
+
+	ipc_answer_0(callid, rc);
+}
+
+
+static void callback_out(device_t *device,
+    usb_transaction_outcome_t outcome, void *arg)
+{
+	async_transaction_t *trans = (async_transaction_t *)arg;
+
+	// FIXME - answer according to outcome
+	ipc_answer_0(trans->caller, EOK);
+
+	free(trans);
+}
+
+static void callback_in(device_t *device,
+    usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
+{
+	async_transaction_t *trans = (async_transaction_t *)arg;
+
+	// FIXME - answer according to outcome
+	ipc_answer_1(trans->caller, EOK, (sysarg_t)trans);
+
+	trans->size = actual_size;
+}
+
+/** Process an outgoing transfer (both OUT and SETUP).
+ *
+ * @param device Target device.
+ * @param callid Initiating caller.
+ * @param call Initiating call.
+ * @param transfer_func Transfer function (might be NULL).
+ */
+static void remote_usbhc_out_transfer(device_t *device,
+    ipc_callid_t callid, ipc_call_t *call,
+    usbhc_iface_transfer_out_t transfer_func)
+{
+	if (!transfer_func) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	size_t expected_len = DEV_IPC_GET_ARG3(*call);
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	size_t len = 0;
+	void *buffer = NULL;
+	if (expected_len > 0) {
+		int rc = async_data_write_accept(&buffer, false,
+		    1, USB_MAX_PAYLOAD_SIZE,
+		    0, &len);
+
+		if (rc != EOK) {
+			ipc_answer_0(callid, rc);
+			return;
+		}
+	}
+
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	trans->caller = callid;
+	trans->buffer = buffer;
+	trans->size = len;
+
+	int rc = transfer_func(device, target, buffer, len,
+	    callback_out, trans);
+
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		if (buffer != NULL) {
+			free(buffer);
+		}
+		free(trans);
+	}
+}
+
+/** Process an incoming transfer.
+ *
+ * @param device Target device.
+ * @param callid Initiating caller.
+ * @param call Initiating call.
+ * @param transfer_func Transfer function (might be NULL).
+ */
+static void remote_usbhc_in_transfer(device_t *device,
+    ipc_callid_t callid, ipc_call_t *call,
+    usbhc_iface_transfer_in_t transfer_func)
+{
+	if (!transfer_func) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	size_t len = DEV_IPC_GET_ARG3(*call);
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	trans->caller = callid;
+	trans->buffer = malloc(len);
+	trans->size = len;
+
+	int rc = transfer_func(device, target, trans->buffer, len,
+	    callback_in, trans);
+
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		free(trans->buffer);
+		free(trans);
+	}
+}
+
+/** Process status part of control transfer.
+ *
+ * @param device Target device.
+ * @param callid Initiating caller.
+ * @param call Initiating call.
+ * @param direction Transfer direction (read ~ in, write ~ out).
+ * @param transfer_in_func Transfer function for control read (might be NULL).
+ * @param transfer_out_func Transfer function for control write (might be NULL).
+ */
+static void remote_usbhc_status_transfer(device_t *device,
+    ipc_callid_t callid, ipc_call_t *call,
+    usb_direction_t direction,
+    int (*transfer_in_func)(device_t *, usb_target_t,
+        usbhc_iface_transfer_in_callback_t, void *),
+    int (*transfer_out_func)(device_t *, usb_target_t,
+        usbhc_iface_transfer_out_callback_t, void *))
+{
+	switch (direction) {
+		case USB_DIRECTION_IN:
+			if (!transfer_in_func) {
+				ipc_answer_0(callid, ENOTSUP);
+				return;
+			}
+			break;
+		case USB_DIRECTION_OUT:
+			if (!transfer_out_func) {
+				ipc_answer_0(callid, ENOTSUP);
+				return;
+			}
+			break;
+		default:
+			assert(false && "unreachable code");
+			break;
+	}
+
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	trans->caller = callid;
+	trans->buffer = NULL;
+	trans->size = 0;
+
+	int rc;
+	switch (direction) {
+		case USB_DIRECTION_IN:
+			rc = transfer_in_func(device, target,
+			    callback_in, trans);
+			break;
+		case USB_DIRECTION_OUT:
+			rc = transfer_out_func(device, target,
+			    callback_out, trans);
+			break;
+		default:
+			assert(false && "unreachable code");
+			break;
+	}
+
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+		free(trans);
+	}
+	return;
+}
+
+
+void remote_usbhc_interrupt_out(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_out_transfer(device, callid, call,
+	    usb_iface->interrupt_out);
+}
+
+void remote_usbhc_interrupt_in(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_in_transfer(device, callid, call,
+	    usb_iface->interrupt_in);
+}
+
+void remote_usbhc_control_write_setup(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_out_transfer(device, callid, call,
+	    usb_iface->control_write_setup);
+}
+
+void remote_usbhc_control_write_data(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_out_transfer(device, callid, call,
+	    usb_iface->control_write_data);
+}
+
+void remote_usbhc_control_write_status(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_status_transfer(device, callid, call,
+	    USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
+}
+
+void remote_usbhc_control_read_setup(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_out_transfer(device, callid, call,
+	    usb_iface->control_read_setup);
+}
+
+void remote_usbhc_control_read_data(device_t *device, void *iface,
+	    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_in_transfer(device, callid, call,
+	    usb_iface->control_read_data);
+}
+
+void remote_usbhc_control_read_status(device_t *device, void *iface,
+	    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_status_transfer(device, callid, call,
+	    USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
+}
+
+
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/driver.h
===================================================================
--- uspace/lib/drv/include/driver.h	(revision 8240dc5a6bfbb4e3c8ad048993eac2db271476f1)
+++ uspace/lib/drv/include/driver.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -199,5 +199,6 @@
 
 int child_device_register(device_t *, device_t *);
-int child_device_register_wrapper(device_t *, const char *, const char *, int);
+int child_device_register_wrapper(device_t *, const char *, const char *, int,
+    devman_handle_t *);
 
 
Index: uspace/lib/drv/include/remote_usbhc.h
===================================================================
--- uspace/lib/drv/include/remote_usbhc.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/drv/include/remote_usbhc.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+
+#ifndef LIBDRV_REMOTE_USBHC_H_
+#define LIBDRV_REMOTE_USBHC_H_
+
+remote_iface_t remote_usbhc_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,256 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief USB interface definition.
+ */
+
+#ifndef LIBDRV_USBHC_IFACE_H_
+#define LIBDRV_USBHC_IFACE_H_
+
+#include "driver.h"
+#include <usb/usb.h>
+
+
+/** IPC methods for communication with HC through DDF interface.
+ *
+ * Notes for async methods:
+ *
+ * Methods for sending data to device (OUT transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
+ * always use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ *   - argument #3 is buffer size
+ * - this call is immediately followed by IPC data write (from caller)
+ * - the initial call (and the whole transaction) is answer after the
+ *   transaction is scheduled by the HC and acknowledged by the device
+ *   or immediately after error is detected
+ * - the answer carries only the error code
+ *
+ * Methods for retrieving data from device (IN transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_IN -
+ * also use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ *   - argument #3 is buffer size
+ * - the call is not answered until the device returns some data (or until
+ *   error occurs)
+ * - if the call is answered with EOK, first argument of the answer is buffer
+ *   hash that could be used to retrieve the actual data
+ *
+ * Some special methods (NO-DATA transactions) do not send any data. These
+ * might behave as both OUT or IN transactions because communication parts
+ * where actual buffers are exchanged are omitted.
+ *
+ * The mentioned data retrieval can be done any time after receiving EOK
+ * answer to IN method.
+ * This retrieval is done using the IPC_M_USBHC_GET_BUFFER where
+ * the first argument is buffer hash from call answer.
+ * This call must be immediately followed by data read-in and after the
+ * data are transferred, the initial call (IPC_M_USBHC_GET_BUFFER)
+ * is answered. Each buffer can be retrieved only once.
+ *
+ * For all these methods, wrap functions exists. Important rule: functions
+ * for IN transactions have (as parameters) buffers where retrieved data
+ * will be stored. These buffers must be already allocated and shall not be
+ * touch until the transaction is completed
+ * (e.g. not before calling usb_wait_for() with appropriate handle).
+ * OUT transactions buffers can be freed immediately after call is dispatched
+ * (i.e. after return from wrapping function).
+ *
+ */
+typedef enum {
+	/** Tell USB address assigned to device.
+	 * Parameters:
+	 * - devman handle id
+	 * Answer:
+	 * - EINVAL - unknown handle or handle not managed by this driver
+	 * - ENOTSUP - operation not supported by HC (shall not happen)
+	 * - arbitrary error code if returned by remote implementation
+	 * - EOK - handle found, first parameter contains the USB address
+	 */
+	IPC_M_USBHC_GET_ADDRESS,
+
+	/** Asks for data buffer.
+	 * See explanation at usb_iface_funcs_t.
+	 * This function does not have counter part in functional interface
+	 * as it is handled by the remote part itself.
+	 */
+	IPC_M_USBHC_GET_BUFFER,
+
+
+	/** 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:
+	 * - ELIMIT - host controller run out of address
+	 * - EOK - address assigned
+	 * Answer arguments:
+	 * - assigned address
+	 *
+	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
+	 */
+	IPC_M_USBHC_REQUEST_ADDRESS,
+
+	/** Bind USB address with devman handle.
+	 * Parameters:
+	 * - USB address
+	 * - devman handle
+	 * Answer:
+	 * - EOK - address binded
+	 * - ENOENT - address is not in use
+	 */
+	IPC_M_USBHC_BIND_ADDRESS,
+
+	/** Release address in use.
+	 * Arguments:
+	 * - address to be released
+	 * Answer:
+	 * - ENOENT - address not in use
+	 * - EPERM - trying to release default USB address
+	 */
+	IPC_M_USBHC_RELEASE_ADDRESS,
+
+
+	/** Send interrupt data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_INTERRUPT_OUT,
+
+	/** Get interrupt data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_INTERRUPT_IN,
+
+
+	/** Start WRITE control transfer.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_CONTROL_WRITE_SETUP,
+
+	/** Send control-transfer data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_CONTROL_WRITE_DATA,
+
+	/** Terminate WRITE control transfer.
+	 * See explanation at usb_iface_funcs_t (NO-DATA transaction).
+	 */
+	IPC_M_USBHC_CONTROL_WRITE_STATUS,
+
+
+
+	/** Start READ control transfer.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_CONTROL_READ_SETUP,
+
+	/** Get control-transfer data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_CONTROL_READ_DATA,
+
+	/** Terminate READ control transfer.
+	 * See explanation at usb_iface_funcs_t (NO-DATA transaction).
+	 */
+	IPC_M_USBHC_CONTROL_READ_STATUS,
+
+
+	/* IPC_M_USB_ */
+} usbhc_iface_funcs_t;
+
+/** Callback for outgoing transfer. */
+typedef void (*usbhc_iface_transfer_out_callback_t)(device_t *,
+    usb_transaction_outcome_t, void *);
+
+/** Callback for incoming transfer. */
+typedef void (*usbhc_iface_transfer_in_callback_t)(device_t *,
+    usb_transaction_outcome_t, size_t, void *);
+
+
+/** Out transfer processing function prototype. */
+typedef int (*usbhc_iface_transfer_out_t)(device_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+
+/** Setup transfer processing function prototype. */
+typedef usbhc_iface_transfer_out_t usbhc_iface_transfer_setup_t;
+
+/** In transfer processing function prototype. */
+typedef int (*usbhc_iface_transfer_in_t)(device_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_in_callback_t, void *);
+
+/** USB devices communication interface. */
+typedef struct {
+	int (*tell_address)(device_t *, devman_handle_t, usb_address_t *);
+
+	int (*reserve_default_address)(device_t *);
+	int (*release_default_address)(device_t *);
+	int (*request_address)(device_t *, usb_address_t *);
+	int (*bind_address)(device_t *, usb_address_t, devman_handle_t);
+	int (*release_address)(device_t *, usb_address_t);
+
+	usbhc_iface_transfer_out_t interrupt_out;
+	usbhc_iface_transfer_in_t interrupt_in;
+
+	usbhc_iface_transfer_setup_t control_write_setup;
+	usbhc_iface_transfer_out_t control_write_data;
+	int (*control_write_status)(device_t *, usb_target_t,
+	    usbhc_iface_transfer_in_callback_t, void *);
+
+	usbhc_iface_transfer_setup_t control_read_setup;
+	usbhc_iface_transfer_in_t control_read_data;
+	int (*control_read_status)(device_t *, usb_target_t,
+	    usbhc_iface_transfer_out_callback_t, void *);
+} usbhc_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/Makefile	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,49 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusb
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -Iinclude
+
+SOURCES = \
+	src/addrkeep.c \
+	src/class.c \
+	src/debug.c \
+	src/drvpsync.c \
+	src/hcdhubd.c \
+	src/hcdrv.c \
+	src/hidparser.c \
+	src/localdrv.c \
+	src/recognise.c \
+	src/remotedrv.c \
+	src/usb.c \
+	src/usbdrvreq.c \
+	src/usbdrv.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usb/include/usb/classes/classes.h
===================================================================
--- uspace/lib/usb/include/usb/classes/classes.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/classes/classes.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,67 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB device classes and subclasses.
+ */
+#ifndef LIBUSB_CLASSES_H_
+#define LIBUSB_CLASSES_H_
+
+/** USB device class. */
+typedef enum {
+	USB_CLASS_USE_INTERFACE = 0x00,
+	USB_CLASS_AUDIO = 0x01,
+	USB_CLASS_COMMUNICATIONS_CDC_CONTROL = 0x02,
+	USB_CLASS_HID = 0x03,
+	USB_CLASS_PHYSICAL = 0x05,
+	USB_CLASS_IMAGE = 0x06,
+	USB_CLASS_PRINTER = 0x07,
+	USB_CLASS_MASS_STORAGE = 0x08,
+	USB_CLASS_HUB = 0x09,
+	USB_CLASS_CDC_DATA = 0x0A,
+	USB_CLASS_SMART_CARD = 0x0B,
+	USB_CLASS_CONTENT_SECURITY = 0x0D,
+	USB_CLASS_VIDEO = 0x0E,
+	USB_CLASS_PERSONAL_HEALTHCARE = 0x0F,
+	USB_CLASS_DIAGNOSTIC = 0xDC,
+	USB_CLASS_WIRELESS_CONTROLLER = 0xE0,
+	USB_CLASS_MISCELLANEOUS = 0xEF,
+	USB_CLASS_APPLICATION_SPECIFIC = 0xFE,
+	USB_CLASS_VENDOR_SPECIFIC = 0xFF,
+	/* USB_CLASS_ = 0x, */
+} usb_class_t;
+
+const char *usb_str_class(usb_class_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hid.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hid.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/classes/hid.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,109 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB HID device related types.
+ */
+#ifndef LIBUSB_HID_H_
+#define LIBUSB_HID_H_
+
+#include <usb/usb.h>
+#include <driver.h>
+#include <usb/classes/hidparser.h>
+
+/** USB/HID device requests. */
+typedef enum {
+	USB_HIDREQ_GET_REPORT = 1,
+	USB_HIDREQ_GET_IDLE = 2,
+	USB_HIDREQ_GET_PROTOCOL = 3,
+	/* Values 4 to 8 are reserved. */
+	USB_HIDREQ_SET_REPORT = 9,
+	USB_HIDREQ_SET_IDLE = 10,
+	USB_HIDREQ_SET_PROTOCOL = 11
+} usb_hid_request_t;
+
+/** USB/HID interface protocols. */
+typedef enum {
+	USB_HID_PROTOCOL_NONE = 0,
+	USB_HID_PROTOCOL_KEYBOARD = 1,
+	USB_HID_PROTOCOL_MOUSE = 2
+} usb_hid_protocol_t;
+
+/** Part of standard USB HID descriptor specifying one class descriptor.
+ *
+ * (See HID Specification, p.22)
+ */
+typedef struct {
+	/** Type of class descriptor (Report or Physical). */
+	uint8_t class_descriptor_type;
+	/** Length of class descriptor. */
+	uint16_t class_descriptor_length;
+} __attribute__ ((packed)) usb_standard_hid_descriptor_class_item_t;
+
+/** Standard USB HID descriptor.
+ *
+ * (See HID Specification, p.22)
+ * 
+ * It is actually only the "header" of the descriptor, as it may have arbitrary
+ * length if more than one class descritor is provided.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_HID). */
+	uint8_t descriptor_type;
+	/** HID Class Specification release. */
+	uint16_t spec_release;
+	/** Country code of localized hardware. */
+	uint8_t country_code;
+	/** Total number of class (i.e. Report and Physical) descriptors. */
+	uint8_t class_count;
+	/** First mandatory class descriptor info. */
+	usb_standard_hid_descriptor_class_item_t class_descriptor;
+} __attribute__ ((packed)) usb_standard_hid_descriptor_t;
+
+
+/**
+ * @brief USB/HID keyboard device type.
+ *
+ * Quite dummy right now.
+ */
+typedef struct {
+	device_t *device;
+	usb_address_t address;
+	usb_endpoint_t poll_endpoint;
+	usb_hid_report_parser_t *parser;
+} usb_hid_dev_kbd_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hidparser.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidparser.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/classes/hidparser.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,65 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB HID parser.
+ */
+#ifndef LIBUSB_HIDPARSER_H_
+#define LIBUSB_HIDPARSER_H_
+
+#include <stdint.h>
+
+/** HID report parser structure. */
+typedef struct {
+} usb_hid_report_parser_t;
+
+/** HID parser callbacks for IN items. */
+typedef struct {
+	/** Callback for keyboard.
+	 *
+	 * @param key_codes Array of pressed key (including modifiers).
+	 * @param count Length of @p key_codes.
+	 * @param arg Custom argument.
+	 */
+	void (*keyboard)(const uint16_t *key_codes, size_t count, void *arg);
+} usb_hid_report_in_callbacks_t;
+
+int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser, 
+    const uint8_t *data, size_t size);
+
+int usb_hid_parse_report(const usb_hid_report_parser_t *parser,  
+    const uint8_t *data, size_t size,
+    const usb_hid_report_in_callbacks_t *callbacks, void *arg);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hidut.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidut.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/classes/hidut.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,68 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB HID Usage Tables.
+ */
+#ifndef LIBUSB_HIDUT_H_
+#define LIBUSB_HIDUT_H_
+
+/** USB/HID Usage Pages. */
+typedef enum {
+	USB_HIDUT_PAGE_GENERIC_DESKTOP = 1,
+	USB_HIDUT_PAGE_SIMULATION = 2,
+	USB_HIDUT_PAGE_VR = 3,
+	USB_HIDUT_PAGE_SPORT = 4,
+	USB_HIDUT_PAGE_GAME = 5,
+	USB_HIDUT_PAGE_GENERIC_DEVICE = 6,
+	USB_HIDUT_PAGE_KEYBOARD = 7,
+	USB_HIDUT_PAGE_LED = 8,
+	USB_HIDUT_PAGE_BUTTON = 9
+	/* USB_HIDUT_PAGE_ = , */
+} usb_hidut_usage_page_t;
+
+/** Usages for Generic Desktop Page. */
+typedef enum {
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_POINTER = 1,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE = 2,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_JOYSTICK = 4,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_GAMEPAD = 5,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD = 6,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYPAD = 7
+	/* USB_HIDUT_USAGE_GENERIC_DESKTOP_ = , */
+	
+} usb_hidut_usage_generic_desktop_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hidutkbd.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidutkbd.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/classes/hidutkbd.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,175 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB HID key codes.
+ * @details
+ * This is not a typical header as by default it is equal to empty file.
+ * However, by cleverly defining the USB_HIDUT_KBD_KEY you can use it
+ * to generate conversion tables etc.
+ *
+ * For example, this creates enum for known keys:
+ * @code
+#define USB_HIDUT_KBD_KEY(name, usage_id, l, lc, l1, l2) \
+	USB_KBD_KEY_##name = usage_id,
+typedef enum {
+	#include <usb/hidutkbd.h>
+} usb_key_code_t;
+ @endcode
+ *
+ * Maybe, it might be better that you would place such enums into separate
+ * files and create them as separate step before compiling to allow tools
+ * such as Doxygen get the definitions right.
+ *
+ * @warning This file does not include guard to prevent multiple inclusions
+ * into a single file.
+ */
+
+
+#ifndef USB_HIDUT_KBD_KEY
+/** Declare keyboard key.
+ * @param name Key name (identifier).
+ * @param usage_id Key code (see Keyboard/Keypad Page (0x07) in HUT1.12.
+ * @param letter Corresponding character (0 if not applicable).
+ * @param letter_caps Corresponding character with Caps on.
+ * @param letter_mod1 Corresponding character with modifier #1 on.
+ * @param letter_mod2 Corresponding character with modifier #2 on.
+ */
+#define USB_HIDUT_KBD_KEY(name, usage_id, letter, letter_caps, letter_mod1, letter_mod2)
+
+#endif
+
+#define __NONPRINT(name, usage_id) \
+	USB_HIDUT_KBD_KEY(name, usage_id, 0, 0, 0, 0)
+
+/* US alphabet letters */
+USB_HIDUT_KBD_KEY(A, 0x04, 'a', 'A', 0, 0)
+USB_HIDUT_KBD_KEY(B, 0x05, 'b', 'B', 0, 0)
+USB_HIDUT_KBD_KEY(C, 0x06, 'c', 'C', 0, 0)
+USB_HIDUT_KBD_KEY(D, 0x07, 'd', 'D', 0, 0)
+USB_HIDUT_KBD_KEY(E, 0x08, 'e', 'E', 0, 0)
+USB_HIDUT_KBD_KEY(F, 0x09, 'f', 'F', 0, 0)
+USB_HIDUT_KBD_KEY(G, 0x0A, 'g', 'G', 0, 0)
+USB_HIDUT_KBD_KEY(H, 0x0B, 'h', 'H', 0, 0)
+USB_HIDUT_KBD_KEY(I, 0x0C, 'i', 'I', 0, 0)
+USB_HIDUT_KBD_KEY(J, 0x0D, 'j', 'J', 0, 0)
+USB_HIDUT_KBD_KEY(K, 0x0E, 'k', 'K', 0, 0)
+USB_HIDUT_KBD_KEY(L, 0x0F, 'l', 'L', 0, 0)
+USB_HIDUT_KBD_KEY(M, 0x10, 'm', 'M', 0, 0)
+USB_HIDUT_KBD_KEY(N, 0x11, 'n', 'N', 0, 0)
+USB_HIDUT_KBD_KEY(O, 0x12, 'o', 'O', 0, 0)
+USB_HIDUT_KBD_KEY(P, 0x13, 'p', 'P', 0, 0)
+USB_HIDUT_KBD_KEY(Q, 0x14, 'q', 'Q', 0, 0)
+USB_HIDUT_KBD_KEY(R, 0x15, 'r', 'R', 0, 0)
+USB_HIDUT_KBD_KEY(S, 0x16, 's', 'S', 0, 0)
+USB_HIDUT_KBD_KEY(T, 0x17, 't', 'T', 0, 0)
+USB_HIDUT_KBD_KEY(U, 0x18, 'u', 'U', 0, 0)
+USB_HIDUT_KBD_KEY(V, 0x19, 'v', 'V', 0, 0)
+USB_HIDUT_KBD_KEY(W, 0x1A, 'w', 'W', 0, 0)
+USB_HIDUT_KBD_KEY(X, 0x1B, 'x', 'X', 0, 0)
+USB_HIDUT_KBD_KEY(Y, 0x1C, 'y', 'Y', 0, 0)
+USB_HIDUT_KBD_KEY(Z, 0x1D, 'z', 'Z', 0, 0)
+
+/* Keyboard digits */
+USB_HIDUT_KBD_KEY(1, 0x1E, '1', '!', 0, 0)
+USB_HIDUT_KBD_KEY(2, 0x1F, '2', '@', 0, 0)
+USB_HIDUT_KBD_KEY(3, 0x20, '3', '#', 0, 0)
+USB_HIDUT_KBD_KEY(4, 0x21, '4', '$', 0, 0)
+USB_HIDUT_KBD_KEY(5, 0x22, '5', '%', 0, 0)
+USB_HIDUT_KBD_KEY(6, 0x23, '6', '^', 0, 0)
+USB_HIDUT_KBD_KEY(7, 0x24, '7', '&', 0, 0)
+USB_HIDUT_KBD_KEY(8, 0x25, '8', '*', 0, 0)
+USB_HIDUT_KBD_KEY(9, 0x26, '9', '(', 0, 0)
+USB_HIDUT_KBD_KEY(0, 0x27, '0', ')', 0, 0)
+
+/* More-or-less typewriter command keys */
+USB_HIDUT_KBD_KEY(ENTER, 0x28, '\n', 0, 0, 0)
+USB_HIDUT_KBD_KEY(ESCAPE, 0x29, 0, 0, 0, 0)
+USB_HIDUT_KBD_KEY(BACKSPACE, 0x2A, '\b', 0, 0, 0)
+USB_HIDUT_KBD_KEY(TAB, 0x2B, '\t', 0, 0, 0)
+USB_HIDUT_KBD_KEY(SPACE, 0x2C, ' ', 0, 0, 0)
+
+/* Special (printable) characters */
+USB_HIDUT_KBD_KEY(DASH, 0x2D, '-', '_', 0, 0)
+USB_HIDUT_KBD_KEY(EQUALS, 0x2E, '=', '+', 0, 0)
+USB_HIDUT_KBD_KEY(LEFT_BRACKET, 0x2F, '[', '{', 0, 0)
+USB_HIDUT_KBD_KEY(RIGHT_BRACKET, 0x30, ']', '}', 0, 0)
+USB_HIDUT_KBD_KEY(BACKSLASH, 0x31, '\\', '|', 0, 0)
+USB_HIDUT_KBD_KEY(HASH, 0x32, '#', '~', 0, 0)
+USB_HIDUT_KBD_KEY(SEMICOLON, 0x33, ';', ':', 0, 0)
+USB_HIDUT_KBD_KEY(APOSTROPHE, 0x34, '\'', '"', 0, 0)
+USB_HIDUT_KBD_KEY(GRAVE_ACCENT, 0x35, '`', '~', 0, 0)
+USB_HIDUT_KBD_KEY(COMMA, 0x36, ',', '<', 0, 0)
+USB_HIDUT_KBD_KEY(PERIOD, 0x37, '.', '>', 0, 0)
+USB_HIDUT_KBD_KEY(SLASH, 0x38, '/', '?', 0, 0)
+
+USB_HIDUT_KBD_KEY(CAPS_LOCK, 0x39, 0, 0, 0, 0)
+
+/* Function keys */
+__NONPRINT( F1, 0x3A)
+__NONPRINT( F2, 0x3B)
+__NONPRINT( F3, 0x3C)
+__NONPRINT( F4, 0x3D)
+__NONPRINT( F5, 0x3E)
+__NONPRINT( F6, 0x3F)
+__NONPRINT( F7, 0x40)
+__NONPRINT( F8, 0x41)
+__NONPRINT( F9, 0x42)
+__NONPRINT(F10, 0x43)
+__NONPRINT(F11, 0x44)
+__NONPRINT(F12, 0x45)
+
+/* Cursor movement keys & co. */
+__NONPRINT(PRINT_SCREEN, 0x46)
+__NONPRINT(SCROLL_LOCK, 0x47)
+__NONPRINT(PAUSE, 0x48)
+__NONPRINT(INSERT, 0x49)
+__NONPRINT(HOME, 0x4A)
+__NONPRINT(PAGE_UP, 0x4B)
+__NONPRINT(DELETE, 0x4C)
+__NONPRINT(END, 0x4D)
+__NONPRINT(PAGE_DOWN, 0x4E)
+__NONPRINT(RIGHT_ARROW, 0x4F)
+__NONPRINT(LEFT_ARROW, 0x50)
+__NONPRINT(DOWN_ARROW, 0x51)
+__NONPRINT(UP_ARROW, 0x52)
+
+
+
+
+/* USB_HIDUT_KBD_KEY(, 0x, '', '', 0, 0) */
+
+#undef __NONPRINT
+
+/**
+ * @}
+ */
+
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,224 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB hub related structures.
+ */
+#ifndef LIBUSB_HUB_H_
+#define LIBUSB_HUB_H_
+
+#include <sys/types.h>
+#include <usb/hcdhubd.h>
+
+
+/** Hub class feature selector.
+ * @warning The constants are not unique (feature selectors are used
+ * for hub and port).
+ */
+typedef enum {
+	USB_HUB_FEATURE_C_HUB_LOCAL_POWER = 0,
+	USB_HUB_FEATURE_C_HUB_OVER_CURRENT = 1,
+	USB_HUB_FEATURE_PORT_CONNECTION = 0,
+	USB_HUB_FEATURE_PORT_ENABLE = 1,
+	USB_HUB_FEATURE_PORT_SUSPEND = 2,
+	USB_HUB_FEATURE_PORT_OVER_CURRENT = 3,
+	USB_HUB_FEATURE_PORT_RESET = 4,
+	USB_HUB_FEATURE_PORT_POWER = 8,
+	USB_HUB_FEATURE_PORT_LOW_SPEED = 9,
+	USB_HUB_FEATURE_C_PORT_CONNECTION = 16,
+	USB_HUB_FEATURE_C_PORT_ENABLE = 17,
+	USB_HUB_FEATURE_C_PORT_SUSPEND = 18,
+	USB_HUB_FEATURE_C_PORT_OVER_CURRENT = 19,
+	USB_HUB_FEATURE_C_PORT_RESET = 20,
+	/* USB_HUB_FEATURE_ = , */
+} usb_hub_class_feature_t;
+
+
+/**
+ *	@brief usb hub descriptor
+ *
+ *	For more information see Universal Serial Bus Specification Revision 1.1 chapter 11.16.2
+ */
+typedef struct hub_descriptor_type{
+    /** Number of bytes in this descriptor, including this byte */
+    //uint8_t bDescLength;
+
+    /** Descriptor Type, value: 29H for hub descriptor */
+    //uint8_t bDescriptorType;
+
+    /** Number of downstream ports that this hub supports */
+    uint8_t ports_count;
+
+    /**
+            D1...D0: Logical Power Switching Mode
+            00: Ganged power switching (all ports’ power at
+            once)
+            01: Individual port power switching
+            1X: Reserved. Used only on 1.0 compliant hubs
+            that implement no power switching.
+            D2: Identifies a Compound Device
+            0: Hub is not part of a compound device
+            1: Hub is part of a compound device
+            D4...D3: Over-current Protection Mode
+            00: Global Over-current Protection. The hub
+            reports over-current as a summation of all
+            ports’ current draw, without a breakdown of
+            individual port over-current status.
+            01: Individual Port Over-current Protection. The
+            hub reports over-current on a per-port basis.
+            Each port has an over-current indicator.
+            1X: No Over-current Protection. This option is
+            allowed only for bus-powered hubs that do not
+            implement over-current protection.
+            D15...D5:
+            Reserved
+     */
+    uint16_t hub_characteristics;
+
+    /**
+            Time (in 2ms intervals) from the time the power-on
+            sequence begins on a port until power is good on that
+            port. The USB System Software uses this value to
+            determine how long to wait before accessing a
+            powered-on port.
+     */
+    uint8_t pwr_on_2_good_time;
+
+    /**
+            Maximum current requirements of the Hub Controller
+            electronics in mA.
+     */
+    uint8_t current_requirement;
+
+    /**
+            Indicates if a port has a removable device attached.
+            This field is reported on byte-granularity. Within a
+            byte, if no port exists for a given location, the field
+            representing the port characteristics returns 0.
+            Bit value definition:
+            0B - Device is removable
+            1B - Device is non-removable
+            This is a bitmap corresponding to the individual ports
+            on the hub:
+            Bit 0: Reserved for future use
+            Bit 1: Port 1
+            Bit 2: Port 2
+            ....
+            Bit n: Port n (implementation-dependent, up to a
+            maximum of 255 ports).
+     */
+    uint8_t * devices_removable;
+
+    /**
+            This field exists for reasons of compatibility with
+            software written for 1.0 compliant devices. All bits in
+            this field should be set to 1B. This field has one bit for
+            each port on the hub with additional pad bits, if
+            necessary, to make the number of bits in the field an
+            integer multiple of 8.
+     */
+    //uint8_t * port_pwr_ctrl_mask;
+} usb_hub_descriptor_t;
+
+
+
+/**	@brief usb hub specific request types.
+ *
+ *	For more information see Universal Serial Bus Specification Revision 1.1 chapter 11.16.2
+ */
+typedef enum {
+    /**	This request resets a value reported in the hub status.	*/
+    USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE = 0x20,
+    /** This request resets a value reported in the port status. */
+    USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE = 0x23,
+    /** This is an optional per-port diagnostic request that returns the bus state value, as sampled at the last EOF2 point. */
+    USB_HUB_REQ_TYPE_GET_STATE = 0xA3,
+    /** This request returns the hub descriptor. */
+    USB_HUB_REQ_TYPE_GET_DESCRIPTOR = 0xA0,
+    /** This request returns the current hub status and the states that have changed since the previous acknowledgment. */
+    USB_HUB_REQ_TYPE_GET_HUB_STATUS = 0xA0,
+    /** This request returns the current port status and the current value of the port status change bits. */
+    USB_HUB_REQ_TYPE_GET_PORT_STATUS = 0xA3,
+    /** This request overwrites the hub descriptor. */
+    USB_HUB_REQ_TYPE_SET_DESCRIPTOR = 0x20,
+    /** This request sets a value reported in the hub status. */
+    USB_HUB_REQ_TYPE_SET_HUB_FEATURE = 0x20,
+    /** This request sets a value reported in the port status. */
+    USB_HUB_REQ_TYPE_SET_PORT_FEATURE = 0x23
+} usb_hub_bm_request_type_t;
+
+/** @brief hub class request codes*/
+/// \TODO these are duplicit to standart descriptors
+typedef enum {
+    /**  */
+    USB_HUB_REQUEST_GET_STATUS = 0,
+    /** */
+    USB_HUB_REQUEST_CLEAR_FEATURE = 1,
+    /** */
+    USB_HUB_REQUEST_GET_STATE = 2,
+    /** */
+    USB_HUB_REQUEST_SET_FEATURE = 3,
+    /** */
+    USB_HUB_REQUEST_GET_DESCRIPTOR = 6,
+    /** */
+    USB_HUB_REQUEST_SET_DESCRIPTOR = 7
+} usb_hub_request_t;
+
+/**
+ *	Maximum size of usb hub descriptor in bytes
+ */
+extern size_t USB_HUB_MAX_DESCRIPTOR_SIZE;
+
+/**
+ * @brief create uint8_t array with serialized descriptor
+ *
+ * @param descriptor
+ */
+void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor);
+
+/**
+ * @brief 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
+ */
+usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * sdescriptor);
+
+
+
+
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/debug.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,42 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Debugging related functions.
+ */
+#ifndef LIBUSB_DEBUG_H_
+#define LIBUSB_DEBUG_H_
+
+void usb_dprintf(const char *tag, int level, const char *format, ...);
+void usb_dprintf_enable(const char *tag, int level);
+
+
+#endif
Index: uspace/lib/usb/include/usb/descriptor.h
===================================================================
--- uspace/lib/usb/include/usb/descriptor.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/descriptor.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,176 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Standard USB descriptors.
+ */
+#ifndef LIBUSB_DESCRIPTOR_H_
+#define LIBUSB_DESCRIPTOR_H_
+
+#include <ipc/ipc.h>
+#include <async.h>
+
+/** Descriptor type. */
+typedef enum {
+	USB_DESCTYPE_DEVICE = 1,
+	USB_DESCTYPE_CONFIGURATION = 2,
+	USB_DESCTYPE_STRING = 3,
+	USB_DESCTYPE_INTERFACE = 4,
+	USB_DESCTYPE_ENDPOINT = 5,
+	USB_DESCTYPE_HID = 0x21,
+	USB_DESCTYPE_HID_REPORT = 0x22,
+	USB_DESCTYPE_HID_PHYSICAL = 0x23,
+	USB_DESCTYPE_HUB = 0x29,
+	/* USB_DESCTYPE_ = */
+} usb_descriptor_type_t;
+
+/** Standard USB device descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_DEVICE). */
+	uint8_t descriptor_type;
+	/** USB specification release number.
+	 * The number shall be coded as binary-coded decimal (BCD).
+	 */
+	uint16_t usb_spec_version;
+	/** Device class. */
+	uint8_t device_class;
+	/** Device sub-class. */
+	uint8_t device_subclass;
+	/** Device protocol. */
+	uint8_t device_protocol;
+	/** Maximum packet size for endpoint zero.
+	 * Valid values are only 8, 16, 32, 64).
+	 */
+	uint8_t max_packet_size;
+	/** Vendor ID. */
+	uint16_t vendor_id;
+	/** Product ID. */
+	uint16_t product_id;
+	/** Device release number (in BCD). */
+	uint16_t device_version;
+	/** Manufacturer descriptor index. */
+	uint8_t str_manufacturer;
+	/** Product descriptor index. */
+	uint8_t str_product;
+	/** Device serial number desriptor index. */
+	uint8_t str_serial_number;
+	/** Number of possible configurations. */
+	uint8_t configuration_count;
+} __attribute__ ((packed)) usb_standard_device_descriptor_t;
+
+/** Standard USB configuration descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_CONFIGURATION). */
+	uint8_t descriptor_type;
+	/** Total length of all data of this configuration.
+	 * This includes the combined length of all descriptors
+	 * (configuration, interface, endpoint, class-specific and
+	 * vendor-specific) valid for this configuration.
+	 */
+	uint16_t total_length;
+	/** Number of possible interfaces under this configuration. */
+	uint8_t interface_count;
+	/** Configuration value used when setting this configuration. */
+	uint8_t configuration_number;
+	/** String descriptor describing this configuration. */
+	uint8_t str_configuration;
+	/** Attribute bitmap. */
+	uint8_t attributes;
+	/** Maximum power consumption from the USB under this configuration.
+	 * Expressed in 2mA unit (e.g. 50 ~ 100mA).
+	 */
+	uint8_t max_power;
+} __attribute__ ((packed)) usb_standard_configuration_descriptor_t;
+
+/** Standard USB interface descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_INTERFACE). */
+	uint8_t descriptor_type;
+	/** Number of interface.
+	 * Zero-based index into array of interfaces for current configuration.
+	 */
+	uint8_t interface_number;
+	/** Alternate setting for value in interface_number. */
+	uint8_t alternate_setting;
+	/** Number of endpoints used by this interface.
+	 * This number must exclude usage of endpoint zero
+	 * (default control pipe).
+	 */
+	uint8_t endpoint_count;
+	/** Class code. */
+	uint8_t interface_class;
+	/** Subclass code. */
+	uint8_t interface_subclass;
+	/** Protocol code. */
+	uint8_t interface_protocol;
+	/** String descriptor describing this interface. */
+	uint8_t str_interface;
+} __attribute__ ((packed)) usb_standard_interface_descriptor_t;
+
+/** Standard USB endpoint descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_ENDPOINT). */
+	uint8_t descriptor_type;
+	/** Endpoint address together with data flow direction. */
+	uint8_t endpoint_address;
+	/** Endpoint attributes.
+	 * Includes transfer type (usb_transfer_type_t).
+	 */
+	uint8_t attributes;
+	/** Maximum packet size. */
+	uint16_t max_packet_size;
+	/** Polling interval in milliseconds.
+	 * Ignored for bulk and control endpoints.
+	 * Isochronous endpoints must use value 1.
+	 * Interrupt endpoints any value from 1 to 255.
+	 */
+	uint8_t poll_interval;
+} __attribute__ ((packed)) usb_standard_endpoint_descriptor_t;
+
+
+/* TODO: string descriptors. */
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/devreq.h
===================================================================
--- uspace/lib/usb/include/usb/devreq.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/devreq.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,99 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Standard USB device requests.
+ */
+#ifndef LIBUSB_DEVREQ_H_
+#define LIBUSB_DEVREQ_H_
+
+#include <ipc/ipc.h>
+#include <async.h>
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+
+/** Standard device request. */
+typedef enum {
+	USB_DEVREQ_GET_STATUS = 0,
+	USB_DEVREQ_CLEAR_FEATURE = 1,
+	USB_DEVREQ_SET_FEATURE = 3,
+	USB_DEVREQ_SET_ADDRESS = 5,
+	USB_DEVREQ_GET_DESCRIPTOR = 6,
+	USB_DEVREQ_SET_DESCRIPTOR = 7,
+	USB_DEVREQ_GET_CONFIGURATION = 8,
+	USB_DEVREQ_SET_CONFIGURATION = 9,
+	USB_DEVREQ_GET_INTERFACE = 10,
+	USB_DEVREQ_SET_INTERFACE = 11,
+	USB_DEVREQ_SYNCH_FRAME = 12,
+	USB_DEVREQ_LAST_STD
+} usb_stddevreq_t;
+
+/** Device request setup packet.
+ * The setup packet describes the request.
+ */
+typedef struct {
+	/** Request type.
+	 * The type combines transfer direction, request type and
+	 * intended recipient.
+	 */
+	uint8_t request_type;
+	/** Request identification. */
+	uint8_t request;
+	/** Main parameter to the request. */
+	union {
+		/* FIXME: add #ifdefs according to host endianess */
+		struct {
+			uint8_t value_low;
+			uint8_t value_high;
+		};
+		uint16_t value;
+	};
+	/** Auxiliary parameter to the request.
+	 * Typically, it is offset to something.
+	 */
+	uint16_t index;
+	/** Length of extra data. */
+	uint16_t length;
+} __attribute__ ((packed)) usb_device_request_setup_packet_t;
+
+int usb_drv_req_set_address(int, usb_address_t, usb_address_t);
+int usb_drv_req_get_device_descriptor(int, usb_address_t,
+    usb_standard_device_descriptor_t *);
+int usb_drv_req_get_bare_configuration_descriptor(int, usb_address_t, int,
+    usb_standard_configuration_descriptor_t *);
+int usb_drv_req_get_full_configuration_descriptor(int, usb_address_t, int,
+    void *, size_t, size_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/hcd.h
===================================================================
--- uspace/lib/usb/include/usb/hcd.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/hcd.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,84 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief HC driver.
+ */
+#ifndef LIBUSB_HCD_H_
+#define LIBUSB_HCD_H_
+
+#include <usb/usb.h>
+#include <fibril_synch.h>
+#include <devman.h>
+
+/** Info about used address. */
+typedef struct {
+	/** Linked list member. */
+	link_t link;
+	/** Address. */
+	usb_address_t address;
+	/** Corresponding devman handle. */
+	devman_handle_t devman_handle;
+} usb_address_keeping_used_t;
+
+/** Structure for keeping track of free and used USB addresses. */
+typedef struct {
+	/** Head of list of used addresses. */
+	link_t used_addresses;
+	/** Upper bound for USB addresses. */
+	usb_address_t max_address;
+	/** Mutex protecting used address. */
+	fibril_mutex_t used_addresses_guard;
+	/** Condition variable for used addresses. */
+	fibril_condvar_t used_addresses_condvar;
+
+	/** Condition variable mutex for default address. */
+	fibril_mutex_t default_condvar_guard;
+	/** Condition variable for default address. */
+	fibril_condvar_t default_condvar;
+	/** Whether is default address available. */
+	bool default_available;
+} usb_address_keeping_t;
+
+void usb_address_keeping_init(usb_address_keeping_t *, usb_address_t);
+
+void usb_address_keeping_reserve_default(usb_address_keeping_t *);
+void usb_address_keeping_release_default(usb_address_keeping_t *);
+
+usb_address_t usb_address_keeping_request(usb_address_keeping_t *);
+int usb_address_keeping_release(usb_address_keeping_t *, usb_address_t);
+void usb_address_keeping_devman_bind(usb_address_keeping_t *, usb_address_t,
+    devman_handle_t);
+usb_address_t usb_address_keeping_find(usb_address_keeping_t *,
+    devman_handle_t);
+
+
+#endif
Index: uspace/lib/usb/include/usb/hcdhubd.h
===================================================================
--- uspace/lib/usb/include/usb/hcdhubd.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/hcdhubd.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,214 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief HC driver and hub driver.
+ */
+#ifndef LIBUSB_HCDHUBD_H_
+#define LIBUSB_HCDHUBD_H_
+
+#include <adt/list.h>
+#include <bool.h>
+#include <driver.h>
+#include <usb/usb.h>
+
+/** Endpoint properties. */
+typedef struct {
+	/** Endpoint number. */
+	usb_endpoint_t endpoint;
+	/** Transfer type. */
+	usb_transfer_type_t transfer_type;
+	/** Endpoint direction. */
+	usb_direction_t direction;
+	/** Data toggle bit. */
+	int data_toggle;
+} usb_hc_endpoint_info_t;
+
+/** Information about attached USB device. */
+typedef struct {
+	/** Assigned address. */
+	usb_address_t address;
+	/** Number of endpoints. */
+	size_t endpoint_count;
+	/** Endpoint properties. */
+	usb_hc_endpoint_info_t *endpoints;
+	/** Link to other attached devices of the same HC. */
+	link_t link;
+} usb_hcd_attached_device_info_t;
+
+
+/** Host controller device. */
+typedef struct usb_hc_device usb_hc_device_t;
+
+/** Callback for OUT transfers. */
+typedef void (*usb_hcd_transfer_callback_out_t)
+    (usb_hc_device_t *, usb_transaction_outcome_t, void *);
+
+/** Callback for IN transfers. */
+typedef void (*usb_hcd_transfer_callback_in_t)
+    (usb_hc_device_t *, size_t, usb_transaction_outcome_t, void *);
+
+
+/** Transfer functions provided by each USB host controller driver. */
+typedef struct {
+	/** OUT transfer.
+	 * @param hc Host controller that shall enqueue the transfer.
+	 * @param dev Target device.
+	 * @param ep Target endpoint.
+	 * @param buffer Buffer to be sent.
+	 * @param size Buffer size.
+	 * @param callback Callback after transfer was processed by hardware.
+	 * @param arg Callback argument.
+	 */
+	int (*transfer_out)(usb_hc_device_t *hc,
+	    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *ep,
+	    void *buffer, size_t size,
+	    usb_hcd_transfer_callback_out_t callback, void *arg);
+
+	/** SETUP transfer. */
+	int (*transfer_setup)(usb_hc_device_t *,
+	    usb_hcd_attached_device_info_t *, usb_hc_endpoint_info_t *,
+	    void *, size_t,
+	    usb_hcd_transfer_callback_out_t, void *);
+
+	/** IN transfer. */
+	int (*transfer_in)(usb_hc_device_t *,
+	    usb_hcd_attached_device_info_t *, usb_hc_endpoint_info_t *,
+	    void *, size_t,
+	    usb_hcd_transfer_callback_in_t, void *);
+} usb_hcd_transfer_ops_t;
+
+/**
+ * @brief structure holding information about free and used addresses
+ *
+ * This structure should not be used outside usb hcd driver.
+ * You better consider it to be 'private'.
+ */
+typedef struct {
+	/** lower bound included in the interval */
+	usb_address_t lower_bound;
+
+	/** upper bound, excluded from the interval */
+	usb_address_t upper_bound;
+
+	/** */
+	link_t link;
+}usb_address_list_t;
+
+struct usb_hc_device {
+	/** Transfer operations. */
+	usb_hcd_transfer_ops_t *transfer_ops;
+
+	/** Custom HC data. */
+	void *data;
+
+	/** Generic device entry (read-only). */
+	device_t *generic;
+
+	/** List of attached devices. */
+	link_t attached_devices;
+
+	/** List of hubs operating from this HC. */
+	link_t hubs;
+
+	/** Structure with free and used addresses */
+	link_t addresses;
+
+	/** Link to other driven HCs. */
+	link_t link;
+};
+
+/** Host controller driver. */
+typedef struct {
+	/** Driver name. */
+	const char *name;
+	/** Callback when device (host controller) is added. */
+	int (*add_hc)(usb_hc_device_t *device);
+} usb_hc_driver_t;
+
+
+int usb_hcd_main(usb_hc_driver_t *);
+int usb_hcd_add_root_hub(device_t *dev);
+
+/**
+ * find first not yet used address on this host controller and use it
+ * @param this_hcd
+ * @return number in the range of allowed usb addresses or
+ *     a negative number if not succesful
+ */
+usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd);
+
+/**
+ * @brief free the address in the address space of this hcd.
+ *
+ * if address is not used, nothing happens
+ * @param this_hcd
+ * @param addr
+ */
+void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr );
+
+
+/*
+ * Functions to be used by drivers within same task as the HC driver.
+ * This will probably include only hub drivers.
+ */
+
+device_t *usb_hc_connect(device_t *);
+
+int usb_hc_async_interrupt_out(usb_hc_device_t *, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hc_async_interrupt_in(usb_hc_device_t *, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+
+int usb_hc_async_control_write_setup(usb_hc_device_t *, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hc_async_control_write_data(usb_hc_device_t *, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hc_async_control_write_status(usb_hc_device_t *, usb_target_t,
+    usb_handle_t *);
+
+int usb_hc_async_control_read_setup(usb_hc_device_t *, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hc_async_control_read_data(usb_hc_device_t *, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+int usb_hc_async_control_read_status(usb_hc_device_t *, usb_target_t,
+    usb_handle_t *);
+
+int usb_hc_async_wait_for(usb_handle_t);
+
+int usb_hc_add_child_device(device_t *, const char *, const char *, bool);
+
+
+/**
+ * @}
+ */
+
+#endif
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/usb.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,135 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Base USB types.
+ */
+#ifndef LIBUSB_USB_H_
+#define LIBUSB_USB_H_
+
+#include <sys/types.h>
+#include <ipc/ipc.h>
+
+/** USB transfer type. */
+typedef enum {
+	USB_TRANSFER_CONTROL = 0,
+	USB_TRANSFER_ISOCHRONOUS = 1,
+	USB_TRANSFER_BULK = 2,
+	USB_TRANSFER_INTERRUPT = 3
+} usb_transfer_type_t;
+
+const char * usb_str_transfer_type(usb_transfer_type_t t);
+
+/** USB data transfer direction. */
+typedef enum {
+	USB_DIRECTION_IN,
+	USB_DIRECTION_OUT
+} usb_direction_t;
+
+/** USB transaction outcome. */
+typedef enum {
+	USB_OUTCOME_OK,
+	USB_OUTCOME_CRCERROR,
+	USB_OUTCOME_BABBLE
+} usb_transaction_outcome_t;
+
+const char * usb_str_transaction_outcome(usb_transaction_outcome_t o);
+
+/** USB address type.
+ * Negative values could be used to indicate error.
+ */
+typedef int usb_address_t;
+
+/** Default USB address. */
+#define USB_ADDRESS_DEFAULT 0
+/** Maximum address number in USB 1.1. */
+#define USB11_ADDRESS_MAX 128
+
+/** USB endpoint number type.
+ * Negative values could be used to indicate error.
+ */
+typedef int usb_endpoint_t;
+
+/** Maximum endpoint number in USB 1.1.
+ */
+#define USB11_ENDPOINT_MAX 16
+
+
+/** USB complete address type. 
+ * Pair address + endpoint is identification of transaction recipient.
+ */
+typedef struct {
+	usb_address_t address;
+	usb_endpoint_t endpoint;
+} usb_target_t;
+
+static inline int usb_target_same(usb_target_t a, usb_target_t b)
+{
+	return (a.address == b.address)
+	    && (a.endpoint == b.endpoint);
+}
+
+/** General handle type.
+ * Used by various USB functions as opaque handle.
+ */
+typedef sysarg_t usb_handle_t;
+
+/** USB packet identifier. */
+typedef enum {
+#define _MAKE_PID_NIBBLE(tag, type) \
+	((uint8_t)(((tag) << 2) | (type)))
+#define _MAKE_PID(tag, type) \
+	( \
+	    _MAKE_PID_NIBBLE(tag, type) \
+	    | ((~_MAKE_PID_NIBBLE(tag, type)) << 4) \
+	)
+	USB_PID_OUT = _MAKE_PID(0, 1),
+	USB_PID_IN = _MAKE_PID(2, 1),
+	USB_PID_SOF = _MAKE_PID(1, 1),
+	USB_PID_SETUP = _MAKE_PID(3, 1),
+
+	USB_PID_DATA0 = _MAKE_PID(0 ,3),
+	USB_PID_DATA1 = _MAKE_PID(2 ,3),
+
+	USB_PID_ACK = _MAKE_PID(0 ,2),
+	USB_PID_NAK = _MAKE_PID(2 ,2),
+	USB_PID_STALL = _MAKE_PID(3 ,2),
+
+	USB_PID_PRE = _MAKE_PID(3 ,0),
+	/* USB_PID_ = _MAKE_PID( ,), */
+#undef _MAKE_PID
+#undef _MAKE_PID_NIBBLE
+} usb_packet_id;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/usbdrv.h
===================================================================
--- uspace/lib/usb/include/usb/usbdrv.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,104 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB driver.
+ */
+#ifndef LIBUSB_USBDRV_H_
+#define LIBUSB_USBDRV_H_
+
+#include <usb/usb.h>
+#include <driver.h>
+#include <usb/devreq.h>
+#include <usb/descriptor.h>
+
+int usb_drv_hc_connect(device_t *, unsigned int);
+
+int usb_drv_reserve_default_address(int);
+int usb_drv_release_default_address(int);
+usb_address_t usb_drv_request_address(int);
+int usb_drv_bind_address(int, usb_address_t, devman_handle_t);
+int usb_drv_release_address(int, usb_address_t);
+
+usb_address_t usb_drv_get_my_address(int, device_t *);
+
+int usb_drv_async_interrupt_out(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_drv_async_interrupt_in(int, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+
+int usb_drv_psync_interrupt_out(int, usb_target_t, void *, size_t);
+int usb_drv_psync_interrupt_in(int, usb_target_t, void *, size_t, size_t *);
+
+
+
+int usb_drv_async_control_write_setup(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_drv_async_control_write_data(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_drv_async_control_write_status(int, usb_target_t,
+    usb_handle_t *);
+
+int usb_drv_psync_control_write_setup(int, usb_target_t, void *, size_t);
+int usb_drv_psync_control_write_data(int, usb_target_t, void *, size_t);
+int usb_drv_psync_control_write_status(int, usb_target_t);
+
+int usb_drv_psync_control_write(int, usb_target_t,
+    void *, size_t, void *, size_t);
+
+
+int usb_drv_async_control_read_setup(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_drv_async_control_read_data(int, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+int usb_drv_async_control_read_status(int, usb_target_t,
+    usb_handle_t *);
+
+int usb_drv_psync_control_read_setup(int, usb_target_t, void *, size_t);
+int usb_drv_psync_control_read_data(int, usb_target_t, void *, size_t, size_t *);
+int usb_drv_psync_control_read_status(int, usb_target_t);
+
+int usb_drv_psync_control_read(int, usb_target_t,
+    void *, size_t, void *, size_t, size_t *);
+
+
+
+int usb_drv_async_wait_for(usb_handle_t);
+
+int usb_drv_create_device_match_ids(int, match_id_list_t *, usb_address_t);
+int usb_drv_register_child_in_devman(int, device_t *, usb_address_t,
+    devman_handle_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/addrkeep.c
===================================================================
--- uspace/lib/usb/src/addrkeep.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/addrkeep.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,341 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Address keeping.
+ */
+#include <usb/hcd.h>
+#include <errno.h>
+#include <assert.h>
+
+/** For loop over all used addresses in address keeping.
+ *
+ * @param link Iterator.
+ * @param addresses Addresses keeping structure to iterate.
+ */
+#define for_all_used_addresses(link, addresses) \
+	for (link = (addresses)->used_addresses.next; \
+	    link != &(addresses)->used_addresses; \
+	    link = link->next)
+
+/** Get instance of usb_address_keeping_used_t. */
+#define used_address_get_instance(lnk) \
+	list_get_instance(lnk, usb_address_keeping_used_t, link)
+
+/** Invalid value of devman handle. */
+#define INVALID_DEVMAN_HANDLE \
+	((devman_handle_t)-1)
+
+/** Creates structure for used USB address.
+ *
+ * @param address USB address.
+ * @return Initialized structure.
+ * @retval NULL Out of memory.
+ */
+static usb_address_keeping_used_t *usb_address_keeping_used_create(
+    usb_address_t address)
+{
+	usb_address_keeping_used_t *info
+	    = malloc(sizeof(usb_address_keeping_used_t));
+	if (info == NULL) {
+		return NULL;
+	}
+
+	info->address = address;
+	info->devman_handle = INVALID_DEVMAN_HANDLE;
+	list_initialize(&info->link);
+	return info;
+}
+
+/** Destroys structure for used USB address.
+ *
+ * @param info Structure to be destroyed.
+ */
+static void usb_address_keeping_used_destroy(usb_address_keeping_used_t *info)
+{
+	free(info);
+}
+
+/** Find used USB address structure by USB address.
+ *
+ * It is expected that guard mutex is already locked.
+ *
+ * @param addresses Address keeping info.
+ * @param address Address to be found.
+ * @return Structure describing looked for address.
+ * @retval NULL Address not found.
+ */
+static usb_address_keeping_used_t *usb_address_keeping_used_find_no_lock(
+    usb_address_keeping_t *addresses, usb_address_t address)
+{
+	link_t *link;
+	for_all_used_addresses(link, addresses) {
+		usb_address_keeping_used_t *info
+		    = used_address_get_instance(link);
+
+		if (info->address == address) {
+			return info;
+		}
+	}
+
+	return NULL;
+}
+
+/** Initialize address keeping structure.
+ *
+ * @param addresses Address keeping info.
+ * @param max_address Maximum USB address (exclusive bound).
+ */
+void usb_address_keeping_init(usb_address_keeping_t *addresses,
+    usb_address_t max_address)
+{
+	/*
+	 * Items related with used addresses.
+	 */
+	addresses->max_address = max_address;
+	list_initialize(&addresses->used_addresses);
+	fibril_mutex_initialize(&addresses->used_addresses_guard);
+	fibril_condvar_initialize(&addresses->used_addresses_condvar);
+
+	/*
+	 * Items related with default address.
+	 */
+	addresses->default_available = true;
+	fibril_condvar_initialize(&addresses->default_condvar);
+	fibril_mutex_initialize(&addresses->default_condvar_guard);
+}
+
+/** Reserved default USB address.
+ *
+ * This function blocks until reserved address is available.
+ *
+ * @see usb_address_keeping_release_default
+ *
+ * @param addresses Address keeping info.
+ */
+void usb_address_keeping_reserve_default(usb_address_keeping_t *addresses)
+{
+	fibril_mutex_lock(&addresses->default_condvar_guard);
+	while (!addresses->default_available) {
+		fibril_condvar_wait(&addresses->default_condvar,
+			&addresses->default_condvar_guard);
+	}
+	fibril_mutex_unlock(&addresses->default_condvar_guard);
+}
+
+/** Releases default USB address.
+ *
+ * @see usb_address_keeping_reserve_default
+ *
+ * @param addresses Address keeping info.
+ */
+void usb_address_keeping_release_default(usb_address_keeping_t *addresses)
+{
+	fibril_mutex_lock(&addresses->default_condvar_guard);
+	addresses->default_available = true;
+	fibril_condvar_signal(&addresses->default_condvar);
+	fibril_mutex_unlock(&addresses->default_condvar_guard);
+}
+
+/** Request free address assignment.
+ *
+ * This function does not block when there are not free addresses to be
+ * assigned.
+ *
+ * @param addresses Address keeping info.
+ * @return USB address that could be used or negative error code.
+ * @retval ELIMIT No more addresses to assign.
+ * @retval ENOMEM Out of memory.
+ */
+usb_address_t usb_address_keeping_request(usb_address_keeping_t *addresses)
+{
+	usb_address_t previous_address = 0;
+	usb_address_t free_address = 0;
+
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+	link_t *new_address_position;
+	if (list_empty(&addresses->used_addresses)) {
+		free_address = 1;
+		new_address_position = addresses->used_addresses.next;
+	} else {
+		for_all_used_addresses(new_address_position, addresses) {
+			usb_address_keeping_used_t *info
+			    = used_address_get_instance(new_address_position);
+			if (info->address > previous_address + 1) {
+				free_address = previous_address + 1;
+				break;
+			}
+		}
+
+		if (free_address == 0) {
+			usb_address_keeping_used_t *last
+			    = used_address_get_instance(addresses->used_addresses.next);
+			free_address = last->address + 1;
+		}
+	}
+
+	if (free_address >= addresses->max_address) {
+		free_address = ELIMIT;
+		goto leave;
+	}
+
+	usb_address_keeping_used_t *used
+	    = usb_address_keeping_used_create(free_address);
+	if (used == NULL) {
+		free_address = ENOMEM;
+		goto leave;
+	}
+
+	list_prepend(&used->link, new_address_position);
+
+leave:
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+
+	return free_address;
+}
+
+/** Release USB address.
+ *
+ * @param addresses Address keeping info.
+ * @param address Address to be released.
+ * @return Error code.
+ * @retval ENOENT Address is not in use.
+ */
+int usb_address_keeping_release(usb_address_keeping_t *addresses,
+    usb_address_t address)
+{
+	int rc = ENOENT;
+
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+
+	usb_address_keeping_used_t *info
+	    = usb_address_keeping_used_find_no_lock(addresses, address);
+
+	if (info != NULL) {
+		rc = EOK;
+		list_remove(&info->link);
+		usb_address_keeping_used_destroy(info);
+	}
+
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+
+	return rc;
+}
+
+/** Bind devman handle with USB address.
+ *
+ * When the @p address is invalid (e.g. no such entry), the request
+ * is silently ignored.
+ *
+ * @param addresses Address keeping info.
+ * @param address USB address.
+ * @param handle Devman handle.
+ */
+void usb_address_keeping_devman_bind(usb_address_keeping_t *addresses,
+    usb_address_t address, devman_handle_t handle)
+{
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+
+	usb_address_keeping_used_t *info
+	    = usb_address_keeping_used_find_no_lock(addresses, address);
+	if (info == NULL) {
+		goto leave;
+	}
+
+	assert(info->address == address);
+	info->devman_handle = handle;
+
+	/*
+	 * Inform that new handle was added.
+	 */
+	fibril_condvar_broadcast(&addresses->used_addresses_condvar);
+
+leave:
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+}
+
+/** Find address by its devman handle.
+ *
+ * @param addresses Address keeping info.
+ * @param handle Devman handle.
+ * @return USB address or negative error code.
+ * @retval ENOENT No such address.
+ */
+static usb_address_t usb_address_keeping_find_no_lock(
+    usb_address_keeping_t *addresses, devman_handle_t handle)
+{
+	usb_address_t address = ENOENT;
+
+	link_t *link;
+	for_all_used_addresses(link, addresses) {
+		usb_address_keeping_used_t *info
+		    = used_address_get_instance(link);
+
+		if (info->devman_handle == handle) {
+			address = info->address;
+			break;
+		}
+	}
+
+	return address;
+}
+
+/** Find USB address by its devman handle.
+ *
+ * This function blocks until corresponding address is found.
+ *
+ * @param addresses Address keeping info.
+ * @param handle Devman handle.
+ * @return USB address or negative error code.
+ */
+usb_address_t usb_address_keeping_find(usb_address_keeping_t *addresses,
+    devman_handle_t handle)
+{
+	usb_address_t address = ENOENT;
+
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+	while (true) {
+		address = usb_address_keeping_find_no_lock(addresses, handle);
+		if (address != ENOENT) {
+			break;
+		}
+		fibril_condvar_wait(&addresses->used_addresses_condvar,
+		    &addresses->used_addresses_guard);
+	}
+
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+
+	return address;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/class.c
===================================================================
--- uspace/lib/usb/src/class.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/class.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,92 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Class related functions.
+ */
+#include <usb/classes/classes.h>
+#include <errno.h>
+
+/** Tell string representation of USB class.
+ *
+ * @param cls Class code.
+ * @return String representation.
+ */
+const char *usb_str_class(usb_class_t cls)
+{
+	switch (cls) {
+		case USB_CLASS_USE_INTERFACE:
+			return "use-interface";
+		case USB_CLASS_AUDIO:
+			return "audio";
+		case USB_CLASS_COMMUNICATIONS_CDC_CONTROL:
+			return "communications";
+		case USB_CLASS_HID:
+			return "HID";
+		case USB_CLASS_PHYSICAL:
+			return "physical";
+		case USB_CLASS_IMAGE:
+			return "image";
+		case USB_CLASS_PRINTER:
+			return "printer";
+		case USB_CLASS_MASS_STORAGE:
+			return "mass-storage";
+		case USB_CLASS_HUB:
+			return "hub";
+		case USB_CLASS_CDC_DATA:
+			return "CDC";
+		case USB_CLASS_SMART_CARD:
+			return "smart-card";
+		case USB_CLASS_CONTENT_SECURITY:
+			return "security";
+		case USB_CLASS_VIDEO:
+			return "video";
+		case USB_CLASS_PERSONAL_HEALTHCARE:
+			return "healthcare";
+		case USB_CLASS_DIAGNOSTIC:
+			return "diagnostic";
+		case USB_CLASS_WIRELESS_CONTROLLER:
+			return "wireless";
+		case USB_CLASS_MISCELLANEOUS:
+			return "misc";
+		case USB_CLASS_APPLICATION_SPECIFIC:
+			return "application";
+		case USB_CLASS_VENDOR_SPECIFIC:
+			return "vendor";
+		default:
+			return "unknown";
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/debug.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,160 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Debugging support.
+ */
+#include <adt/list.h>
+#include <fibril_synch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <usb/debug.h>
+
+/** Debugging tag. */
+typedef struct {
+	/** Linked list member. */
+	link_t link;
+	/** Tag name.
+	 * We always have a private copy of the name.
+	 */
+	char *tag;
+	/** Enabled level of debugging. */
+	int level;
+} usb_debug_tag_t;
+
+/** Get instance of usb_debug_tag_t from link_t. */
+#define USB_DEBUG_TAG_INSTANCE(iterator) \
+	list_get_instance(iterator, usb_debug_tag_t, link)
+
+/** List of all known tags. */
+static LIST_INITIALIZE(tag_list);
+/** Mutex guard for the list of all tags. */
+static FIBRIL_MUTEX_INITIALIZE(tag_list_guard);
+
+/** Find or create new tag with given name.
+ *
+ * @param tagname Tag name.
+ * @return Debug tag structure.
+ * @retval NULL Out of memory.
+ */
+static usb_debug_tag_t *get_tag(const char *tagname)
+{
+	link_t *link;
+	for (link = tag_list.next; \
+	    link != &tag_list; \
+	    link = link->next) {
+		usb_debug_tag_t *tag = USB_DEBUG_TAG_INSTANCE(link);
+		if (str_cmp(tag->tag, tagname) == 0) {
+			return tag;
+		}
+	}
+
+	/*
+	 * Tag not found, we will create a new one.
+	 */
+	usb_debug_tag_t *new_tag = malloc(sizeof(usb_debug_tag_t));
+	int rc = asprintf(&new_tag->tag, "%s", tagname);
+	if (rc < 0) {
+		free(new_tag);
+		return NULL;
+	}
+	list_initialize(&new_tag->link);
+	new_tag->level = 1;
+
+	/*
+	 * Append it to the end of known tags.
+	 */
+	list_append(&new_tag->link, &tag_list);
+
+	return new_tag;
+}
+
+/** Print debugging information.
+ * If the tag is used for the first time, its structures are automatically
+ * created and initial verbosity level is set to 1.
+ *
+ * @param tagname Tag name.
+ * @param level Level (verbosity) of the message.
+ * @param format Formatting string for printf().
+ */
+void usb_dprintf(const char *tagname, int level, const char *format, ...)
+{
+	fibril_mutex_lock(&tag_list_guard);
+	usb_debug_tag_t *tag = get_tag(tagname);
+	if (tag == NULL) {
+		printf("USB debug: FATAL ERROR - failed to create tag.\n");
+		goto leave;
+	}
+
+	if (tag->level < level) {
+		goto leave;
+	}
+
+	va_list args;
+	va_start(args, format);
+
+	printf("[%s:%d]: ", tagname, level);
+	vprintf(format, args);
+
+	va_end(args);
+
+leave:
+	fibril_mutex_unlock(&tag_list_guard);
+}
+
+/** Enable debugging prints for given tag.
+ *
+ * Setting level to <i>n</i> will cause that only printing messages
+ * with level lower or equal to <i>n</i> will be printed.
+ *
+ * @param tagname Tag name.
+ * @param level Enabled level.
+ */
+void usb_dprintf_enable(const char *tagname, int level)
+{
+	fibril_mutex_lock(&tag_list_guard);
+	usb_debug_tag_t *tag = get_tag(tagname);
+	if (tag == NULL) {
+		printf("USB debug: FATAL ERROR - failed to create tag.\n");
+		goto leave;
+	}
+
+	tag->level = level;
+
+leave:
+	fibril_mutex_unlock(&tag_list_guard);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/drvpsync.c
===================================================================
--- uspace/lib/usb/src/drvpsync.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/drvpsync.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,218 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Implementation of pseudo-synchronous transfers.
+ */
+#include <usb/usbdrv.h>
+#include <usbhc_iface.h>
+#include <errno.h>
+
+int usb_drv_psync_interrupt_out(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_interrupt_out(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_interrupt_in(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_interrupt_in(phone, target, buffer, size,
+	    actual_size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+
+
+int usb_drv_psync_control_write_setup(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_write_setup(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_write_data(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_write_data(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_write_status(int phone, usb_target_t target)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_write_status(phone, target, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+
+/** Perform complete control write transaction over USB.
+ *
+ * The DATA stage is performed only when @p data is not NULL and
+ * @p data_size is greater than zero.
+ *
+ * @param phone Open phone to host controller.
+ * @param target Target device and endpoint.
+ * @param setup_packet Setup packet data.
+ * @param setup_packet_size Size of the setup packet.
+ * @param data Data to be sent.
+ * @param data_size Size of the @p data buffer.
+ * @return Error code.
+ */
+int usb_drv_psync_control_write(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size)
+{
+	int rc;
+	
+	rc = usb_drv_psync_control_write_setup(phone, target,
+	    setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if ((data != NULL) && (data_size > 0)) {
+		rc = usb_drv_psync_control_write_data(phone, target,
+		    data, data_size);
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+
+	rc = usb_drv_psync_control_write_status(phone, target);
+
+	return rc;
+}
+
+
+int usb_drv_psync_control_read_setup(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_read_setup(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_read_data(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_read_data(phone, target, buffer, size,
+	    actual_size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_read_status(int phone, usb_target_t target)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_read_status(phone, target, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+
+/** Perform complete control read transaction over USB.
+ *
+ * @param phone Open phone to host controller.
+ * @param target Target device and endpoint.
+ * @param setup_packet Setup packet data.
+ * @param setup_packet_size Size of the setup packet.
+ * @param data Storage for read data.
+ * @param data_size Size of the @p data buffer.
+ * @param actual_data_size Storage for number of actually transferred data from
+ *        device.
+ * @return Error code.
+ */
+int usb_drv_psync_control_read(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size, size_t *actual_data_size)
+{
+	int rc;
+	
+	rc = usb_drv_psync_control_read_setup(phone, target,
+	    setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_drv_psync_control_read_data(phone, target,
+	    data, data_size, actual_data_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_drv_psync_control_read_status(phone, target);
+
+	return rc;
+}
+
+
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hcdhubd.c
===================================================================
--- uspace/lib/usb/src/hcdhubd.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/hcdhubd.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,309 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Common stuff for both HC driver and hub driver.
+ */
+#include <usb/hcdhubd.h>
+#include <usb/devreq.h>
+#include <usbhc_iface.h>
+#include <usb/descriptor.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/classes/hub.h>
+
+#include "hcdhubd_private.h"
+
+/** Callback when new device is detected and must be handled by this driver.
+ *
+ * @param dev New device.
+ * @return Error code.
+ */
+static int add_device(device_t *dev) {
+	return ENOTSUP;
+}
+
+/** Operations for combined HC and HUB driver. */
+static driver_ops_t hc_driver_generic_ops = {
+	.add_device = add_device
+};
+
+/** Combined HC and HUB driver. */
+static driver_t hc_driver_generic = {
+	.driver_ops = &hc_driver_generic_ops
+};
+
+/** Main USB host controller driver routine.
+ *
+ * @see driver_main
+ *
+ * @param hc Host controller driver.
+ * @return Error code.
+ */
+int usb_hcd_main(usb_hc_driver_t *hc) {
+	hc_driver = hc;
+	hc_driver_generic.name = hc->name;
+
+	/*
+	 * Run the device driver framework.
+	 */
+	return driver_main(&hc_driver_generic);
+}
+
+/** Add a root hub for given host controller.
+ * This function shall be called only once for each host controller driven
+ * by this driver.
+ * It takes care of creating child device - hub - that will be driven by
+ * this task.
+ *
+ * @param dev Host controller device.
+ * @return Error code.
+ */
+int usb_hcd_add_root_hub(device_t *dev)
+{
+	char *id;
+	int rc = asprintf(&id, "usb&hub");
+	if (rc <= 0) {
+		return rc;
+	}
+
+	rc = usb_hc_add_child_device(dev, USB_HUB_DEVICE_NAME, id, true);
+	if (rc != EOK) {
+		free(id);
+	}
+
+	return rc;
+}
+
+/** Info about child device. */
+struct child_device_info {
+	device_t *parent;
+	const char *name;
+	const char *match_id;
+};
+
+/** Adds a child device fibril worker. */
+static int fibril_add_child_device(void *arg) {
+	struct child_device_info *child_info
+			= (struct child_device_info *) arg;
+	int rc;
+
+	async_usleep(1000);
+
+	device_t *child = create_device();
+	match_id_t *match_id = NULL;
+
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+	child->name = child_info->name;
+
+	match_id = create_match_id();
+	if (match_id == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+	match_id->id = child_info->match_id;
+	match_id->score = 10;
+	add_match_id(&child->match_ids, match_id);
+
+	printf("%s: adding child device `%s' with match \"%s\"\n",
+			hc_driver->name, child->name, match_id->id);
+	rc = child_device_register(child, child_info->parent);
+	printf("%s: child device `%s' registration: %s\n",
+			hc_driver->name, child->name, str_error(rc));
+
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	goto leave;
+
+failure:
+	if (child != NULL) {
+		child->name = NULL;
+		delete_device(child);
+	}
+
+	if (match_id != NULL) {
+		match_id->id = NULL;
+		delete_match_id(match_id);
+	}
+
+leave:
+	free(arg);
+	return EOK;
+}
+
+/** Adds a child.
+ * Due to deadlock in devman when parent registers child that oughts to be
+ * driven by the same task, the child adding is done in separate fibril.
+ * Not optimal, but it works.
+ * Update: not under all circumstances the new fibril is successful either.
+ * Thus the last parameter to let the caller choose.
+ *
+ * @param parent Parent device.
+ * @param name Device name.
+ * @param match_id Match id.
+ * @param create_fibril Whether to run the addition in new fibril.
+ * @return Error code.
+ */
+int usb_hc_add_child_device(device_t *parent, const char *name,
+		const char *match_id, bool create_fibril) {
+	printf("%s: about to add child device `%s' (%s)\n", hc_driver->name,
+			name, match_id);
+
+	/*
+	 * Seems that creating fibril which postpones the action
+	 * is the best solution.
+	 */
+	create_fibril = true;
+
+	struct child_device_info *child_info
+			= malloc(sizeof (struct child_device_info));
+
+	child_info->parent = parent;
+	child_info->name = name;
+	child_info->match_id = match_id;
+
+	if (create_fibril) {
+		fid_t fibril = fibril_create(fibril_add_child_device, child_info);
+		if (!fibril) {
+			return ENOMEM;
+		}
+		fibril_add_ready(fibril);
+	} else {
+		fibril_add_child_device(child_info);
+	}
+
+	return EOK;
+}
+
+/** Tell USB address of given device.
+ *
+ * @param handle Devman handle of the device.
+ * @return USB device address or error code.
+ */
+usb_address_t usb_get_address_by_handle(devman_handle_t handle) {
+	/* TODO: search list of attached devices. */
+	return ENOENT;
+}
+
+usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd) {
+	//is there free address?
+	link_t * addresses = &this_hcd->addresses;
+	if (list_empty(addresses)) return -1;
+	link_t * link_addr = addresses;
+	bool found = false;
+	usb_address_list_t * range = NULL;
+	while (!found) {
+		link_addr = link_addr->next;
+		if (link_addr == addresses) return -2;
+		range = list_get_instance(link_addr,
+				usb_address_list_t, link);
+		if (range->upper_bound - range->lower_bound > 0) {
+			found = true;
+		}
+	}
+	//now we have interval
+	int result = range->lower_bound;
+	++(range->lower_bound);
+	if (range->upper_bound - range->lower_bound == 0) {
+		list_remove(&range->link);
+		free(range);
+	}
+	return result;
+}
+
+void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr) {
+	//check range
+	if (addr < usb_lowest_address || addr > usb_highest_address)
+		return;
+	link_t * addresses = &this_hcd->addresses;
+	link_t * link_addr = addresses;
+	//find 'good' interval
+	usb_address_list_t * found_range = NULL;
+	bool found = false;
+	while (!found) {
+		link_addr = link_addr->next;
+		if (link_addr == addresses) {
+			found = true;
+		} else {
+			usb_address_list_t * range = list_get_instance(link_addr,
+					usb_address_list_t, link);
+			if (	(range->lower_bound - 1 == addr) ||
+					(range->upper_bound == addr)) {
+				found = true;
+				found_range = range;
+			}
+			if (range->lower_bound - 1 > addr) {
+				found = true;
+			}
+
+		}
+	}
+	if (found_range == NULL) {
+		//no suitable range found
+		usb_address_list_t * result_range =
+				(usb_address_list_t*) malloc(sizeof (usb_address_list_t));
+		result_range->lower_bound = addr;
+		result_range->upper_bound = addr + 1;
+		list_insert_before(&result_range->link, link_addr);
+	} else {
+		//we have good range
+		if (found_range->lower_bound - 1 == addr) {
+			--found_range->lower_bound;
+		} else {
+			//only one possible case
+			++found_range->upper_bound;
+			if (found_range->link.next != addresses) {
+				usb_address_list_t * next_range =
+						list_get_instance( &found_range->link.next,
+						usb_address_list_t, link);
+				//check neighbour range
+				if (next_range->lower_bound == addr + 1) {
+					//join ranges
+					found_range->upper_bound = next_range->upper_bound;
+					list_remove(&next_range->link);
+					free(next_range);
+				}
+			}
+		}
+	}
+
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hcdhubd_private.h
===================================================================
--- uspace/lib/usb/src/hcdhubd_private.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/hcdhubd_private.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,77 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Common definitions for both HC driver and hub driver.
+ */
+#ifndef LIBUSB_HCDHUBD_PRIVATE_H_
+#define LIBUSB_HCDHUBD_PRIVATE_H_
+
+#define USB_HUB_DEVICE_NAME "usbhub"
+#define USB_KBD_DEVICE_NAME "hid"
+
+extern link_t hc_list;
+extern usb_hc_driver_t *hc_driver;
+
+extern usbhc_iface_t usbhc_interface;
+
+usb_address_t usb_get_address_by_handle(devman_handle_t);
+int usb_add_hc_device(device_t *);
+
+/** lowest allowed usb address */
+extern int usb_lowest_address;
+
+/** highest allowed usb address */
+extern int usb_highest_address;
+
+/**
+ * @brief initialize address list of given hcd
+ *
+ * This function should be used only for hcd initialization.
+ * It creates interval list of free addresses, thus it is initialized as
+ * list with one interval with whole address space. Using an address shrinks
+ * the interval, freeing an address extends an interval or creates a
+ * new one. 
+ *
+ * @param hcd
+ * @return
+ */
+void  usb_create_address_list(usb_hc_device_t * hcd);
+
+
+
+
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hcdrv.c
===================================================================
--- uspace/lib/usb/src/hcdrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/hcdrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,127 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief HC driver.
+ */
+#include <usb/hcdhubd.h>
+#include <usb/devreq.h>
+#include <usbhc_iface.h>
+#include <usb/descriptor.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+#include <usb/classes/hub.h>
+
+#include "hcdhubd_private.h"
+
+/** List of handled host controllers. */
+LIST_INITIALIZE(hc_list);
+
+/* Fake driver to have the name item initialized. */
+static usb_hc_driver_t hc_driver_fake = {
+	.name = "HCD",
+};
+
+/** Our HC driver. */
+usb_hc_driver_t *hc_driver = &hc_driver_fake;
+
+int usb_lowest_address = 1;
+
+int usb_highest_address = 255;
+
+static device_ops_t usb_device_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &usbhc_interface
+};
+
+
+void usb_create_address_list(usb_hc_device_t * hcd){
+	list_initialize(&hcd->addresses);
+	usb_address_list_t * range =
+			(usb_address_list_t*)malloc(sizeof(usb_address_list_t));
+	range->lower_bound = usb_lowest_address;
+	range->upper_bound = usb_highest_address + 1;
+	list_append(&range->link, &hcd->addresses);
+}
+
+static usb_hc_device_t *usb_hc_device_create(device_t *dev) {
+	usb_hc_device_t *hc_dev = malloc(sizeof (usb_hc_device_t));
+
+	list_initialize(&hc_dev->link);
+	list_initialize(&hc_dev->hubs);
+	usb_create_address_list(hc_dev);
+	list_initialize(&hc_dev->attached_devices);
+	hc_dev->transfer_ops = NULL;
+
+	hc_dev->generic = dev;
+	dev->ops = &usb_device_ops;
+	hc_dev->generic->driver_data = hc_dev;
+
+	return hc_dev;
+}
+
+int usb_add_hc_device(device_t *dev)
+{
+	return ENOTSUP;
+	usb_hc_device_t *hc_dev = usb_hc_device_create(dev);
+
+	int rc = hc_driver->add_hc(hc_dev);
+	if (rc != EOK) {
+		free(hc_dev);
+		return rc;
+	}
+
+	/*
+	 * FIXME: The following line causes devman to hang.
+	 * Will investigate later why.
+	 */
+	// add_device_to_class(dev, "usbhc");
+
+	list_append(&hc_dev->link, &hc_list);
+
+	/*
+	 * FIXME: the following is a workaround to force loading of USB
+	 * keyboard driver.
+	 * Will be removed as soon as the hub driver is completed and
+	 * can detect connected devices.
+	 */
+	printf("%s: trying to add USB HID child device...\n", hc_driver->name);
+	rc = usb_hc_add_child_device(dev, USB_KBD_DEVICE_NAME, "usb&hid", false);
+	if (rc != EOK) {
+		printf("%s: adding USB HID child failed...\n", hc_driver->name);
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/hidparser.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,84 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief HID parser implementation.
+ */
+#include <usb/classes/hidparser.h>
+#include <errno.h>
+
+/** Parse HID report descriptor.
+ *
+ * @param parser Opaque HID report parser structure.
+ * @param data Data describing the report.
+ * @param size Size of the descriptor in bytes.
+ * @return Error code.
+ */
+int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser, 
+    const uint8_t *data, size_t size)
+{
+	return ENOTSUP;
+}
+
+/** Parse and act upon a HID report.
+ *
+ * @see usb_hid_parse_report_descriptor
+ *
+ * @param parser Opaque HID report parser structure.
+ * @param data Data for the report.
+ * @param size Size of the data in bytes.
+ * @param callbacks Callbacks for report actions.
+ * @param arg Custom argument (passed through to the callbacks).
+ * @return Error code.
+ */
+int usb_hid_parse_report(const usb_hid_report_parser_t *parser,  
+    const uint8_t *data, size_t size,
+    const usb_hid_report_in_callbacks_t *callbacks, void *arg)
+{
+	int i;
+	
+	// TODO: parse report
+	
+	uint16_t keys[6];
+	
+	for (i = 0; i < 6; ++i) {
+		keys[i] = data[i];
+	}
+	
+	callbacks->keyboard(keys, 6, arg);
+	
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/localdrv.c
===================================================================
--- uspace/lib/usb/src/localdrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/localdrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,414 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Driver communication for local drivers (hubs).
+ */
+#include <usb/hcdhubd.h>
+#include <usbhc_iface.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+
+/** Find host controller when handled by current task.
+ *
+ * @param dev Device asking for connection.
+ * @return Device structure corresponding to parent host controller.
+ * @retval NULL Corresponding host controller not found.
+ */
+device_t *usb_hc_connect(device_t *dev)
+{
+	/*
+	 * FIXME: this will not work when some hub on the path is
+	 * not driven by the same task.
+	 */
+	device_t *parent = dev;
+	while (parent->parent != NULL) {
+		parent = parent->parent;
+	}
+	
+	if (dev == parent) {
+		printf("FIXME in %s:%d encountered!\n", __FILE__, __LINE__);
+		parent = NULL;
+	}
+
+	return parent;
+}
+
+/** Information about pending transaction on HC. */
+typedef struct {
+	/** Storage for actual number of bytes transferred. */
+	size_t *size_transferred;
+
+	/** Target device. */
+	usb_hcd_attached_device_info_t *device;
+	/** Target endpoint. */
+	usb_hc_endpoint_info_t *endpoint;
+
+	/** Guard for the condition variable. */
+	fibril_mutex_t condvar_guard;
+	/** Condition variable for waiting for done. */
+	fibril_condvar_t condvar;
+
+	/** Flag whether the transfer is done. */
+	bool done;
+} transfer_info_t;
+
+/** Create new transfer info.
+ *
+ * @param device Attached device.
+ * @param endpoint Endpoint.
+ * @return Transfer info with pre-filled values.
+ */
+static transfer_info_t *transfer_info_create(
+    usb_hcd_attached_device_info_t *device, usb_hc_endpoint_info_t *endpoint)
+{
+	transfer_info_t *transfer = malloc(sizeof(transfer_info_t));
+
+	transfer->size_transferred = NULL;
+	fibril_condvar_initialize(&transfer->condvar);
+	fibril_mutex_initialize(&transfer->condvar_guard);
+	transfer->done = false;
+
+	transfer->device = device;
+	transfer->endpoint = endpoint;
+
+	return transfer;
+}
+
+/** Destroy transfer info.
+ *
+ * @param transfer Transfer to be destroyed.
+ */
+static void transfer_info_destroy(transfer_info_t *transfer)
+{
+	free(transfer->device);
+	free(transfer->endpoint);
+	free(transfer);
+}
+
+/** Create info about attached device.
+ *
+ * @param address Device address.
+ * @return Device info structure.
+ */
+static usb_hcd_attached_device_info_t *create_attached_device_info(
+    usb_address_t address)
+{
+	usb_hcd_attached_device_info_t *dev
+	    = malloc(sizeof(usb_hcd_attached_device_info_t));
+
+	dev->address = address;
+	dev->endpoint_count = 0;
+	dev->endpoints = NULL;
+	list_initialize(&dev->link);
+
+	return dev;
+}
+
+/** Create info about device endpoint.
+ *
+ * @param endpoint Endpoint number.
+ * @param direction Endpoint data direction.
+ * @param transfer_type Transfer type of the endpoint.
+ * @return Endpoint info structure.
+ */
+static usb_hc_endpoint_info_t *create_endpoint_info(usb_endpoint_t endpoint,
+    usb_direction_t direction, usb_transfer_type_t transfer_type)
+{
+	usb_hc_endpoint_info_t *ep = malloc(sizeof(usb_hc_endpoint_info_t));
+	ep->data_toggle = 0;
+	ep->direction = direction;
+	ep->transfer_type = transfer_type;
+	ep->endpoint = endpoint;
+
+	return ep;
+}
+
+/** Marks given transfer as done.
+ *
+ * @param transfer Transfer to be completed.
+ */
+static void transfer_mark_complete(transfer_info_t *transfer)
+{
+	fibril_mutex_lock(&transfer->condvar_guard);
+	transfer->done = true;
+	fibril_condvar_signal(&transfer->condvar);
+	fibril_mutex_unlock(&transfer->condvar_guard);
+}
+
+/** Callback for OUT transfers.
+ *
+ * @param hc Host controller that processed the transfer.
+ * @param outcome Transfer outcome.
+ * @param arg Custom argument.
+ */
+static void callback_out(usb_hc_device_t *hc,
+    usb_transaction_outcome_t outcome, void *arg)
+{
+	transfer_info_t *transfer = (transfer_info_t *) arg;
+
+	/*
+	 * For out transfers, marking them complete is enough.
+	 * No other processing is necessary.
+	 */
+	transfer_mark_complete(transfer);
+}
+
+/** Callback for IN transfers.
+ *
+ * @param hc Host controller that processed the transfer.
+ * @param actual_size Number of actually transferred bytes.
+ * @param outcome Transfer outcome.
+ * @param arg Custom argument.
+ */
+static void callback_in(usb_hc_device_t *hc,
+    size_t actual_size, usb_transaction_outcome_t outcome, void *arg)
+{
+	transfer_info_t *transfer = (transfer_info_t *) arg;
+
+	/*
+	 * Set the number of actually transferred bytes and
+	 * mark the transfer as complete.
+	 */
+	if (transfer->size_transferred != NULL) {
+		*transfer->size_transferred = actual_size;
+	}
+
+	transfer_mark_complete(transfer);
+}
+
+static int async_transfer_out(usb_hc_device_t *hc,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *data, size_t size,
+    usb_handle_t *handle)
+{
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_out == NULL)) {
+		return ENOTSUP;
+	}
+
+	/* This creation of the device on the fly is just a workaround. */
+
+	transfer_info_t *transfer = transfer_info_create(
+	    create_attached_device_info(target.address),
+	    create_endpoint_info(target.endpoint,
+		USB_DIRECTION_OUT, transfer_type));
+
+	int rc = hc->transfer_ops->transfer_out(hc,
+	    transfer->device, transfer->endpoint,
+	    data, size,
+	    callback_out, transfer);
+
+	if (rc != EOK) {
+		transfer_info_destroy(transfer);
+		return rc;
+	}
+
+	*handle = (usb_handle_t)transfer;
+
+	return EOK;
+}
+
+static int async_transfer_setup(usb_hc_device_t *hc,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *data, size_t size,
+    usb_handle_t *handle)
+{
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_setup == NULL)) {
+		return ENOTSUP;
+	}
+
+	/* This creation of the device on the fly is just a workaround. */
+
+	transfer_info_t *transfer = transfer_info_create(
+	    create_attached_device_info(target.address),
+	    create_endpoint_info(target.endpoint,
+		USB_DIRECTION_OUT, transfer_type));
+
+	int rc = hc->transfer_ops->transfer_setup(hc,
+	    transfer->device, transfer->endpoint,
+	    data, size,
+	    callback_out, transfer);
+
+	if (rc != EOK) {
+		transfer_info_destroy(transfer);
+		return rc;
+	}
+
+	*handle = (usb_handle_t)transfer;
+
+	return EOK;
+}
+
+static int async_transfer_in(usb_hc_device_t *hc, usb_target_t target,
+    usb_transfer_type_t transfer_type,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_in == NULL)) {
+		return ENOTSUP;
+	}
+
+	/* This creation of the device on the fly is just a workaround. */
+
+	transfer_info_t *transfer = transfer_info_create(
+	    create_attached_device_info(target.address),
+	    create_endpoint_info(target.endpoint,
+		USB_DIRECTION_IN, transfer_type));
+	transfer->size_transferred = actual_size;
+
+	int rc = hc->transfer_ops->transfer_in(hc,
+	    transfer->device, transfer->endpoint,
+	    buffer, size,
+	    callback_in, transfer);
+
+	if (rc != EOK) {
+		transfer_info_destroy(transfer);
+		return rc;
+	}
+
+	*handle = (usb_handle_t)transfer;
+
+	return EOK;
+}
+
+
+/** Issue interrupt OUT transfer to HC driven by current task.
+ *
+ * @param hc Host controller to handle the transfer.
+ * @param target Target device address.
+ * @param buffer Data buffer.
+ * @param size Buffer size.
+ * @param handle Transfer handle.
+ * @return Error code.
+ */
+int usb_hc_async_interrupt_out(usb_hc_device_t *hc, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_transfer_out(hc, target,
+	    USB_TRANSFER_INTERRUPT, buffer, size, handle);
+}
+
+
+/** Issue interrupt IN transfer to HC driven by current task.
+ *
+ * @warning The @p buffer and @p actual_size parameters shall not be
+ * touched until this transfer is waited for by usb_hc_async_wait_for().
+ *
+ * @param hc Host controller to handle the transfer.
+ * @param target Target device address.
+ * @param buffer Data buffer.
+ * @param size Buffer size.
+ * @param actual_size Size of actually transferred data.
+ * @param handle Transfer handle.
+ * @return Error code.
+ */
+int usb_hc_async_interrupt_in(usb_hc_device_t *hc, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_transfer_in(hc, target,
+	    USB_TRANSFER_INTERRUPT, buffer, size, actual_size, handle);
+}
+
+int usb_hc_async_control_write_setup(usb_hc_device_t *hc, usb_target_t target,
+    void *data, size_t size, usb_handle_t *handle)
+{
+	return async_transfer_setup(hc, target,
+	    USB_TRANSFER_CONTROL, data, size, handle);
+}
+
+int usb_hc_async_control_write_data(usb_hc_device_t *hc, usb_target_t target,
+    void *data, size_t size, usb_handle_t *handle)
+{
+	return async_transfer_out(hc, target,
+	    USB_TRANSFER_CONTROL, data, size, handle);
+}
+
+int usb_hc_async_control_write_status(usb_hc_device_t *hc, usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_transfer_in(hc, target,
+	    USB_TRANSFER_CONTROL, NULL, 0, NULL, handle);
+}
+
+int usb_hc_async_control_read_setup(usb_hc_device_t *hc, usb_target_t target,
+    void *data, size_t size, usb_handle_t *handle)
+{
+	return async_transfer_setup(hc, target,
+	    USB_TRANSFER_CONTROL, data, size, handle);
+}
+
+int usb_hc_async_control_read_data(usb_hc_device_t *hc, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_transfer_in(hc, target,
+	    USB_TRANSFER_CONTROL, buffer, size, actual_size, handle);
+}
+
+int usb_hc_async_control_read_status(usb_hc_device_t *hc, usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_transfer_out(hc, target,
+	    USB_TRANSFER_CONTROL, NULL, 0, handle);
+}
+
+/** Wait for transfer to complete.
+ *
+ * @param handle Transfer handle.
+ * @return Error code.
+ */
+int usb_hc_async_wait_for(usb_handle_t handle)
+{
+	transfer_info_t *transfer = (transfer_info_t *) handle;
+	if (transfer == NULL) {
+		return ENOENT;
+	}
+
+	fibril_mutex_lock(&transfer->condvar_guard);
+	while (!transfer->done) {
+		fibril_condvar_wait(&transfer->condvar, &transfer->condvar_guard);
+	}
+	fibril_mutex_unlock(&transfer->condvar_guard);
+
+	transfer_info_destroy(transfer);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/recognise.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,322 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Functions for recognising kind of attached devices.
+ */
+#include <usb/usbdrv.h>
+#include <usb/classes/classes.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+#define BCD_INT(a) (((unsigned int)(a)) / 256)
+#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
+
+#define BCD_FMT "%x.%x"
+#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
+
+/* FIXME: make this dynamic */
+#define MATCH_STRING_MAX 256
+
+/** Add formatted match id.
+ *
+ * @param matches List of match ids where to add to.
+ * @param score Score of the match.
+ * @param format Printf-like format
+ * @return Error code.
+ */
+static int usb_add_match_id(match_id_list_t *matches, int score,
+    const char *format, ...)
+{
+	char *match_str = NULL;
+	match_id_t *match_id = NULL;
+	int rc;
+	
+	match_str = malloc(MATCH_STRING_MAX + 1);
+	if (match_str == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	/*
+	 * FIXME: replace with dynamic allocation of exact size
+	 */
+	va_list args;
+	va_start(args, format	);
+	vsnprintf(match_str, MATCH_STRING_MAX, format, args);
+	match_str[MATCH_STRING_MAX] = 0;
+	va_end(args);
+
+	match_id = create_match_id();
+	if (match_id == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	match_id->id = match_str;
+	match_id->score = score;
+	add_match_id(matches, match_id);
+
+	return EOK;
+	
+failure:
+	if (match_str != NULL) {
+		free(match_str);
+	}
+	if (match_id != NULL) {
+		match_id->id = NULL;
+		delete_match_id(match_id);
+	}
+	
+	return rc;
+}
+
+/** Add match ids based on configuration descriptor.
+ *
+ * @param hc Open phone to host controller.
+ * @param matches Match ids list to add matches to.
+ * @param address USB address of the attached device.
+ * @return Error code.
+ */
+static int usb_add_config_descriptor_match_ids(int hc,
+    match_id_list_t *matches, usb_address_t address,
+    int config_count)
+{
+	int final_rc = EOK;
+	
+	int config_index;
+	for (config_index = 0; config_index < config_count; config_index++) {
+		int rc;
+		usb_standard_configuration_descriptor_t config_descriptor;
+		rc = usb_drv_req_get_bare_configuration_descriptor(hc,
+		    address,  config_index, &config_descriptor);
+		if (rc != EOK) {
+			final_rc = rc;
+			continue;
+		}
+
+		size_t full_config_descriptor_size;
+		void *full_config_descriptor
+		    = malloc(config_descriptor.total_length);
+		rc = usb_drv_req_get_full_configuration_descriptor(hc,
+		    address, config_index,
+		    full_config_descriptor, config_descriptor.total_length,
+		    &full_config_descriptor_size);
+		if (rc != EOK) {
+			final_rc = rc;
+			continue;
+		}
+		if (full_config_descriptor_size
+		    != config_descriptor.total_length) {
+			final_rc = ERANGE;
+			continue;
+		}
+
+		/*
+		 * Iterate through config descriptor to find the interface
+		 * descriptors.
+		 */
+		size_t position = sizeof(config_descriptor);
+		while (position + 1 < full_config_descriptor_size) {
+			uint8_t *current_descriptor
+			    = ((uint8_t *) full_config_descriptor) + position;
+			uint8_t cur_descr_len = current_descriptor[0];
+			uint8_t cur_descr_type = current_descriptor[1];
+			
+			position += cur_descr_len;
+			
+			if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
+				continue;
+			}
+			/*
+			 * Finally, we found an interface descriptor.
+			 */
+			usb_standard_interface_descriptor_t *interface
+			    = (usb_standard_interface_descriptor_t *)
+			    current_descriptor;
+			
+			rc = usb_add_match_id(matches, 50,
+			    "usb&interface&class=%s",
+			    usb_str_class(interface->interface_class));
+			if (rc != EOK) {
+				final_rc = rc;
+				break;
+			}
+		}
+	}
+	
+	return final_rc;
+}
+
+/** Create match ids describing attached device.
+ *
+ * @warning The list of match ids @p matches may change even when
+ * function exits with error.
+ *
+ * @param hc Open phone to host controller.
+ * @param matches Initialized list of match ids.
+ * @param address USB address of the attached device.
+ * @return Error code.
+ */
+int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches,
+    usb_address_t address)
+{
+	int rc;
+	usb_standard_device_descriptor_t device_descriptor;
+
+	rc = usb_drv_req_get_device_descriptor(hc, address,
+	    &device_descriptor);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/*
+	 * Unless the vendor id is 0, the pair idVendor-idProduct
+	 * quite uniquely describes the device.
+	 */
+	if (device_descriptor.vendor_id != 0) {
+		/* First, with release number. */
+		rc = usb_add_match_id(matches, 100,
+		    "usb&vendor=%d&product=%d&release=" BCD_FMT,
+		    (int) device_descriptor.vendor_id,
+		    (int) device_descriptor.product_id,
+		    BCD_ARGS(device_descriptor.device_version));
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		/* Next, without release number. */
+		rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
+		    (int) device_descriptor.vendor_id,
+		    (int) device_descriptor.product_id);
+		if (rc != EOK) {
+			return rc;
+		}
+
+	}	
+
+	/*
+	 * If the device class points to interface we skip adding
+	 * class directly.
+	 */
+	if (device_descriptor.device_class != USB_CLASS_USE_INTERFACE) {
+		rc = usb_add_match_id(matches, 50, "usb&class=%s",
+		    usb_str_class(device_descriptor.device_class));
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+	/*
+	 * Go through all configurations and add matches
+	 * based on interface class.
+	 */
+	rc = usb_add_config_descriptor_match_ids(hc, matches,
+	    address, device_descriptor.configuration_count);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/*
+	 * As a fallback, provide the simplest match id possible.
+	 */
+	rc = usb_add_match_id(matches, 1, "usb&fallback");
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return EOK;
+}
+
+
+/** Probe for device kind and register it in devman.
+ *
+ * @param hc Open phone to the host controller.
+ * @param parent Parent device.
+ * @param address Address of the (unknown) attached device.
+ * @return Error code.
+ */
+int usb_drv_register_child_in_devman(int hc, device_t *parent,
+    usb_address_t address, devman_handle_t *child_handle)
+{
+	device_t *child = NULL;
+	char *child_name = NULL;
+	int rc;
+
+	child = create_device();
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	/*
+	 * TODO: some better child naming
+	 */
+	rc = asprintf(&child_name, "usb%p", child);
+	if (rc < 0) {
+		goto failure;
+	}
+	child->name = child_name;
+	
+	rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	rc = child_device_register(child, parent);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	if (child_handle != NULL) {
+		*child_handle = child->handle;
+	}
+	
+	return EOK;
+
+failure:
+	if (child != NULL) {
+		child->name = NULL;
+		/* This takes care of match_id deallocation as well. */
+		delete_device(child);
+	}
+	if (child_name != NULL) {
+		free(child_name);
+	}
+
+	return rc;
+
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/remotedrv.c
===================================================================
--- uspace/lib/usb/src/remotedrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/remotedrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,437 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Driver communication for remote drivers (interface implementation).
+ */
+#include <usb/hcdhubd.h>
+#include <usbhc_iface.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+
+#include "hcdhubd_private.h"
+
+static int remote_get_address(device_t *, devman_handle_t, usb_address_t *);
+
+static int remote_interrupt_out(device_t *, usb_target_t, void *, size_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+static int remote_interrupt_in(device_t *, usb_target_t, void *, size_t,
+    usbhc_iface_transfer_in_callback_t, void *);
+
+static int remote_control_write_setup(device_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+static int remote_control_write_data(device_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+static int remote_control_write_status(device_t *, usb_target_t,
+    usbhc_iface_transfer_in_callback_t, void *);
+
+static int remote_control_read_setup(device_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+static int remote_control_read_data(device_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_in_callback_t, void *);
+static int remote_control_read_status(device_t *, usb_target_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+
+/** Implementation of USB HC interface. */
+usbhc_iface_t usbhc_interface = {
+	.tell_address = remote_get_address,
+	.interrupt_out = remote_interrupt_out,
+	.interrupt_in = remote_interrupt_in,
+	.control_write_setup = remote_control_write_setup,
+	.control_write_data = remote_control_write_data,
+	.control_write_status = remote_control_write_status,
+	.control_read_setup = remote_control_read_setup,
+	.control_read_data = remote_control_read_data,
+	.control_read_status = remote_control_read_status
+};
+
+/** Get USB address for remote USBHC interface.
+ *
+ * @param dev Device asked for the information.
+ * @param handle Devman handle of the USB device.
+ * @param address Storage for obtained address.
+ * @return Error code.
+ */
+int remote_get_address(device_t *dev, devman_handle_t handle,
+    usb_address_t *address)
+{
+	usb_address_t addr = usb_get_address_by_handle(handle);
+	if (addr < 0) {
+		return addr;
+	}
+
+	*address = addr;
+
+	return EOK;
+}
+
+/** Information about pending transaction on HC. */
+typedef struct {
+	/** Target device. */
+	usb_hcd_attached_device_info_t *device;
+	/** Target endpoint. */
+	usb_hc_endpoint_info_t *endpoint;
+
+	/** Callbacks. */
+	union {
+		/** Callback for outgoing transfers. */
+		usbhc_iface_transfer_out_callback_t out_callback;
+		/** Callback for incoming transfers. */
+		usbhc_iface_transfer_in_callback_t in_callback;
+	};
+
+	/** Custom argument for the callback. */
+	void *arg;
+} transfer_info_t;
+
+/** Create new transfer info.
+ *
+ * @param device Attached device.
+ * @param endpoint Endpoint.
+ * @param custom_arg Custom argument.
+ * @return Transfer info with pre-filled values.
+ */
+static transfer_info_t *transfer_info_create(
+    usb_hcd_attached_device_info_t *device, usb_hc_endpoint_info_t *endpoint,
+    void *custom_arg)
+{
+	transfer_info_t *transfer = malloc(sizeof(transfer_info_t));
+
+	transfer->device = device;
+	transfer->endpoint = endpoint;
+	transfer->arg = custom_arg;
+	transfer->out_callback = NULL;
+	transfer->in_callback = NULL;
+
+	return transfer;
+}
+
+/** Destroy transfer info.
+ *
+ * @param transfer Transfer to be destroyed.
+ */
+static void transfer_info_destroy(transfer_info_t *transfer)
+{
+	free(transfer->device);
+	free(transfer->endpoint);
+	free(transfer);
+}
+
+/** Create info about attached device.
+ *
+ * @param address Device address.
+ * @return Device info structure.
+ */
+static usb_hcd_attached_device_info_t *create_attached_device_info(
+    usb_address_t address)
+{
+	usb_hcd_attached_device_info_t *dev
+	    = malloc(sizeof(usb_hcd_attached_device_info_t));
+
+	dev->address = address;
+	dev->endpoint_count = 0;
+	dev->endpoints = NULL;
+	list_initialize(&dev->link);
+
+	return dev;
+}
+
+/** Create info about device endpoint.
+ *
+ * @param endpoint Endpoint number.
+ * @param direction Endpoint data direction.
+ * @param transfer_type Transfer type of the endpoint.
+ * @return Endpoint info structure.
+ */
+static usb_hc_endpoint_info_t *create_endpoint_info(usb_endpoint_t endpoint,
+    usb_direction_t direction, usb_transfer_type_t transfer_type)
+{
+	usb_hc_endpoint_info_t *ep = malloc(sizeof(usb_hc_endpoint_info_t));
+	ep->data_toggle = 0;
+	ep->direction = direction;
+	ep->transfer_type = transfer_type;
+	ep->endpoint = endpoint;
+
+	return ep;
+}
+
+
+
+/** Callback for OUT transfers.
+ * This callback is called by implementation of HC operations.
+ *
+ * @param hc Host controller that processed the transfer.
+ * @param outcome Transfer outcome.
+ * @param arg Custom argument.
+ */
+static void remote_out_callback(usb_hc_device_t *hc,
+    usb_transaction_outcome_t outcome, void *arg)
+{
+	transfer_info_t *transfer = (transfer_info_t *) arg;
+	transfer->out_callback(hc->generic, outcome, transfer->arg);
+
+	transfer_info_destroy(transfer);
+}
+
+/** Start an OUT transfer.
+ *
+ * @param dev Device that shall process the transfer.
+ * @param target Target device for the data.
+ * @param transfer_type Transfer type.
+ * @param data Data buffer.
+ * @param size Size of data buffer.
+ * @param callback Callback after transfer is complete.
+ * @param arg Custom argument to the callback.
+ * @return Error code.
+ */
+static int remote_out_transfer(device_t *dev, usb_target_t target,
+    usb_transfer_type_t transfer_type, void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_hc_device_t *hc = (usb_hc_device_t *) dev->driver_data;
+
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_out == NULL)) {
+		return ENOTSUP;
+	}
+
+	transfer_info_t *transfer = transfer_info_create(
+	    create_attached_device_info(target.address),
+	    create_endpoint_info(target.endpoint,
+		USB_DIRECTION_OUT, transfer_type),
+	    arg);
+	transfer->out_callback = callback;
+
+	int rc = hc->transfer_ops->transfer_out(hc,
+	    transfer->device, transfer->endpoint,
+	    data, size,
+	    remote_out_callback, transfer);
+
+	if (rc != EOK) {
+		transfer_info_destroy(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Start a SETUP transfer.
+ *
+ * @param dev Device that shall process the transfer.
+ * @param target Target device for the data.
+ * @param transfer_type Transfer type.
+ * @param data Data buffer.
+ * @param size Size of data buffer.
+ * @param callback Callback after transfer is complete.
+ * @param arg Custom argument to the callback.
+ * @return Error code.
+ */
+static int remote_setup_transfer(device_t *dev, usb_target_t target,
+    usb_transfer_type_t transfer_type, void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_hc_device_t *hc = (usb_hc_device_t *) dev->driver_data;
+
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_setup == NULL)) {
+		return ENOTSUP;
+	}
+
+	transfer_info_t *transfer = transfer_info_create(
+	    create_attached_device_info(target.address),
+	    create_endpoint_info(target.endpoint,
+		USB_DIRECTION_OUT, transfer_type),
+	    arg);
+	transfer->out_callback = callback;
+
+	int rc = hc->transfer_ops->transfer_setup(hc,
+	    transfer->device, transfer->endpoint,
+	    data, size,
+	    remote_out_callback, transfer);
+
+	if (rc != EOK) {
+		transfer_info_destroy(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Callback for IN transfers.
+ * This callback is called by implementation of HC operations.
+ *
+ * @param hc Host controller that processed the transfer.
+ * @param outcome Transfer outcome.
+ * @param actual_size Size of actually received data.
+ * @param arg Custom argument.
+ */
+static void remote_in_callback(usb_hc_device_t *hc,
+    size_t actual_size, usb_transaction_outcome_t outcome, void *arg)
+{
+	transfer_info_t *transfer = (transfer_info_t *) arg;
+	transfer->in_callback(hc->generic, outcome, actual_size, transfer->arg);
+
+	transfer_info_destroy(transfer);
+}
+
+/** Start an IN transfer.
+ *
+ * @param dev Device that shall process the transfer.
+ * @param target Target device for the data.
+ * @param transfer_type Transfer type.
+ * @param data Data buffer.
+ * @param size Size of data buffer.
+ * @param callback Callback after transfer is complete.
+ * @param arg Custom argument to the callback.
+ * @return Error code.
+ */
+static int remote_in_transfer(device_t *dev, usb_target_t target,
+    usb_transfer_type_t transfer_type, void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_hc_device_t *hc = (usb_hc_device_t *) dev->driver_data;
+
+	if ((hc->transfer_ops == NULL)
+	    || (hc->transfer_ops->transfer_in == NULL)) {
+		return ENOTSUP;
+	}
+
+	transfer_info_t *transfer = transfer_info_create(
+	    create_attached_device_info(target.address),
+	    create_endpoint_info(target.endpoint,
+		USB_DIRECTION_OUT, transfer_type),
+	    arg);
+	transfer->in_callback = callback;
+
+	int rc = hc->transfer_ops->transfer_in(hc,
+	    transfer->device, transfer->endpoint,
+	    data, size,
+	    remote_in_callback, transfer);
+
+	if (rc != EOK) {
+		transfer_info_destroy(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Start outgoing interrupt transfer (USBHC remote interface).
+ *
+ * @param dev Host controller device processing the transfer.
+ * @param target Target USB device.
+ * @param buffer Data buffer.
+ * @param size Data buffer size.
+ * @param callback Callback after the transfer is completed.
+ * @param arg Custom argument to the callback.
+ * @return Error code.
+ */
+int remote_interrupt_out(device_t *dev, usb_target_t target,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return remote_out_transfer(dev, target, USB_TRANSFER_INTERRUPT,
+	    buffer, size, callback, arg);
+}
+
+/** Start incoming interrupt transfer (USBHC remote interface).
+ *
+ * @param dev Host controller device processing the transfer.
+ * @param target Target USB device.
+ * @param buffer Data buffer.
+ * @param size Data buffer size.
+ * @param callback Callback after the transfer is completed.
+ * @param arg Custom argument to the callback.
+ * @return Error code.
+ */
+int remote_interrupt_in(device_t *dev, usb_target_t target,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return remote_in_transfer(dev, target, USB_TRANSFER_INTERRUPT,
+	    buffer, size, callback, arg);
+}
+
+
+int remote_control_write_setup(device_t *device, usb_target_t target,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return remote_setup_transfer(device, target, USB_TRANSFER_CONTROL,
+	    buffer, size, callback, arg);
+}
+
+int remote_control_write_data(device_t *device, usb_target_t target,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return remote_out_transfer(device, target, USB_TRANSFER_CONTROL,
+	    buffer, size, callback, arg);
+}
+
+int remote_control_write_status(device_t *device, usb_target_t target,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return remote_in_transfer(device, target, USB_TRANSFER_CONTROL,
+	    NULL, 0, callback, arg);
+}
+
+int remote_control_read_setup(device_t *device, usb_target_t target,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return remote_setup_transfer(device, target, USB_TRANSFER_CONTROL,
+	    buffer, size, callback, arg);
+}
+
+int remote_control_read_data(device_t *dev, usb_target_t target,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return remote_in_transfer(dev, target, USB_TRANSFER_CONTROL,
+	    buffer, size, callback, arg);
+}
+
+int remote_control_read_status(device_t *device, usb_target_t target,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return remote_out_transfer(device, target, USB_TRANSFER_CONTROL,
+	    NULL, 0, callback, arg);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usb.c
===================================================================
--- uspace/lib/usb/src/usb.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/usb.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,74 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Base USB types.
+ */
+#include <usb/usb.h>
+#include <errno.h>
+
+
+/** String representation for USB transfer type. */
+const char * usb_str_transfer_type(usb_transfer_type_t t)
+{
+	switch (t) {
+		case USB_TRANSFER_ISOCHRONOUS:
+			return "isochronous";
+		case USB_TRANSFER_INTERRUPT:
+			return "interrupt";
+		case USB_TRANSFER_CONTROL:
+			return "control";
+		case USB_TRANSFER_BULK:
+			return "bulk";
+		default:
+			return "unknown";
+	}
+}
+
+/** String representation of USB transaction outcome. */
+const char * usb_str_transaction_outcome(usb_transaction_outcome_t o)
+{
+	switch (o) {
+		case USB_OUTCOME_OK:
+			return "ok";
+		case USB_OUTCOME_CRCERROR:
+			return "CRC error";
+		case USB_OUTCOME_BABBLE:
+			return "babble";
+		default:
+			return "unknown";
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/usbdrv.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,490 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB driver (implementation).
+ */
+#include <usb/usbdrv.h>
+#include <usbhc_iface.h>
+#include <errno.h>
+#include <str_error.h>
+
+/** Information about pending transaction on HC. */
+typedef struct {
+	/** Phone to host controller driver. */
+	int phone;
+	/** Data buffer. */
+	void *buffer;
+	/** Buffer size. */
+	size_t size;
+	/** Storage for actual number of bytes transferred. */
+	size_t *size_transferred;
+	/** Initial call replay data. */
+	ipc_call_t reply;
+	/** Initial call identifier. */
+	aid_t request;
+} transfer_info_t;
+
+/** Connect to host controller the device is physically attached to.
+ *
+ * @param dev Device asking for connection.
+ * @param flags Connection flags (blocking connection).
+ * @return Phone to corresponding HC or error code.
+ */
+int usb_drv_hc_connect(device_t *dev, unsigned int flags)
+{
+	/*
+	 * Call parent hub to obtain device handle of respective HC.
+	 */
+
+	/*
+	 * FIXME: currently we connect always to virtual host controller.
+	 */
+	int rc;
+	devman_handle_t handle;
+
+	rc = devman_device_get_handle("/virt/usbhc", &handle, flags);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	int phone = devman_device_connect(handle, flags);
+
+	return phone;
+}
+
+/** Tell USB address assigned to given device.
+ *
+ * @param phone Phone to my HC.
+ * @param dev Device in question.
+ * @return USB address or error code.
+ */
+usb_address_t usb_drv_get_my_address(int phone, device_t *dev)
+{
+	sysarg_t address;
+	int rc = async_req_2_1(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_GET_ADDRESS,
+	    dev->handle, &address);
+
+	if (rc != EOK) {
+		printf("usb_drv_get_my_address over %d failed: %s\n", phone, str_error(rc));
+		return rc;
+	}
+
+	return (usb_address_t) address;
+}
+
+/** Tell HC to reserve default address.
+ *
+ * @param phone Open phone to host controller driver.
+ * @return Error code.
+ */
+int usb_drv_reserve_default_address(int phone)
+{
+	return async_req_1_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS);
+}
+
+/** Tell HC to release default address.
+ *
+ * @param phone Open phone to host controller driver.
+ * @return Error code.
+ */
+int usb_drv_release_default_address(int phone)
+{
+	return async_req_1_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
+}
+
+/** Ask HC for free address assignment.
+ *
+ * @param phone Open phone to host controller driver.
+ * @return Assigned USB address or negative error code.
+ */
+usb_address_t usb_drv_request_address(int phone)
+{
+	sysarg_t address;
+	int rc = async_req_1_1(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REQUEST_ADDRESS, &address);
+	if (rc != EOK) {
+		return rc;
+	} else {
+		return (usb_address_t) address;
+	}
+}
+
+/** Inform HC about binding address with devman handle.
+ *
+ * @param phone Open phone to host controller driver.
+ * @param address Address to be binded.
+ * @param handle Devman handle of the device.
+ * @return Error code.
+ */
+int usb_drv_bind_address(int phone, usb_address_t address,
+    devman_handle_t handle)
+{
+	int rc = async_req_3_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_BIND_ADDRESS,
+	    address, handle);
+
+	return rc;
+}
+
+/** Inform HC about address release.
+ *
+ * @param phone Open phone to host controller driver.
+ * @param address Address to be released.
+ * @return Error code.
+ */
+int usb_drv_release_address(int phone, usb_address_t address)
+{
+	return async_req_2_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_ADDRESS, address);
+}
+
+/** Send data to HCD.
+ *
+ * @param phone Phone to HC.
+ * @param method Method used for calling.
+ * @param target Targeted device.
+ * @param buffer Data buffer (NULL to skip data transfer phase).
+ * @param size Buffer size (must be zero when @p buffer is NULL).
+ * @param handle Storage for transaction handle (cannot be NULL).
+ * @return Error status.
+ * @retval EINVAL Invalid parameter.
+ * @retval ENOMEM Not enough memory to complete the operation.
+ */
+static int async_send_buffer(int phone, int method,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+
+	if ((buffer == NULL) && (size > 0)) {
+		return EINVAL;
+	}
+
+	if (handle == NULL) {
+		return EINVAL;
+	}
+
+	transfer_info_t *transfer
+	    = (transfer_info_t *) malloc(sizeof(transfer_info_t));
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->size_transferred = NULL;
+	transfer->buffer = NULL;
+	transfer->size = 0;
+	transfer->phone = phone;
+
+	int rc;
+
+	transfer->request = async_send_4(phone,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    method,
+	    target.address, target.endpoint,
+	    size,
+	    &transfer->reply);
+
+	if (size > 0) {
+		rc = async_data_write_start(phone, buffer, size);
+		if (rc != EOK) {
+			async_wait_for(transfer->request, NULL);
+			return rc;
+		}
+	}
+
+	*handle = (usb_handle_t) transfer;
+
+	return EOK;
+}
+
+/** Prepare data retrieval.
+ *
+ * @param phone Opened phone to HCD.
+ * @param method Method used for calling.
+ * @param target Targeted device.
+ * @param buffer Buffer where to store retrieved data
+ * 	(NULL to skip data transfer phase).
+ * @param size Buffer size (must be zero when @p buffer is NULL).
+ * @param actual_size Storage where actual number of bytes transferred will
+ * 	be stored.
+ * @param handle Storage for transaction handle (cannot be NULL).
+ * @return Error status.
+ * @retval EINVAL Invalid parameter.
+ * @retval ENOMEM Not enough memory to complete the operation.
+ */
+static int async_recv_buffer(int phone, int method,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+
+	if ((buffer == NULL) && (size > 0)) {
+		return EINVAL;
+	}
+
+	if (handle == NULL) {
+		return EINVAL;
+	}
+
+	transfer_info_t *transfer
+	    = (transfer_info_t *) malloc(sizeof(transfer_info_t));
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->size_transferred = actual_size;
+	transfer->buffer = buffer;
+	transfer->size = size;
+	transfer->phone = phone;
+
+	transfer->request = async_send_4(phone,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    method,
+	    target.address, target.endpoint,
+	    size,
+	    &transfer->reply);
+
+	*handle = (usb_handle_t) transfer;
+
+	return EOK;
+}
+
+/** Read buffer from HCD.
+ *
+ * @param phone Opened phone to HCD.
+ * @param hash Buffer hash (obtained after completing IN transaction).
+ * @param buffer Buffer where to store data data.
+ * @param size Buffer size.
+ * @param actual_size Storage where actual number of bytes transferred will
+ * 	be stored.
+ * @return Error status.
+ */
+static int read_buffer_in(int phone, sysarg_t hash,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	ipc_call_t answer_data;
+	sysarg_t answer_rc;
+	aid_t req;
+	int rc;
+
+	req = async_send_2(phone,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_GET_BUFFER,
+	    hash,
+	    &answer_data);
+
+	rc = async_data_read_start(phone, buffer, size);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return EINVAL;
+	}
+
+	async_wait_for(req, &answer_rc);
+	rc = (int)answer_rc;
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	*actual_size = IPC_GET_ARG1(answer_data);
+
+	return EOK;
+}
+
+/** Blocks caller until given USB transaction is finished.
+ * After the transaction is finished, the user can access all output data
+ * given to initial call function.
+ *
+ * @param handle Transaction handle.
+ * @return Error status.
+ * @retval EOK No error.
+ * @retval EBADMEM Invalid handle.
+ * @retval ENOENT Data buffer associated with transaction does not exist.
+ */
+int usb_drv_async_wait_for(usb_handle_t handle)
+{
+	if (handle == 0) {
+		return EBADMEM;
+	}
+
+	int rc = EOK;
+
+	transfer_info_t *transfer = (transfer_info_t *) handle;
+
+	sysarg_t answer_rc;
+	async_wait_for(transfer->request, &answer_rc);
+
+	if (answer_rc != EOK) {
+		rc = (int) answer_rc;
+		goto leave;
+	}
+
+	/*
+	 * If the buffer is not NULL, we must accept some data.
+	 */
+	if ((transfer->buffer != NULL) && (transfer->size > 0)) {
+		/*
+		 * The buffer hash identifies the data on the server
+		 * side.
+		 * We will use it when actually reading-in the data.
+		 */
+		sysarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
+		if (buffer_hash == 0) {
+			rc = ENOENT;
+			goto leave;
+		}
+
+		size_t actual_size;
+		rc = read_buffer_in(transfer->phone, buffer_hash,
+		    transfer->buffer, transfer->size, &actual_size);
+
+		if (rc != EOK) {
+			goto leave;
+		}
+
+		if (transfer->size_transferred) {
+			*(transfer->size_transferred) = actual_size;
+		}
+	}
+
+leave:
+	free(transfer);
+
+	return rc;
+}
+
+/** Send interrupt data to device. */
+int usb_drv_async_interrupt_out(int phone, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(phone,
+	    IPC_M_USBHC_INTERRUPT_OUT,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Request interrupt data from device. */
+int usb_drv_async_interrupt_in(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(phone,
+	    IPC_M_USBHC_INTERRUPT_IN,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+/** Start control write transfer. */
+int usb_drv_async_control_write_setup(int phone, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(phone,
+	    IPC_M_USBHC_CONTROL_WRITE_SETUP,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Send data during control write transfer. */
+int usb_drv_async_control_write_data(int phone, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(phone,
+	    IPC_M_USBHC_CONTROL_WRITE_DATA,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Finalize control write transfer. */
+int usb_drv_async_control_write_status(int phone, usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(phone,
+	    IPC_M_USBHC_CONTROL_WRITE_STATUS,
+	    target,
+	    NULL, 0, NULL,
+	    handle);
+}
+
+/** Start control read transfer. */
+int usb_drv_async_control_read_setup(int phone, usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(phone,
+	    IPC_M_USBHC_CONTROL_READ_SETUP,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Read data during control read transfer. */
+int usb_drv_async_control_read_data(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(phone,
+	    IPC_M_USBHC_CONTROL_READ_DATA,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+/** Finalize control read transfer. */
+int usb_drv_async_control_read_status(int phone, usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(phone,
+	    IPC_M_USBHC_CONTROL_READ_STATUS,
+	    target,
+	    NULL, 0,
+	    handle);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/usbdrvreq.c
===================================================================
--- uspace/lib/usb/src/usbdrvreq.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usb/src/usbdrvreq.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,243 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief USB driver - standard USB requests (implementation).
+ */
+#include <usb/usbdrv.h>
+#include <errno.h>
+
+/** Change address of connected device.
+ *
+ * @see usb_drv_reserve_default_address
+ * @see usb_drv_release_default_address
+ * @see usb_drv_request_address
+ * @see usb_drv_release_address
+ * @see usb_drv_bind_address
+ *
+ * @param phone Open phone to HC driver.
+ * @param old_address Current address.
+ * @param address Address to be set.
+ * @return Error code.
+ */
+int usb_drv_req_set_address(int phone, usb_address_t old_address,
+    usb_address_t new_address)
+{
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = old_address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 0,
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.index = 0,
+		.length = 0,
+	};
+	setup_packet.value = new_address;
+
+	int rc = usb_drv_psync_control_write(phone, target,
+	    &setup_packet, sizeof(setup_packet), NULL, 0);
+
+	return rc;
+}
+
+/** Retrieve device descriptor of connected USB device.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[out] descriptor Storage for the device descriptor.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_device_descriptor(int phone, usb_address_t address,
+    usb_standard_device_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_device_descriptor_t)
+	};
+	setup_packet.value_high = USB_DESCTYPE_DEVICE;
+	setup_packet.value_low = 0;
+
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_device_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+
+/** Retrieve configuration descriptor of connected USB device.
+ *
+ * The function does not retrieve additional data binded with configuration
+ * descriptor (such as its interface and endpoint descriptors) - use
+ * usb_drv_req_get_full_configuration_descriptor() instead.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] index Configuration descriptor index.
+ * @param[out] descriptor Storage for the configuration descriptor.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_bare_configuration_descriptor(int phone,
+    usb_address_t address, int index,
+    usb_standard_configuration_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_configuration_descriptor_t)
+	};
+	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
+	setup_packet.value_low = index;
+
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_configuration_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+/** Retrieve full configuration descriptor of connected USB device.
+ *
+ * @warning The @p buffer might be touched (i.e. its contents changed)
+ * even when error occurres.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] index Configuration descriptor index.
+ * @param[out] buffer Buffer for the whole configuration descriptor.
+ * @param[in] buffer_size Size of the prepared @p buffer.
+ * @param[out] actual_buffer_size Bytes actually transfered.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_full_configuration_descriptor(int phone,
+    usb_address_t address, int index,
+    void *buffer, size_t buffer_size, size_t *actual_buffer_size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = buffer_size
+	};
+	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
+	setup_packet.value_low = index;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    buffer, buffer_size, actual_buffer_size);
+
+	return rc;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/Makefile	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusbvirt
+
+LIBS = $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -Iinclude
+
+SOURCES = \
+	src/callback.c \
+	src/ctrlpipe.c \
+	src/debug.c \
+	src/main.c \
+	src/stdreq.c \
+	src/transaction.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,285 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB device.
+ */
+#ifndef LIBUSBVIRT_DEVICE_H_
+#define LIBUSBVIRT_DEVICE_H_
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/devreq.h>
+
+/** Request type of a control transfer. */
+typedef enum {
+	/** Standard USB request. */
+	USBVIRT_REQUEST_TYPE_STANDARD = 0,
+	/** Standard class USB request. */
+	USBVIRT_REQUEST_TYPE_CLASS = 1
+} usbvirt_request_type_t;
+
+/** Recipient of control request. */
+typedef enum {
+	/** Device is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_DEVICE = 0,
+	/** Interface is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_INTERFACE = 1,
+	/** Endpoint is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_ENDPOINT = 2,
+	/** Other part of the device is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_OTHER = 3
+} usbvirt_request_recipient_t;
+
+/** Possible states of virtual USB device.
+ * Notice that these are not 1:1 mappings to those in USB specification.
+ */
+typedef enum {
+	/** Default state, device listens at default address. */
+	USBVIRT_STATE_DEFAULT,
+	/** Device has non-default address assigned. */
+	USBVIRT_STATE_ADDRESS,
+	/** Device is configured. */
+	USBVIRT_STATE_CONFIGURED
+} usbvirt_device_state_t;
+
+typedef struct usbvirt_device usbvirt_device_t;
+struct usbvirt_control_transfer;
+
+typedef int (*usbvirt_on_device_request_t)(usbvirt_device_t *dev,
+	usb_device_request_setup_packet_t *request,
+	uint8_t *data);
+
+/** Callback for control request over pipe zero.
+ *
+ * @param dev Virtual device answering the call.
+ * @param request Request setup packet.
+ * @param data Data when DATA stage is present.
+ * @return Error code.
+ */
+typedef int (*usbvirt_control_request_callback_t)(usbvirt_device_t *dev,
+	usb_device_request_setup_packet_t *request,
+	uint8_t *data);
+
+/** Handler for control transfer on endpoint zero. */
+typedef struct {
+	/** Request type bitmap.
+	 * Use USBVIRT_MAKE_CONTROL_REQUEST_TYPE for creating the bitmap.
+	 */
+	uint8_t request_type;
+	/** Request code. */
+	uint8_t request;
+	/** Request name for debugging. */
+	const char *name;
+	/** Callback for the request.
+	 * NULL value here announces end of a list.
+	 */
+	usbvirt_control_request_callback_t callback;
+} usbvirt_control_transfer_handler_t;
+
+/** Create control request type bitmap.
+ *
+ * @param direction Transfer direction (use usb_direction_t).
+ * @param type Request type (use usbvirt_request_type_t).
+ * @param recipient Recipient of the request (use usbvirt_request_recipient_t).
+ * @return Request type bitmap.
+ */
+#define USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, type, recipient) \
+	((((direction) == USB_DIRECTION_IN) ? 1 : 0) << 7) \
+	| (((type) & 3) << 5) \
+	| (((recipient) & 31))
+
+/** Create last item in an array of control request handlers. */
+#define USBVIRT_CONTROL_TRANSFER_HANDLER_LAST { 0, 0, NULL, NULL }
+
+/** Device operations. */
+typedef struct {
+	/** Callbacks for transfers over control pipe zero. */
+	usbvirt_control_transfer_handler_t *control_transfer_handlers;
+
+	int (*on_control_transfer)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, struct usbvirt_control_transfer *transfer);
+	
+	/** Callback for all other incoming data. */
+	int (*on_data)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	
+	/** Callback for host request for data. */
+	int (*on_data_request)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *actual_size);
+	
+	/** Decides direction of control transfer. */
+	usb_direction_t (*decide_control_transfer_direction)(
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+	/** Callback when device changes its state.
+	 *
+	 * It is correct that this function is called when both states
+	 * are equal (e.g. this function is called during SET_CONFIGURATION
+	 * request done on already configured device).
+	 *
+	 * @warning The value of <code>dev->state</code> before calling
+	 * this function is not specified (i.e. can be @p old_state or
+	 * @p new_state).
+	 */
+	void (*on_state_change)(usbvirt_device_t *dev,
+	    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state);
+} usbvirt_device_ops_t;
+
+/** Extra configuration data for GET_CONFIGURATION request. */
+typedef struct {
+	/** Actual data. */
+	uint8_t *data;
+	/** Data length. */
+	size_t length;
+} usbvirt_device_configuration_extras_t;
+
+/** Single device configuration. */
+typedef struct {
+	/** Standard configuration descriptor. */
+	usb_standard_configuration_descriptor_t *descriptor;
+	/** Array of extra data. */
+	usbvirt_device_configuration_extras_t *extra;
+	/** Length of @c extra array. */
+	size_t extra_count;
+} usbvirt_device_configuration_t;
+
+/** Standard USB descriptors. */
+typedef struct {
+	/** Standard device descriptor.
+	 * There is always only one such descriptor for the device.
+	 */
+	usb_standard_device_descriptor_t *device;
+	
+	/** Configurations. */
+	usbvirt_device_configuration_t *configuration;
+	/** Number of configurations. */
+	size_t configuration_count;
+	/** Index of currently selected configuration. */
+	uint8_t current_configuration;
+} usbvirt_descriptors_t;
+
+/** Information about on-going control transfer.
+ */
+typedef struct usbvirt_control_transfer {
+	/** Transfer direction (read/write control transfer). */
+	usb_direction_t direction;
+	/** Request data. */
+	void *request;
+	/** Size of request data. */
+	size_t request_size;
+	/** Payload. */
+	void *data;
+	/** Size of payload. */
+	size_t data_size;
+} usbvirt_control_transfer_t;
+
+typedef enum {
+	USBVIRT_DEBUGTAG_BASE = 1,
+	USBVIRT_DEBUGTAG_TRANSACTION = 2,
+	USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO = 4,
+	USBVIRT_DEBUGTAG_ALL = 255
+} usbvirt_debug_tags_t;
+
+/** Virtual USB device. */
+struct usbvirt_device {
+	/** Callback device operations. */
+	usbvirt_device_ops_t *ops;
+	
+	/** Custom device data. */
+	void *device_data;
+
+	/** Reply onto control transfer.
+	 */
+	int (*control_transfer_reply)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	
+	/** Device name.
+	 * Used in debug prints and sent to virtual host controller.
+	 */
+	const char *name;
+	
+	/** Standard descriptors. */
+	usbvirt_descriptors_t *descriptors;
+	
+	/** Current device state. */
+	usbvirt_device_state_t state;
+	
+	/** Device address. */
+	usb_address_t address;
+	/** New device address.
+	 * This field is used during SET_ADDRESS request.
+	 * On all other occasions, it holds invalid address (e.g. -1).
+	 */
+	usb_address_t new_address;
+	
+	/** Process OUT transaction. */
+	int (*transaction_out)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	/** Process SETUP transaction. */
+	int (*transaction_setup)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	/** Process IN transaction. */
+	int (*transaction_in)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *data_size);
+	
+	/** State information on control-transfer endpoints. */
+	usbvirt_control_transfer_t current_control_transfers[USB11_ENDPOINT_MAX];
+	
+	/* User debugging. */
+	
+	/** Debug print. */
+	void (*debug)(usbvirt_device_t *dev, int level, uint8_t tag,
+	    const char *format, ...);
+	
+	/** Current debug level. */
+	int debug_level;
+	
+	/** Bitmap of currently enabled tags. */
+	uint8_t debug_enabled_tags;
+	
+	/* Library debugging. */
+	
+	/** Debug print. */
+	void (*lib_debug)(usbvirt_device_t *dev, int level, uint8_t tag,
+	    const char *format, ...);
+	
+	/** Current debug level. */
+	int lib_debug_level;
+	
+	/** Bitmap of currently enabled tags. */
+	uint8_t lib_debug_enabled_tags;
+};
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/include/usbvirt/hub.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/hub.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/include/usbvirt/hub.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,68 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB device.
+ */
+#ifndef LIBUSBVIRT_HUB_H_
+#define LIBUSBVIRT_HUB_H_
+
+#include "device.h"
+
+/** USB transaction type.
+ * This types does not correspond directly to types in USB specification,
+ * as actually DATA transactions are marked with these types to identify
+ * their direction (and tag).
+ */
+typedef enum {
+	USBVIRT_TRANSACTION_SETUP,
+	USBVIRT_TRANSACTION_IN,
+	USBVIRT_TRANSACTION_OUT
+} usbvirt_transaction_type_t;
+
+const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type);
+
+/** Telephony methods of virtual devices. */
+typedef enum {
+	IPC_M_USBVIRT_GET_NAME = IPC_FIRST_USER_METHOD,
+	IPC_M_USBVIRT_TRANSACTION_SETUP,
+	IPC_M_USBVIRT_TRANSACTION_OUT,
+	IPC_M_USBVIRT_TRANSACTION_IN,
+} usbvirt_device_method_t;
+
+int usbvirt_connect(usbvirt_device_t *);
+int usbvirt_connect_local(usbvirt_device_t *);
+int usbvirt_disconnect(usbvirt_device_t *dev);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/callback.c
===================================================================
--- uspace/lib/usbvirt/src/callback.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/callback.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,234 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Callback connection handling.
+ */
+#include <devmap.h>
+#include <fcntl.h>
+#include <vfs/vfs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+
+#include "private.h"
+
+#define NAMESPACE "usb"
+#define USB_MAX_PAYLOAD_SIZE 1020
+
+/** Wrapper for SETUP transaction over telephone. */
+static void handle_setup_transaction(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	if (expected_len == 0) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	size_t len = 0;
+	void * buffer = NULL;
+	int rc = async_data_write_accept(&buffer, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
+		
+	if (rc != EOK) {
+		ipc_answer_0(iid, rc);
+		return;
+	}
+	
+	rc = device->transaction_setup(device, endpoint, buffer, len);
+	
+	ipc_answer_0(iid, rc);
+}
+
+/** Wrapper for OUT transaction over telephone. */
+static void handle_out_transaction(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	int rc = EOK;
+	
+	size_t len = 0;
+	void *buffer = NULL;
+	
+	if (expected_len > 0) {
+		rc = async_data_write_accept(&buffer, false,
+		    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
+			
+		if (rc != EOK) {
+			ipc_answer_0(iid, rc);
+			return;
+		}
+	}
+	
+	rc = device->transaction_out(device, endpoint, buffer, len);
+	
+	if (buffer != NULL) {
+		free(buffer);
+	}
+	
+	ipc_answer_0(iid, rc);
+}
+
+
+/** Wrapper for IN transaction over telephone. */
+static void handle_in_transaction(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	int rc = EOK;
+	
+	void *buffer = expected_len > 0 ? malloc(expected_len) : NULL;
+	size_t len;
+	
+	rc = device->transaction_in(device, endpoint, buffer, expected_len, &len);
+	/*
+	 * If the request was processed, we will send data back.
+	 */
+	if ((rc == EOK) && (expected_len > 0)) {
+		size_t receive_len;
+		ipc_callid_t callid;
+		if (!async_data_read_receive(&callid, &receive_len)) {
+			ipc_answer_0(iid, EINVAL);
+			return;
+		}
+		async_data_read_finalize(callid, buffer, receive_len);
+	}
+	
+	ipc_answer_0(iid, rc);
+}
+
+/** Wrapper for getting device name. */
+static void handle_get_name(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	if (device->name == NULL) {
+		ipc_answer_0(iid, ENOENT);
+	}
+	
+	size_t size = str_size(device->name);
+	
+	ipc_callid_t callid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&callid, &accepted_size)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	if (accepted_size > size) {
+		accepted_size = size;
+	}
+	async_data_read_finalize(callid, device->name, accepted_size);
+	
+	ipc_answer_1(iid, EOK, accepted_size);
+}
+
+/** Callback connection for a given device. */
+void device_callback_connection(usbvirt_device_t *device, ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_answer_0(iid, EOK);
+	
+	while (true) {
+		ipc_callid_t callid; 
+		ipc_call_t call; 
+		
+		callid = async_get_call(&call);
+		switch (IPC_GET_IMETHOD(call)) {
+			case IPC_M_PHONE_HUNGUP:
+				ipc_answer_0(callid, EOK);
+				return;
+			
+			case IPC_M_USBVIRT_GET_NAME:
+				handle_get_name(device, callid, call);
+				break;
+			
+			case IPC_M_USBVIRT_TRANSACTION_SETUP:
+				handle_setup_transaction(device, callid, call);
+				break;
+			
+			case IPC_M_USBVIRT_TRANSACTION_OUT:
+				handle_out_transaction(device, callid, call);
+				break;
+				
+			case IPC_M_USBVIRT_TRANSACTION_IN:
+				handle_in_transaction(device, callid, call);
+				break;
+			
+			default:
+				ipc_answer_0(callid, EINVAL);
+				break;
+		}
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/src/ctrlpipe.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/ctrlpipe.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,182 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Device control pipe.
+ */
+#include <errno.h>
+
+#include "private.h"
+
+/** Compares handler type with request packet type.
+ *
+ * @param handler Handler.
+ * @param request_packet Request packet.
+ * @return Whether handler can serve this packet.
+ */
+static bool is_suitable_handler(usbvirt_control_transfer_handler_t *handler,
+    usb_device_request_setup_packet_t *request_packet)
+{
+	return (
+	    (handler->request_type == request_packet->request_type)
+	    && (handler->request == request_packet->request));
+
+}
+
+/** Find suitable transfer handler for given request packet.
+ *
+ * @param handlers Array of available handlers.
+ * @param request_packet Request SETUP packet.
+ * @return Handler or NULL.
+ */
+static usbvirt_control_transfer_handler_t *find_handler(
+    usbvirt_control_transfer_handler_t *handlers,
+    usb_device_request_setup_packet_t *request_packet)
+{
+	if (handlers == NULL) {
+		return NULL;
+	}
+
+	while (handlers->callback != NULL) {
+		if (is_suitable_handler(handlers, request_packet)) {
+			return handlers;
+		}
+		handlers++;
+	}
+
+	return NULL;
+}
+
+#define _GET_BIT(byte, bit) \
+	(((byte) & (1 << (bit))) ? '1' : '0')
+#define _GET_BITS(byte) \
+	_GET_BIT(byte, 7), _GET_BIT(byte, 6), _GET_BIT(byte, 5), \
+	_GET_BIT(byte, 4), _GET_BIT(byte, 3), _GET_BIT(byte, 2), \
+	_GET_BIT(byte, 1), _GET_BIT(byte, 0)
+
+static int find_and_run_handler(usbvirt_device_t *device,
+    usbvirt_control_transfer_handler_t *handlers,
+    usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data)
+{
+	int rc = EFORWARD;
+	usbvirt_control_transfer_handler_t *suitable_handler
+	    = find_handler(handlers, setup_packet);
+	if (suitable_handler != NULL) {
+		const char *callback_name = "user handler";
+		if (suitable_handler->name != NULL) {
+			callback_name = suitable_handler->name;
+		}
+		device->lib_debug(device, 1, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+		    "pipe #0 - calling %s " \
+		        "[%c.%c%c.%c%c%c%c%c, R%d, V%d, I%d, L%d]",
+		    callback_name,
+		    _GET_BITS(setup_packet->request_type),
+		    setup_packet->request, setup_packet->value,
+		    setup_packet->index, setup_packet->length);
+		rc = suitable_handler->callback(device, setup_packet, data);
+	}
+
+	return rc;
+}
+#undef _GET_BITS
+#undef _GET_BIT
+
+
+/** Handle communication over control pipe zero.
+ */
+int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer)
+{
+	device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+	    "op on control pipe zero (request_size=%u)", transfer->request_size);
+	
+	if (transfer->request_size < sizeof(usb_device_request_setup_packet_t)) {
+		return ENOMEM;
+	}
+	
+	usb_device_request_setup_packet_t *request
+	    = (usb_device_request_setup_packet_t *) transfer->request;
+
+	/*
+	 * First, see whether user provided its own callback.
+	 */
+	int rc = EFORWARD;
+	if (device->ops) {
+		rc = find_and_run_handler(device,
+		    device->ops->control_transfer_handlers,
+		    request, transfer->data);
+	}
+
+	/*
+	 * If there was no user callback or the callback returned EFORWARD,
+	 * we need to run a local handler.
+	 */
+	if (rc == EFORWARD) {
+		rc = find_and_run_handler(device,
+		    control_pipe_zero_local_handlers,
+		    request, transfer->data);
+	}
+	
+	/*
+	 * Check for SET_ADDRESS finalization.
+	 */
+	if (device->new_address != -1) {
+		/*
+		 * TODO: handle when this request is invalid (e.g.
+		 * setting address when in configured state).
+		 */
+		usbvirt_device_state_t new_state;
+		if (device->new_address == 0) {
+			new_state = USBVIRT_STATE_DEFAULT;
+		} else {
+			new_state = USBVIRT_STATE_ADDRESS;
+		}
+		device->address = device->new_address;
+		
+		device->new_address = -1;
+		
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    new_state);
+		}
+		device->state = new_state;
+
+		device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+		    "device address changed to %d (state %s)",
+		    device->address, str_device_state(device->state));
+	}
+	
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/debug.c
===================================================================
--- uspace/lib/usbvirt/src/debug.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/debug.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,103 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Debugging support.
+ */
+#include <stdio.h>
+#include <bool.h>
+
+#include "private.h"
+
+
+static void debug_print(int level, uint8_t tag,
+    int current_level, uint8_t enabled_tags,
+    const char *format, va_list args)
+{
+	if (level > current_level) {
+		return;
+	}
+	
+	if ((tag & enabled_tags) == 0) {
+		return;
+	}
+	
+	bool print_prefix = true;
+	
+	if ((format[0] == '%') && (format[1] == 'M')) {
+		format += 2;
+		print_prefix = false;
+	}
+	
+	if (print_prefix) {
+		printf("[vusb]: ");
+		while (--level > 0) {
+			printf(" ");
+		}
+	}
+	
+	vprintf(format, args);
+	
+	if (print_prefix) {
+		printf("\n");
+	}
+}
+
+
+void user_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	
+	debug_print(level, tag,
+	    device->debug_level, device->debug_enabled_tags,
+	    format, args);
+	
+	va_end(args);
+}
+
+void lib_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	
+	debug_print(level, tag,
+	    device->lib_debug_level, device->lib_debug_enabled_tags,
+	    format, args);
+	
+	va_end(args);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/main.c
===================================================================
--- uspace/lib/usbvirt/src/main.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/main.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,287 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Device registration with virtual USB framework.
+ */
+#include <devman.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <assert.h>
+
+#include "private.h"
+
+#define NAMESPACE "usb"
+
+/** Virtual device wrapper. */
+typedef struct {
+	/** Actual device. */
+	usbvirt_device_t *device;
+	/** Phone to host controller. */
+	int vhcd_phone;
+	/** Device id. */
+	sysarg_t id;
+	/** Linked-list member. */
+	link_t link;
+} virtual_device_t;
+
+/*** List of known device. */
+static LIST_INITIALIZE(device_list);
+
+/** Find virtual device wrapper based on the contents. */
+static virtual_device_t *find_device(usbvirt_device_t *device)
+{
+	if (list_empty(&device_list)) {
+		return NULL;
+	}
+	
+	link_t *pos;
+	for (pos = device_list.next; pos != &device_list; pos = pos->next) {
+		virtual_device_t *dev
+		    = list_get_instance(pos, virtual_device_t, link);
+		if (dev->device == device) {
+			return dev;
+		}
+	}
+	
+	return NULL;
+}
+
+/** Find virtual device wrapper by its id. */
+static virtual_device_t *find_device_by_id(sysarg_t id)
+{
+	if (list_empty(&device_list)) {
+		return NULL;
+	}
+	
+	link_t *pos;
+	for (pos = device_list.next; pos != &device_list; pos = pos->next) {
+		virtual_device_t *dev
+		    = list_get_instance(pos, virtual_device_t, link);
+		if (dev->id == id) {
+			return dev;
+		}
+	}
+	
+	return NULL;
+}
+
+/** Reply to a control transfer. */
+static int control_transfer_reply(usbvirt_device_t *device,
+	    usb_endpoint_t endpoint, void *buffer, size_t size)
+{
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->data != NULL) {
+		free(transfer->data);
+	}
+	transfer->data = malloc(size);
+	memcpy(transfer->data, buffer, size);
+	transfer->data_size = size;
+	
+	return EOK;
+}
+
+/** Initialize virtual device. */
+static void device_init(usbvirt_device_t *dev)
+{
+	dev->transaction_out = transaction_out;
+	dev->transaction_setup = transaction_setup;
+	dev->transaction_in = transaction_in;
+	
+	dev->control_transfer_reply = control_transfer_reply;
+	
+	dev->debug = user_debug;
+	dev->lib_debug = lib_debug;
+	
+	dev->state = USBVIRT_STATE_DEFAULT;
+	dev->address = 0;
+	dev->new_address = -1;
+	
+	size_t i;
+	for (i = 0; i < USB11_ENDPOINT_MAX; i++) {
+		usbvirt_control_transfer_t *transfer = &dev->current_control_transfers[i];
+		transfer->direction = 0;
+		transfer->request = NULL;
+		transfer->request_size = 0;
+		transfer->data = NULL;
+		transfer->data_size = 0;
+	}
+}
+
+/** Add a virtual device.
+ * The returned device (if not NULL) shall be destroy via destroy_device().
+ */
+static virtual_device_t *add_device(usbvirt_device_t *dev)
+{
+	assert(find_device(dev) == NULL);
+	virtual_device_t *new_device
+	    = (virtual_device_t *) malloc(sizeof(virtual_device_t));
+	
+	new_device->device = dev;
+	link_initialize(&new_device->link);
+	
+	list_append(&new_device->link, &device_list);
+	
+	return new_device;
+}
+
+/** Destroy virtual device. */
+static void destroy_device(virtual_device_t *dev)
+{
+	if (dev->vhcd_phone > 0) {
+		ipc_hangup(dev->vhcd_phone);
+	}
+	
+	list_remove(&dev->link);
+	
+	free(dev);
+}
+
+/** Callback connection handler. */
+static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	// FIXME - determine which device just called back
+	virtual_device_t *dev = find_device_by_id(0);
+	if (dev == NULL) {
+		ipc_answer_0(iid, EINVAL);
+		printf("Ooops\n");
+		return;
+	}
+
+	device_callback_connection(dev->device, iid, icall);
+}
+
+/** Create necessary phones for communication with virtual HCD.
+ * This function wraps following calls:
+ * -# open <code>/dev/devices/\\virt\\usbhc for reading
+ * -# access phone of file opened in previous step
+ * -# create callback through just opened phone
+ * -# create handler for calling on data from host to function
+ * -# return the (outgoing) phone
+ *
+ * @warning This function is wrapper for several actions and therefore
+ * it is not possible - in case of error - to determine at which point
+ * error occurred.
+ *
+ * @param dev Device to connect.
+ * @return EOK on success or error code from errno.h.
+ */
+int usbvirt_connect(usbvirt_device_t *dev)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device != NULL) {
+		return EEXISTS;
+	}
+	
+	const char *vhc_path = "/virt/usbhc";
+	int rc;
+	devman_handle_t handle;
+
+	rc = devman_device_get_handle(vhc_path, &handle, 0);
+	if (rc != EOK) {
+		printf("devman_device_get_handle() failed\n");
+		return rc;
+	}
+	
+	int hcd_phone = devman_device_connect(handle, 0);
+	
+	if (hcd_phone < 0) {
+		printf("devman_device_connect() failed\n");
+		return hcd_phone;
+	}
+	
+	sysarg_t phonehash;
+	rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
+	if (rc != EOK) {
+		printf("ipc_connect_to_me() failed\n");
+		return rc;
+	}
+	
+	device_init(dev);
+	
+	virtual_device = add_device(dev);
+	virtual_device->vhcd_phone = hcd_phone;
+	virtual_device->id = 0;
+	
+	async_new_connection(phonehash, 0, NULL, callback_connection);
+	
+	return EOK;
+}
+
+/** Prepares device as local.
+ * This is useful if you want to have a virtual device in the same task
+ * as HCD.
+ *
+ * @param dev Device to connect.
+ * @return Error code.
+ * @retval EOK Device connected.
+ * @retval EEXISTS This device is already connected.
+ */
+int usbvirt_connect_local(usbvirt_device_t *dev)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device != NULL) {
+		return EEXISTS;
+	}
+	
+	device_init(dev);
+	
+	virtual_device = add_device(dev);
+	virtual_device->vhcd_phone = -1;
+	virtual_device->id = 0;
+	
+	return EOK;
+}
+
+/** Disconnects device from HCD.
+ *
+ * @param dev Device to be disconnected.
+ * @return Error code.
+ * @retval EOK Device connected.
+ * @retval ENOENT This device is not connected.
+ */
+int usbvirt_disconnect(usbvirt_device_t *dev)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device == NULL) {
+		return ENOENT;
+	}
+	
+	destroy_device(virtual_device);
+	
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/private.h	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,94 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB private header.
+ */
+#ifndef LIBUSBVIRT_PRIVATE_H_
+#define LIBUSBVIRT_PRIVATE_H_
+
+#include <usbvirt/device.h>
+#include <usbvirt/hub.h>
+#include <assert.h>
+
+
+#define DEVICE_HAS_OP(dev, op) \
+	( \
+		(  ((dev)->ops) != NULL  ) \
+		&& \
+		(  ((dev)->ops->op) != NULL  ) \
+	)
+
+int usbvirt_data_to_host(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+int handle_incoming_data(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer);
+
+int handle_std_request(usbvirt_device_t *device, usb_device_request_setup_packet_t *request, uint8_t *data);
+
+void device_callback_connection(usbvirt_device_t *device, ipc_callid_t iid, ipc_call_t *icall);
+
+int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size);
+int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size);
+int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *data_size);
+
+
+void user_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...);
+void lib_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...);
+    
+static inline const char *str_device_state(usbvirt_device_state_t state)
+{
+	switch (state) {
+		case USBVIRT_STATE_DEFAULT:
+			return "default";
+		case USBVIRT_STATE_ADDRESS:
+			return "address";
+		case USBVIRT_STATE_CONFIGURED:
+			return "configured";
+		default:
+			return "unknown";
+	}
+}
+
+extern usbvirt_control_transfer_handler_t control_pipe_zero_local_handlers[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,214 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Preprocessing of standard device requests.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <usb/devreq.h>
+
+#include "private.h"
+
+/*
+ * All sub handlers must return EFORWARD to inform the caller that
+ * they were not able to process the request (yes, it is abuse of
+ * this error code but such error code shall not collide with anything
+ * else in this context).
+ */
+ 
+/** GET_DESCRIPTOR handler. */
+static int handle_get_descriptor(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
+{
+	uint8_t type = setup_packet->value_high;
+	uint8_t index = setup_packet->value_low;
+
+	/* 
+	 * Standard device descriptor.
+	 */
+	if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
+		if (device->descriptors && device->descriptors->device) {
+			return device->control_transfer_reply(device, 0,
+			    device->descriptors->device,
+			    device->descriptors->device->length);
+		} else {
+			return EFORWARD;
+		}
+	}
+	
+	/*
+	 * Configuration descriptor together with interface, endpoint and
+	 * class-specific descriptors.
+	 */
+	if (type == USB_DESCTYPE_CONFIGURATION) {
+		if (!device->descriptors) {
+			return EFORWARD;
+		}
+		if (index >= device->descriptors->configuration_count) {
+			return EFORWARD;
+		}
+		/* Copy the data. */
+		usbvirt_device_configuration_t *config = &device->descriptors
+		    ->configuration[index];
+		uint8_t *all_data = malloc(config->descriptor->total_length);
+		if (all_data == NULL) {
+			return ENOMEM;
+		}
+		
+		uint8_t *ptr = all_data;
+		memcpy(ptr, config->descriptor, config->descriptor->length);
+		ptr += config->descriptor->length;
+		size_t i;
+		for (i = 0; i < config->extra_count; i++) {
+			usbvirt_device_configuration_extras_t *extra
+			    = &config->extra[i];
+			memcpy(ptr, extra->data, extra->length);
+			ptr += extra->length;
+		}
+		
+		int rc = device->control_transfer_reply(device, 0,
+		    all_data, config->descriptor->total_length);
+		
+		free(all_data);
+		
+		return rc;
+	}
+	
+	return EFORWARD;
+}
+
+/** SET_ADDRESS handler. */
+static int handle_set_address(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
+{
+	uint16_t new_address = setup_packet->value;
+	uint16_t zero1 = setup_packet->index;
+	uint16_t zero2 = setup_packet->length;
+
+	if ((zero1 != 0) || (zero2 != 0)) {
+		return EINVAL;
+	}
+	
+	if (new_address > 127) {
+		return EINVAL;
+	}
+	
+	device->new_address = new_address;
+	
+	return EOK;
+}
+
+/** SET_CONFIGURATION handler. */
+static int handle_set_configuration(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
+{
+	uint16_t configuration_value = setup_packet->value;
+	uint16_t zero1 = setup_packet->index;
+	uint16_t zero2 = setup_packet->length;
+
+	if ((zero1 != 0) || (zero2 != 0)) {
+		return EINVAL;
+	}
+	
+	/*
+	 * Configuration value is 1 byte information.
+	 */
+	if (configuration_value > 255) {
+		return EINVAL;
+	}
+	
+	/*
+	 * Do nothing when in default state. According to specification,
+	 * this is not specified.
+	 */
+	if (device->state == USBVIRT_STATE_DEFAULT) {
+		return EOK;
+	}
+	
+	if (configuration_value == 0) {
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    USBVIRT_STATE_ADDRESS);
+		}
+		device->state = USBVIRT_STATE_ADDRESS;
+	} else {
+		/*
+		* TODO: browse provided configurations and verify that
+		* user selected existing configuration.
+		*/
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    USBVIRT_STATE_CONFIGURED);
+		}
+		device->state = USBVIRT_STATE_CONFIGURED;
+		if (device->descriptors) {
+			device->descriptors->current_configuration
+			    = configuration_value;
+		}
+	}
+		
+	return EOK;
+}
+
+
+#define MAKE_BM_REQUEST(direction, recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_STANDARD, recipient)
+#define MAKE_BM_REQUEST_DEV(direction) \
+	MAKE_BM_REQUEST(direction, USBVIRT_REQUEST_RECIPIENT_DEVICE)
+
+usbvirt_control_transfer_handler_t control_pipe_zero_local_handlers[] = {
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_IN),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "GetDescriptor()",
+		.callback = handle_get_descriptor
+	},
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_OUT),
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.name = "SetAddress()",
+		.callback = handle_set_address
+	},
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_OUT),
+		.request = USB_DEVREQ_SET_CONFIGURATION,
+		.name = "SetConfiguration()",
+		.callback = handle_set_configuration
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
+};
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/transaction.c
===================================================================
--- uspace/lib/usbvirt/src/transaction.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
+++ uspace/lib/usbvirt/src/transaction.c	(revision 467bf403640ee108a5beaa0da88dce261ba9fabf)
@@ -0,0 +1,268 @@
+/*
+ * 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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Transaction processing.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+
+#include "private.h"
+
+static usb_direction_t setup_transaction_direction(usbvirt_device_t *,
+    usb_endpoint_t, void *, size_t);
+static void process_control_transfer(usbvirt_device_t *,
+    usb_endpoint_t, usbvirt_control_transfer_t *);
+
+/** Convert virtual USB transaction type to string.
+ */
+const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type)
+{
+	switch (type) {
+		case USBVIRT_TRANSACTION_SETUP:
+			return "setup";
+		case USBVIRT_TRANSACTION_IN:
+			return "in";
+		case USBVIRT_TRANSACTION_OUT:
+			return "out";
+		default:
+			return "unknown";
+	}
+}
+
+/** SETUP transaction handling.
+ * The setup transaction only prepares control transfer on given endpoint.
+ */
+int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size)
+{
+	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+	    "setup transaction: endpoint=%d, size=%u", endpoint, size);
+	
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	
+	if (transfer->request != NULL) {
+		free(transfer->request);
+	}
+	if (transfer->data != NULL) {
+		free(transfer->data);
+	}
+	
+	transfer->direction = setup_transaction_direction(device, endpoint,
+	    buffer, size);
+	transfer->request = malloc(size);
+	memcpy(transfer->request, buffer, size);
+	transfer->request_size = size;
+	transfer->data = NULL;
+	transfer->data_size = 0;
+	
+	if (transfer->direction == USB_DIRECTION_IN) {
+		process_control_transfer(device, endpoint, transfer);
+	}
+	
+	return EOK;
+}
+
+/** OUT transaction handling.
+ * The OUT transaction can trigger processing of a control transfer.
+ */
+int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size)
+{
+	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+	    "out transaction: endpoint=%d, size=%u", endpoint, size);
+	
+	/*
+	 * First check whether it is a transaction over control pipe.
+	 */
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->request != NULL) {
+		if (transfer->direction == USB_DIRECTION_OUT) {
+			/*
+			 * For out transactions, append the data to the buffer.
+			 */
+			uint8_t *new_buffer = (uint8_t *) malloc(transfer->data_size + size);
+			if (transfer->data) {
+				memcpy(new_buffer, transfer->data, transfer->data_size);
+			}
+			memcpy(new_buffer + transfer->data_size, buffer, size);
+			
+			if (transfer->data) {
+				free(transfer->data);
+			}
+			transfer->data = new_buffer;
+			transfer->data_size += size;
+		} else {
+			/*
+			 * For in transactions, this means end of the
+			 * transaction.
+			 */
+			free(transfer->request);
+			if (transfer->data) {
+				free(transfer->data);
+			}
+			transfer->request = NULL;
+			transfer->request_size = 0;
+			transfer->data = NULL;
+			transfer->data_size = 0;
+		}
+		
+		return EOK;
+	}
+	
+	/*
+	 * Otherwise, announce that some data has come.
+	 */
+	if (device->ops && device->ops->on_data) {
+		return device->ops->on_data(device, endpoint, buffer, size);
+	} else {
+		return ENOTSUP;
+	}
+}
+
+/** IN transaction handling.
+ * The IN transaction can trigger processing of a control transfer.
+ */
+int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *data_size)
+{
+	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+	    "in transaction: endpoint=%d, size=%u", endpoint, size);
+	
+	/*
+	 * First check whether it is a transaction over control pipe.
+	 */
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->request != NULL) {
+		if (transfer->direction == USB_DIRECTION_OUT) {
+			/*
+			 * This means end of input data.
+			 */
+			process_control_transfer(device, endpoint, transfer);
+		} else {
+			/*
+			 * For in transactions, this means sending next part
+			 * of the buffer.
+			 */
+			// FIXME: handle when the HC wants the data back
+			// in more chunks
+			size_t actual_size = 0;
+			if (transfer->data) {
+				actual_size = transfer->data_size;
+			}
+			if (actual_size > size) {
+				actual_size = size;
+			}
+			device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+			    "in transaction: will copy %zu bytes", actual_size);
+			if (actual_size > 0) {
+				memcpy(buffer, transfer->data, actual_size);
+				if (data_size) {
+					*data_size = actual_size;
+				}
+			}
+		}
+		
+		return EOK;
+	}
+	
+	if (size == 0) {
+		return EINVAL;
+	}
+	
+	int rc = 1;
+	
+	if (device->ops && device->ops->on_data_request) {
+		rc = device->ops->on_data_request(device, endpoint, buffer, size, data_size);
+	}
+	
+	return rc;
+}
+
+/** Determine direction of control transfer.
+ * First, try the user provided callback, otherwise guess, believing that
+ * it uses the same format as control pipe 0.
+ */
+static usb_direction_t setup_transaction_direction(usbvirt_device_t *device,
+    usb_endpoint_t endpoint,
+    void *data, size_t size)
+{
+	int direction = -1;
+	if (device->ops && device->ops->decide_control_transfer_direction) {
+		direction = device->ops->decide_control_transfer_direction(endpoint,
+		    data, size);
+	}
+	
+	/*
+	 * If the user-supplied routine have not handled the direction
+	 * (or simply was not provided) we will guess, hoping that it 
+	 * uses same format as standard request on control pipe zero.
+	 */
+	if (direction < 0) {
+		if (size > 0) {
+			uint8_t *ptr = (uint8_t *) data;
+			if ((ptr[0] & 128) == 128) {
+				direction = USB_DIRECTION_IN;
+			} else {
+				direction = USB_DIRECTION_OUT;
+			}
+		} else {
+			/* This shall not happen anyway. */
+			direction = USB_DIRECTION_OUT;
+		}
+	}
+	
+	return (usb_direction_t) direction;
+}
+
+/** Process control transfer.
+ */
+static void process_control_transfer(usbvirt_device_t *device,
+    usb_endpoint_t endpoint,
+    usbvirt_control_transfer_t *transfer)
+{
+	int rc = EFORWARD;
+	
+	if (device->ops && device->ops->on_control_transfer) {
+		rc = device->ops->on_control_transfer(device, endpoint, transfer);
+	}
+	
+	if (rc == EFORWARD) {
+		if (endpoint == 0) {
+			rc = control_pipe(device, transfer);
+		}
+	}
+}
+
+/**
+ * @}
+ */
