Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/Makefile	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -51,5 +51,4 @@
 	app/top \
 	app/usbinfo \
-	app/virtusbkbd \
 	app/vuhid \
 	app/netecho \
Index: uspace/app/virtusbkbd/Makefile
===================================================================
--- uspace/app/virtusbkbd/Makefile	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,43 +1,0 @@
-#
-# Copyright (c) 2010 Vojtech Horky
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../..
-# acronym for virtual usb keyboard
-# (it is really annoying to write long names)
-BINARY = vuk
-
-LIBS = $(LIBUSBVIRT_PREFIX)/libusbvirt.a $(LIBUSB_PREFIX)/libusb.a
-EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -I$(LIBUSBVIRT_PREFIX)/include -I$(LIBDRV_PREFIX)/include
-
-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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/** @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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,113 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/** @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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,155 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/**
- * @file
- * @brief Keyboard configuration.
- */
-#include "kbdconfig.h"
-#include "keys.h"
-#include <usb/usb.h>
-#include <usb/classes/hid.h>
-#include <usb/classes/hidut.h>
-#include <usb/classes/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 = USB_HID_SUBCLASS_BOOT,
-	.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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,60 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/** @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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,123 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/**
- * @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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,121 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/** @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 6
-
-/** 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/classes/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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,85 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/** @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 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,64 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/**
- * @file
- * @brief Keyboard configuration.
- */
-#include <errno.h>
-#include <usb/descriptor.h>
-#include "stdreq.h"
-#include "kbdconfig.h"
-
-int req_get_descriptor(usbvirt_device_t *device,
-    const usb_device_request_setup_packet_t *setup_packet,
-    uint8_t *data, size_t *act_size)
-{
-	if (setup_packet->value_high == USB_DESCTYPE_HID_REPORT) {
-		/*
-		 * For simplicity, always return the same
-		 * report descriptor.
-		 */
-		usbvirt_control_reply_helper(setup_packet,
-		    data, act_size,
-		    report_descriptor, report_descriptor_size);
-
-		return EOK;
-	}
-	
-	/* Let the framework handle all the rest. */
-	return EFORWARD;
-}
-
-
-
-/** @}
- */
Index: uspace/app/virtusbkbd/stdreq.h
===================================================================
--- uspace/app/virtusbkbd/stdreq.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/** @file
- * @brief Standard device request handlers.
- */
-#ifndef VUK_STDREQ_H_
-#define VUK_STDREQ_H_
-
-#include <usbvirt/device.h>
-
-int req_get_descriptor(usbvirt_device_t *device,
-    const usb_device_request_setup_packet_t *setup_packet,
-    uint8_t *data, size_t *act_size);
-
-#endif
-/**
- * @}
- */
Index: uspace/app/virtusbkbd/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,267 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup usbvirtkbd
- * @{
- */
-/**
- * @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/usb.h>
-#include <usb/descriptor.h>
-#include <usb/classes/hid.h>
-#include <usb/debug.h>
-#include <usbvirt/device.h>
-
-#include "kbdconfig.h"
-#include "keys.h"
-#include "stdreq.h"
-
-/** Pause between individual key-presses in seconds. */
-#define KEY_PRESS_DELAY 2
-#define NAME "virt-usb-kbd"
-
-
-#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;
-
-/** Compares current and last status of pressed keys.
- *
- * @warning Has side-efect - changes status_last field.
- *
- * @param status_now Status now.
- * @param status_last Last status.
- * @param len Size of status.
- * @return Whether they are the same.
- */
-static bool keypress_check_with_last_request(uint8_t *status_now,
-    uint8_t *status_last, size_t len)
-{
-	bool same = true;
-	size_t i;
-	for (i = 0; i < len; i++) {
-		if (status_now[i] != status_last[i]) {
-			status_last[i] = status_now[i];
-			same = false;
-		}
-	}
-	return same;
-}
-
-static int on_request_for_data(usbvirt_device_t *dev,
-    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
-    void *buffer, size_t size, size_t *actual_size)
-{
-	static uint8_t last_data[2 + KB_MAX_KEYS_AT_ONCE];
-
-	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];
-	}
-	
-	if (keypress_check_with_last_request(data, last_data,
-	    2 + KB_MAX_KEYS_AT_ONCE)) {
-		return ENAK;
-	}
-
-	memcpy(buffer, &data, *actual_size);
-	
-	return EOK;
-}
-
-static usbvirt_control_request_handler_t endpoint_zero_handlers[] = {
-	{
-		.req_direction = USB_DIRECTION_IN,
-		.req_type = USB_REQUEST_TYPE_STANDARD,
-		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
-		.request = USB_DEVREQ_GET_DESCRIPTOR,
-		.name = "GetDescriptor",
-		.callback = req_get_descriptor
-	},
-	{
-		.callback = NULL
-	}
-};
-
-/** Keyboard callbacks.
- * We abuse the fact that static variables are zero-filled.
- */
-static usbvirt_device_ops_t keyboard_ops = {
-	.control = endpoint_zero_handlers,
-	.data_in[1] = 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: %02hhx", 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(KEY_PRESS_DELAY);
-}
-
-/** 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 (%zu 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_device_plug(&keyboard_dev, "/virt/usbhc/hc");
-	if (rc != EOK) {
-		printf("%s: Unable to start communication with VHCD (%s).\n",
-		    NAME, str_error(rc));
-		return rc;
-	}
-	
-	printf("%s: Simulating keyboard events...\n", NAME);
-	fibril_sleep(10);
-	//while (1) {
-		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/app/vuhid/device.c
===================================================================
--- uspace/app/vuhid/device.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/app/vuhid/device.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -77,8 +77,14 @@
 {
 	vuhid_interface_t *iface = arg;
+	vuhid_data_t *hid_data = iface->vuhid_data;
 
 	if (iface->live != NULL) {
 		iface->live(iface);
 	}
+
+	fibril_mutex_lock(&hid_data->iface_count_mutex);
+	hid_data->iface_died_count++;
+	fibril_condvar_broadcast(&hid_data->iface_count_cv);
+	fibril_mutex_unlock(&hid_data->iface_count_mutex);
 
 	return EOK;
@@ -110,4 +116,11 @@
 	if ((iface->in_data_size == 0) && (iface->out_data_size == 0)) {
 		return EEMPTY;
+	}
+
+	// FIXME - we shall set vuhid_data to NULL in the main() rather
+	// than to depend on individual interfaces
+	/* Already used interface. */
+	if (iface->vuhid_data != NULL) {
+		return EEXISTS;
 	}
 
@@ -252,4 +265,5 @@
 
 	/* Launch the "life" fibril. */
+	iface->vuhid_data = hid_data;
 	fid_t life_fibril = fibril_create(interface_life_fibril, iface);
 	if (life_fibril == 0) {
@@ -310,4 +324,5 @@
 	    += total_descr_size;
 
+	hid_data->iface_count++;
 	fibril_add_ready(life_fibril);
 
@@ -331,4 +346,15 @@
 }
 
+void wait_for_interfaces_death(usbvirt_device_t *dev)
+{
+	vuhid_data_t *hid_data = dev->device_data;
+
+	fibril_mutex_lock(&hid_data->iface_count_mutex);
+	while (hid_data->iface_died_count < hid_data->iface_count) {
+		fibril_condvar_wait(&hid_data->iface_count_cv,
+		    &hid_data->iface_count_mutex);
+	}
+	fibril_mutex_unlock(&hid_data->iface_count_mutex);
+}
 
 /** @}
Index: uspace/app/vuhid/hids/bootkbd.c
===================================================================
--- uspace/app/vuhid/hids/bootkbd.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/app/vuhid/hids/bootkbd.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -39,5 +39,5 @@
 #include <usb/classes/hidut.h>
 
-#include "../../virtusbkbd/report.h"
+#include "../report.h"
 
 uint8_t report_descriptor[] = {
@@ -169,5 +169,7 @@
 	.on_data_out = on_data_out,
 
-	.live = live
+	.live = live,
+
+	.vuhid_data = NULL
 };
 
Index: uspace/app/vuhid/items.h
===================================================================
--- uspace/app/vuhid/items.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/app/vuhid/items.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -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 usbvirtkbd
+ * @{
+ */
+/** @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/vuhid/main.c
===================================================================
--- uspace/app/vuhid/main.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/app/vuhid/main.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -132,6 +132,11 @@
 	.in_endpoint_first_free = 1,
 	.out_endpoints_mapping = { NULL },
-	.out_endpoint_first_free = 1
-};
+	.out_endpoint_first_free = 1,
+
+	.iface_count = 0,
+	.iface_died_count = 0
+	// mutex and CV must be initialized elsewhere
+};
+
 
 /** Keyboard device.
@@ -151,4 +156,7 @@
 
 	usb_log_enable(USB_LOG_LEVEL_DEBUG2, "vusbhid");
+
+	fibril_mutex_initialize(&vuhid_data.iface_count_mutex);
+	fibril_condvar_initialize(&vuhid_data.iface_count_cv);
 
 	/* Determine which interfaces to initialize. */
@@ -182,10 +190,10 @@
 	printf("Connected to VHCD...\n");
 
-	while (true) {
-		async_usleep(10 * 1000 * 1000);
-	}
+	wait_for_interfaces_death(&hid_dev);
 	
 	printf("Terminating...\n");
 	
+	usbvirt_device_unplug(&hid_dev);
+
 	return 0;
 }
