Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 854bfa5d2185cdfd2a48821f92b573df304c7247)
+++ uspace/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -50,4 +50,6 @@
 	app/trace \
 	app/top \
+	app/usb \
+	app/virtusbkbd \
 	app/netstart \
 	app/netecho \
@@ -79,4 +81,5 @@
 	srv/hw/char/s3c24xx_uart \
 	srv/hw/netif/dp8390 \
+	srv/hw/bus/usb/hcd/virtual \
 	srv/net/cfg \
 	srv/net/netif/lo \
@@ -143,4 +146,14 @@
 	lib/net
 
+ifeq ($(UARCH),amd64)
+	LIBS += lib/usb
+	LIBS += lib/usbvirt
+endif
+
+ifeq ($(UARCH),ia32)
+	LIBS += lib/usb
+	LIBS += lib/usbvirt
+endif
+
 LIBC_BUILD = $(addsuffix .build,$(LIBC))
 LIBS_BUILD = $(addsuffix .build,$(LIBS))
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 854bfa5d2185cdfd2a48821f92b573df304c7247)
+++ uspace/Makefile.common	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -86,4 +86,7 @@
 LIBCLUI_PREFIX = $(LIB_PREFIX)/clui
 
+
+LIBUSB_PREFIX = $(LIB_PREFIX)/usb
+LIBUSBVIRT_PREFIX = $(LIB_PREFIX)/usbvirt
 LIBDRV_PREFIX = $(LIB_PREFIX)/drv
 LIBPACKET_PREFIX = $(LIB_PREFIX)/packet
