Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision b997e7b1c887fcaf9ee6d5e50359333226bd57c8)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -73,6 +73,9 @@
 	/** Characteristics bitmask. */
 	uint8_t characteristics;
-#define HUB_CHAR_POWER_PER_PORT_FLAG  (1 << 0)
-#define HUB_CHAR_NO_POWER_SWITCH_FLAG (1 << 1)
+#define HUB_CHAR_POWER_PER_PORT_FLAG    (1 << 0)
+#define HUB_CHAR_NO_POWER_SWITCH_FLAG   (1 << 1)
+#define HUB_CHAR_COMPUND_DEVICE         (1 << 2)
+#define HUB_CHAR_OC_PER_PORT_FLAG       (1 << 3)
+#define HUB_CHAR_NO_OC_FLAG             (1 << 4)
 	/* Unused part of characteristics field */
 	uint8_t characteristics_reserved;
@@ -83,4 +86,6 @@
 } __attribute__ ((packed)) usb_hub_descriptor_header_t;
 
+
+#if 0
 /**
  * @brief usb hub descriptor
@@ -169,5 +174,5 @@
     //uint8_t * port_pwr_ctrl_mask;
 } usb_hub_descriptor_t;
-
+#endif
 
 
Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision b997e7b1c887fcaf9ee6d5e50359333226bd57c8)
+++ uspace/lib/usbvirt/Makefile	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -34,5 +34,6 @@
 	-I$(LIBUSB_PREFIX)/include \
 	-I$(LIBUSBDEV_PREFIX)/include \
-	-Iinclude
+	-Iinclude \
+	-Iinclude/usbvirt
 
 SOURCES = \
@@ -42,5 +43,7 @@
 	src/ipc_hc.c \
 	src/stdreq.c \
-	src/transfer.c
+	src/transfer.c \
+	src/virthub_base.c \
+	src/virthub_descriptors.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision b997e7b1c887fcaf9ee6d5e50359333226bd57c8)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -239,4 +239,9 @@
 };
 
+
+int req_nop(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
 int usbvirt_device_plug(usbvirt_device_t *, const char *);
 void usbvirt_device_unplug(usbvirt_device_t *);
Index: uspace/lib/usbvirt/include/usbvirt/virthub_base.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/virthub_base.h	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
+++ uspace/lib/usbvirt/include/usbvirt/virthub_base.h	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device.
+ */
+
+#ifndef LIBUSBVIRT_VIRTHUB_BASE_H_
+#define LIBUSBVIRT_VIRTHUB_BASE_H_
+
+#include <usbvirt/device.h>
+#include <usb/classes/hub.h>
+
+enum {
+	VIRTHUB_EXTR_DESC = 3,
+	HUB_STATUS_CHANGE_PIPE = 1,
+};
+
+typedef struct {
+	usb_standard_configuration_descriptor_t config_descriptor;
+	usbvirt_device_configuration_extras_t extra[VIRTHUB_EXTR_DESC];
+	usbvirt_device_configuration_t configuration;
+	usbvirt_descriptors_t descriptors;
+	usbvirt_device_t device;
+	void *data;
+} virthub_base_t;
+
+void *virthub_get_data(usbvirt_device_t *dev);
+
+int virthub_base_init(virthub_base_t *instance,
+    const char *name, usbvirt_device_ops_t *ops, void *data,
+    const usb_standard_device_descriptor_t *device_desc,
+    const usb_hub_descriptor_header_t *hub_desc);
+
+usb_address_t virthub_base_get_address(virthub_base_t *instance);
+
+int virthub_base_request(virthub_base_t *instance, usb_target_t target,
+    usb_direction_t dir, const usb_device_request_setup_packet_t *setup,
+    void *buffer, size_t buffer_size, size_t *real_size);
+
+int virthub_base_get_hub_descriptor(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size);
+int virthub_base_get_null_status(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size);
+
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision b997e7b1c887fcaf9ee6d5e50359333226bd57c8)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -65,4 +65,12 @@
 }
 