Index: uspace/app/vuhid/report.h
===================================================================
--- uspace/app/vuhid/report.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/app/vuhid/report.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -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 usbvirtkbd
+ * @{
+ */
+/** @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/vuhid/virthid.h
===================================================================
--- uspace/app/vuhid/virthid.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/app/vuhid/virthid.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -38,4 +38,5 @@
 #include <usb/usb.h>
 #include <usbvirt/device.h>
+#include <fibril_synch.h>
 
 #define VUHID_ENDPOINT_MAX USB11_ENDPOINT_MAX
@@ -43,4 +44,17 @@
 
 typedef struct vuhid_interface vuhid_interface_t;
+
+typedef struct {
+	vuhid_interface_t *in_endpoints_mapping[VUHID_ENDPOINT_MAX];
+	size_t in_endpoint_first_free;
+	vuhid_interface_t *out_endpoints_mapping[VUHID_ENDPOINT_MAX];
+	size_t out_endpoint_first_free;
+	vuhid_interface_t *interface_mapping[VUHID_INTERFACE_MAX];
+
+	fibril_mutex_t iface_count_mutex;
+	fibril_condvar_t iface_count_cv;
+	size_t iface_count;
+	size_t iface_died_count;
+} vuhid_data_t;
 
 struct vuhid_interface {
@@ -63,13 +77,7 @@
 
 	void *interface_data;
+
+	vuhid_data_t *vuhid_data;
 };
-
-typedef struct {
-	vuhid_interface_t *in_endpoints_mapping[VUHID_ENDPOINT_MAX];
-	size_t in_endpoint_first_free;
-	vuhid_interface_t *out_endpoints_mapping[VUHID_ENDPOINT_MAX];
-	size_t out_endpoint_first_free;
-	vuhid_interface_t *interface_mapping[VUHID_INTERFACE_MAX];
-} vuhid_data_t;
 
 typedef struct {
@@ -84,4 +92,5 @@
 
 int add_interface_by_id(vuhid_interface_t **, const char *, usbvirt_device_t *);
+void wait_for_interfaces_death(usbvirt_device_t *);
 
 #endif
Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/ohci/hc.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -49,5 +49,4 @@
 static int interrupt_emulator(hc_t *instance);
 static void hc_gain_control(hc_t *instance);
-static void hc_init_hw(hc_t *instance);
 static int hc_init_transfer_lists(hc_t *instance);
 static int hc_init_memory(hc_t *instance);
@@ -92,4 +91,5 @@
 		usb_log_error("Failed add root hub match-id.\n");
 	}
+	ret = ddf_fun_bind(hub_fun);
 	return ret;
 }
@@ -111,4 +111,5 @@
 	    ret, str_error(ret));
 
+	list_initialize(&instance->pending_batches);
 	usb_device_keeper_init(&instance->manager);
 	ret = usb_endpoint_manager_init(&instance->ep_manager,
@@ -117,9 +118,12 @@
 	    str_error(ret));
 
-	hc_gain_control(instance);
 	ret = hc_init_memory(instance);
 	CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures: %s.\n",
 	    str_error(ret));
-	hc_init_hw(instance);
+#undef CHECK_RET_RETURN
+
+
+//	hc_init_hw(instance);
+	hc_gain_control(instance);
 	fibril_mutex_initialize(&instance->guard);
 
@@ -132,6 +136,4 @@
 	}
 
-	list_initialize(&instance->pending_batches);
-#undef CHECK_RET_RETURN
 	return EOK;
 }
@@ -287,5 +289,5 @@
 {
 	assert(instance);
-	usb_log_debug("OHCI interrupt: %x.\n", status);
+	usb_log_debug("OHCI(%p) interrupt: %x.\n", instance, status);
 	if ((status & ~I_SF) == 0) /* ignore sof status */
 		return;
@@ -339,6 +341,9 @@
 	    (uint32_t*)((char*)instance->registers + 0x100);
 	usb_log_debug("OHCI legacy register %p: %x.\n",
-		ohci_emulation_reg, *ohci_emulation_reg);
-	*ohci_emulation_reg &= ~0x1;
+	    ohci_emulation_reg, *ohci_emulation_reg);
+	/* Do not change A20 state */
+	*ohci_emulation_reg &= 0x100;
+	usb_log_debug("OHCI legacy register %p: %x.\n",
+	    ohci_emulation_reg, *ohci_emulation_reg);
 
 	/* Interrupt routing enabled => smm driver is active */
@@ -350,4 +355,6 @@
 		}
 		usb_log_info("SMM driver: Ownership taken.\n");
+		instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
+		async_usleep(50000);
 		return;
 	}
@@ -375,5 +382,5 @@
 }
 /*----------------------------------------------------------------------------*/