Index: uspace/app/usb/Makefile
===================================================================
--- uspace/app/usb/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/usb/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,36 @@
+#
+# 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 = ../..
+BINARY = usb
+LIBS = $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS = -I$(LIB_PREFIX)
+SOURCES = \
+	example.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/usb/example.c
===================================================================
--- uspace/app/usb/example.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/usb/example.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,187 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief Simple application that connects to USB/HCD.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vfs/vfs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <async.h>
+
+#include <usb/hcd.h>
+#include <usb/devreq.h>
+
+#define LOOPS 5
+#define MAX_SIZE_RECEIVE 64
+#define NAME "hcd-example"
+
+#define DEV_HCD_NAME "hcd-virt"
+
+#define __QUOTEME(x) #x
+#define _QUOTEME(x) __QUOTEME(x)
+
+#define VERBOSE_EXEC(cmd, fmt, ...) \
+	(printf("%s: %s" fmt "\n", NAME, _QUOTEME(cmd), __VA_ARGS__), cmd(__VA_ARGS__))
+
+#define EXEC2(cmd, fmt, ...) \
+	do { \
+		printf("%s: " fmt " = ", NAME, __VA_ARGS__); \
+		fflush(stdout); \
+		int _rc = cmd; \
+		if (_rc != EOK) { \
+			printf("E%d\n", _rc); \
+			printf("%s: ... aborting.\n", NAME); \
+			exit(_rc); \
+		} \
+		printf("EOK\n"); \
+	} while (false)
+#define EXEC(cmd, fmt, ...) \
+	EXEC2(cmd(__VA_ARGS__), _QUOTEME(cmd) fmt, __VA_ARGS__)
+
+static void fibril_sleep(size_t sec)
+{
+	while (sec-- > 0) {
+		async_usleep(1000*1000);
+	}
+}
+
+static void data_dump(uint8_t *data, size_t len)
+{
+	size_t i;
+	for (i = 0; i < len; i++) {
+		printf("  0x%02X", data[i]);
+		if (((i > 0) && (((i+1) % 10) == 0))
+		    || (i + 1 == len)) {
+			printf("\n");
+		}
+	}
+}
+
+int main(int argc, char * argv[])
+{
+	int hcd_phone = usb_hcd_connect(DEV_HCD_NAME);
+	if (hcd_phone < 0) {
+		printf("%s: Unable to start comunication with HCD at usb://%s (%d: %s).\n",
+		    NAME, DEV_HCD_NAME, hcd_phone, str_error(hcd_phone));
+		return 1;
+	}
+	
+	printf("%s: example communication with HCD\n", NAME);
+	
+	usb_target_t target = {0, 0};
+	usb_handle_t handle;
+	
+	
+	
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 0,
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.index = 0,
+		.length = 0,
+	};
+	setup_packet.value = 5;
+	
+	printf("\n%s: === setting device address to %d ===\n", NAME,
+	    (int)setup_packet.value);
+	EXEC2(usb_hcd_async_transfer_control_write_setup(hcd_phone, target,
+	    &setup_packet, sizeof(setup_packet), &handle),
+	    "usb_hcd_async_transfer_control_write_setup(%d, {%d:%d}, &data, %u, &h)",
+	    hcd_phone, target.address, target.endpoint, sizeof(setup_packet));
+	    
+	EXEC(usb_hcd_async_wait_for, "(h=%x)", handle);
+	
+	EXEC2(usb_hcd_async_transfer_control_write_status(hcd_phone, target,
+	    &handle),
+	    "usb_hcd_async_transfer_control_write_status(%d, {%d:%d}, &h)",
+	    hcd_phone, target.address, target.endpoint);
+	
+	EXEC(usb_hcd_async_wait_for, "(h=%x)", handle);
+	
+	target.address = setup_packet.value;
+	
+	
+	printf("\n%s: === getting standard device descriptor ===\n", NAME);
+	usb_device_request_setup_packet_t get_descriptor = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = MAX_SIZE_RECEIVE,
+	};
+	get_descriptor.value_low = 0;
+	get_descriptor.value_high = 1;
+	
+	uint8_t descriptor[MAX_SIZE_RECEIVE];
+	size_t descriptor_length;
+	
+	EXEC2(usb_hcd_async_transfer_control_read_setup(hcd_phone, target,
+	    &get_descriptor, sizeof(get_descriptor), &handle),
+	    "usb_hcd_async_transfer_control_read_setup(%d, {%d:%d}, &data, %u, &h)",
+	    hcd_phone, target.address, target.endpoint, sizeof(get_descriptor));
+	
+	EXEC(usb_hcd_async_wait_for, "(h=%x)", handle);
+	
+	usb_handle_t data_handle;
+	EXEC2(usb_hcd_async_transfer_control_read_data(hcd_phone, target,
+	    descriptor, MAX_SIZE_RECEIVE, &descriptor_length, &data_handle),
+	    "usb_hcd_async_transfer_control_read_data(%d, {%d:%d}, &data, %u, &len, &h2)",
+	    hcd_phone, target.address, target.endpoint, MAX_SIZE_RECEIVE);
+	
+	EXEC2(usb_hcd_async_transfer_control_read_status(hcd_phone, target,
+	    &handle),
+	    "usb_hcd_async_transfer_control_read_status(%d, {%d:%d}, &h)",
+	    hcd_phone, target.address, target.endpoint);
+	
+	EXEC(usb_hcd_async_wait_for, "(h=%x)", handle);
+	EXEC(usb_hcd_async_wait_for, "(h2=%x)", data_handle);
+	
+	printf("%s: standard device descriptor dump (%dB):\n", NAME, descriptor_length);
+	data_dump(descriptor, descriptor_length);
+	
+	fibril_sleep(1);
+
+	printf("%s: exiting.\n", NAME);
+	
+	ipc_hangup(hcd_phone);
+	
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/virtusbkbd/Makefile
===================================================================
--- uspace/app/virtusbkbd/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 = ../..
+# acronym for virtual usb keyboard
+# (it is really annoying to write long names)
+BINARY = vuk
+
+LIBS = $(LIBUSB_PREFIX)/libusb.a $(LIBUSBVIRT_PREFIX)/libusbvirt.a
+EXTRA_CFLAGS = -I$(LIB_PREFIX)
+
+SOURCES = \
+	kbdconfig.c \
+	keys.c \
+	stdreq.c \
+	virtusbkbd.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/virtusbkbd/descriptor.h
===================================================================
--- uspace/app/virtusbkbd/descriptor.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/descriptor.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,51 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief USB keyboard descriptors.
+ */
+#ifndef VUK_DESCRIPTOR_H_
+#define VUK_DESCRIPTOR_H_
+
+typedef struct {
+	uint8_t length;
+	uint8_t type;
+	uint16_t hid_spec_release;
+	uint8_t country_code;
+	uint8_t descriptor_count;
+	uint8_t descriptor1_type;
+	uint16_t descriptor1_length;
+} __attribute__ ((packed)) hid_descriptor_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/items.h
===================================================================
--- uspace/app/virtusbkbd/items.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/items.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,113 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief HID Item related functions.
+ */
+#ifndef VUK_ITEM_H_
+#define VUK_ITEM_H_
+
+#include <sys/types.h>
+
+typedef uint8_t report_descriptor_data_t[];
+
+/* Item types. */
+#define ITEM_MAIN 0
+#define ITEM_GLOBAL 1
+#define ITEM_LOCAL 2
+
+
+
+/* Item tags. */
+
+/* Main item tags. */
+#define TAG_INPUT 8
+#define TAG_OUTPUT 9
+#define TAG_FEATURE 11
+#define TAG_COLLECTION 10
+#define TAG_END_COLLECTION 12
+
+/* Global item tags. */
+#define TAG_USAGE_PAGE 0
+#define TAG_LOGICAL_MINIMUM 1
+#define TAG_LOGICAL_MAXIMUM 2
+#define TAG_REPORT_SIZE 7
+#define TAG_REPORT_COUNT 9
+
+/* Local item tags. */
+#define TAG_USAGE 0
+#define TAG_USAGE_MINIMUM 1
+#define TAG_USAGE_MAXIMUM 2
+
+
+/* Bits for Input, Output and Feature items. */
+#define _IOF(value, shift) ((value) << (shift))
+#define IOF_DATA _IOF(0, 0)
+#define IOF_CONSTANT _IOF(1, 0)
+#define IOF_ARRAY _IOF(0, 1)
+#define IOF_VARIABLE _IOF(1, 1)
+#define IOF_ABSOLUTE _IOF(0, 2)
+#define IOF_RELATIVE _IOF(1, 2)
+/* ... */
+
+/* Collection types. */
+#define COLLECTION_PHYSICAL 0x00
+#define COLLECTION_APPLICATION 0x01
+
+
+/** Creates item prefix.
+ * @param size Item size.
+ * @param type Item type.
+ * @param tag Item tag.
+ */
+#define BUILD_ITEM_PREFIX(size, type, tag) \
+	((size) | ((type) << 2) | ((tag) << 4))
+
+/** Create no-data item.
+ * @param type Item type.
+ * @param tag Item tag.
+ */
+#define ITEM_CREATE0(type, tag) \
+	BUILD_ITEM_PREFIX(0, type, tag)
+
+/** Create item with 1-byte data.
+ * @param type Item type.
+ * @param tag Item tag.
+ * @param data Item data (single byte).
+ */
+#define ITEM_CREATE1(type, tag, data) \
+	BUILD_ITEM_PREFIX(1, type, tag), data
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/kbdconfig.c
===================================================================
--- uspace/app/virtusbkbd/kbdconfig.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/kbdconfig.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,155 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief Keyboard configuration.
+ */
+#include "kbdconfig.h"
+#include "keys.h"
+#include <usb/hcd.h>
+#include <usb/hid.h>
+#include <usb/hidut.h>
+#include <usb/classes.h>
+
+/** Standard device descriptor. */
+usb_standard_device_descriptor_t std_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_USE_INTERFACE,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+/** Standard interface descriptor. */
+usb_standard_interface_descriptor_t std_interface_descriptor = {
+	.length = sizeof(usb_standard_interface_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_INTERFACE,
+	.interface_number = 0,
+	.alternate_setting = 0,
+	.endpoint_count = 1,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = 0,
+	.interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
+	.str_interface = 0
+};
+
+/** USB keyboard report descriptor.
+ * Copied from USB HID 1.11 (section E.6).
+ */
+report_descriptor_data_t report_descriptor = {
+	STD_USAGE_PAGE(USB_HIDUT_PAGE_GENERIC_DESKTOP),
+	USAGE1(USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD),
+	START_COLLECTION(COLLECTION_APPLICATION),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_KEYBOARD),
+		USAGE_MINIMUM1(224),
+		USAGE_MAXIMUM1(231),
+		LOGICAL_MINIMUM1(0),
+		LOGICAL_MAXIMUM1(1),
+		REPORT_SIZE1(1),
+		REPORT_COUNT1(8),
+		/* Modifiers */
+		INPUT(IOF_DATA | IOF_VARIABLE | IOF_ABSOLUTE),
+		REPORT_COUNT1(1),
+		REPORT_SIZE1(8),
+		/* Reserved */
+		INPUT(IOF_CONSTANT),
+		REPORT_COUNT1(5),
+		REPORT_SIZE1(1),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_LED),
+		USAGE_MINIMUM1(1),
+		USAGE_MAXIMUM1(5),
+		/* LED states */
+		OUTPUT(IOF_DATA | IOF_VARIABLE | IOF_ABSOLUTE),
+		REPORT_COUNT1(1),
+		REPORT_SIZE1(3),
+		/* LED states padding */
+		OUTPUT(IOF_CONSTANT),
+		REPORT_COUNT1(KB_MAX_KEYS_AT_ONCE),
+		REPORT_SIZE1(8),
+		LOGICAL_MINIMUM1(0),
+		LOGICAL_MAXIMUM1(101),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_KEYBOARD),
+		USAGE_MINIMUM1(0),
+		USAGE_MAXIMUM1(101),
+		/* Key array */
+		INPUT(IOF_DATA | IOF_ARRAY),
+	END_COLLECTION()
+};
+size_t report_descriptor_size = sizeof(report_descriptor);
+
+/** HID descriptor. */
+hid_descriptor_t hid_descriptor = {
+	.length = sizeof(hid_descriptor_t),
+	.type = 0x21, // HID descriptor
+	.hid_spec_release = 0x101,
+	.country_code = 0,
+	.descriptor_count = 1,
+	.descriptor1_type = 0x22, // Report descriptor
+	.descriptor1_length = sizeof(report_descriptor)
+};
+
+/** Endpoint descriptor. */
+usb_standard_endpoint_descriptor_t endpoint_descriptor = {
+	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_ENDPOINT,
+	.endpoint_address = 1 | 128,
+	.attributes = USB_TRANSFER_INTERRUPT,
+	.max_packet_size = 8,
+	.poll_interval = 10
+};
+
+/** Standard configuration descriptor. */
+usb_standard_configuration_descriptor_t std_configuration_descriptor = {
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	.total_length = 
+		sizeof(usb_standard_configuration_descriptor_t)
+		+ sizeof(std_interface_descriptor)
+		+ sizeof(hid_descriptor)
+		+ sizeof(endpoint_descriptor)
+		,
+	.interface_count = 1,
+	.configuration_number = 1,
+	.str_configuration = 0,
+	.attributes = 128, /* denotes bus-powered device */
+	.max_power = 50
+};
+
+
+
+
+
+/** @}
+ */
Index: uspace/app/virtusbkbd/kbdconfig.h
===================================================================
--- uspace/app/virtusbkbd/kbdconfig.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/kbdconfig.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,60 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief USB keyboard configuration.
+ */
+#ifndef VUK_KBDCONFIG_H_
+#define VUK_KBDCONFIG_H_
+
+#include <usb/descriptor.h>
+#include "report.h"
+#include "descriptor.h"
+
+extern usb_standard_device_descriptor_t std_device_descriptor;
+
+extern usb_standard_configuration_descriptor_t std_configuration_descriptor;
+
+extern usb_standard_interface_descriptor_t std_interface_descriptor;
+
+extern usb_standard_endpoint_descriptor_t endpoint_descriptor;
+
+
+extern hid_descriptor_t hid_descriptor;
+
+extern report_descriptor_data_t report_descriptor;
+extern size_t report_descriptor_size;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/keys.c
===================================================================
--- uspace/app/virtusbkbd/keys.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/keys.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,123 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief Keyboard keys related structures.
+ */
+#include "keys.h"
+
+/** Initializes keyboard status. */
+void kb_init(kb_status_t *status)
+{
+	status->modifiers = 0;
+	size_t i;
+	for (i = 0; i < KB_MAX_KEYS_AT_ONCE; i++) {
+		status->pressed_keys[i] = 0;
+	}
+}
+
+/** Change pressed modifiers. */
+void kb_change_modifier(kb_status_t *status, kb_key_action_t action,
+    kb_modifier_t modifier)
+{
+	if (action == KB_KEY_DOWN) {
+		status->modifiers = status->modifiers | modifier;
+	} else {
+		status->modifiers = status->modifiers & (~modifier);
+	}
+}
+
+/** Find index of given key in key code array.
+ * @retval (size_t)-1 Key not found.
+ */
+static size_t find_key_index(kb_key_code_t *keys, size_t size, kb_key_code_t key)
+{
+	size_t i;
+	for (i = 0; i < size; i++) {
+		if (keys[i] == key) {
+			return i;
+		}
+	}
+	return (size_t)-1;
+}
+
+/** Change pressed key. */
+void kb_change_key(kb_status_t *status, kb_key_action_t action,
+    kb_key_code_t key_code)
+{
+	size_t pos = find_key_index(status->pressed_keys, KB_MAX_KEYS_AT_ONCE,
+	    key_code);
+	if (action == KB_KEY_DOWN) {
+		if (pos != (size_t)-1) {
+			return;
+		}
+		/*
+		 * Find first free item in the array.
+		 */
+		size_t i;
+		for (i = 0; i < KB_MAX_KEYS_AT_ONCE; i++) {
+			if (status->pressed_keys[i] == 0) {
+				status->pressed_keys[i] = key_code;
+				return;
+			}
+		}
+		// TODO - handle buffer overflow
+	} else {
+		if (pos == (size_t)-1) {
+			return;
+		}
+		status->pressed_keys[pos] = 0;
+	}	
+}
+
+/** Process list of events. */
+void kb_process_events(kb_status_t *status,
+    kb_event_t *events, size_t count,
+    kb_on_status_change on_change)
+{
+	while (count-- > 0) {
+		if (events->normal_key) {
+			kb_change_key(status, events->action,
+			    events->key_change);
+		} else {
+			kb_change_modifier(status, events->action,
+			    events->modifier_change);
+		}
+		if (on_change) {
+			on_change(status);
+		}
+		events++;
+	}
+}
+
+/** @}
+ */
Index: uspace/app/virtusbkbd/keys.h
===================================================================
--- uspace/app/virtusbkbd/keys.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/keys.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,121 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Keyboard keys related structures.
+ */
+#ifndef VUK_KEYS_H_
+#define VUK_KEYS_H_
+
+#include <sys/types.h>
+#include <bool.h>
+
+/** Maximum number of keys that can be pressed simultaneously. */
+#define KB_MAX_KEYS_AT_ONCE 4
+
+/** Key code type. */
+typedef uint8_t kb_key_code_t;
+
+#define USB_HIDUT_KBD_KEY(name, usage_id, l, lc, l1, l2) \
+	KB_KEY_##name = usage_id,
+/** USB key code. */
+typedef enum {
+	#include <usb/hidutkbd.h>
+} key_code_t;
+
+/** Modifier type. */
+typedef uint8_t kb_modifier_t;
+#define _KB_MOD(shift) (1 << (shift))
+#define KB_MOD_LEFT_CTRL _KB_MOD(0)
+#define KB_MOD_LEFT_SHIFT _KB_MOD(1)
+#define KB_MOD_LEFT_ALT _KB_MOD(2)
+#define KB_MOD_LEFT_GUI _KB_MOD(3)
+#define KB_MOD_RIGHT_CTRL _KB_MOD(4)
+#define KB_MOD_RIGHT_SHIFT _KB_MOD(5)
+#define KB_MOD_RIGHT_ALT _KB_MOD(6)
+#define KB_MOD_RIGHT_GUI _KB_MOD(7)
+
+/** Base key action. */
+typedef enum {
+	KB_KEY_DOWN,
+	KB_KEY_UP
+} kb_key_action_t;
+
+/** Keyboard status. */
+typedef struct {
+	/** Bitmap of pressed modifiers. */
+	kb_modifier_t modifiers;
+	/** Array of currently pressed keys. */
+	kb_key_code_t pressed_keys[KB_MAX_KEYS_AT_ONCE];
+} kb_status_t;
+
+/** Callback type for status change. */
+typedef void (*kb_on_status_change)(kb_status_t *);
+
+
+void kb_init(kb_status_t *);
+void kb_change_modifier(kb_status_t *, kb_key_action_t, kb_modifier_t);
+void kb_change_key(kb_status_t *, kb_key_action_t, kb_key_code_t);
+
+/** Keyboard event.
+ * Use macros M_DOWN, M_UP, K_DOWN, K_UP, K_PRESS to generate list
+ * of them.
+ */
+typedef struct {
+	/** Key action. */
+	kb_key_action_t action;
+	/** Switch whether action is about modifier or normal key. */
+	bool normal_key;
+	/** Modifier change. */
+	kb_modifier_t modifier_change;
+	/** Normal key change. */
+	kb_key_code_t key_change;
+} kb_event_t;
+
+#define M_DOWN(mod) \
+	{ KB_KEY_DOWN, false, (mod), 0 }
+#define M_UP(mod) \
+	{ KB_KEY_UP, false, (mod), 0 }
+#define K_DOWN(key) \
+	{ KB_KEY_DOWN, true, 0, (key) }
+#define K_UP(key) \
+	{ KB_KEY_UP, true, 0, (key) }
+#define K_PRESS(key) \
+	K_DOWN(key), K_UP(key)
+
+
+void kb_process_events(kb_status_t *, kb_event_t *, size_t, kb_on_status_change);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/report.h
===================================================================
--- uspace/app/virtusbkbd/report.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/report.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,85 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief HID Report Descriptor.
+ */
+#ifndef VUK_REPORT_H_
+#define VUK_REPORT_H_
+
+#include "items.h"
+
+/** Use standard Usage Page. */
+#define STD_USAGE_PAGE(page) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_USAGE_PAGE, page)
+
+/** Usage with one byte usage ID. */
+#define USAGE1(usage_id) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE, usage_id)
+
+/** Start a collection. */
+#define START_COLLECTION(collection) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_COLLECTION, collection)
+
+/** End a collection. */
+#define END_COLLECTION() \
+	ITEM_CREATE0(ITEM_MAIN, TAG_END_COLLECTION)
+
+
+#define USAGE_MINIMUM1(value) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE_MINIMUM, value)
+	
+#define USAGE_MAXIMUM1(value) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE_MAXIMUM, value)
+	
+#define LOGICAL_MINIMUM1(value) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_LOGICAL_MINIMUM, value)
+
+#define LOGICAL_MAXIMUM1(value) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_LOGICAL_MAXIMUM, value)
+
+#define REPORT_SIZE1(size) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_REPORT_SIZE, size)
+
+#define REPORT_COUNT1(count) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_REPORT_COUNT, count)
+	
+#define INPUT(modifiers) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_INPUT, modifiers)
+
+#define OUTPUT(modifiers) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_OUTPUT, modifiers)
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/stdreq.c
===================================================================
--- uspace/app/virtusbkbd/stdreq.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/stdreq.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,80 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief Keyboard configuration.
+ */
+#include <errno.h>
+#include <usb/descriptor.h>
+#include "stdreq.h"
+#include "kbdconfig.h"
+
+static int on_get_descriptor(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data);
+
+usbvirt_standard_device_request_ops_t standard_request_ops = {
+	.on_get_status = NULL,
+	.on_clear_feature = NULL,
+	.on_set_feature = NULL,
+	.on_set_address = NULL,
+	.on_get_descriptor = on_get_descriptor,
+	.on_set_descriptor = NULL,
+	.on_get_configuration = NULL,
+	.on_set_configuration = NULL,
+	.on_get_interface = NULL,
+	.on_set_interface = NULL,
+	.on_synch_frame = NULL
+};
+
+
+static int on_get_descriptor(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data)
+{
+	if (request->value_high == USB_DESCTYPE_HID_REPORT) {
+		/*
+		 * For simplicity, always return the same
+		 * report descriptor.
+		 */
+		int rc = dev->control_transfer_reply(dev, 0,
+		    report_descriptor, report_descriptor_size);
+		
+		return rc;
+	}
+	
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+
+
+/** @}
+ */
Index: uspace/app/virtusbkbd/stdreq.h
===================================================================
--- uspace/app/virtusbkbd/stdreq.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/stdreq.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,45 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Standard device request handlers.
+ */
+#ifndef VUK_STDREQ_H_
+#define VUK_STDREQ_H_
+
+#include <usbvirt/device.h>
+
+extern usbvirt_standard_device_request_ops_t standard_request_ops;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/app/virtusbkbd/virtusbkbd.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,238 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief Virtual USB keyboard.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vfs/vfs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <async.h>
+
+#include <usb/hcd.h>
+#include <usb/descriptor.h>
+#include <usb/hid.h>
+#include <usbvirt/device.h>
+#include <usbvirt/hub.h>
+
+#include "kbdconfig.h"
+#include "keys.h"
+#include "stdreq.h"
+
+#define LOOPS 5
+#define NAME "virt-usb-kbd"
+
+#define DEV_HCD_NAME "hcd-virt-dev"
+
+#define __QUOTEME(x) #x
+#define _QUOTEME(x) __QUOTEME(x)
+
+#define VERBOSE_EXEC(cmd, fmt, ...) \
+	(printf("%s: %s" fmt "\n", NAME, _QUOTEME(cmd), __VA_ARGS__), cmd(__VA_ARGS__))
+
+kb_status_t status;
+
+static int on_incoming_data(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint, void *buffer, size_t size)
+{
+	printf("%s: ignoring incomming data to endpoint %d\n", NAME, endpoint);
+	
+	return EOK;
+}
+
+static int on_class_request(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data)
+{	
+	printf("%s: class request (%d)\n", NAME, (int) request->request);
+	
+	return EOK;
+}
+
+static int on_request_for_data(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *actual_size)
+{
+	if (size < 2 + KB_MAX_KEYS_AT_ONCE) {
+		return EINVAL;
+	}
+	
+	*actual_size = 2 + KB_MAX_KEYS_AT_ONCE;
+	
+	uint8_t data[2 + KB_MAX_KEYS_AT_ONCE];
+	data[0] = status.modifiers;
+	data[1] = 0;
+	
+	size_t i;
+	for (i = 0; i < KB_MAX_KEYS_AT_ONCE; i++) {
+		data[2 + i] = status.pressed_keys[i];
+	}
+	
+	memcpy(buffer, &data, *actual_size);
+	
+	return EOK;
+}
+
+
+/** Keyboard callbacks.
+ * We abuse the fact that static variables are zero-filled.
+ */
+static usbvirt_device_ops_t keyboard_ops = {
+	.standard_request_ops = &standard_request_ops,
+	.on_class_device_request = on_class_request,
+	.on_data = on_incoming_data,
+	.on_data_request = on_request_for_data
+};
+
+usbvirt_device_configuration_extras_t extra_descriptors[] = {
+	{
+		.data = (uint8_t *) &std_interface_descriptor,
+		.length = sizeof(std_interface_descriptor)
+	},
+	{
+		.data = (uint8_t *) &hid_descriptor,
+		.length = sizeof(hid_descriptor)
+	},
+	{
+		.data = (uint8_t *) &endpoint_descriptor,
+		.length = sizeof(endpoint_descriptor)
+	}
+};
+
+/** Keyboard configuration. */
+usbvirt_device_configuration_t configuration = {
+	.descriptor = &std_configuration_descriptor,
+	.extra = extra_descriptors,
+	.extra_count = sizeof(extra_descriptors)/sizeof(extra_descriptors[0])
+};
+
+/** Keyboard standard descriptors. */
+usbvirt_descriptors_t descriptors = {
+	.device = &std_device_descriptor,
+	.configuration = &configuration,
+	.configuration_count = 1,
+};
+
+/** Keyboard device.
+ * Rest of the items will be initialized later.
+ */
+static usbvirt_device_t keyboard_dev = {
+	.ops = &keyboard_ops,
+	.descriptors = &descriptors,
+	.name = "keyboard"
+};
+
+
+static void fibril_sleep(size_t sec)
+{
+	while (sec-- > 0) {
+		async_usleep(1000*1000);
+	}
+}
+
+
+/** Callback when keyboard status changed.
+ *
+ * @param status Current keyboard status.
+ */
+static void on_keyboard_change(kb_status_t *status)
+{
+	printf("%s: Current keyboard status: %08hhb", NAME, status->modifiers);
+	size_t i;
+	for (i = 0; i < KB_MAX_KEYS_AT_ONCE; i++) {
+		printf(" 0x%02X", (int)status->pressed_keys[i]);
+	}
+	printf("\n");
+	
+	fibril_sleep(1);
+}
+
+/** Simulated keyboard events. */
+static kb_event_t keyboard_events[] = {
+	/* Switch to VT6 (Alt+F6) */
+	M_DOWN(KB_MOD_LEFT_ALT),
+	K_PRESS(KB_KEY_F6),
+	M_UP(KB_MOD_LEFT_ALT),
+	/* Type the word 'Hello' */
+	M_DOWN(KB_MOD_LEFT_SHIFT),
+	K_PRESS(KB_KEY_H),
+	M_UP(KB_MOD_LEFT_SHIFT),
+	K_PRESS(KB_KEY_E),
+	K_PRESS(KB_KEY_L),
+	K_PRESS(KB_KEY_L),
+	K_PRESS(KB_KEY_O)
+};
+static size_t keyboard_events_count =
+    sizeof(keyboard_events)/sizeof(keyboard_events[0]);
+
+
+
+int main(int argc, char * argv[])
+{
+	printf("Dump of report descriptor (%u bytes):\n", report_descriptor_size);
+	size_t i;
+	for (i = 0; i < report_descriptor_size; i++) {
+		printf("  0x%02X", report_descriptor[i]);
+		if (((i > 0) && (((i+1) % 10) == 0))
+		    || (i + 1 == report_descriptor_size)) {
+			printf("\n");
+		}
+	}
+	
+	kb_init(&status);
+	
+	
+	int rc = usbvirt_connect(&keyboard_dev, DEV_HCD_NAME);
+	if (rc != EOK) {
+		printf("%s: Unable to start comunication with VHCD at usb://%s (%s).\n",
+		    NAME, DEV_HCD_NAME, str_error(rc));
+		return rc;
+	}
+	
+	printf("%s: Simulating keyboard events...\n", NAME);
+	kb_process_events(&status, keyboard_events, keyboard_events_count,
+	    on_keyboard_change);
+	
+	printf("%s: Terminating...\n", NAME);
+	
+	usbvirt_disconnect(&keyboard_dev);
+	
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision 854bfa5d2185cdfd2a48821f92b573df304c7247)
+++ uspace/doc/doxygroups.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -155,5 +155,5 @@
 	 * @endcond
 	 */
-	
+
 /**
  * @defgroup emul Emulation Libraries
@@ -170,2 +170,13 @@
 	 * @ingroup emul
 	 */
+
+/**
+ * @defgroup usb USB
+ * @ingroup uspace
+ * @brief USB support for HelenOS.
+ */
+	/**
+	 * @defgroup libusb USB library
+	 * @ingroup usb
+	 * @brief Library for creating USB devices drivers.
+	 */
Index: uspace/lib/packet/include/net_byteorder.h
===================================================================
--- uspace/lib/packet/include/net_byteorder.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/packet/include/net_byteorder.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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 net
+ *  @{
+ */
+
+/** @file
+ *  Host - network byte order manipulation functions.
+ */
+
+#ifndef __NET_BYTEORDER_H__
+#define __NET_BYTEORDER_H__
+
+#include <byteorder.h>
+#include <sys/types.h>
+
+
+/** Converts the given short number (16 bit) from the host byte order to the network byte order (big endian).
+ *  @param[in] number The number in the host byte order to be converted.
+ *  @returns The number in the network byte order.
+ */
+#define htons(number)		host2uint16_t_be(number)
+
+/** Converts the given long number (32 bit) from the host byte order to the network byte order (big endian).
+ *  @param[in] number The number in the host byte order to be converted.
+ *  @returns The number in the network byte order.
+ */
+#define htonl(number)		host2uint32_t_be(number)
+
+/** Converts the given short number (16 bit) from the network byte order (big endian) to the host byte order.
+ *  @param[in] number The number in the network byte order to be converted.
+ *  @returns The number in the host byte order.
+ */
+#define ntohs(number) 	uint16_t_be2host(number)
+
+/** Converts the given long number (32 bit) from the network byte order (big endian) to the host byte order.
+ *  @param[in] number The number in the network byte order to be converted.
+ *  @returns The number in the host byte order.
+ */
+#define ntohl(number)		uint32_t_be2host(number)
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/packet/include/net_err.h
===================================================================
--- uspace/lib/packet/include/net_err.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/packet/include/net_err.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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 net
+ * @{
+ */
+
+/** @file
+ * Common error processing codes and routines.
+ */
+
+#ifndef __NET_ERR_H__
+#define __NET_ERR_H__
+
+#include <errno.h>
+
+#ifdef CONFIG_DEBUG
+	#include <stdio.h>
+	#include <str_error.h>
+#endif
+
+/** An actual stored error code.
+ *
+ */
+#define ERROR_CODE  error_check_return_value
+
+/** An error processing routines declaration.
+ *
+ * This has to be declared in the block where the error processing
+ * is desired.
+ *
+ */
+#define ERROR_DECLARE  int ERROR_CODE
+
+/** Store the value as an error code and checks if an error occurred.
+ *
+ * @param[in] value The value to be checked. May be a function call.
+ * @return False if the value indicates success (EOK).
+ * @return True otherwise.
+ *
+ */
+#ifdef CONFIG_DEBUG
+
+#define ERROR_OCCURRED(value) \
+	(((ERROR_CODE = (value)) != EOK) \
+	&& ({ \
+		fprintf(stderr, "libsocket error at %s:%d (%s)\n", \
+		__FILE__, __LINE__, str_error(ERROR_CODE)); \
+		1; \
+	}))
+
+#else
+
+#define ERROR_OCCURRED(value)  ((ERROR_CODE = (value)) != EOK)
+
+#endif
+
+/** Error propagation
+ *
+ * Check if an error occurred and immediately exit the actual
+ * function returning the error code.
+ *
+ * @param[in] value The value to be checked. May be a function call.
+ *
+ */
+
+#define ERROR_PROPAGATE(value) \
+	if (ERROR_OCCURRED(value)) \
+		return ERROR_CODE
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/packet/include/socket_errno.h
===================================================================
--- uspace/lib/packet/include/socket_errno.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/packet/include/socket_errno.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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 net
+ *  @{
+ */
+
+/** @file
+ *  Socket error codes.
+ *  Based on BSD.
+ */
+
+#ifndef __NET_SOCKET_ERR_H__
+#define __NET_SOCKET_ERR_H__
+
+#include <errno.h>
+
+/** @name Socket error codes definitions
+ */
+/*@{*/
+
+////#define EINTR			(-10004)
+////#define EBADF			(-10009)
+//#define EACCES			(-10013)
+//#define EFAULT			(-10014)
+////#define EINVAL			(-10022)
+////#define EMFILE			(-10024)
+//#define EWOULDBLOCK		(-10035)
+
+/** An API function is called while another blocking function is in progress.
+ */
+#define EINPROGRESS		(-10036)
+
+//#define EALREADY		(-10037)
+
+/** The socket identifier is not valid.
+ */
+#define ENOTSOCK		(-10038)
+
+/** The destination address required.
+ */
+#define EDESTADDRREQ	(-10039)
+
+//#define EMSGSIZE		(-10040)
+//#define EPROTOTYPE		(-10041)
+//#define ENOPROTOOPT		(-10042)
+
+/** Protocol is not supported.
+ */
+#define EPROTONOSUPPORT	(-10043)
+
+/** Socket type is not supported.
+ */
+#define ESOCKTNOSUPPORT	(-10044)
+
+//#define EOPNOTSUPP		(-10045)
+
+/** Protocol family is not supported.
+ */
+#define EPFNOSUPPORT	(-10046)
+
+/** Address family is not supported.
+ */
+#define EAFNOSUPPORT	(-10047)
+
+/** Address is already in use.
+ */
+#define EADDRINUSE		(-10048)
+
+//#define EADDRNOTAVAIL	(-10049)
+/* May be reported at any time if the implementation detects an underlying failure.
+ */
+//#define ENETDOWN		(-10050)
+//#define ENETUNREACH		(-10051)
+//#define ENETRESET		(-10052)
+//#define ECONNABORTED	(-10053)
+//#define ECONNRESET		(-10054)
+//#define ENOBUFS			(-10055)
+//#define EISCONN			(-10056)
+
+/** The socket is not connected or bound.
+ */
+#define ENOTCONN		(-10057)
+
+//#define ESHUTDOWN		(-10058)
+//#define ETOOMANYREFS	(-10059)
+//#define ETIMEDOUT		(-10060)
+//#define ECONNREFUSED	(-10061)
+//#define ELOOP			(-10062)
+////#define ENAMETOOLONG	(-10063)
+//#define EHOSTDOWN		(-10064)
+//#define EHOSTUNREACH	(-10065)
+//#define HOST_NOT_FOUND	(-11001)
+
+/** The requested operation was not performed.
+ *  Try again later.
+ */
+#define TRY_AGAIN		(-11002)
+
+//#define NO_RECOVERY		(-11003)
+
+/** No data.
+ */
+#define NO_DATA			(-11004)
+
+/*@}*/
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,36 @@
+#
+# 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
+
+SOURCES = \
+	hcd.c \
+	usb.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usb/classes.h
===================================================================
--- uspace/lib/usb/classes.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/classes.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/descriptor.h
===================================================================
--- uspace/lib/usb/descriptor.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/descriptor.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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/devreq.h
===================================================================
--- uspace/lib/usb/devreq.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/devreq.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,88 @@
+/*
+ * 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>
+
+/** 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;
+	};
+	/** Auxilary 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;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/hcd.c
===================================================================
--- uspace/lib/usb/hcd.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/hcd.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,448 @@
+/*
+ * 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 Host Controller Driver (implementation).
+ */
+#include "hcd.h"
+#include <devmap.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <vfs/vfs.h>
+#include <errno.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;
+
+#define NAMESPACE "usb"
+
+/** 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";
+	}
+}
+
+/** Create necessary phones for communicating with HCD.
+ * This function wraps following calls:
+ * -# open <code>/dev/usb/<i>hcd_path</i></code> for reading
+ * -# access phone of file opened in previous step
+ * -# 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 hcd_path HCD identification under devfs
+ *     (without <code>/dev/usb/</code>).
+ * @return Phone for communicating with HCD or error code from errno.h.
+ */
+int usb_hcd_connect(const char * hcd_path)
+{
+	char dev_path[DEVMAP_NAME_MAXLEN + 1];
+	snprintf(dev_path, DEVMAP_NAME_MAXLEN,
+	    "/dev/%s/%s", NAMESPACE, hcd_path);
+	
+	int fd = open(dev_path, O_RDONLY);
+	if (fd < 0) {
+		return fd;
+	}
+	
+	int hcd_phone = fd_phone(fd);
+	
+	if (hcd_phone < 0) {
+		return hcd_phone;
+	}
+
+	return hcd_phone;
+}
+
+/** Send data to HCD.
+ *
+ * @param phone Opened phone to HCD.
+ * @param method Method used for calling.
+ * @param target Target 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_3(phone,
+	    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 Target 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_3(phone,
+	    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, ipcarg_t hash,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	ipc_call_t answer_data;
+	ipcarg_t answer_rc;
+	aid_t req;
+	int rc;
+	
+	req = async_send_1(phone,
+	    IPC_M_USB_HCD_GET_BUFFER_ASYNC,
+	    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_hcd_async_wait_for(usb_handle_t handle)
+{
+	if (handle == 0) {
+		return EBADMEM;
+	}
+	
+	int rc = EOK;
+	
+	transfer_info_t *transfer = (transfer_info_t *) handle;
+	
+	ipcarg_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.
+		 */
+		ipcarg_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_hcd_async_transfer_interrupt_out(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Request interrupt data from device. */
+int usb_hcd_async_transfer_interrupt_in(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(hcd_phone,
+	    IPC_M_USB_HCD_INTERRUPT_IN_ASYNC,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+/** Start WRITE control transfer. */
+int usb_hcd_async_transfer_control_write_setup(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Send data during WRITE control transfer. */
+int usb_hcd_async_transfer_control_write_data(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Terminate WRITE control transfer. */
+int usb_hcd_async_transfer_control_write_status(int hcd_phone,
+    usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC,
+	    target,
+	    NULL, 0, NULL,
+	    handle);
+}
+
+/** Start READ control transfer. */
+int usb_hcd_async_transfer_control_read_setup(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC,
+	    target,
+	    buffer, size,
+	    handle);
+}
+
+/** Request data during READ control transfer. */
+int usb_hcd_async_transfer_control_read_data(int hcd_phone,
+    usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size,
+    usb_handle_t *handle)
+{
+	return async_recv_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC,
+	    target,
+	    buffer, size, actual_size,
+	    handle);
+}
+
+/** Terminate READ control transfer. */
+int usb_hcd_async_transfer_control_read_status(int hcd_phone,
+    usb_target_t target,
+    usb_handle_t *handle)
+{
+	return async_send_buffer(hcd_phone,
+	    IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC,
+	    target,
+	    NULL, 0,
+	    handle);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/hcd.h
===================================================================
--- uspace/lib/usb/hcd.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/hcd.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,261 @@
+/*
+ * 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 Host Controller Driver.
+ */
+#ifndef LIBUSB_HCD_H_
+#define LIBUSB_HCD_H_
+
+#include "usb.h"
+
+#include <ipc/ipc.h>
+#include <async.h>
+
+/** Maximum size of transaction payload. */
+#define USB_MAX_PAYLOAD_SIZE 1020
+
+/** Opaque handle of active USB transaction.
+ * This handle is when informing about transaction outcome (or status).
+ */
+typedef ipcarg_t usb_transaction_handle_t;
+
+/** USB transaction outcome. */
+typedef enum {
+	USB_OUTCOME_OK,
+	USB_OUTCOME_CRCERROR,
+	USB_OUTCOME_BABBLE
+} usb_transaction_outcome_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;
+
+const char * usb_str_transaction_outcome(usb_transaction_outcome_t o);
+
+/** IPC methods for HCD.
+ *
+ * Notes for async methods:
+ *
+ * Methods for sending data to device (OUT transactions)
+ * - e.g. IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC -
+ * 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 immediatelly after error is detected
+ * - the answer carries only the error code
+ *
+ * Methods for retrieving data from device (IN transactions)
+ * - e.g. IPC_M_USB_HCD_INTERRUPT_IN_ASYNC -
+ * 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 ommitted.
+ *
+ * The mentioned data retrieval can be done any time after receiving EOK
+ * answer to IN method.
+ * This retrieval is done using the IPC_M_USB_HCD_GET_BUFFER_ASYNC where
+ * the first argument is buffer hash from call answer.
+ * This call must be immediatelly followed by data read-in and after the
+ * data are transferred, the initial call (IPC_M_USB_HCD_GET_BUFFER_ASYNC)
+ * 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_hcd_async_wait_for() with appropriate handle).
+ * OUT transactions buffers can be freed immediatelly after call is dispatched
+ * (i.e. after return from wrapping function).
+ *
+ */
+typedef enum {
+	/** Tell maximum size of the transaction buffer (payload).
+	 * 
+	 * Arguments of the call:
+	 *  (none)
+	 * 
+	 * Answer:
+	 * - EOK - always
+	 * 
+	 * Arguments of the answer:
+	 * - buffer size (in bytes):
+	 */
+	IPC_M_USB_HCD_TRANSACTION_SIZE = IPC_FIRST_USER_METHOD,
+	
+	/** Asks for data buffer.
+	 * See explanation at usb_hcd_method_t.
+	 */
+	IPC_M_USB_HCD_GET_BUFFER_ASYNC,
+	
+	
+	
+	/** Send interrupt data to device.
+	 * See explanation at usb_hcd_method_t (OUT transaction).
+	 */
+	IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC,
+	
+	/** Get interrupt data from device.
+	 * See explanation at usb_hcd_method_t (IN transaction).
+	 */
+	IPC_M_USB_HCD_INTERRUPT_IN_ASYNC,
+	
+	
+	/** Start WRITE control transfer.
+	 * See explanation at usb_hcd_method_t (OUT transaction).
+	 */
+	IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC,
+	
+	/** Send control-transfer data to device.
+	 * See explanation at usb_hcd_method_t (OUT transaction).
+	 */
+	IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC,
+	
+	/** Terminate WRITE control transfer.
+	 * See explanation at usb_hcd_method_t (NO-DATA transaction).
+	 */
+	IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC,
+	
+	
+	
+	/** Start READ control transfer.
+	 * See explanation at usb_hcd_method_t (OUT transaction).
+	 */
+	IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC,
+	
+	/** Get control-transfer data from device.
+	 * See explanation at usb_hcd_method_t (IN transaction).
+	 */
+	IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC,
+	
+	/** Terminate READ control transfer.
+	 * See explanation at usb_hcd_method_t (NO-DATA transaction).
+	 */
+	IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC,
+	
+	
+	/* IPC_M_USB_HCD_ */
+} usb_hcd_method_t;
+
+/** IPC methods for callbacks from HCD. */
+typedef enum {
+	/** Confimation after data sent.
+	 * 
+	 * Arguments of the call:
+	 * - transaction handle
+	 * - transaction outcome
+	 */
+	IPC_M_USB_HCD_DATA_SENT = IPC_FIRST_USER_METHOD,
+	
+	/** Notification of data received.
+	 * This call initiates sending a data buffer from HCD to the client.
+	 * See IPC_M_USB_HCD_SEND_DATA for details for buffer transfer is
+	 * done.
+	 * 
+	 * Arguments of the call:
+	 * - transaction handle
+	 * - transaction outcome
+	 * - actual data length
+	 */
+	IPC_M_USB_HCD_DATA_RECEIVED,
+	
+	/** Notification about a serious trouble with HC.
+	 */
+	IPC_M_USB_HCD_CONTROLLER_FAILURE,
+	
+	/* IPC_M_USB_HCD_ */
+} usb_hcd_callback_method_t;
+
+
+int usb_hcd_connect(const char *);
+
+int usb_hcd_async_transfer_interrupt_out(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_interrupt_in(int, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+
+int usb_hcd_async_transfer_control_write_setup(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_control_write_data(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_control_write_status(int, usb_target_t,
+    usb_handle_t *);
+
+int usb_hcd_async_transfer_control_read_setup(int, usb_target_t,
+    void *, size_t, usb_handle_t *);
+int usb_hcd_async_transfer_control_read_data(int, usb_target_t,
+    void *, size_t, size_t *, usb_handle_t *);
+int usb_hcd_async_transfer_control_read_status(int, usb_target_t,
+    usb_handle_t *);
+
+int usb_hcd_async_wait_for(usb_handle_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/hid.h
===================================================================
--- uspace/lib/usb/hid.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/hid.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,59 @@
+/*
+ * 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_
+
+/** 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;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/hidut.h
===================================================================
--- uspace/lib/usb/hidut.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/hidut.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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/hidutkbd.h
===================================================================
--- uspace/lib/usb/hidutkbd.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/hidutkbd.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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/hub.h
===================================================================
--- uspace/lib/usb/hub.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/hub.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 USB hub related structures.
+ */
+#ifndef LIBUSB_HUB_H_
+#define LIBUSB_HUB_H_
+
+/** Hub class request. */
+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_ = , */
+} usb_hub_class_request_t;
+
+/** 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;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/usb.c
===================================================================
--- uspace/lib/usb/usb.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/usb.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,59 @@
+/*
+ * 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.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";
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/usb.h
===================================================================
--- uspace/lib/usb/usb.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usb/usb.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 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 address type.
+ * Negative values could be used to indicate error.
+ */
+typedef int usb_address_t;
+
+/** 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 ipcarg_t usb_handle_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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$(LIB_PREFIX)
+
+SOURCES = \
+	callback.c \
+	ctrlpipe.c \
+	debug.c \
+	main.c \
+	stdreq.c \
+	transaction.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbvirt/callback.c
===================================================================
--- uspace/lib/usbvirt/callback.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/callback.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,235 @@
+/*
+ * 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 "hub.h"
+#include "device.h"
+#include "private.h"
+
+#define NAMESPACE "usb"
+
+/** 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) {
+		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_METHOD(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/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/ctrlpipe.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/ctrlpipe.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Device control pipe.
+ */
+#include <errno.h>
+
+#include "private.h"
+
+#define REQUEST_TYPE_STANDARD 0 
+#define REQUEST_TYPE_CLASS 1
+
+#define GET_MIDBITS_MASK(size, shift) \
+	(((1 << size) - 1) << shift)
+#define GET_MIDBITS(value, size, shift) \
+	((value & GET_MIDBITS_MASK(size, shift)) >> shift)
+
+
+static const char *str_request_type(int type)
+{
+	switch (type) {
+		case REQUEST_TYPE_STANDARD:
+			return "standard";
+		case REQUEST_TYPE_CLASS:
+			return "class";
+		default:
+			return "unknown";
+	}
+}
+
+/** Tell request type.
+ * By type is meant either standard, class, vendor or other.
+ */
+static int request_get_type(uint8_t request_type)
+{
+	return GET_MIDBITS(request_type, 2, 5);
+}
+
+/** Handle communication over control pipe zero.
+ */
+int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer)
+{
+	device->lib_debug(device, 1, 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;
+	uint8_t *remaining_data = transfer->data;
+	
+	int type = request_get_type(request->request_type);
+	
+	int rc = EOK;
+	
+	device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+	    "request type: %s", str_request_type(type));
+	
+	switch (type) {
+		case REQUEST_TYPE_STANDARD:
+			rc = handle_std_request(device, request, remaining_data);
+			break;
+		case REQUEST_TYPE_CLASS:
+			if (DEVICE_HAS_OP(device, on_class_device_request)) {
+				rc = device->ops->on_class_device_request(device,
+				    request, remaining_data);
+			}
+			break;
+		default:
+			break;
+	}
+	
+	if (device->new_address != -1) {
+		/*
+		 * TODO: handle when this request is invalid (e.g.
+		 * setting address when in configured state).
+		 */
+		if (device->new_address == 0) {
+			device->state = USBVIRT_STATE_DEFAULT;
+		} else {
+			device->state = USBVIRT_STATE_ADDRESS;
+		}
+		device->address = device->new_address;
+		
+		device->new_address = -1;
+		
+		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/debug.c
===================================================================
--- uspace/lib/usbvirt/debug.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/debug.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Debugging support.
+ */
+#include <stdio.h>
+#include <bool.h>
+
+#include "device.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]: ", level);
+		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/device.h
===================================================================
--- uspace/lib/usbvirt/device.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/device.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB device.
+ */
+#ifndef LIBUSBVIRT_DEVICE_H_
+#define LIBUSBVIRT_DEVICE_H_
+
+#include <usb/hcd.h>
+#include <usb/descriptor.h>
+#include <usb/devreq.h>
+
+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);
+
+/** Callbacks for standard device requests.
+ * When these functions are NULL or return EFORWARD, this
+ * framework will try to satisfy the request by itself.
+ */
+typedef struct {
+	usbvirt_on_device_request_t on_get_status;
+	usbvirt_on_device_request_t on_clear_feature;
+	usbvirt_on_device_request_t on_set_feature;
+	usbvirt_on_device_request_t on_set_address;
+	usbvirt_on_device_request_t on_get_descriptor;
+	usbvirt_on_device_request_t on_set_descriptor;
+	usbvirt_on_device_request_t on_get_configuration;
+	usbvirt_on_device_request_t on_set_configuration;
+	usbvirt_on_device_request_t on_get_interface;
+	usbvirt_on_device_request_t on_set_interface;
+	usbvirt_on_device_request_t on_synch_frame;
+} usbvirt_standard_device_request_ops_t;
+
+/** Device operations. */
+typedef struct {
+	/** Callbacks for standard deivce requests. */
+	usbvirt_standard_device_request_ops_t *standard_request_ops;
+	/** Callback for class-specific USB request. */
+	usbvirt_on_device_request_t on_class_device_request;
+	
+	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);
+} 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;
+
+/** Possible states of virtual USB device.
+ * Notice that these are not 1:1 mappings to those in USB specification.
+ */
+typedef enum {
+	USBVIRT_STATE_DEFAULT,
+	USBVIRT_STATE_ADDRESS,
+	USBVIRT_STATE_CONFIGURED
+} usbvirt_device_state_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;
+	
+	/** 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/hub.h
===================================================================
--- uspace/lib/usbvirt/hub.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/hub.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 *, const char *);
+int usbvirt_connect_local(usbvirt_device_t *);
+int usbvirt_disconnect(usbvirt_device_t *dev);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/main.c
===================================================================
--- uspace/lib/usbvirt/main.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/main.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,290 @@
+/*
+ * 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 <devmap.h>
+#include <fcntl.h>
+#include <vfs/vfs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <assert.h>
+
+#include "hub.h"
+#include "device.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. */
+	ipcarg_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(ipcarg_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 comunication with virtual HCD.
+ * This function wraps following calls:
+ * -# open <code>/dev/usb/<i>hcd_path</i></code> 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 occured.
+ *
+ * @param hcd_path HCD identification under devfs
+ *     (without <code>/dev/usb/</code>).
+ * @param dev Device to connect.
+ * @return EOK on success or error code from errno.h.
+ */
+int usbvirt_connect(usbvirt_device_t *dev, const char *hcd_path)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device != NULL) {
+		return EEXISTS;
+	}
+	
+	char dev_path[DEVMAP_NAME_MAXLEN + 1];
+	snprintf(dev_path, DEVMAP_NAME_MAXLEN,
+	    "/dev/%s/%s", NAMESPACE, hcd_path);
+	
+	int fd = open(dev_path, O_RDONLY);
+	if (fd < 0) {
+		return fd;
+	}
+	
+	int hcd_phone = fd_phone(fd);
+	
+	if (hcd_phone < 0) {
+		return hcd_phone;
+	}
+	
+	ipcarg_t phonehash;
+	int rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
+	if (rc != EOK) {
+		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/private.h
===================================================================
--- uspace/lib/usbvirt/private.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/private.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,91 @@
+/*
+ * 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 "device.h"
+#include "hub.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";
+	}
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/stdreq.c
===================================================================
--- uspace/lib/usbvirt/stdreq.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/stdreq.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,212 @@
+/*
+ * 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,
+    uint8_t type, uint8_t index, uint16_t language,
+    uint16_t length)
+{
+	/* 
+	 * 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,
+    uint16_t new_address,
+    uint16_t zero1, uint16_t zero2)
+{
+	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,
+    uint16_t configuration_value,
+    uint16_t zero1, uint16_t zero2)
+{
+	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) {
+		device->state = USBVIRT_STATE_ADDRESS;
+	} else {
+		/*
+		* TODO: browse provided configurations and verify that
+		* user selected existing configuration.
+		*/
+		device->state = USBVIRT_STATE_CONFIGURED;
+		if (device->descriptors) {
+			device->descriptors->current_configuration
+			    = configuration_value;
+		}
+	}
+		
+	return EOK;
+}
+
+#define HANDLE_REQUEST(request, data, type, dev, user_callback, default_handler) \
+	do { \
+		if ((request)->request == (type)) { \
+			int _rc = EFORWARD; \
+			if (((dev)->ops) && ((dev)->ops->standard_request_ops) \
+			    && ((dev)->ops->standard_request_ops->user_callback)) { \
+				_rc = (dev)->ops->standard_request_ops->\
+				    user_callback(dev, request, data); \
+			} \
+			if (_rc == EFORWARD) { \
+				default_handler; \
+			} \
+			return _rc; \
+		} \
+	} while (false)
+
+/** Handle standard device request. */
+int handle_std_request(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *request, uint8_t *data)
+{
+	device->lib_debug(device, 3, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+	    "handling standard request %d", request->request);
+	
+	HANDLE_REQUEST(request, data, USB_DEVREQ_GET_DESCRIPTOR,
+	    device, on_get_descriptor,
+	    handle_get_descriptor(device, request->value_high, request->value_low,
+	        request->index, request->length));
+	
+	HANDLE_REQUEST(request, data, USB_DEVREQ_SET_ADDRESS,
+	    device, on_set_address,
+	    handle_set_address(device, request->value,
+	        request->index, request->length));
+	
+	HANDLE_REQUEST(request, data, USB_DEVREQ_SET_CONFIGURATION,
+	    device, on_set_configuration,
+	    handle_set_configuration(device, request->value,
+	        request->index, request->length));
+	
+	return ENOTSUP;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/transaction.c
===================================================================
--- uspace/lib/usbvirt/transaction.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/lib/usbvirt/transaction.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,267 @@
+/*
+ * 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 "hub.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;
+			}
+			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);
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/Makefile
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/Makefile	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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.
+#
+
+USPACE_PREFIX = ../../../../../..
+LIBS = $(LIBUSB_PREFIX)/libusb.a $(LIBUSBVIRT_PREFIX)/libusbvirt.a
+EXTRA_CFLAGS = -I$(LIB_PREFIX)
+BINARY = vhcd
+
+SOURCES = \
+	conndev.c \
+	connhost.c \
+	debug.c \
+	devices.c \
+	hc.c \
+	hcd.c \
+	hub.c \
+	hubops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/hw/bus/usb/hcd/virtual/conn.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/conn.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/conn.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,48 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Connection handling of incoming calls.
+ */
+#ifndef VHCD_CONN_H_
+#define VHCD_CONN_H_
+
+#include <usb/hcd.h>
+#include "vhcd.h"
+#include "devices.h"
+
+void connection_handler_host(ipcarg_t);
+void connection_handler_device(ipcarg_t, virtdev_connection_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/conndev.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/conndev.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/conndev.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,122 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Connection handling of calls from virtual device (implementation).
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <usbvirt/hub.h>
+
+#include "conn.h"
+#include "hc.h"
+#include "hub.h"
+
+#define DEVICE_NAME_MAXLENGTH 32
+
+static int get_device_name(int phone, char *buffer, size_t len)
+{
+	ipc_call_t answer_data;
+	ipcarg_t answer_rc;
+	aid_t req;
+	int rc;
+	
+	req = async_send_0(phone,
+	    IPC_M_USBVIRT_GET_NAME,
+	    &answer_data);
+	
+	rc = async_data_read_start(phone, buffer, len);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return EINVAL;
+	}
+	
+	async_wait_for(req, &answer_rc);
+	rc = (int)answer_rc;
+	
+	if (IPC_GET_ARG1(answer_data) < len) {
+		len = IPC_GET_ARG1(answer_data);
+	} else {
+		len--;
+	}
+	buffer[len] = 0;
+	
+	return rc;
+}
+
+/** Connection handler for communcation with virtual device.
+ *
+ * This function also takes care of proper phone hung-up.
+ *
+ * @param phone_hash Incoming phone hash.
+ * @param dev Virtual device handle.
+ */
+void connection_handler_device(ipcarg_t phone_hash, virtdev_connection_t *dev)
+{
+	assert(dev != NULL);
+	
+	char devname[DEVICE_NAME_MAXLENGTH + 1];
+	int rc = get_device_name(dev->phone, devname, DEVICE_NAME_MAXLENGTH);
+	
+	dprintf(0, "virtual device connected (phone: %#x, name: %s)",
+	    phone_hash, rc == EOK ? devname : "<unknown>");
+	
+	
+	while (true) {
+		ipc_callid_t callid; 
+		ipc_call_t call; 
+		
+		callid = async_get_call(&call);
+		
+		switch (IPC_GET_METHOD(call)) {
+			case IPC_M_PHONE_HUNGUP:
+				ipc_hangup(dev->phone);
+				ipc_answer_0(callid, EOK);
+				dprintf(0, "phone%#x: device hung-up",
+				    phone_hash);
+				return;
+			
+			case IPC_M_CONNECT_TO_ME:
+				ipc_answer_0(callid, ELIMIT);
+				break;
+			
+			default:
+				dprintf_inval_call(2, call, phone_hash);
+				ipc_answer_0(callid, EINVAL);
+				break;
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/connhost.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/connhost.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/connhost.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 usb
+ * @{
+ */
+/** @file
+ * @brief Connection handling of calls from host (implementation).
+ */
+#include <assert.h>
+#include <errno.h>
+#include <usb/hcd.h>
+
+#include "vhcd.h"
+#include "conn.h"
+#include "hc.h"
+
+typedef struct {
+	ipc_callid_t caller;
+	void *buffer;
+	size_t size;
+} async_transaction_t;
+
+static void async_out_callback(void * buffer, size_t len,
+    usb_transaction_outcome_t outcome, void * arg)
+{
+	async_transaction_t * trans = (async_transaction_t *)arg;
+	
+	dprintf(2, "async_out_callback(buffer, %u, %d, %p) -> %x",
+	    len, outcome, arg, trans->caller);
+	
+	// FIXME - answer according to outcome
+	ipc_answer_1(trans->caller, EOK, 0);
+	
+	free(trans);
+	if (buffer) {
+		free(buffer);
+	}
+	dprintf(4, "async_out_callback answered");
+}
+
+static void async_to_device(ipc_callid_t iid, ipc_call_t icall, bool setup_transaction)
+{
+	size_t expected_len = IPC_GET_ARG3(icall);
+	usb_target_t target = {
+		.address = IPC_GET_ARG1(icall),
+		.endpoint = IPC_GET_ARG2(icall)
+	};
+	
+	dprintf(1, "async_to_device: dev=%d:%d, size=%d, iid=%x",
+	    target.address, target.endpoint, expected_len, iid);
+	
+	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(iid, rc);
+			return;
+		}
+	}
+	
+	async_transaction_t * trans = malloc(sizeof(async_transaction_t));
+	trans->caller = iid;
+	trans->buffer = NULL;
+	trans->size = 0;
+	
+	hc_add_transaction_to_device(setup_transaction, target,
+	    buffer, len,
+	    async_out_callback, trans);
+	
+	dprintf(2, "async transaction to device scheduled (%p)", trans);
+}
+
+static void async_in_callback(void * buffer, size_t len,
+    usb_transaction_outcome_t outcome, void * arg)
+{	
+	async_transaction_t * trans = (async_transaction_t *)arg;
+	
+	dprintf(2, "async_in_callback(buffer, %u, %d, %p) -> %x",
+	    len, outcome, arg, trans->caller);
+	
+	trans->buffer = buffer;
+	trans->size = len;
+	
+	ipc_callid_t caller = trans->caller;
+	
+	if (buffer == NULL) {
+		free(trans);
+		trans = NULL;
+	}
+	
+	
+	// FIXME - answer according to outcome
+	ipc_answer_1(caller, EOK, (ipcarg_t)trans);
+	dprintf(4, "async_in_callback answered (%#x)", (ipcarg_t)trans);
+}
+
+static void async_from_device(ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_target_t target = {
+		.address = IPC_GET_ARG1(icall),
+		.endpoint = IPC_GET_ARG2(icall)
+	};
+	size_t len = IPC_GET_ARG3(icall);
+	
+	dprintf(1, "async_from_device: dev=%d:%d, size=%d, iid=%x",
+	    target.address, target.endpoint, len, iid);
+	
+	void * buffer = NULL;
+	if (len > 0) {
+		buffer = malloc(len);
+	}
+	
+	async_transaction_t * trans = malloc(sizeof(async_transaction_t));
+	trans->caller = iid;
+	trans->buffer = NULL;
+	trans->size = 0;
+	
+	hc_add_transaction_from_device(target,
+	    buffer, len,
+	    async_in_callback, trans);
+	
+	dprintf(2, "async transfer from device scheduled (%p)", trans);
+}
+
+static void async_get_buffer(ipc_callid_t iid, ipc_call_t icall)
+{
+	ipcarg_t buffer_hash = IPC_GET_ARG1(icall);
+	async_transaction_t * trans = (async_transaction_t *)buffer_hash;
+	if (trans == NULL) {
+		ipc_answer_0(iid, ENOENT);
+		return;
+	}
+	if (trans->buffer == NULL) {
+		ipc_answer_0(iid, EINVAL);
+		free(trans);
+		return;
+	}
+	
+	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 > trans->size) {
+		accepted_size = trans->size;
+	}
+	async_data_read_finalize(callid, trans->buffer, accepted_size);
+	
+	ipc_answer_1(iid, EOK, accepted_size);
+	
+	free(trans->buffer);
+	free(trans);
+}
+
+
+/** Connection handler for communcation with host.
+ * By host is typically meant top-level USB driver.
+ *
+ * This function also takes care of proper phone hung-up.
+ *
+ * @param phone_hash Incoming phone hash.
+ */
+void connection_handler_host(ipcarg_t phone_hash)
+{
+	dprintf(0, "host connected through phone %#x", phone_hash);
+	
+	
+	while (true) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+		
+		callid = async_get_call(&call);
+		
+		dprintf(6, "host on %#x calls [%x: %u (%u, %u, %u, %u, %u)]",
+		    phone_hash,
+		    callid,
+		    IPC_GET_METHOD(call),
+		    IPC_GET_ARG1(call), IPC_GET_ARG2(call), IPC_GET_ARG3(call),
+		    IPC_GET_ARG4(call), IPC_GET_ARG5(call));
+		
+		switch (IPC_GET_METHOD(call)) {
+
+			/* standard IPC methods */
+
+			case IPC_M_PHONE_HUNGUP:
+				ipc_answer_0(callid, EOK);
+				dprintf(0, "phone%#x: host hung-up",
+				    phone_hash);
+				return;
+			
+			case IPC_M_CONNECT_TO_ME:
+				ipc_answer_0(callid, ELIMIT);
+				break;
+			
+
+			/* USB methods */
+
+			case IPC_M_USB_HCD_TRANSACTION_SIZE:
+				ipc_answer_1(callid, EOK, USB_MAX_PAYLOAD_SIZE);
+				break;
+			
+			case IPC_M_USB_HCD_GET_BUFFER_ASYNC:
+				async_get_buffer(callid, call);
+				break;
+	
+			case IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC:
+				async_to_device(callid, call, false);
+				break;
+			
+			case IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC:
+				async_to_device(callid, call, true);
+				break;
+			
+			case IPC_M_USB_HCD_INTERRUPT_IN_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC:
+			case IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC:
+				async_from_device(callid, call);
+				break;
+			
+
+			/* end of known methods */
+			
+			default:
+				dprintf_inval_call(2, call, phone_hash);
+				ipc_answer_0(callid, EINVAL);
+				break;
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/debug.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/debug.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/debug.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,78 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Debugging support.
+ */
+#include <stdio.h>
+#include <ipc/ipc.h>
+
+#include "vhcd.h"
+
+/** Current debug level. */
+int debug_level = 0;
+
+/** Debugging printf.
+ * This function is intended for single-line messages as it
+ * automatically prints debugging prefix at the beginning of the
+ * line.
+ *
+ * @see printf
+ * @param level Debugging level.
+ */
+void dprintf(int level, const char *format, ...)
+{
+	if (level > debug_level) {
+		return;
+	}
+	
+	printf("%s(%d): ", NAME, level);
+	va_list args;
+	va_start(args, format);
+	vprintf(format, args);
+	va_end(args);
+	printf("\n");
+}
+
+/** Debug print informing of invalid call.
+ */
+void dprintf_inval_call(int level, ipc_call_t call, ipcarg_t phone_hash)
+{
+	dprintf(level, "phone%#x: invalid call [%u (%u, %u, %u, %u, %u)]",
+	    phone_hash,
+	    IPC_GET_METHOD(call),
+	    IPC_GET_ARG1(call), IPC_GET_ARG2(call), IPC_GET_ARG3(call),
+	    IPC_GET_ARG4(call), IPC_GET_ARG5(call));
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/devices.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/devices.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/devices.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,186 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual device management (implementation).
+ */
+
+#include <ipc/ipc.h>
+#include <adt/list.h>
+#include <bool.h>
+#include <async.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usbvirt/hub.h>
+
+#include "devices.h"
+#include "hub.h"
+#include "vhcd.h"
+
+#define list_foreach(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next)
+
+LIST_INITIALIZE(devices);
+
+/** Create virtual device.
+ *
+ * @param address USB address.
+ * @param phone Callback phone.
+ * @return New device.
+ * @retval NULL Out of memory or address already occupied.
+ */
+virtdev_connection_t *virtdev_add_device(int phone)
+{
+	virtdev_connection_t *dev = (virtdev_connection_t *)
+	    malloc(sizeof(virtdev_connection_t));
+	dev->phone = phone;
+	list_append(&dev->link, &devices);
+	
+	hub_add_device(dev);
+	
+	return dev;
+}
+
+/** Destroy virtual device.
+ */
+void virtdev_destroy_device(virtdev_connection_t *dev)
+{
+	hub_remove_device(dev);
+	list_remove(&dev->link);
+	free(dev);
+}
+
+/** Send data to all connected devices.
+ *
+ * @param transaction Transaction to be sent over the bus.
+ */
+usb_transaction_outcome_t virtdev_send_to_all(transaction_t *transaction)
+{
+	link_t *pos;
+	list_foreach(pos, &devices) {
+		virtdev_connection_t *dev
+		    = list_get_instance(pos, virtdev_connection_t, link);
+		
+		if (!hub_can_device_signal(dev)) {
+			continue;
+		}
+		
+		ipc_call_t answer_data;
+		ipcarg_t answer_rc;
+		aid_t req;
+		int rc = EOK;
+		int method = IPC_M_USBVIRT_TRANSACTION_SETUP;
+		
+		switch (transaction->type) {
+			case USBVIRT_TRANSACTION_SETUP:
+				method = IPC_M_USBVIRT_TRANSACTION_SETUP;
+				break;
+			case USBVIRT_TRANSACTION_IN:
+				method = IPC_M_USBVIRT_TRANSACTION_IN;
+				break;
+			case USBVIRT_TRANSACTION_OUT:
+				method = IPC_M_USBVIRT_TRANSACTION_OUT;
+				break;
+		}
+		
+		req = async_send_3(dev->phone,
+		    method,
+		    transaction->target.address,
+		    transaction->target.endpoint,
+		    transaction->len,
+		    &answer_data);
+		
+		if (transaction->len > 0) {
+			if (transaction->type == USBVIRT_TRANSACTION_IN) {
+				rc = async_data_read_start(dev->phone,
+				    transaction->buffer, transaction->len);
+			} else {
+				rc = async_data_write_start(dev->phone,
+				    transaction->buffer, transaction->len);
+			}
+		}
+		
+		if (rc != EOK) {
+			async_wait_for(req, NULL);
+		} else {
+			async_wait_for(req, &answer_rc);
+			rc = (int)answer_rc;
+		}
+	}
+	
+	/*
+	 * Send the data to the virtual hub as well
+	 * (if the address matches).
+	 */
+	if (virthub_dev.address == transaction->target.address) {
+		size_t tmp;
+		dprintf(3, "sending `%s' transaction to hub",
+		    usbvirt_str_transaction_type(transaction->type));
+		switch (transaction->type) {
+			case USBVIRT_TRANSACTION_SETUP:
+				virthub_dev.transaction_setup(&virthub_dev,
+				    transaction->target.endpoint,
+				    transaction->buffer, transaction->len);
+				break;
+				
+			case USBVIRT_TRANSACTION_IN:
+				virthub_dev.transaction_in(&virthub_dev,
+				    transaction->target.endpoint,
+				    transaction->buffer, transaction->len,
+				    &tmp);
+				if (tmp < transaction->len) {
+					transaction->len = tmp;
+				}
+				break;
+				
+			case USBVIRT_TRANSACTION_OUT:
+				virthub_dev.transaction_out(&virthub_dev,
+				    transaction->target.endpoint,
+				    transaction->buffer, transaction->len);
+				break;
+		}
+		dprintf(4, "transaction on hub processed...");
+	}
+	
+	/*
+	 * TODO: maybe screw some transactions to get more
+	 * real-life image.
+	 */
+	return USB_OUTCOME_OK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/devices.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/devices.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/devices.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,58 @@
+/*
+ * 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 usb
+ * @{
+ */ 
+/** @file
+ * @brief Virtual device management.
+ */
+#ifndef VHCD_DEVICES_H_
+#define VHCD_DEVICES_H_
+
+#include <adt/list.h>
+#include <usb/hcd.h>
+
+#include "hc.h"
+
+/** Connected virtual device. */
+typedef struct {
+	/** Phone used when sending data to device. */
+	int phone;
+	/** Linked-list handle. */
+	link_t link;
+} virtdev_connection_t;
+
+virtdev_connection_t *virtdev_add_device(int);
+void virtdev_destroy_device(virtdev_connection_t *);
+usb_transaction_outcome_t virtdev_send_to_all(transaction_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hc.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hc.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hc.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,186 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual HC (implementation).
+ */
+
+#include <ipc/ipc.h>
+#include <adt/list.h>
+#include <bool.h>
+#include <async.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usbvirt/hub.h>
+
+#include "vhcd.h"
+#include "hc.h"
+#include "devices.h"
+#include "hub.h"
+
+#define USLEEP_BASE (500 * 1000)
+
+#define USLEEP_VAR 5000
+
+#define SHORTENING_VAR 15
+
+#define PROB_OUTCOME_BABBLE 5
+#define PROB_OUTCOME_CRCERROR 7
+
+#define PROB_TEST(var, new_value, prob, number) \
+	do { \
+		if (((number) % (prob)) == 0) { \
+			var = (new_value); \
+		} \
+	} while (0)
+
+static link_t transaction_list;
+
+#define TRANSACTION_FORMAT "T[%d:%d %s (%d)]"
+#define TRANSACTION_PRINTF(t) \
+	(t).target.address, (t).target.endpoint, \
+	usbvirt_str_transaction_type((t).type), \
+	(int)(t).len
+
+#define transaction_get_instance(lnk) \
+	list_get_instance(lnk, transaction_t, link)
+
+static inline unsigned int pseudo_random(unsigned int *seed)
+{
+	*seed = ((*seed) * 873511) % 22348977 + 7;
+	return ((*seed) >> 8);
+}
+
+/** Call transaction callback.
+ * Calling this callback informs the backend that transaction was processed.
+ */
+static void process_transaction_with_outcome(transaction_t * transaction,
+    usb_transaction_outcome_t outcome)
+{
+	dprintf(3, "processing transaction " TRANSACTION_FORMAT ", outcome: %s",
+	    TRANSACTION_PRINTF(*transaction),
+	    usb_str_transaction_outcome(outcome));
+	
+	transaction->callback(transaction->buffer, transaction->len, outcome,
+	    transaction->callback_arg);
+}
+
+/** Host controller manager main function.
+ */
+void hc_manager(void)
+{
+	list_initialize(&transaction_list);
+	
+	static unsigned int seed = 4573;
+	
+	printf("%s: transaction processor ready.\n", NAME);
+	
+	while (true) {
+		async_usleep(USLEEP_BASE + (pseudo_random(&seed) % USLEEP_VAR));
+		
+		if (list_empty(&transaction_list)) {
+			continue;
+		}
+		
+		char ports[HUB_PORT_COUNT + 2];
+		hub_get_port_statuses(ports, HUB_PORT_COUNT + 1);
+		dprintf(3, "virtual hub: addr=%d ports=%s",
+		    virthub_dev.address, ports);
+		
+		link_t *first_transaction_link = transaction_list.next;
+		transaction_t *transaction
+		    = transaction_get_instance(first_transaction_link);
+		list_remove(first_transaction_link);
+		
+		dprintf(3, "processing transaction " TRANSACTION_FORMAT "",
+		    TRANSACTION_PRINTF(*transaction));
+		
+		usb_transaction_outcome_t outcome;
+		outcome = virtdev_send_to_all(transaction);
+		
+		process_transaction_with_outcome(transaction, outcome);
+		
+		free(transaction);
+	}
+}
+
+/** Create new transaction
+ */
+static transaction_t *transaction_create(usbvirt_transaction_type_t type,
+    usb_target_t target,
+    void * buffer, size_t len,
+    hc_transaction_done_callback_t callback, void * arg)
+{
+	transaction_t * transaction = malloc(sizeof(transaction_t));
+	
+	list_initialize(&transaction->link);
+	transaction->type = type;
+	transaction->target = target;
+	transaction->buffer = buffer;
+	transaction->len = len;
+	transaction->callback = callback;
+	transaction->callback_arg = arg;
+	
+	dprintf(1, "creating transaction " TRANSACTION_FORMAT,
+	    TRANSACTION_PRINTF(*transaction));
+	
+	return transaction;
+}
+
+/** Add transaction directioned towards the device.
+ */
+void hc_add_transaction_to_device(bool setup, usb_target_t target,
+    void * buffer, size_t len,
+    hc_transaction_done_callback_t callback, void * arg)
+{
+	transaction_t *transaction = transaction_create(
+	    setup ? USBVIRT_TRANSACTION_SETUP : USBVIRT_TRANSACTION_OUT, target,
+	    buffer, len, callback, arg);
+	list_append(&transaction->link, &transaction_list);
+}
+
+/** Add transaction directioned from the device.
+ */
+void hc_add_transaction_from_device(usb_target_t target,
+    void * buffer, size_t len,
+    hc_transaction_done_callback_t callback, void * arg)
+{
+	transaction_t *transaction = transaction_create(USBVIRT_TRANSACTION_IN,
+	    target, buffer, len, callback, arg);
+	list_append(&transaction->link, &transaction_list);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hc.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hc.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hc.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,87 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual HC.
+ */
+#ifndef VHCD_HC_H_
+#define VHCD_HC_H_
+
+#include <usb/hcd.h>
+#include <usbvirt/hub.h>
+
+/** Callback after transaction is sent to USB.
+ *
+ * @param buffer Transaction data buffer.
+ * @param size Transaction data size.
+ * @param outcome Transaction outcome.
+ * @param arg Custom argument.
+ */
+typedef void (*hc_transaction_done_callback_t)(void *buffer, size_t size,
+    usb_transaction_outcome_t outcome, void *arg);
+
+/** Pending transaction details. */
+typedef struct {
+	/** Linked-list link. */
+	link_t link;
+	/** Transaction type. */
+	usbvirt_transaction_type_t type;
+	/** Device address. */
+	usb_target_t target;
+	/** Direction of the transaction. */
+	usb_direction_t direction;
+	/** Transaction data buffer. */
+	void * buffer;
+	/** Transaction data length. */
+	size_t len;
+	/** Callback after transaction is done. */
+	hc_transaction_done_callback_t callback;
+	/** Argument to the callback. */
+	void * callback_arg;
+} transaction_t;
+
+void hc_manager(void);
+
+void hc_add_transaction_to_device(bool setup, usb_target_t target,
+    void * buffer, size_t len,
+    hc_transaction_done_callback_t callback, void * arg);
+
+void hc_add_transaction_from_device(usb_target_t target,
+    void * buffer, size_t len,
+    hc_transaction_done_callback_t callback, void * arg);
+
+int hc_fillin_transaction_from_device(usb_target_t target,
+    void * buffer, size_t len);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hcd.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hcd.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hcd.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,172 @@
+/*
+ * 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 usb
+ * @{
+ */ 
+/** @file
+ * @brief Virtual host controller driver.
+ */
+
+#include <devmap.h>
+#include <ipc/ipc.h>
+#include <async.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sysinfo.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/hcd.h>
+#include "vhcd.h"
+#include "hc.h"
+#include "devices.h"
+#include "hub.h"
+#include "conn.h"
+
+
+static dev_handle_t handle_virtual_device;
+static dev_handle_t handle_host_driver;
+
+static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipcarg_t phone_hash = icall->in_phone_hash;
+	dev_handle_t handle = (dev_handle_t)IPC_GET_ARG1(*icall);
+	
+	if (handle == handle_host_driver) {
+		/*
+		 * We can connect host controller driver immediately.
+		 */
+		ipc_answer_0(iid, EOK);
+		connection_handler_host(phone_hash);
+	} else if (handle == handle_virtual_device) {
+		ipc_answer_0(iid, EOK);
+
+		while (true) {
+			/*
+			 * We need to wait for callback request to allow
+			 * connection of virtual device.
+			 */
+			ipc_callid_t callid;
+			ipc_call_t call;
+
+			callid = async_get_call(&call);
+
+			/*
+			 * We can do nothing until we have the callback phone.
+			 * Thus, we will wait for the callback and start processing
+			 * after that.
+			 */
+			int method = (int) IPC_GET_METHOD(call);
+
+			if (method == IPC_M_PHONE_HUNGUP) {
+				ipc_answer_0(callid, EOK);
+				return;
+			}
+
+			if (method == IPC_M_CONNECT_TO_ME) {
+				int callback = IPC_GET_ARG5(call);
+				virtdev_connection_t *dev
+				    = virtdev_add_device(callback);
+				if (!dev) {
+					ipc_answer_0(callid, EEXISTS);
+					ipc_hangup(callback);
+					return;
+				}
+				ipc_answer_0(callid, EOK);
+				connection_handler_device(phone_hash, dev);
+				virtdev_destroy_device(dev);
+				return;
+			}
+
+			/*
+			 * No other methods could be served now.
+			 */
+			dprintf_inval_call(1, call, phone_hash);
+			ipc_answer_0(callid, ENOTSUP);
+		}
+	} else {
+		/*
+		 * Hmmm, someone else just tried to connect to us.
+		 * Kick him out ;-).
+		 */
+		ipc_answer_0(iid, ENOTSUP);
+		return;
+	}
+}
+
+int main(int argc, char * argv[])
+{	
+	printf("%s: virtual USB host controller driver.\n", NAME);
+	
+	int i;
+	for (i = 1; i < argc; i++) {
+		if (str_cmp(argv[i], "-d") == 0) {
+			debug_level++;
+		}
+	}
+	
+	int rc;
+	
+	rc = devmap_driver_register(NAME, client_connection); 
+	if (rc != EOK) {
+		printf("%s: unable to register driver (%s).\n",
+		    NAME, str_error(rc));
+		return 1;
+	}
+
+	rc = devmap_device_register(DEVMAP_PATH_HC, &handle_host_driver);
+	if (rc != EOK) {
+		printf("%s: unable to register device %s (%s).\n",
+		    NAME, DEVMAP_PATH_HC, str_error(rc));
+		return 1;
+	}
+	
+	rc = devmap_device_register(DEVMAP_PATH_DEV, &handle_virtual_device);
+	if (rc != EOK) {
+		printf("%s: unable to register device %s (%s).\n",
+		    NAME, DEVMAP_PATH_DEV, str_error(rc));
+		return 1;
+	}
+
+	hub_init();
+	
+	printf("%s: accepting connections [debug=%d]\n", NAME, debug_level);
+	printf("%s:  -> host controller at %s\n", NAME, DEVMAP_PATH_HC);
+	printf("%s:  -> virtual hub at %s\n", NAME, DEVMAP_PATH_DEV);
+
+	hc_manager();
+	
+	return 0;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hub.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hub.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hub.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub.
+ */
+#include <usb/classes.h>
+#include <usbvirt/hub.h>
+#include <usbvirt/device.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "vhcd.h"
+#include "hub.h"
+#include "hubintern.h"
+
+
+/** Standard device descriptor. */
+usb_standard_device_descriptor_t std_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_HUB,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+/** Standard interface descriptor. */
+usb_standard_interface_descriptor_t std_interface_descriptor = {
+	.length = sizeof(usb_standard_interface_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_INTERFACE,
+	.interface_number = 0,
+	.alternate_setting = 0,
+	.endpoint_count = 1,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.str_interface = 0
+};
+
+hub_descriptor_t hub_descriptor = {
+	.length = sizeof(hub_descriptor_t),
+	.type = USB_DESCTYPE_HUB,
+	.port_count = HUB_PORT_COUNT,
+	.characteristics = 0, 
+	.power_on_warm_up = 50, /* Huh? */
+	.max_current = 100, /* Huh again. */
+	.removable_device = { 0 },
+	.port_power = { 0xFF }
+};
+
+/** Endpoint descriptor. */
+usb_standard_endpoint_descriptor_t endpoint_descriptor = {
+	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_ENDPOINT,
+	.endpoint_address = HUB_STATUS_CHANGE_PIPE | 128,
+	.attributes = USB_TRANSFER_INTERRUPT,
+	.max_packet_size = 8,
+	.poll_interval = 0xFF
+};
+
+/** Standard configuration descriptor. */
+usb_standard_configuration_descriptor_t std_configuration_descriptor = {
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	.total_length = 
+		sizeof(usb_standard_configuration_descriptor_t)
+		+ sizeof(std_interface_descriptor)
+		+ sizeof(hub_descriptor)
+		+ sizeof(endpoint_descriptor)
+		,
+	.interface_count = 1,
+	.configuration_number = HUB_CONFIGURATION_ID,
+	.str_configuration = 0,
+	.attributes = 128, /* denotes bus-powered device */
+	.max_power = 50
+};
+
+/** All hub configuration descriptors. */
+static usbvirt_device_configuration_extras_t extra_descriptors[] = {
+	{
+		.data = (uint8_t *) &std_interface_descriptor,
+		.length = sizeof(std_interface_descriptor)
+	},
+	{
+		.data = (uint8_t *) &hub_descriptor,
+		.length = sizeof(hub_descriptor)
+	},
+	{
+		.data = (uint8_t *) &endpoint_descriptor,
+		.length = sizeof(endpoint_descriptor)
+	}
+};
+
+/** Hub configuration. */
+usbvirt_device_configuration_t configuration = {
+	.descriptor = &std_configuration_descriptor,
+	.extra = extra_descriptors,
+	.extra_count = sizeof(extra_descriptors)/sizeof(extra_descriptors[0])
+};
+
+/** Hub standard descriptors. */
+usbvirt_descriptors_t descriptors = {
+	.device = &std_device_descriptor,
+	.configuration = &configuration,
+	.configuration_count = 1,
+};
+
+/** Hub as a virtual device. */
+usbvirt_device_t virthub_dev = {
+	.ops = &hub_ops,
+	.descriptors = &descriptors,
+	.lib_debug_level = 4,
+	.lib_debug_enabled_tags = USBVIRT_DEBUGTAG_ALL
+};
+
+/** Hub device. */
+hub_device_t hub_dev;
+
+/** Initialize virtual hub. */
+void hub_init(void)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub_dev.ports[i];
+		
+		port->device = NULL;
+		port->state = HUB_PORT_STATE_NOT_CONFIGURED;
+		port->status_change = 0;
+	}
+	
+	usbvirt_connect_local(&virthub_dev);
+	
+	dprintf(1, "virtual hub (%d ports) created", HUB_PORT_COUNT);
+}
+
+/** Connect device to the hub.
+ *
+ * @param device Device to be connected.
+ * @return Port where the device was connected to.
+ */
+size_t hub_add_device(virtdev_connection_t *device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub_dev.ports[i];
+		
+		if (port->device != NULL) {
+			continue;
+		}
+		
+		port->device = device;
+		
+		/*
+		 * TODO:
+		 * If the hub was configured, we can normally
+		 * announce the plug-in.
+		 * Otherwise, we will wait until hub is configured
+		 * and announce changes in single burst.
+		 */
+		//if (port->state == HUB_PORT_STATE_DISCONNECTED) {
+			port->state = HUB_PORT_STATE_DISABLED;
+			set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+		//}
+		
+		return i;
+	}
+	
+	return (size_t)-1;
+}
+
+/** Disconnect device from the hub. */
+void hub_remove_device(virtdev_connection_t *device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub_dev.ports[i];
+		
+		if (port->device != device) {
+			continue;
+		}
+		
+		port->device = NULL;
+		port->state = HUB_PORT_STATE_DISCONNECTED;
+		
+		set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+	}
+}
+
+/** Tell whether device port is open.
+ *
+ * @return Whether communication to and from the device can go through the hub.
+ */
+bool hub_can_device_signal(virtdev_connection_t * device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		if (hub_dev.ports[i].device == device) {
+			return hub_dev.ports[i].state == HUB_PORT_STATE_ENABLED;
+		}
+	}
+	
+	return false;
+}
+
+/** Format hub port status.
+ *
+ * @param result Buffer where to store status string.
+ * @param len Number of characters that is possible to store in @p result
+ * 	(excluding trailing zero).
+ */
+void hub_get_port_statuses(char *result, size_t len)
+{
+	if (len > HUB_PORT_COUNT) {
+		len = HUB_PORT_COUNT;
+	}
+	size_t i;
+	for (i = 0; i < len; i++) {
+		result[i] = hub_port_state_as_char(hub_dev.ports[i].state);
+	}
+	result[len] = 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hub.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hub.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hub.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,58 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub.
+ */
+#ifndef VHCD_HUB_H_
+#define VHCD_HUB_H_
+
+#include <usbvirt/device.h>
+
+#include "devices.h"
+
+#define HUB_PORT_COUNT 6
+
+#define BITS2BYTES(bits) \
+    (bits ? ((((bits)-1)>>3)+1) : 0)
+
+extern usbvirt_device_t virthub_dev;
+
+void hub_init(void);
+size_t hub_add_device(virtdev_connection_t *);
+void hub_remove_device(virtdev_connection_t *);
+bool hub_can_device_signal(virtdev_connection_t *);
+void hub_get_port_statuses(char *result, size_t len);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hubintern.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hubintern.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hubintern.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,145 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief
+ */
+#ifndef VHCD_HUBINTERN_H_
+#define VHCD_HUBINTERN_H_
+
+#include "hub.h"
+
+/** Endpoint number for status change pipe. */
+#define HUB_STATUS_CHANGE_PIPE 1
+/** Configuration value for hub configuration. */
+#define HUB_CONFIGURATION_ID 1
+
+/** Hub descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_HUB). */
+	uint8_t type;
+	/** Number of downstream ports. */
+	uint8_t port_count;
+	/** Hub characteristics. */
+	uint16_t characteristics;
+	/** Time from power-on to stabilized current.
+	 * Expressed in 2ms unit.
+	 */
+	uint8_t power_on_warm_up;
+	/** Maximum current (in mA). */
+	uint8_t max_current;
+	/** Whether device at given port is removable. */
+	uint8_t removable_device[BITS2BYTES(HUB_PORT_COUNT+1)];
+	/** Port power control.
+	 * This is USB1.0 compatibility field, all bits must be 1.
+	 */
+	uint8_t port_power[BITS2BYTES(HUB_PORT_COUNT+1)];
+} __attribute__ ((packed)) hub_descriptor_t;
+
+/** Hub port internal state.
+ * Some states (e.g. port over current) are not covered as they are not
+ * simulated at all.
+ */
+typedef enum {
+	HUB_PORT_STATE_NOT_CONFIGURED,
+	HUB_PORT_STATE_POWERED_OFF,
+	HUB_PORT_STATE_DISCONNECTED,
+	HUB_PORT_STATE_DISABLED,
+	HUB_PORT_STATE_RESETTING,
+	HUB_PORT_STATE_ENABLED,
+	HUB_PORT_STATE_SUSPENDED,
+	HUB_PORT_STATE_RESUMING,
+	/* HUB_PORT_STATE_, */
+} hub_port_state_t;
+
+/** Convert hub port state to a char. */
+static inline char hub_port_state_as_char(hub_port_state_t state) {
+	switch (state) {
+		case HUB_PORT_STATE_NOT_CONFIGURED:
+			return '-';
+		case HUB_PORT_STATE_POWERED_OFF:
+			return 'O';
+		case HUB_PORT_STATE_DISCONNECTED:
+			return 'X';
+		case HUB_PORT_STATE_DISABLED:
+			return 'D';
+		case HUB_PORT_STATE_RESETTING:
+			return 'R';
+		case HUB_PORT_STATE_ENABLED:
+			return 'E';
+		case HUB_PORT_STATE_SUSPENDED:
+			return 'S';
+		case HUB_PORT_STATE_RESUMING:
+			return 'F';
+		default:
+			return '?';
+	}
+}
+
+/** Hub status change mask bits. */
+typedef enum {
+	HUB_STATUS_C_PORT_CONNECTION = (1 << 0),
+	HUB_STATUS_C_PORT_ENABLE = (1 << 1),
+	HUB_STATUS_C_PORT_SUSPEND = (1 << 2),
+	HUB_STATUS_C_PORT_OVER_CURRENT = (1 << 3),
+	HUB_STATUS_C_PORT_RESET = (1 << 4),
+	/* HUB_STATUS_C_ = (1 << ), */
+} hub_status_change_t;
+
+/** Hub port information. */
+typedef struct {
+	virtdev_connection_t *device;
+	hub_port_state_t state;
+	uint16_t status_change;
+} hub_port_t;
+
+/** Hub device type. */
+typedef struct {
+	hub_port_t ports[HUB_PORT_COUNT];
+} hub_device_t;
+
+extern hub_device_t hub_dev;
+
+extern hub_descriptor_t hub_descriptor;
+
+extern usbvirt_device_ops_t hub_ops;
+
+void clear_port_status_change(hub_port_t *, uint16_t);
+void set_port_status_change(hub_port_t *, uint16_t);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/hubops.c
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/hubops.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/hubops.c	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,384 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub operations.
+ */
+#include <usb/classes.h>
+#include <usb/hub.h>
+#include <usbvirt/hub.h>
+#include <usbvirt/device.h>
+#include <errno.h>
+
+#include "vhcd.h"
+#include "hub.h"
+#include "hubintern.h"
+
+/** Produce a byte from bit values.
+ */
+#define MAKE_BYTE(b0, b1, b2, b3, b4, b5, b6, b7) \
+	(( \
+		((b0) << 0) \
+		| ((b1) << 1) \
+		| ((b2) << 2) \
+		| ((b3) << 3) \
+		| ((b4) << 4) \
+		| ((b5) << 5) \
+		| ((b6) << 6) \
+		| ((b7) << 7) \
+	))
+
+static int on_get_descriptor(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data);
+static int on_class_request(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data);
+static int on_data_request(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *actual_size);
+
+/** Standard USB requests. */
+static usbvirt_standard_device_request_ops_t standard_request_ops = {
+	.on_get_status = NULL,
+	.on_clear_feature = NULL,
+	.on_set_feature = NULL,
+	.on_set_address = NULL,
+	.on_get_descriptor = on_get_descriptor,
+	.on_set_descriptor = NULL,
+	.on_get_configuration = NULL,
+	.on_set_configuration = NULL,
+	.on_get_interface = NULL,
+	.on_set_interface = NULL,
+	.on_synch_frame = NULL
+};
+
+/** Hub operations. */
+usbvirt_device_ops_t hub_ops = {
+	.standard_request_ops = &standard_request_ops,
+	.on_class_device_request = on_class_request,
+	.on_data = NULL,
+	.on_data_request = on_data_request
+};
+
+/** Callback for GET_DESCRIPTOR request. */
+static int on_get_descriptor(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data)
+{
+	if (request->value_high == USB_DESCTYPE_HUB) {
+		int rc = dev->control_transfer_reply(dev, 0,
+		    &hub_descriptor, hub_descriptor.length);
+		
+		return rc;
+	}
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+/** Change port status and updates status change status fields.
+ */
+static void set_port_state(hub_port_t *port, hub_port_state_t state)
+{
+	port->state = state;
+	if (state == HUB_PORT_STATE_POWERED_OFF) {
+		clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+		clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
+		clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
+	}
+	if (state == HUB_PORT_STATE_RESUMING) {
+		async_usleep(10*1000);
+		if (port->state == state) {
+			set_port_state(port, HUB_PORT_STATE_ENABLED);
+		}
+	}
+	if (state == HUB_PORT_STATE_RESETTING) {
+		async_usleep(10*1000);
+		if (port->state == state) {
+			set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
+			set_port_state(port, HUB_PORT_STATE_ENABLED);
+		}
+	}
+}
+
+/** Get access to a port or return with EINVAL. */
+#define _GET_PORT(portvar, index) \
+	do { \
+		if (virthub_dev.state != USBVIRT_STATE_CONFIGURED) { \
+			return EINVAL; \
+		} \
+		if (((index) == 0) || ((index) > HUB_PORT_COUNT)) { \
+			return EINVAL; \
+		} \
+	} while (false); \
+	hub_port_t *portvar = &hub_dev.ports[index]
+
+
+static int clear_hub_feature(uint16_t feature)
+{
+	return ENOTSUP;
+}
+
+static int clear_port_feature(uint16_t feature, uint16_t portindex)
+{	
+	_GET_PORT(port, portindex);
+	
+	switch (feature) {
+		case USB_HUB_FEATURE_PORT_ENABLE:
+			if ((port->state != HUB_PORT_STATE_NOT_CONFIGURED)
+			    && (port->state != HUB_PORT_STATE_POWERED_OFF)) {
+				set_port_state(port, HUB_PORT_STATE_DISABLED);
+			}
+			return EOK;
+		
+		case USB_HUB_FEATURE_PORT_SUSPEND:
+			if (port->state != HUB_PORT_STATE_SUSPENDED) {
+				return EOK;
+			}
+			set_port_state(port, HUB_PORT_STATE_RESUMING);
+			return EOK;
+			
+		case USB_HUB_FEATURE_PORT_POWER:
+			if (port->state != HUB_PORT_STATE_NOT_CONFIGURED) {
+				set_port_state(port, HUB_PORT_STATE_POWERED_OFF);
+			}
+			return EOK;
+		
+		case USB_HUB_FEATURE_C_PORT_CONNECTION:
+			clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+			return EOK;
+		
+		case USB_HUB_FEATURE_C_PORT_ENABLE:
+			clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
+			return EOK;
+		
+		case USB_HUB_FEATURE_C_PORT_SUSPEND:
+			clear_port_status_change(port, HUB_STATUS_C_PORT_SUSPEND);
+			return EOK;
+			
+		case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
+			clear_port_status_change(port, HUB_STATUS_C_PORT_OVER_CURRENT);
+			return EOK;
+	}
+	
+	return ENOTSUP;
+}
+
+static int get_bus_state(uint16_t portindex)
+{
+	return ENOTSUP;
+}
+
+static int get_hub_descriptor(uint8_t descriptor_type,
+    uint8_t descriptor_index, uint16_t length)
+{
+	return ENOTSUP;
+}
+
+static int get_hub_status(void)
+{
+	uint32_t hub_status = 0;
+	
+	return virthub_dev.control_transfer_reply(&virthub_dev, 0,
+	    &hub_status, 4);
+}
+
+static int get_port_status(uint16_t portindex)
+{
+	_GET_PORT(port, portindex);
+	
+	uint32_t status;
+	status = MAKE_BYTE(
+	    /* Current connect status. */
+	    port->device == NULL ? 0 : 1,
+	    /* Port enabled/disabled. */
+	    port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
+	    /* Suspend. */
+	    (port->state == HUB_PORT_STATE_SUSPENDED)
+	        || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
+	    /* Over-current. */
+	    0,
+	    /* Reset. */
+	    port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
+	    /* Reserved. */
+	    0, 0, 0)
+	    
+	    | (MAKE_BYTE(
+	    /* Port power. */
+	    port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
+	    /* Full-speed device. */
+	    0,
+	    /* Reserved. */
+	    0, 0, 0, 0, 0, 0
+	    )) << 8;
+	    
+	status |= (port->status_change << 16);
+	
+	return virthub_dev.control_transfer_reply(&virthub_dev, 0, &status, 4);
+}
+
+
+static int set_hub_feature(uint16_t feature)
+{
+	return ENOTSUP;
+}
+
+static int set_port_feature(uint16_t feature, uint16_t portindex)
+{
+	_GET_PORT(port, portindex);
+	
+	switch (feature) {
+		case USB_HUB_FEATURE_PORT_RESET:
+			if (port->state != HUB_PORT_STATE_POWERED_OFF) {
+				set_port_state(port, HUB_PORT_STATE_RESETTING);
+			}
+			return EOK;
+		
+		case USB_HUB_FEATURE_PORT_SUSPEND:
+			if (port->state == HUB_PORT_STATE_ENABLED) {
+				set_port_state(port, HUB_PORT_STATE_SUSPENDED);
+			}
+			return EOK;
+		
+		case USB_HUB_FEATURE_PORT_POWER:
+			if (port->state == HUB_PORT_STATE_POWERED_OFF) {
+				set_port_state(port, HUB_PORT_STATE_DISCONNECTED);
+			}
+			return EOK;
+	}
+	return ENOTSUP;
+}
+
+#undef _GET_PORT
+
+
+/** Callback for class request. */
+static int on_class_request(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data)
+{	
+	dprintf(2, "hub class request (%d)\n", (int) request->request);
+	
+	uint8_t recipient = request->request_type & 31;
+	uint8_t direction = request->request_type >> 7;
+	
+#define _VERIFY(cond) \
+	do { \
+		if (!(cond)) { \
+			dprintf(0, "WARN: invalid class request (%s not met).\n", \
+			    NAME, #cond); \
+			return EINVAL; \
+		} \
+	} while (0)
+	
+	switch (request->request) {
+		case USB_HUB_REQUEST_CLEAR_FEATURE:
+			_VERIFY(direction == 0);
+			_VERIFY(request->length == 0);
+			if (recipient == 0) {
+				_VERIFY(request->index == 0);
+				return clear_hub_feature(request->value);
+			} else {
+				_VERIFY(recipient == 3);
+				return clear_port_feature(request->value,
+				    request->index);
+			}
+			
+		case USB_HUB_REQUEST_GET_STATE:
+			return get_bus_state(request->index);
+			
+		case USB_HUB_REQUEST_GET_DESCRIPTOR:
+			return get_hub_descriptor(request->value_low,
+			    request->value_high, request->length);
+			
+		case USB_HUB_REQUEST_GET_STATUS:
+			if (recipient == 0) {
+				return get_hub_status();
+			} else {
+				return get_port_status(request->index);
+			}
+			
+		case USB_HUB_REQUEST_SET_FEATURE:
+			if (recipient == 0) {
+				return set_hub_feature(request->value);
+			} else {
+				return set_port_feature(request->value, request->index);
+			}
+			
+		default:
+			break;
+	}
+	
+#undef _VERIFY	
+
+
+	return EOK;
+}
+
+void clear_port_status_change(hub_port_t *port, uint16_t change)
+{
+	port->status_change &= (~change);
+}
+
+void set_port_status_change(hub_port_t *port, uint16_t change)
+{
+	port->status_change |= change;
+}
+
+/** Callback for data request. */
+static int on_data_request(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	if (endpoint != HUB_STATUS_CHANGE_PIPE) {
+		return EINVAL;
+	}
+	
+	uint8_t change_map = 0;
+	
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub_dev.ports[i];
+		
+		if (port->status_change != 0) {
+			change_map |= (1 << (i + 1));
+		}
+	}
+	
+	uint8_t *b = (uint8_t *) buffer;
+	if (size > 0) {
+		*b = change_map;
+		*actual_size = 1;
+	}
+	
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h
===================================================================
--- uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
+++ uspace/srv/hw/bus/usb/hcd/virtual/vhcd.h	(revision 7494fb489ce735af325ebee50e0e47a2d47e7111)
@@ -0,0 +1,52 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB host controller common definitions.
+ */
+#ifndef VHCD_VHCD_H_
+#define VHCD_VHCD_H_
+
+#define NAME "hcd-virt"
+#define NAME_DEV "hcd-virt-dev"
+#define NAMESPACE "usb"
+
+#define DEVMAP_PATH_HC NAMESPACE "/" NAME
+#define DEVMAP_PATH_DEV NAMESPACE "/" NAME_DEV
+
+extern int debug_level;
+void dprintf(int, const char *, ...);
+void dprintf_inval_call(int, ipc_call_t, ipcarg_t);
+
+#endif
+/**
+ * @}
+ */