+/** NOP handler */
+int req_nop(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	return EOK;
+}
+
 /** GET_DESCRIPTOR handler. */
 static int req_get_descriptor(usbvirt_device_t *device,
Index: uspace/lib/usbvirt/src/virthub_base.c
===================================================================
--- uspace/lib/usbvirt/src/virthub_base.c	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
+++ uspace/lib/usbvirt/src/virthub_base.c	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device main routines.
+ */
+
+#include <assert.h>
+#include <str.h>
+
+#include "virthub_base.h"
+
+extern const usb_standard_device_descriptor_t virthub_device_descriptor;
+extern const usb_standard_configuration_descriptor_t virthub_configuration_descriptor_without_hub_size;
+extern const usbvirt_device_configuration_extras_t virthub_interface_descriptor_ex;
+extern const usbvirt_device_configuration_extras_t virthub_endpoint_descriptor_ex;
+
+void *virthub_get_data(usbvirt_device_t *dev)
+{
+	assert(dev);
+	virthub_base_t *base = dev->device_data;
+	assert(base);
+	return base->data;
+}
+
+int virthub_base_init(virthub_base_t *instance,
+    const char *name, usbvirt_device_ops_t *ops, void *data,
+    const usb_standard_device_descriptor_t *device_desc,
+    const usb_hub_descriptor_header_t *hub_desc)
+{
+	assert(instance);
+	assert(hub_desc);
+	assert(name);
+
+	instance->config_descriptor =
+	    virthub_configuration_descriptor_without_hub_size;
+	instance->config_descriptor.total_length += hub_desc->length;
+
+	instance->descriptors.device =
+	    device_desc ? device_desc : &virthub_device_descriptor;
+	instance->descriptors.configuration = &instance->configuration;
+	instance->descriptors.configuration_count = 1;
+
+	instance->configuration.descriptor = &instance->config_descriptor;
+	instance->configuration.extra = instance->extra;
+	instance->configuration.extra_count = VIRTHUB_EXTR_DESC;
+
+	instance->extra[0] = virthub_interface_descriptor_ex;
+	instance->extra[1].data = (void *)hub_desc;
+	instance->extra[1].length = hub_desc->length;
+	instance->extra[2] = virthub_endpoint_descriptor_ex;
+
+	instance->device.ops = ops;
+	instance->device.descriptors = &instance->descriptors;
+	instance->device.name = str_dup(name);
+	instance->device.device_data = instance;
+	instance->device.address = 0;
+	instance->data = data;
+
+	return EOK;
+}
+
+usb_address_t virthub_base_get_address(virthub_base_t *instance)
+{
+	assert(instance);
+	return instance->device.address;
+}
+
+int virthub_base_request(virthub_base_t *instance, usb_target_t target,
+    usb_direction_t dir, const usb_device_request_setup_packet_t *setup,
+    void *buffer, size_t buffer_size, size_t *real_size)
+{
+	assert(instance);
+	assert(real_size);
+	assert(setup);
+
+	if (target.address != virthub_base_get_address(instance))
+		return ENOENT;
+
+	switch (dir) {
+	case USB_DIRECTION_IN:
+		if (target.endpoint == 0) {
+			return usbvirt_control_read(&instance->device,
+			    setup, sizeof(*setup), buffer, buffer_size,
+			    real_size);
+		} else {
+			return usbvirt_data_in(&instance->device,
+			    USB_TRANSFER_INTERRUPT, target.endpoint,
+			    buffer, buffer_size, real_size);
+		}
+	case USB_DIRECTION_OUT:
+		if (target.endpoint == 0) {
+			return usbvirt_control_write(&instance->device,
+			    setup, sizeof(*setup), buffer, buffer_size);
+		}
+		/* fall through */
+	default:
+		return ENOTSUP;
+
+	}
+}
+
+int virthub_base_get_hub_descriptor(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	assert(dev);
+	virthub_base_t *instance = dev->device_data;
+	assert(instance);
+	if (request->value_high == USB_DESCTYPE_HUB) {
+		usbvirt_control_reply_helper(request, data, act_size,
+		    &instance->extra[2].data, instance->extra[2].length);
+
+		return EOK;
+	}
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+int virthub_base_get_null_status(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	uint32_t zero = 0;
+	if (request->length != sizeof(zero))
+		return ESTALL;
+	usbvirt_control_reply_helper(request, data, act_size,
+	    &zero, sizeof(zero));
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/virthub_descriptors.c
===================================================================
--- uspace/lib/usbvirt/src/virthub_descriptors.c	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
+++ uspace/lib/usbvirt/src/virthub_descriptors.c	(revision 32c2c8ff3a269049cd57134f1bd558c595b7f35d)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device main routines.
+ */
+
+#include <usb/classes/classes.h>
+#include <usb/classes/hub.h>
+#include <usb/descriptor.h>
+#include <usb/usb.h>
+#include <usbvirt/device.h>
+
+#include "virthub_base.h"
+
+#define HUB_CONFIGURATION_ID   1
+
+/** Standard device descriptor. */
+const usb_standard_device_descriptor_t virthub_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_HUB,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+
+/** Standard interface descriptor. */
+const usb_standard_interface_descriptor_t virthub_interface_descriptor = {
+	.length = sizeof(usb_standard_interface_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_INTERFACE,
+	.interface_number = 0,
+	.alternate_setting = 0,
+	.endpoint_count = 1,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.str_interface = 0
+};
+
+/** Endpoint descriptor. */
+const usb_standard_endpoint_descriptor_t virthub_endpoint_descriptor = {
+	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_ENDPOINT,
+	.endpoint_address = HUB_STATUS_CHANGE_PIPE | 128,
+	.attributes = USB_TRANSFER_INTERRUPT,
+	.max_packet_size = 8,
+	.poll_interval = 0xFF,
+};
+
+/** Standard configuration descriptor. */
+const usb_standard_configuration_descriptor_t virthub_configuration_descriptor_without_hub_size = {
+	.length = sizeof(virthub_configuration_descriptor_without_hub_size),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	.total_length =
+		sizeof(virthub_configuration_descriptor_without_hub_size)
+		+ sizeof(virthub_interface_descriptor)
+		+ sizeof(virthub_endpoint_descriptor)
+		,
+	.interface_count = 1,
+	.configuration_number = HUB_CONFIGURATION_ID,
+	.str_configuration = 0,
+	.attributes = 0, /* We are self-powered device */
+	.max_power = 0,
+};
+
+const usbvirt_device_configuration_extras_t virthub_interface_descriptor_ex = {
+	.data = (uint8_t *) &virthub_interface_descriptor,
+	.length = sizeof(virthub_interface_descriptor),
+};
+
+const usbvirt_device_configuration_extras_t virthub_endpoint_descriptor_ex = {
+	.data = (uint8_t *) &virthub_endpoint_descriptor,
+	.length = sizeof(virthub_endpoint_descriptor),
+};
+
+
+/**
+ * @}
+ */