-void hc_init_hw(hc_t *instance)
+void hc_start_hw(hc_t *instance)
 {
 	/* OHCI guide page 42 */
@@ -474,4 +481,6 @@
 {
 	assert(instance);
+
+	bzero(&instance->rh, sizeof(instance->rh));
 	/* Init queues */
 	hc_init_transfer_lists(instance);
Index: uspace/drv/ohci/hc.h
===================================================================
--- uspace/drv/ohci/hc.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/ohci/hc.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -80,4 +80,6 @@
      uintptr_t regs, size_t reg_size, bool interrupts);
 
+void hc_start_hw(hc_t *instance);
+
 /** Safely dispose host controller internal structures
  *
Index: uspace/drv/ohci/main.c
===================================================================
--- uspace/drv/ohci/main.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/ohci/main.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -75,5 +75,6 @@
 		return ret;
 	}
-	device->driver_data = ohci;
+//	device->driver_data = ohci;
+	hc_register_hub(&ohci->hc, ohci->rh_fun);
 
 	usb_log_info("Controlling new OHCI device `%s'.\n", device->name);
@@ -93,5 +94,4 @@
 {
 	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
-	sleep(5);
 	return ddf_driver_main(&ohci_driver);
 }
Index: uspace/drv/ohci/ohci.c
===================================================================
--- uspace/drv/ohci/ohci.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/ohci/ohci.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -54,4 +54,5 @@
 {
 	assert(dev);
+	assert(dev->driver_data);
 	hc_t *hc = &((ohci_t*)dev->driver_data)->hc;
 	uint16_t status = IPC_GET_ARG1(*call);
@@ -152,8 +153,4 @@
 	usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
 	    (void *) mem_reg_base, mem_reg_size, irq);
-
-	ret = pci_disable_legacy(device);
-	CHECK_RET_DEST_FUN_RETURN(ret,
-	    "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
 
 	bool interrupts = false;
@@ -212,12 +209,11 @@
 	    "Failed(%d) to create root hub function.\n", ret);
 
-	hc_register_hub(&instance->hc, instance->rh_fun);
 
 	instance->rh_fun->ops = &rh_ops;
 	instance->rh_fun->driver_data = NULL;
-	ret = ddf_fun_bind(instance->rh_fun);
-	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to register OHCI root hub.\n", ret);
-
+	
+	device->driver_data = instance;
+
+	hc_start_hw(&instance->hc);
 	return EOK;
 #undef CHECK_RET_FINI_RETURN
Index: uspace/drv/ohci/pci.c
===================================================================
--- uspace/drv/ohci/pci.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/ohci/pci.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -136,16 +136,4 @@
 	return enabled ? EOK : EIO;
 }
-/*----------------------------------------------------------------------------*/
-/** Implements BIOS handoff routine as decribed in OHCI spec
- *
- * @param[in] device Device asking for interrupts
- * @return Error code.
- */
-int pci_disable_legacy(ddf_dev_t *device)
-{
-	/* TODO: implement */
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
 /**
  * @}
Index: uspace/drv/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/usbhid/generic/hiddev.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/generic/hiddev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -39,4 +39,5 @@
 #include <errno.h>
 #include <str_error.h>
+#include <bool.h>
 
 #include <usbhid_iface.h>
@@ -64,4 +65,6 @@
     size_t size, size_t *act_size, unsigned int flags);
 
+static int usb_generic_hid_client_connected(ddf_fun_t *fun);
+
 /*----------------------------------------------------------------------------*/
 
@@ -72,5 +75,6 @@
 
 static ddf_dev_ops_t usb_generic_hid_ops = {
-	.interfaces[USBHID_DEV_IFACE] = &usb_generic_iface
+	.interfaces[USBHID_DEV_IFACE] = &usb_generic_iface,
+	.open = usb_generic_hid_client_connected
 };
 
@@ -104,10 +108,25 @@
 	
 	/*! @todo This should probably be atomic. */
-	memcpy(buffer, hid_dev->input_report, hid_dev->input_report_size);
-	*act_size = hid_dev->input_report_size;
+	if (usb_hid_report_ready()) {
+		memcpy(buffer, hid_dev->input_report, 
+		    hid_dev->input_report_size);
+		*act_size = hid_dev->input_report_size;
+		usb_hid_report_received();
+	}
 	
 	// clear the buffer so that it will not be received twice
-	memset(hid_dev->input_report, 0, hid_dev->input_report_size);
+	//memset(hid_dev->input_report, 0, hid_dev->input_report_size);
 	
+	// note that we already received this report
+//	report_received = true;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_generic_hid_client_connected(ddf_fun_t *fun)
+{
+	usb_hid_report_received();
 	return EOK;
 }
Index: uspace/drv/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/kbd/kbddev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -255,4 +255,6 @@
 	
 	if (hid_dev == NULL || hid_dev->data == NULL) {
+		usb_log_debug("default_connection_handler: "
+		    "Missing parameter.\n");
 		async_answer_0(icallid, EINVAL);
 		return;
@@ -267,4 +269,6 @@
 
 		if (kbd_dev->console_phone != -1) {
+			usb_log_debug("default_connection_handler: "
+			    "console phone already set\n");
 			async_answer_0(icallid, ELIMIT);
 			return;
@@ -272,8 +276,11 @@
 
 		kbd_dev->console_phone = callback;
+		
+		usb_log_debug("default_connection_handler: OK\n");
 		async_answer_0(icallid, EOK);
 		return;
 	}
 	
+	usb_log_debug("default_connection_handler: Wrong function.\n");
 	async_answer_0(icallid, EINVAL);
 }
@@ -555,8 +562,8 @@
 			usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
 			    kbd_dev->keys[i]);
-			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, key);
 			if (!usb_kbd_is_lock(key)) {
 				usb_kbd_repeat_start(kbd_dev, key);
 			}
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, key);
 		} else {
 			// found, nothing happens
Index: uspace/drv/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/usbhid/mouse/mousedev.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/mouse/mousedev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -43,4 +43,8 @@
 #include <str_error.h>
 #include <ipc/mouse.h>
+#include <io/console.h>
+
+#include <ipc/kbd.h>
+#include <io/keycode.h>
 
 #include "mousedev.h"
@@ -61,5 +65,7 @@
 
 const char *HID_MOUSE_FUN_NAME = "mouse";
+const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
 const char *HID_MOUSE_CLASS_NAME = "mouse";
+const char *HID_MOUSE_WHEEL_CLASS_NAME = "keyboard";
 
 /** Default idle rate for mouses. */
@@ -119,4 +125,6 @@
 	
 	if (hid_dev == NULL || hid_dev->data == NULL) {
+		usb_log_debug("default_connection_handler: Missing "
+		    "parameters.\n");
 		async_answer_0(icallid, EINVAL);
 		return;
@@ -127,13 +135,19 @@
 	usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
 	
+	int *phone = (str_cmp(fun->name, HID_MOUSE_FUN_NAME) == 0) 
+		     ? &mouse_dev->mouse_phone : &mouse_dev->wheel_phone;
+	
 	if (method == IPC_M_CONNECT_TO_ME) {
 		int callback = IPC_GET_ARG5(*icall);
 
-		if (mouse_dev->console_phone != -1) {
+		if (*phone != -1) {
+			usb_log_debug("default_connection_handler: Console "
+			    "phone to mouse already set.\n");
 			async_answer_0(icallid, ELIMIT);
+			//async_answer_0(icallid, EOK);
 			return;
 		}
 
-		mouse_dev->console_phone = callback;
+		*phone = callback;
 		usb_log_debug("Console phone to mouse set ok (%d).\n", callback);
 		async_answer_0(icallid, EOK);
@@ -141,4 +155,5 @@
 	}
 
+	usb_log_debug("default_connection_handler: Invalid function.\n");
 	async_answer_0(icallid, EINVAL);
 }
@@ -152,5 +167,6 @@
 		return NULL;
 	}
-	mouse->console_phone = -1;
+	mouse->mouse_phone = -1;
+	mouse->wheel_phone = -1;
 	
 	return mouse;
@@ -164,6 +180,10 @@
 	
 	// hangup phone to the console
-	if ((*mouse_dev)->console_phone >= 0) {
-		async_hangup((*mouse_dev)->console_phone);
+	if ((*mouse_dev)->mouse_phone >= 0) {
+		async_hangup((*mouse_dev)->mouse_phone);
+	}
+	
+	if ((*mouse_dev)->wheel_phone >= 0) {
+		async_hangup((*mouse_dev)->wheel_phone);
 	}
 	
@@ -174,6 +194,36 @@
 /*----------------------------------------------------------------------------*/
 
-static bool usb_mouse_process_boot_report(usb_hid_dev_t *hid_dev,
-    uint8_t *buffer, size_t buffer_size)
+static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel)
+{
+	console_event_t ev;
+	
+	ev.type = KEY_PRESS;
+	ev.key = (wheel > 0) ? KC_UP : (wheel < 0) ? KC_DOWN : 0;
+	ev.mods = 0;
+	ev.c = 0;
+
+	if (mouse_dev->wheel_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+	
+	int count = (wheel < 0) ? -wheel : wheel;
+	int i;
+	
+	for (i = 0; i < count * 3; ++i) {
+		usb_log_debug2("Sending key %d to the console\n", ev.key);
+		async_msg_4(mouse_dev->wheel_phone, KBD_EVENT, ev.type, 
+		    ev.key, ev.mods, ev.c);
+		// send key release right away
+		async_msg_4(mouse_dev->wheel_phone, KBD_EVENT, KEY_RELEASE, 
+		    ev.key, ev.mods, ev.c);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev, uint8_t *buffer,
+    size_t buffer_size)
 {
 	usb_mouse_t *mouse_dev = (usb_mouse_t *)hid_dev->data;
@@ -182,5 +232,5 @@
 	    usb_debug_str_buffer(buffer, buffer_size, 0));
 	
-	if (mouse_dev->console_phone < 0) {
+	if (mouse_dev->mouse_phone < 0) {
 		usb_log_error(NAME " No console phone.\n");
 		return false;	// ??
@@ -252,7 +302,35 @@
 	
 	if ((shift_x != 0) || (shift_y != 0)) {
-		async_req_2_0(mouse_dev->console_phone,
+		async_req_2_0(mouse_dev->mouse_phone,
 		    MEVENT_MOVE, shift_x, shift_y);
 	}
+	
+	/*
+	 * Wheel
+	 */
+	int wheel = 0;
+	
+	path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP, 
+	    USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
+
+	usb_hid_report_path_set_report_id(path, report_id);
+	
+	field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END, 
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	if (field != NULL) {
+		usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value, 
+		    field->usage);
+		wheel = field->value;
+	}
+
+	usb_hid_report_path_free(path);
+	
+	// send arrow up for positive direction and arrow down for negative
+	// direction; three arrows for difference of 1
+	usb_mouse_send_wheel(mouse_dev, wheel);
+	
 	
 	/*
@@ -274,5 +352,5 @@
 		if (mouse_dev->buttons[field->usage - field->usage_minimum] == 0
 		    && field->value != 0) {
-			async_req_2_0(mouse_dev->console_phone,
+			async_req_2_0(mouse_dev->mouse_phone,
 			    MEVENT_BUTTON, field->usage, 1);
 			mouse_dev->buttons[field->usage - field->usage_minimum]
@@ -281,5 +359,5 @@
 		    mouse_dev->buttons[field->usage - field->usage_minimum] != 0
 		    && field->value == 0) {
-		       async_req_2_0(mouse_dev->console_phone,
+		       async_req_2_0(mouse_dev->mouse_phone,
 			   MEVENT_BUTTON, field->usage, 0);
 		       mouse_dev->buttons[field->usage - field->usage_minimum]
@@ -337,4 +415,42 @@
 	}
 	
+	/*
+	 * Special function for acting as keyboard (wheel)
+	 */
+	usb_log_debug("Creating DDF function %s...\n", 
+	              HID_MOUSE_WHEEL_FUN_NAME);
+	fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	    HID_MOUSE_WHEEL_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/*
+	 * Store the initialized HID device and HID ops
+	 * to the DDF function.
+	 */
+	fun->ops = &hid_dev->ops;
+	fun->driver_data = hid_dev;   // TODO: maybe change to hid_dev->data
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	usb_log_debug("Adding DDF function to class %s...\n", 
+	    HID_MOUSE_WHEEL_CLASS_NAME);
+	rc = ddf_fun_add_to_class(fun, HID_MOUSE_WHEEL_CLASS_NAME);
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class %s: %s.\n",
+		    HID_MOUSE_WHEEL_CLASS_NAME, str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
 	return EOK;
 }
@@ -407,5 +523,5 @@
 	}
 	
-	return usb_mouse_process_boot_report(hid_dev, buffer, buffer_size);
+	return usb_mouse_process_report(hid_dev, buffer, buffer_size);
 }
 
Index: uspace/drv/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/usbhid/mouse/mousedev.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/mouse/mousedev.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -48,5 +48,6 @@
 	//suseconds_t poll_interval_us;
 	/** IPC phone to console (consumer). */
-	int console_phone;
+	int mouse_phone;
+	int wheel_phone;
 	
 	int32_t *buttons;
Index: uspace/drv/usbhid/subdrivers.c
===================================================================
--- uspace/drv/usbhid/subdrivers.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/subdrivers.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -36,9 +36,16 @@
 #include "subdrivers.h"
 #include "usb/classes/hidut.h"
+#include "usb/classes/hidpath.h"
 
 #include "lgtch-ultrax/lgtch-ultrax.h"
+#include "mouse/mousedev.h"
 
 static usb_hid_subdriver_usage_t path_kbd[] = {
 	{USB_HIDUT_PAGE_KEYBOARD, 0}, 
+	{0, 0}
+};
+
+static usb_hid_subdriver_usage_t path_mouse2[] = {
+	{USB_HIDUT_PAGE_GENERIC_DESKTOP, USB_HIDUT_USAGE_GENERIC_DESKTOP_X},
 	{0, 0}
 };
@@ -79,4 +86,18 @@
 		}
 	},
+	{
+		path_mouse2,
+		-1,
+		USB_HID_PATH_COMPARE_END 
+		| USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		-1,
+		-1,
+		{
+			.init = usb_mouse_init,
+			.deinit = usb_mouse_deinit,
+			.poll = usb_mouse_polling_callback,
+			.poll_end = NULL
+		}
+	},
 	{NULL, -1, 0, -1, -1, {NULL, NULL, NULL, NULL}}
 };
Index: uspace/drv/usbhid/usbhid.c
===================================================================
--- uspace/drv/usbhid/usbhid.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/usbhid.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -63,4 +63,6 @@
 static const int USB_HID_MAX_SUBDRIVERS = 10;
 
+static fibril_local bool report_received;
+
 /*----------------------------------------------------------------------------*/
 
@@ -412,7 +414,5 @@
 	}
 	
-	// TODO: remove the mouse hack
-	if (hid_dev->poll_pipe_index == USB_HID_MOUSE_POLL_EP_NO ||
-	    fallback) {
+	if (fallback) {
 		// fall back to boot protocol
 		switch (hid_dev->poll_pipe_index) {
@@ -509,4 +509,5 @@
 				free(input_old);
 			}
+			usb_hid_new_report();
 		}
 	}
@@ -589,4 +590,25 @@
 /*----------------------------------------------------------------------------*/
 
+void usb_hid_new_report(void)
+{
+	report_received = false;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_report_received(void)
+{
+	report_received = true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_hid_report_ready(void)
+{
+	return !report_received;
+}
+
+/*----------------------------------------------------------------------------*/
+
 void usb_hid_free(usb_hid_dev_t **hid_dev)
 {
Index: uspace/drv/usbhid/usbhid.h
===================================================================
--- uspace/drv/usbhid/usbhid.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/usbhid/usbhid.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -44,4 +44,5 @@
 #include <usb/devdrv.h>
 #include <usb/classes/hid.h>
+#include <bool.h>
 
 struct usb_hid_dev;
@@ -128,4 +129,10 @@
 //const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev);
 
+void usb_hid_new_report(void);
+
+void usb_hid_report_received(void);
+
+bool usb_hid_report_ready(void);
+
 void usb_hid_free(usb_hid_dev_t **hid_dev);
 
Index: uspace/drv/vhc/transfer.c
===================================================================
--- uspace/drv/vhc/transfer.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/drv/vhc/transfer.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -135,5 +135,4 @@
 		if (transfer->direction == USB_DIRECTION_IN) {
 			rc = usbvirt_ipc_send_control_read(phone,
-			    transfer->endpoint,
 			    transfer->setup_buffer, transfer->setup_buffer_size,
 			    transfer->data_buffer, transfer->data_buffer_size,
@@ -142,5 +141,4 @@
 			assert(transfer->direction == USB_DIRECTION_OUT);
 			rc = usbvirt_ipc_send_control_write(phone,
-			    transfer->endpoint,
 			    transfer->setup_buffer, transfer->setup_buffer_size,
 			    transfer->data_buffer, transfer->data_buffer_size);
Index: uspace/lib/usb/include/usb/classes/hiddescriptor.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hiddescriptor.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usb/include/usb/classes/hiddescriptor.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -78,4 +78,5 @@
 uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
 
+usb_hid_report_path_t *usb_hid_report_path_try_insert(usb_hid_report_t *report, usb_hid_report_path_t *cmp_path);
 #endif
 /**
Index: uspace/lib/usb/include/usb/classes/hidpath.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidpath.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usb/include/usb/classes/hidpath.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -43,8 +43,14 @@
  * Description of path of usage pages and usages in report descriptor
  */
-#define USB_HID_PATH_COMPARE_STRICT				0
-#define USB_HID_PATH_COMPARE_END				1
-#define USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY	4
-#define USB_HID_PATH_COMPARE_COLLECTION_ONLY	2 /* porovnava jenom cestu z Kolekci */
+/** Wanted usage path must be exactly the same as the searched one */
+#define USB_HID_PATH_COMPARE_STRICT		0
+/** Wanted usage path must be the suffix in the searched one */
+#define USB_HID_PATH_COMPARE_END		1
+/** */
+#define USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY	2
+/** Searched usage page must be prefix of the other one */
+#define USB_HID_PATH_COMPARE_BEGIN		4
+/** Searched couple of usage page and usage can be anywhere in usage path */
+#define USB_HID_PATH_COMPARE_ANYWHERE		8
 
 
Index: uspace/lib/usb/include/usb/classes/hidtypes.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidtypes.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usb/include/usb/classes/hidtypes.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -165,4 +165,6 @@
 	/** */	
 	link_t link;
+
+	int in_delimiter;
 } usb_hid_report_item_t;
 
Index: uspace/lib/usb/src/hiddescriptor.c
===================================================================
--- uspace/lib/usb/src/hiddescriptor.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usb/src/hiddescriptor.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -41,4 +41,9 @@
 #include <assert.h>
 
+
+#define OUTSIDE_DELIMITER_SET	0
+#define START_DELIMITER_SET	1
+#define INSIDE_DELIMITER_SET	2
+	
 /** The new report item flag. Used to determine when the item is completly
  * configured and should be added to the report structure
@@ -56,31 +61,6 @@
 #define USB_HID_UNKNOWN_TAG		-99
 
-
-/**
- * Initialize the report descriptor parser structure
- *
- * @param parser Report descriptor parser structure
- * @return Error code
- */
-int usb_hid_report_init(usb_hid_report_t *report)
-{
-	if(report == NULL) {
-		return EINVAL;
-	}
-
-	memset(report, 0, sizeof(usb_hid_report_t));
-	list_initialize(&report->reports);
-	list_initialize(&report->collection_paths);
-
-	report->use_report_ids = 0;
-    return EOK;   
-}
-
-int usb_hid_report_append_fields(usb_hid_report_t *report, usb_hid_report_item_t *report_item)
-{
-	usb_hid_report_field_t *field;
-	int i;
-
-
+usb_hid_report_path_t *usb_hid_report_path_try_insert(usb_hid_report_t *report, usb_hid_report_path_t *cmp_path)
+{
 	/* find or append current collection path to the list */
 	link_t *path_it = report->collection_paths.next;
@@ -89,5 +69,5 @@
 		path = list_get_instance(path_it, usb_hid_report_path_t, link);
 		
-		if(usb_hid_report_compare_usage_path(path, report_item->usage_path, USB_HID_PATH_COMPARE_STRICT) == EOK){
+		if(usb_hid_report_compare_usage_path(path, cmp_path, USB_HID_PATH_COMPARE_STRICT) == EOK){
 			break;
 		}			
@@ -95,8 +75,44 @@
 	}
 	if(path_it == &report->collection_paths) {
-		path = usb_hid_report_path_clone(report_item->usage_path);			
+		path = usb_hid_report_path_clone(cmp_path);			
 		list_append(&path->link, &report->collection_paths);					
 		report->collection_paths_count++;
-	}
+
+		return path;
+	}
+	else {
+		return list_get_instance(path_it, usb_hid_report_path_t, link);
+	}
+}
+
+/**
+ * Initialize the report descriptor parser structure
+ *
+ * @param parser Report descriptor parser structure
+ * @return Error code
+ */
+int usb_hid_report_init(usb_hid_report_t *report)
+{
+	if(report == NULL) {
+		return EINVAL;
+	}
+
+	memset(report, 0, sizeof(usb_hid_report_t));
+	list_initialize(&report->reports);
+	list_initialize(&report->collection_paths);
+
+	report->use_report_ids = 0;
+    return EOK;   
+}
+
+
+/*
+ *
+ *
+ */
+int usb_hid_report_append_fields(usb_hid_report_t *report, usb_hid_report_item_t *report_item)
+{
+	usb_hid_report_field_t *field;
+	int i;
 
 	for(i=0; i<report_item->usages_count; i++){
@@ -104,5 +120,5 @@
 	}
 
-	
+	usb_hid_report_path_t *path = report_item->usage_path;	
 	for(i=0; i<report_item->count; i++){
 
@@ -112,5 +128,4 @@
 
 		/* fill the attributes */		
-		field->collection_path = path;
 		field->logical_minimum = report_item->logical_minimum;
 		field->logical_maximum = report_item->logical_maximum;
@@ -129,19 +144,9 @@
 		if(report_item->usages_count > 0 && ((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0))) {
 			uint32_t usage;
-			if(report_item->type != USB_HID_REPORT_TYPE_OUTPUT) {
-				if(i < report_item->usages_count){
-					usage = report_item->usages[i];
-				}
-				else {
-					usage = report_item->usages[report_item->usages_count - 1];
-				}
+			if(i < report_item->usages_count){
+				usage = report_item->usages[i];
 			}
 			else {
-				if((report_item->count - i - 1) < report_item->usages_count){
-					usage = report_item->usages[(report_item->count - i - 1)];
-				}
-				else {
-					usage = report_item->usages[report_item->usages_count - 1];
-				}
+				usage = report_item->usages[report_item->usages_count - 1];
 			}
 
@@ -159,15 +164,18 @@
 
 		if((USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) != 0) && (!((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0)))) {
-			if(report_item->type == USB_HID_REPORT_TYPE_INPUT) {
-				field->usage = report_item->usage_maximum - i;
-			}
-			else {
-				field->usage = report_item->usage_minimum + i;					
-			}
-
-		}
-		
+			field->usage = report_item->usage_minimum + i;					
+		}
+		
+		usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_GLOBAL, field->usage_page);
+		usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_LOCAL, field->usage);
+
+		field->collection_path = usb_hid_report_path_try_insert(report, path);
+
 		field->size = report_item->size;
-		field->offset = report_item->offset + (i * report_item->size);
+		
+		size_t offset_byte = (report_item->offset + (i * report_item->size)) / 8;
+		size_t offset_bit = 8 - ((report_item->offset + (i * report_item->size)) % 8) - report_item->size;
+
+		field->offset = 8 * offset_byte + offset_bit;
 		if(report_item->id != 0) {
 			field->offset += 8;
@@ -264,4 +272,5 @@
 		return ENOMEM;
 	}
+	usb_hid_report_path_append_item(usage_path, 0, 0);	
 	
 	while(i<size){	
@@ -349,5 +358,6 @@
 					tmp_usage_path = list_get_instance(report_item->usage_path->link.prev, usb_hid_report_usage_path_t, link);
 					
-					usb_hid_report_set_last_item(usage_path, tmp_usage_path->usage_page, tmp_usage_path->usage);
+					usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
+					usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
 
 					usb_hid_report_path_free(report_item->usage_path);
@@ -427,5 +437,7 @@
 int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
                              usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
-{		
+{
+	usb_hid_report_usage_path_t *path_item;
+	
 	switch(tag)
 	{
@@ -438,6 +450,15 @@
 			
 		case USB_HID_REPORT_TAG_COLLECTION:
-			// TODO usage_path->flags = *data;
-			usb_hid_report_path_append_item(usage_path, report_item->usage_page, report_item->usages[report_item->usages_count-1]);						
+			// store collection atributes
+			path_item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
+			path_item->flags = *data;	
+			
+			// set last item
+			usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_GLOBAL, report_item->usage_page);
+			usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_LOCAL, report_item->usages[report_item->usages_count-1]);
+			
+			// append the new one which will be set by common
+			// usage/usage page
+			usb_hid_report_path_append_item(usage_path, report_item->usage_page, report_item->usages[report_item->usages_count-1]);	
 			usb_hid_report_reset_local_items (report_item);
 			return USB_HID_NO_ACTION;
@@ -530,9 +551,17 @@
                              usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
 {
-	switch(tag)
-	{
+	switch(tag) {
 		case USB_HID_REPORT_TAG_USAGE:
-			report_item->usages[report_item->usages_count] = usb_hid_report_tag_data_uint32(data,item_size);
-			report_item->usages_count++;
+			switch(report_item->in_delimiter) {
+				case INSIDE_DELIMITER_SET:
+					// nothing to do
+					break;
+				case START_DELIMITER_SET:
+					report_item->in_delimiter = INSIDE_DELIMITER_SET;
+				case OUTSIDE_DELIMITER_SET:
+					report_item->usages[report_item->usages_count] = usb_hid_report_tag_data_uint32(data,item_size);
+					report_item->usages_count++;
+					break;
+			}
 			break;
 		case USB_HID_REPORT_TAG_USAGE_MINIMUM:
@@ -575,13 +604,11 @@
 			break;			
 		case USB_HID_REPORT_TAG_DELIMITER:
-			//report_item->delimiter = usb_hid_report_tag_data_uint32(data,item_size);
-			//TODO: 
-			//	DELIMITER STUFF
-			break;
-		
+			report_item->in_delimiter = usb_hid_report_tag_data_uint32(data,item_size);
+			break;
+
 		default:
 			return USB_HID_NO_ACTION;
 	}
-	
+
 	return EOK;
 }
@@ -629,5 +656,5 @@
 
 		usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
-		usb_log_debug("\t\tSIZE: %zu\n", report_item->size);
+		usb_log_debug("\t\tSIZE: %zu\n", report_item->size);				
 		usb_log_debug("\t\tLOGMIN: %d\n", report_item->logical_minimum);
 		usb_log_debug("\t\tLOGMAX: %d\n", report_item->logical_maximum);		
@@ -640,6 +667,8 @@
 		usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
 		usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
-						
-//		usb_log_debug("\n");		
+		
+		//usb_hid_print_usage_path(report_item->collection_path);
+
+		usb_log_debug("\n");		
 
 	}
@@ -666,6 +695,6 @@
 		usb_log_debug("Report ID: %d\n", report_des->report_id);
 		usb_log_debug("\tType: %d\n", report_des->type);
-		usb_log_debug("\tLength: %zu\n", report_des->bit_length);
-		usb_log_debug("\tItems: %zu\n", report_des->item_length);
+		usb_log_debug("\tLength: %zu\n", report_des->bit_length);		
+		usb_log_debug("\tItems: %zu\n", report_des->item_length);		
 
 		usb_hid_descriptor_print_list(&report_des->report_items);
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usb/src/hidparser.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -405,5 +405,5 @@
 				}
 
-				size_t shift = offset%8;
+				size_t shift = 8 - offset%8 - length;
 
 				value = value << shift;							
Index: uspace/lib/usb/src/hidpath.c
===================================================================
--- uspace/lib/usb/src/hidpath.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usb/src/hidpath.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -149,5 +149,5 @@
 		usb_log_debug("\tFLAGS: %d\n", path_item->flags);		
 		
-		item = item->next;
+       		item = item->next;
 	}
 }
@@ -156,7 +156,6 @@
  * Compares two usage paths structures
  *
- * If USB_HID_PATH_COMPARE_COLLECTION_ONLY flag is given, the last item in report_path structure is forgotten
- *
- * @param report_path usage path structure to compare
+ *
+ * @param report_path usage path structure to compare with @path 
  * @param path usage patrh structure to compare
  * @param flags Flags determining the mode of comparison
@@ -179,4 +178,5 @@
 	}
 
+	// Empty path match all others
 	if(path->depth == 0){
 		return EOK;
@@ -189,10 +189,43 @@
 	
 	switch(flags){
-		/* path must be completly identical */
+		/* path is somewhere in report_path */
+		case USB_HID_PATH_COMPARE_ANYWHERE:
+			if(path->depth != 1){
+				return 1;
+			}
+
+			// projit skrz cestu a kdyz nekde sedi tak vratim EOK
+			// dojduli az za konec tak nnesedi
+			report_link = report_path->head.next;
+			path_link = path->head.next;
+			path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
+
+			while(report_link != &report_path->head) {
+				report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
+				if(report_item->usage_page == path_item->usage_page){
+					if(only_page == 0){
+						if(report_item->usage == path_item->usage) {
+							return EOK;
+						}
+					}
+					else {
+						return EOK;
+					}
+				}
+
+				report_link = report_link->next;
+			}
+
+			return 1;
+			break;
+		/* the paths must be identical */
 		case USB_HID_PATH_COMPARE_STRICT:
 				if(report_path->depth != path->depth){
 					return 1;
 				}
-
+		
+		/* path is prefix of the report_path */
+		case USB_HID_PATH_COMPARE_BEGIN:
+	
 				report_link = report_path->head.next;
 				path_link = path->head.next;
@@ -221,8 +254,6 @@
 				}
 
-				if(((report_link == &report_path->head) && (path_link == &path->head)) || 
-				   (((flags & USB_HID_PATH_COMPARE_COLLECTION_ONLY) != 0) && 
-				    (path_link = &path->head) && 
-				    (report_link == report_path->head.prev))) {
+				if((((flags & USB_HID_PATH_COMPARE_BEGIN) != 0) && (path_link == &path->head)) || 
+				   ((report_link == &report_path->head) && (path_link == &path->head))) {
 					return EOK;
 				}
@@ -232,13 +263,8 @@
 			break;
 
-		/* compare with only the end of path*/
+		/* path is suffix of report_path */
 		case USB_HID_PATH_COMPARE_END:
 
-				if((flags & USB_HID_PATH_COMPARE_COLLECTION_ONLY) != 0) {
-					report_link = report_path->head.prev->prev;
-				}
-				else {
-					report_link = report_path->head.prev;
-				}
+				report_link = report_path->head.prev;
 				path_link = path->head.prev;
 
Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/Makefile	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -33,6 +33,8 @@
 
 SOURCES = \
-	src/ipc.c \
 	src/ctrltransfer.c \
+	src/device.c \
+	src/ipc_dev.c \
+	src/ipc_hc.c \
 	src/stdreq.c \
 	src/transfer.c
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief Virtual USB device.
+ * Virtual USB device.
  */
 #ifndef LIBUSBVIRT_DEVICE_H_
@@ -39,21 +39,68 @@
 #include <usb/request.h>
 
+/** Maximum number of endpoints supported by virtual USB. */
 #define USBVIRT_ENDPOINT_MAX 16
 
 typedef struct usbvirt_device usbvirt_device_t;
 
-typedef int (*usbvirt_on_data_to_device_t)(usbvirt_device_t *, usb_endpoint_t,
-    usb_transfer_type_t, void *, size_t);
-typedef int (*usbvirt_on_data_from_device_t)(usbvirt_device_t *, usb_endpoint_t,
-    usb_transfer_type_t, void *, size_t, size_t *);
-typedef int (*usbvirt_on_control_t)(usbvirt_device_t *,
-    const usb_device_request_setup_packet_t *, uint8_t *, size_t *);
-
-typedef struct {
+/** Callback for data to device (OUT transaction).
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param endpoint Target endpoint number.
+ * @param transfer_type Transfer type.
+ * @param buffer Data buffer.
+ * @param buffer_size Size of the buffer in bytes.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_data_to_device_t)(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
+    void *buffer, size_t buffer_size);
+
+/** Callback for data from device (IN transaction).
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param endpoint Target endpoint number.
+ * @param transfer_type Transfer type.
+ * @param buffer Data buffer to write answer to.
+ * @param buffer_size Size of the buffer in bytes.
+ * @param act_buffer_size Write here how many bytes were actually written.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_data_from_device_t)(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
+    void *buffer, size_t buffer_size, size_t *act_buffer_size);
+
+/** Callback for control transfer on endpoint zero.
+ *
+ * Notice that size of the data buffer is expected to be read from the
+ * setup packet.
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param setup_packet Standard setup packet.
+ * @param data Data (might be NULL).
+ * @param act_data_size Size of returned data in bytes.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_control_t)(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_data_size);
+
+/** Callback for control request on a virtual USB device.
+ *
+ * See usbvirt_control_reply_helper() for simple way of answering
+ * control read requests.
+ */
+typedef struct {
+	/** Request direction (in or out). */
 	usb_direction_t req_direction;
+	/** Request recipient (device, interface or endpoint). */
 	usb_request_recipient_t req_recipient;
+	/** Request type (standard, class or vendor). */
 	usb_request_type_t req_type;
+	/** Actual request code. */
 	uint8_t request;
+	/** Request handler name for debugging purposes. */
 	const char *name;
+	/** Callback to be executed on matching request. */
 	usbvirt_on_control_t callback;
 } usbvirt_control_request_handler_t;
@@ -77,5 +124,5 @@
 } usbvirt_device_configuration_t;
 
-/** Standard USB descriptors. */
+/** Standard USB descriptors for virtual device. */
 typedef struct {
 	/** Standard device descriptor.
@@ -102,22 +149,57 @@
 } usbvirt_device_state_t;
 
-typedef struct {
+/** Ops structure for virtual USB device. */
+typedef struct {
+	/** Callbacks for data to device.
+	 * Index zero is ignored.
+	 */
 	usbvirt_on_data_to_device_t data_out[USBVIRT_ENDPOINT_MAX];
+	/** Callbacks for data from device.
+	 * Index zero is ignored.
+	 */
 	usbvirt_on_data_from_device_t data_in[USBVIRT_ENDPOINT_MAX];
+	/** Array of control handlers.
+	 * Last handler is expected to have the @c callback field set to NULL
+	 */
 	usbvirt_control_request_handler_t *control;
+	/** Callback when device changes state.
+	 *
+	 * The value of @c state attribute of @p dev device is not
+	 * defined during call of this function.
+	 *
+	 * @param dev The virtual USB device.
+	 * @param old_state Old device state.
+	 * @param new_state New device state.
+	 */
 	void (*state_changed)(usbvirt_device_t *dev,
 	    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state);
 } usbvirt_device_ops_t;
 
+/** Virtual USB device. */
 struct usbvirt_device {
+	/** Name for debugging purposes. */
 	const char *name;
+	/** Custom device data. */
 	void *device_data;
+	/** Device ops. */
 	usbvirt_device_ops_t *ops;
+	/** Device descriptors. */
 	usbvirt_descriptors_t *descriptors;
+	/** Current device address.
+	 * You shall treat this field as read only in your code.
+	 */
 	usb_address_t address;
+	/** Current device state.
+	 * You shall treat this field as read only in your code.
+	 */
 	usbvirt_device_state_t state;
+	/** Phone to the host controller.
+	 * You shall treat this field as read only in your code.
+	 */
+	int vhc_phone;
 };
 
 int usbvirt_device_plug(usbvirt_device_t *, const char *);
+void usbvirt_device_unplug(usbvirt_device_t *);
 
 void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *,
Index: uspace/lib/usbvirt/include/usbvirt/ipc.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Vojtech Horky
  * All rights reserved.
  *
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief Virtual USB device.
+ * IPC wrappers for virtual USB.
  */
 #ifndef LIBUSBVIRT_IPC_H_
@@ -40,4 +40,5 @@
 #include <bool.h>
 
+/** IPC methods communication between host controller and virtual device. */
 typedef enum {
 	IPC_M_USBVIRT_GET_NAME = IPC_FIRST_USER_METHOD + 80,
@@ -45,10 +46,12 @@
 	IPC_M_USBVIRT_CONTROL_WRITE,
 	IPC_M_USBVIRT_INTERRUPT_IN,
-	IPC_M_USBVIRT_INTERRUPT_OUT
-} usbvirt_ipc_t;
+	IPC_M_USBVIRT_INTERRUPT_OUT,
+	IPC_M_USBVIRT_BULK_IN,
+	IPC_M_USBVIRT_BULK_OUT
+} usbvirt_hc_to_device_method_t;
 
-int usbvirt_ipc_send_control_read(int, usb_endpoint_t, void *, size_t,
+int usbvirt_ipc_send_control_read(int, void *, size_t,
     void *, size_t, size_t *);
-int usbvirt_ipc_send_control_write(int, usb_endpoint_t, void *, size_t,
+int usbvirt_ipc_send_control_write(int, void *, size_t,
     void *, size_t);
 int usbvirt_ipc_send_data_in(int, usb_endpoint_t, usb_transfer_type_t,
Index: uspace/lib/usbvirt/src/ctrltransfer.c
===================================================================
--- uspace/lib/usbvirt/src/ctrltransfer.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/src/ctrltransfer.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,2 +1,36 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Control transfer handling.
+ */
 #include "private.h"
 #include <usb/request.h>
@@ -5,4 +39,14 @@
 #include <errno.h>
 
+/** Find and execute control transfer handler for virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param control_handlers Array of control request handlers.
+ * @param setup Setup packet.
+ * @param data Extra data.
+ * @param data_sent_size Size of extra data in bytes.
+ * @return Error code.
+ * @retval EFORWARD No suitable handler found.
+ */
 int process_control_transfer(usbvirt_device_t *dev,
     usbvirt_control_request_handler_t *control_handlers,
@@ -52,2 +96,7 @@
 	return EFORWARD;
 }
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/device.c
===================================================================
--- uspace/lib/usbvirt/src/device.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/lib/usbvirt/src/device.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device main routines.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+
+#include <usb/debug.h>
+
+/** Current device. */
+static usbvirt_device_t *DEV = NULL;
+
+/** Main IPC call handling from virtual host controller.
+ *
+ * @param iid Caller identification.
+ * @param icall Initial incoming call.
+ */
+static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	assert(DEV != NULL);
+
+	async_answer_0(iid, EOK);
+
+	while (true) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+
+		callid = async_get_call(&call);
+		bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
+		if (!processed) {
+			switch (IPC_GET_IMETHOD(call)) {
+				case IPC_M_PHONE_HUNGUP:
+					async_answer_0(callid, EOK);
+					return;
+				default:
+					async_answer_0(callid, EINVAL);
+					break;
+			}
+		}
+	}
+}
+
+/** Connect the device to the virtual host controller.
+ *
+ * @param dev The virtual device to be (virtually) plugged in.
+ * @param vhc_path Devman path to the virtual host controller.
+ * @return Error code.
+ */
+int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
+{
+	int rc;
+	devman_handle_t handle;
+
+	if (DEV != NULL) {
+		return ELIMIT;
+	}
+
+	rc = devman_device_get_handle(vhc_path, &handle, 0);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	int hcd_phone = devman_device_connect(handle, 0);
+
+	if (hcd_phone < 0) {
+		return hcd_phone;
+	}
+
+	DEV = dev;
+	dev->vhc_phone = hcd_phone;
+
+	rc = async_connect_to_me(hcd_phone, 0, 0, 0, callback_connection);
+	if (rc != EOK) {
+		DEV = NULL;
+	}
+
+	return rc;
+}
+
+/** Disconnect the device from virtual host controller.
+ *
+ * @param dev Device to be disconnected.
+ */
+void usbvirt_device_unplug(usbvirt_device_t *dev)
+{
+	async_hangup(dev->vhc_phone);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ipc.c
===================================================================
--- uspace/lib/usbvirt/src/ipc.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ 	(revision )
@@ -1,455 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libusbvirt
- * @{
- */
-/** @file
- *
- */
-#include <errno.h>
-#include <str.h>
-#include <stdio.h>
-#include <assert.h>
-#include <async.h>
-#include <devman.h>
-#include <usbvirt/device.h>
-#include <usbvirt/ipc.h>
-
-#include <usb/debug.h>
-
-static usbvirt_device_t *DEV = NULL;
-
-static void ipc_get_name(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	if (dev->name == NULL) {
-		async_answer_0(iid, ENOENT);
-	}
-
-	size_t size = str_size(dev->name);
-
-	ipc_callid_t callid;
-	size_t accepted_size;
-	if (!async_data_read_receive(&callid, &accepted_size)) {
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-
-	if (accepted_size > size) {
-		accepted_size = size;
-	}
-	async_data_read_finalize(callid, dev->name, accepted_size);
-
-	async_answer_1(iid, EOK, accepted_size);
-}
-
-static void ipc_control_read(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	//usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-
-	int rc;
-
-	void *setup_packet = NULL;
-	size_t setup_packet_len = 0;
-	size_t data_len = 0;
-
-	rc = async_data_write_accept(&setup_packet, false,
-	    1, 1024, 0, &setup_packet_len);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-
-	ipc_callid_t data_callid;
-	if (!async_data_read_receive(&data_callid, &data_len)) {
-		async_answer_0(iid, EPARTY);
-		free(setup_packet);
-		return;
-	}
-
-	void *buffer = malloc(data_len);
-	if (buffer == NULL) {
-		async_answer_0(iid, ENOMEM);
-		free(setup_packet);
-		return;
-	}
-
-	size_t actual_len;
-	rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
-	    buffer, data_len, &actual_len);
-
-	if (rc != EOK) {
-		async_answer_0(data_callid, rc);
-		async_answer_0(iid, rc);
-		free(setup_packet);
-		free(buffer);
-		return;
-	}
-
-	async_data_read_finalize(data_callid, buffer, actual_len);
-	async_answer_0(iid, EOK);
-
-	free(setup_packet);
-	free(buffer);
-}
-
-static void ipc_control_write(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	size_t data_buffer_len = IPC_GET_ARG2(*icall);
-	int rc;
-
-	void *setup_packet = NULL;
-	void *data_buffer = NULL;
-	size_t setup_packet_len = 0;
-
-	rc = async_data_write_accept(&setup_packet, false,
-	    1, 1024, 0, &setup_packet_len);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-
-	if (data_buffer_len > 0) {
-		rc = async_data_write_accept(&data_buffer, false,
-		    1, 1024, 0, &data_buffer_len);
-		if (rc != EOK) {
-			async_answer_0(iid, rc);
-			free(setup_packet);
-			return;
-		}
-	}
-
-	rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
-	    data_buffer, data_buffer_len);
-
-	async_answer_0(iid, rc);
-}
-
-static void ipc_interrupt_in(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-	usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
-
-	int rc;
-
-	size_t data_len = 0;
-	ipc_callid_t data_callid;
-	if (!async_data_read_receive(&data_callid, &data_len)) {
-		async_answer_0(iid, EPARTY);
-		return;
-	}
-
-	void *buffer = malloc(data_len);
-	if (buffer == NULL) {
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-
-	size_t actual_len;
-	rc = usbvirt_data_in(dev, transfer_type, endpoint,
-	    buffer, data_len, &actual_len);
-
-	if (rc != EOK) {
-		async_answer_0(data_callid, rc);
-		async_answer_0(iid, rc);
-		free(buffer);
-		return;
-	}
-
-	async_data_read_finalize(data_callid, buffer, actual_len);
-	async_answer_0(iid, EOK);
-
-	free(buffer);
-}
-
-static void ipc_interrupt_out(usbvirt_device_t *dev,
-    ipc_callid_t iid, ipc_call_t *icall)
-{
-	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
-	usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
-
-	void *data_buffer = NULL;
-	size_t data_buffer_size = 0;
-
-	int rc = async_data_write_accept(&data_buffer, false,
-	    1, 1024, 0, &data_buffer_size);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-
-	rc = usbvirt_data_out(dev, transfer_type, endpoint,
-	    data_buffer, data_buffer_size);
-
-	async_answer_0(iid, rc);
-
-	free(data_buffer);
-}
-
-
-bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	switch (IPC_GET_IMETHOD(*call)) {
-		case IPC_M_USBVIRT_GET_NAME:
-			ipc_get_name(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_CONTROL_READ:
-			ipc_control_read(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_CONTROL_WRITE:
-			ipc_control_write(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_INTERRUPT_IN:
-			ipc_interrupt_in(dev, callid, call);
-			break;
-
-		case IPC_M_USBVIRT_INTERRUPT_OUT:
-			ipc_interrupt_out(dev, callid, call);
-			break;
-
-		default:
-			return false;
-	}
-
-	return true;
-}
-
-static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	assert(DEV != NULL);
-
-	async_answer_0(iid, EOK);
-
-	while (true) {
-		ipc_callid_t callid;
-		ipc_call_t call;
-
-		callid = async_get_call(&call);
-		bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
-		if (!processed) {
-			switch (IPC_GET_IMETHOD(call)) {
-				case IPC_M_PHONE_HUNGUP:
-					async_answer_0(callid, EOK);
-					return;
-				default:
-					async_answer_0(callid, EINVAL);
-					break;
-			}
-		}
-	}
-}
-
-int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
-{
-	int rc;
-	devman_handle_t handle;
-
-	rc = devman_device_get_handle(vhc_path, &handle, 0);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	int hcd_phone = devman_device_connect(handle, 0);
-
-	if (hcd_phone < 0) {
-		return hcd_phone;
-	}
-
-	DEV = dev;
-
-	rc = async_connect_to_me(hcd_phone, 0, 0, 0, callback_connection);
-	if (rc != EOK) {
-		DEV = NULL;
-		return rc;
-	}
-
-
-
-	return EOK;
-}
-
-
-
-int usbvirt_ipc_send_control_read(int phone, usb_endpoint_t ep,
-    void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
-{
-	aid_t opening_request = async_send_1(phone,
-	    IPC_M_USBVIRT_CONTROL_READ, ep, NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	int rc = async_data_write_start(phone,
-	    setup_buffer, setup_buffer_size);
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(phone,
-	    data_buffer, data_buffer_size,
-	    &data_request_call);
-
-	if (data_request == 0) {
-		async_wait_for(opening_request, NULL);
-		return ENOMEM;
-	}
-
-	sysarg_t data_request_rc;
-	sysarg_t opening_request_rc;
-	async_wait_for(data_request, &data_request_rc);
-	async_wait_for(opening_request, &opening_request_rc);
-
-	if (data_request_rc != EOK) {
-		/* Prefer the return code of the opening request. */
-		if (opening_request_rc != EOK) {
-			return (int) opening_request_rc;
-		} else {
-			return (int) data_request_rc;
-		}
-	}
-	if (opening_request_rc != EOK) {
-		return (int) opening_request_rc;
-	}
-
-	*data_transfered_size = IPC_GET_ARG2(data_request_call);
-
-	return EOK;
-}
-
-int usbvirt_ipc_send_control_write(int phone, usb_endpoint_t ep,
-    void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size)
-{
-	aid_t opening_request = async_send_2(phone,
-	    IPC_M_USBVIRT_CONTROL_WRITE, ep, data_buffer_size,  NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	int rc = async_data_write_start(phone,
-	    setup_buffer, setup_buffer_size);
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-
-	if (data_buffer_size > 0) {
-		rc = async_data_write_start(phone,
-		    data_buffer, data_buffer_size);
-
-		if (rc != EOK) {
-			async_wait_for(opening_request, NULL);
-			return rc;
-		}
-	}
-
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-
-	return (int) opening_request_rc;
-}
-
-int usbvirt_ipc_send_data_in(int phone, usb_endpoint_t ep,
-    usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
-{
-	aid_t opening_request = async_send_2(phone,
-	    IPC_M_USBVIRT_INTERRUPT_IN, ep, tr_type, NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(phone,
-	    data, data_size,  &data_request_call);
-
-	if (data_request == 0) {
-		async_wait_for(opening_request, NULL);
-		return ENOMEM;
-	}
-
-	sysarg_t data_request_rc;
-	sysarg_t opening_request_rc;
-	async_wait_for(data_request, &data_request_rc);
-	async_wait_for(opening_request, &opening_request_rc);
-
-	if (data_request_rc != EOK) {
-		/* Prefer the return code of the opening request. */
-		if (opening_request_rc != EOK) {
-			return (int) opening_request_rc;
-		} else {
-			return (int) data_request_rc;
-		}
-	}
-	if (opening_request_rc != EOK) {
-		return (int) opening_request_rc;
-	}
-
-	if (act_size != NULL) {
-		*act_size = IPC_GET_ARG2(data_request_call);
-	}
-
-	return EOK;
-}
-
-int usbvirt_ipc_send_data_out(int phone, usb_endpoint_t ep,
-    usb_transfer_type_t tr_type, void *data, size_t data_size)
-{
-	aid_t opening_request = async_send_2(phone,
-	    IPC_M_USBVIRT_INTERRUPT_OUT, ep, tr_type, NULL);
-	if (opening_request == 0) {
-		return ENOMEM;
-	}
-
-	int rc = async_data_write_start(phone,
-	    data, data_size);
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-
-	return (int) opening_request_rc;
-}
-
-
-/**
- * @}
- */
Index: uspace/lib/usbvirt/src/ipc_dev.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_dev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/lib/usbvirt/src/ipc_dev.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers, device side.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include <usb/debug.h>
+
+/** Handle VHC request for device name.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_get_name(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (dev->name == NULL) {
+		async_answer_0(iid, ENOENT);
+	}
+
+	size_t size = str_size(dev->name);
+
+	ipc_callid_t callid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&callid, &accepted_size)) {
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	if (accepted_size > size) {
+		accepted_size = size;
+	}
+	async_data_read_finalize(callid, dev->name, accepted_size);
+
+	async_answer_1(iid, EOK, accepted_size);
+}
+
+/** Handle VHC request for control read from the device.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_control_read(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc;
+
+	void *setup_packet = NULL;
+	size_t setup_packet_len = 0;
+	size_t data_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, 1024, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EPARTY);
+		free(setup_packet);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(iid, ENOMEM);
+		free(setup_packet);
+		return;
+	}
+
+	size_t actual_len;
+	rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
+	    buffer, data_len, &actual_len);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(iid, rc);
+		free(setup_packet);
+		free(buffer);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, buffer, actual_len);
+	async_answer_0(iid, EOK);
+
+	free(setup_packet);
+	free(buffer);
+}
+
+/** Handle VHC request for control write to the device.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_control_write(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	size_t data_buffer_len = IPC_GET_ARG1(*icall);
+	int rc;
+
+	void *setup_packet = NULL;
+	void *data_buffer = NULL;
+	size_t setup_packet_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, 0, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	if (data_buffer_len > 0) {
+		rc = async_data_write_accept(&data_buffer, false,
+		    1, 0, 0, &data_buffer_len);
+		if (rc != EOK) {
+			async_answer_0(iid, rc);
+			free(setup_packet);
+			return;
+		}
+	}
+
+	rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
+	    data_buffer, data_buffer_len);
+
+	async_answer_0(iid, rc);
+
+	free(setup_packet);
+	if (data_buffer != NULL) {
+		free(data_buffer);
+	}
+}
+
+/** Handle VHC request for data read from the device (in transfer).
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_data_in(usbvirt_device_t *dev,
+    usb_transfer_type_t transfer_type,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
+
+	int rc;
+
+	size_t data_len = 0;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EPARTY);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	size_t actual_len;
+	rc = usbvirt_data_in(dev, transfer_type, endpoint,
+	    buffer, data_len, &actual_len);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(iid, rc);
+		free(buffer);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, buffer, actual_len);
+	async_answer_0(iid, EOK);
+
+	free(buffer);
+}
+
+/** Handle VHC request for data write to the device (out transfer).
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_data_out(usbvirt_device_t *dev,
+    usb_transfer_type_t transfer_type,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
+
+	void *data_buffer = NULL;
+	size_t data_buffer_size = 0;
+
+	int rc = async_data_write_accept(&data_buffer, false,
+	    1, 0, 0, &data_buffer_size);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = usbvirt_data_out(dev, transfer_type, endpoint,
+	    data_buffer, data_buffer_size);
+
+	async_answer_0(iid, rc);
+
+	free(data_buffer);
+}
+
+/** Handle incoming IPC call for virtual USB device.
+ *
+ * @param dev Target USB device.
+ * @param callid Caller id.
+ * @param call Incoming call.
+ * @return Whether the call was handled.
+ */
+bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	switch (IPC_GET_IMETHOD(*call)) {
+	case IPC_M_USBVIRT_GET_NAME:
+		ipc_get_name(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_CONTROL_READ:
+		ipc_control_read(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_CONTROL_WRITE:
+		ipc_control_write(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_INTERRUPT_IN:
+		ipc_data_in(dev, USB_TRANSFER_INTERRUPT, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_BULK_IN:
+		ipc_data_in(dev, USB_TRANSFER_BULK, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_INTERRUPT_OUT:
+		ipc_data_out(dev, USB_TRANSFER_INTERRUPT, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_BULK_OUT:
+		ipc_data_out(dev, USB_TRANSFER_BULK, callid, call);
+		break;
+
+
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ipc_hc.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_hc.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
+++ uspace/lib/usbvirt/src/ipc_hc.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers, host controller side.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include <usb/debug.h>
+
+/** Send control read transfer to virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param setup_buffer Setup buffer.
+ * @param setup_buffer_size Setup buffer size in bytes.
+ * @param data_buffer Data buffer (DATA stage of control transfer).
+ * @param data_buffer_size Size of data buffer in bytes.
+ * @param data_transfered_size Number of actually transferred bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_control_read(int phone,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+		return EINVAL;
+	}
+	if ((data_buffer == NULL) || (data_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	aid_t opening_request = async_send_0(phone,
+	    IPC_M_USBVIRT_CONTROL_READ, NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	int rc = async_data_write_start(phone,
+	    setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(phone,
+	    data_buffer, data_buffer_size,
+	    &data_request_call);
+
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	if (data_transfered_size != NULL) {
+		*data_transfered_size = IPC_GET_ARG2(data_request_call);
+	}
+
+	return EOK;
+}
+
+/** Send control write transfer to virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param setup_buffer Setup buffer.
+ * @param setup_buffer_size Setup buffer size in bytes.
+ * @param data_buffer Data buffer (DATA stage of control transfer).
+ * @param data_buffer_size Size of data buffer in bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_control_write(int phone,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+		return EINVAL;
+	}
+	if ((data_buffer_size > 0) && (data_buffer == NULL)) {
+		return EINVAL;
+	}
+
+	aid_t opening_request = async_send_1(phone,
+	    IPC_M_USBVIRT_CONTROL_WRITE, data_buffer_size,  NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	int rc = async_data_write_start(phone,
+	    setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+
+	if (data_buffer_size > 0) {
+		rc = async_data_write_start(phone,
+		    data_buffer, data_buffer_size);
+
+		if (rc != EOK) {
+			async_wait_for(opening_request, NULL);
+			return rc;
+		}
+	}
+
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
+/** Request data transfer from virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param tr_type Transfer type (interrupt or bulk).
+ * @param data Data buffer.
+ * @param data_size Size of the data buffer in bytes.
+ * @param act_size Number of actually returned bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_data_in(int phone, usb_endpoint_t ep,
+    usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	usbvirt_hc_to_device_method_t method;
+	switch (tr_type) {
+	case USB_TRANSFER_INTERRUPT:
+		method = IPC_M_USBVIRT_INTERRUPT_IN;
+		break;
+	case USB_TRANSFER_BULK:
+		method = IPC_M_USBVIRT_BULK_IN;
+		break;
+	default:
+		return EINVAL;
+	}
+	if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX)) {
+		return EINVAL;
+	}
+	if ((data == NULL) || (data_size == 0)) {
+		return EINVAL;
+	}
+
+
+	aid_t opening_request = async_send_2(phone, method, ep, tr_type, NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(phone,
+	    data, data_size,  &data_request_call);
+
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	if (act_size != NULL) {
+		*act_size = IPC_GET_ARG2(data_request_call);
+	}
+
+	return EOK;
+}
+
+/** Send data to virtual USB device.
+ *
+ * @param phone IPC phone to the virtual device.
+ * @param ep Target endpoint number.
+ * @param tr_type Transfer type (interrupt or bulk).
+ * @param data Data buffer.
+ * @param data_size Size of the data buffer in bytes.
+ * @return Error code.
+ */
+int usbvirt_ipc_send_data_out(int phone, usb_endpoint_t ep,
+    usb_transfer_type_t tr_type, void *data, size_t data_size)
+{
+	if (phone < 0) {
+		return EINVAL;
+	}
+	usbvirt_hc_to_device_method_t method;
+	switch (tr_type) {
+	case USB_TRANSFER_INTERRUPT:
+		method = IPC_M_USBVIRT_INTERRUPT_OUT;
+		break;
+	case USB_TRANSFER_BULK:
+		method = IPC_M_USBVIRT_BULK_OUT;
+		break;
+	default:
+		return EINVAL;
+	}
+	if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX)) {
+		return EINVAL;
+	}
+	if ((data == NULL) || (data_size == 0)) {
+		return EINVAL;
+	}
+
+	aid_t opening_request = async_send_1(phone, method, ep, NULL);
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	int rc = async_data_write_start(phone,
+	    data, data_size);
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/src/private.h	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,2 +1,39 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Private definitions.
+ */
+#ifndef USBVIRT_PRIVATE_H_
+#define USBVIRT_PRIVATE_H_
+
 #include <usbvirt/device.h>
 
@@ -7,2 +44,7 @@
 
 extern usbvirt_control_request_handler_t library_handlers[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -1,2 +1,36 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Standard control request handlers.
+ */
 #include "private.h"
 #include <usb/request.h>
@@ -4,4 +38,15 @@
 #include <errno.h>
 
+/** Helper for replying to control read transfer from virtual USB device.
+ *
+ * This function takes care of copying data to answer buffer taking care
+ * of buffer sizes properly.
+ *
+ * @param setup_packet The setup packet.
+ * @param data Data buffer to write to.
+ * @param act_size Where to write actual size of returned data.
+ * @param actual_data Data to be returned.
+ * @param actual_data_size Size of answer data (@p actual_data) in bytes.
+ */
 void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *setup_packet,
     uint8_t *data, size_t *act_size,
@@ -144,4 +189,5 @@
 }
 
+/** Standard request handlers. */
 usbvirt_control_request_handler_t library_handlers[] = {
 	{
@@ -173,2 +219,5 @@
 };
 
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/transfer.c
===================================================================
--- uspace/lib/usbvirt/src/transfer.c	(revision 9528537818083d8908d40cf32ab9e77e2559f9f6)
+++ uspace/lib/usbvirt/src/transfer.c	(revision 1866945c7da7a2ddfebcb5abd73e1b4f8cd1c987)
@@ -31,5 +31,5 @@
  */
 /** @file
- *
+ * Transfer handling.
  */
 #include <usbvirt/device.h>
@@ -39,4 +39,15 @@
 #include "private.h"
 
+/** Process a control transfer to the virtual USB device.
+ *
+ * @param dev Target device.
+ * @param setup Setup packet data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data in bytes.
+ * @param data_size_sent Number of actually send bytes during the transfer
+ *	(only used for READ transfers).
+ * @return Error code.
+ */
 static int usbvirt_control_transfer(usbvirt_device_t *dev,
     void *setup, size_t setup_size,
@@ -78,4 +89,15 @@
 }
 
+/** Issue a control write transfer to virtual USB device.
+ *
+ * @see usbvirt_control_transfer
+ *
+ * @param dev Target virtual device.
+ * @param setup Setup data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data buffer in bytes.
+ * @return Error code.
+ */
 int usbvirt_control_write(usbvirt_device_t *dev, void *setup, size_t setup_size,
     void *data, size_t data_size)
@@ -85,4 +107,16 @@
 }
 
+/** Issue a control read transfer to virtual USB device.
+ *
+ * @see usbvirt_control_transfer
+ *
+ * @param dev Target virtual device.
+ * @param setup Setup data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data buffer in bytes.
+ * @param data_size_sent Number of actually send bytes during the transfer.
+ * @return Error code.
+ */
 int usbvirt_control_read(usbvirt_device_t *dev, void *setup, size_t setup_size,
     void *data, size_t data_size, size_t *data_size_sent)
@@ -92,4 +126,13 @@
 }
 
+/** Send data to virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param transf_type Transfer type (interrupt, bulk).
+ * @param endpoint Endpoint number.
+ * @param data Data sent from the driver to the device.
+ * @param data_size Size of the @p data buffer in bytes.
+ * @return Error code.
+ */
 int usbvirt_data_out(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
     usb_endpoint_t endpoint, void *data, size_t data_size)
@@ -108,4 +151,14 @@
 }
 
+/** Request data from virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param transf_type Transfer type (interrupt, bulk).
+ * @param endpoint Endpoint number.
+ * @param data Where to stored data the device returns to the driver.
+ * @param data_size Size of the @p data buffer in bytes.
+ * @param data_size_sent Number of actually written bytes.
+ * @return Error code.
+ */
 int usbvirt_data_in(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
     usb_endpoint_t endpoint, void *data, size_t data_size, size_t *data_size_sent)
