Index: uspace/lib/usbvirt/src/ctrltransfer.c
===================================================================
--- uspace/lib/usbvirt/src/ctrltransfer.c	(revision f9b2cb4cf365498e1fe141b1aa66950fbc3dcb17)
+++ uspace/lib/usbvirt/src/ctrltransfer.c	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
@@ -50,6 +50,6 @@
  */
 int process_control_transfer(usbvirt_device_t *dev,
-    usbvirt_control_request_handler_t *control_handlers,
-    usb_device_request_setup_packet_t *setup,
+    const usbvirt_control_request_handler_t *control_handlers,
+    const usb_device_request_setup_packet_t *setup,
     uint8_t *data, size_t *data_sent_size)
 {
@@ -60,23 +60,9 @@
 		return EFORWARD;
 	}
-
-	usb_direction_t direction = setup->request_type & 128 ?
-	    USB_DIRECTION_IN : USB_DIRECTION_OUT;
-	usb_request_recipient_t req_recipient = setup->request_type & 31;
-	usb_request_type_t req_type = (setup->request_type >> 5) & 3;
-
-	usbvirt_control_request_handler_t *handler = control_handlers;
-	while (handler->callback != NULL) {
-		if (handler->req_direction != direction) {
-			goto next;
-		}
-		if (handler->req_recipient != req_recipient) {
-			goto next;
-		}
-		if (handler->req_type != req_type) {
-			goto next;
-		}
-		if (handler->request != setup->request) {
-			goto next;
+	const usbvirt_control_request_handler_t *handler = control_handlers;
+	for (;handler->callback != NULL; ++handler) {
+		if (handler->request != setup->request ||
+		    handler->request_type != setup->request_type) {
+			continue;
 		}
 
@@ -84,12 +70,8 @@
 		    usb_debug_str_buffer((uint8_t*) setup, sizeof(*setup), 0));
 		int rc = handler->callback(dev, setup, data, data_sent_size);
-		if (rc == EFORWARD) {
-			goto next;
+		if (rc != EFORWARD) {
+			return rc;
 		}
 
-		return rc;
-
-next:
-		handler++;
 	}
 
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision f9b2cb4cf365498e1fe141b1aa66950fbc3dcb17)
+++ uspace/lib/usbvirt/src/private.h	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
@@ -39,6 +39,6 @@
 
 int process_control_transfer(usbvirt_device_t *,
-    usbvirt_control_request_handler_t *,
-    usb_device_request_setup_packet_t *,
+    const usbvirt_control_request_handler_t *,
+    const usb_device_request_setup_packet_t *,
     uint8_t *, size_t *);
 
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision f9b2cb4cf365498e1fe141b1aa66950fbc3dcb17)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
@@ -51,5 +51,5 @@
 void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *setup_packet,
     uint8_t *data, size_t *act_size,
-    void *actual_data, size_t actual_data_size)
+    const void *actual_data, size_t actual_data_size)
 {
 	size_t expected_size = setup_packet->length;
@@ -63,4 +63,12 @@
 		*act_size = actual_data_size;
 	}
+}
+
+/** 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;
 }
 
@@ -98,6 +106,6 @@
 		}
 		/* Copy the data. */
-		usbvirt_device_configuration_t *config = &device->descriptors
-		    ->configuration[index];
+		const usbvirt_device_configuration_t *config =
+		    &device->descriptors->configuration[index];
 		uint8_t *all_data = malloc(config->descriptor->total_length);
 		if (all_data == NULL) {
@@ -110,5 +118,5 @@
 		size_t i;
 		for (i = 0; i < config->extra_count; i++) {
-			usbvirt_device_configuration_extras_t *extra
+			const usbvirt_device_configuration_extras_t *extra
 			    = &config->extra[i];
 			memcpy(ptr, extra->data, extra->length);
@@ -189,31 +197,58 @@
 }
 
+static int req_get_dev_status(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
+{
+	if (setup_packet->length != 2)
+		return ESTALL;
+	data[0] = (device->self_powered ? 1 : 0) | (device->remote_wakeup ? 2 : 0);
+	data[1] = 0;
+	*act_size = 2;
+	return EOK;
+}
+static int req_get_iface_ep_status(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
+{
+	if (setup_packet->length != 2)
+		return ESTALL;
+	data[0] = 0;
+	data[1] = 0;
+	*act_size = 2;
+	return EOK;
+}
+
 /** Standard request handlers. */
 usbvirt_control_request_handler_t library_handlers[] = {
 	{
-		.req_direction = USB_DIRECTION_OUT,
-		.req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
-		.req_type = USB_REQUEST_TYPE_STANDARD,
-		.request = USB_DEVREQ_SET_ADDRESS,
+		STD_REQ_OUT(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_SET_ADDRESS),
 		.name = "SetAddress",
 		.callback = req_set_address
 	},
 	{
-		.req_direction = USB_DIRECTION_IN,
-		.req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
-		.req_type = USB_REQUEST_TYPE_STANDARD,
-		.request = USB_DEVREQ_GET_DESCRIPTOR,
-		.name = "GetDescriptor",
+		STD_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.name = "GetStdDescriptor",
 		.callback = req_get_descriptor
 	},
 	{
-		.req_direction = USB_DIRECTION_OUT,
-		.req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
-		.req_type = USB_REQUEST_TYPE_STANDARD,
-		.request = USB_DEVREQ_SET_CONFIGURATION,
+		STD_REQ_OUT(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_SET_CONFIGURATION),
 		.name = "SetConfiguration",
 		.callback = req_set_configuration
 	},
-
+	{
+		STD_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_STATUS),
+		.name = "GetDeviceStatus",
+		.callback = req_get_dev_status,
+	},
+	{
+		STD_REQ_IN(USB_REQUEST_RECIPIENT_INTERFACE, USB_DEVREQ_GET_STATUS),
+		.name = "GetInterfaceStatus",
+		.callback = req_get_iface_ep_status,
+	},
+	{
+		/* virtual EPs by default cannot be stalled */
+		STD_REQ_IN(USB_REQUEST_RECIPIENT_ENDPOINT, USB_DEVREQ_GET_STATUS),
+		.name = "GetEndpointStatus",
+		.callback = req_get_iface_ep_status,
+	},
 	{ .callback = NULL }
 };
Index: uspace/lib/usbvirt/src/transfer.c
===================================================================
--- uspace/lib/usbvirt/src/transfer.c	(revision f9b2cb4cf365498e1fe141b1aa66950fbc3dcb17)
+++ uspace/lib/usbvirt/src/transfer.c	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
@@ -51,5 +51,5 @@
  */
 static int usbvirt_control_transfer(usbvirt_device_t *dev,
-    void *setup, size_t setup_size,
+    const void *setup, size_t setup_size,
     void *data, size_t data_size, size_t *data_size_sent)
 {
@@ -60,5 +60,5 @@
 		return ESTALL;
 	}
-	usb_device_request_setup_packet_t *setup_packet = setup;
+	const usb_device_request_setup_packet_t *setup_packet = setup;
 	if (data_size != setup_packet->length) {
 		return ESTALL;
@@ -100,6 +100,6 @@
  * @return Error code.
  */
-int usbvirt_control_write(usbvirt_device_t *dev, void *setup, size_t setup_size,
-    void *data, size_t data_size)
+int usbvirt_control_write(usbvirt_device_t *dev, const void *setup,
+    size_t setup_size, void *data, size_t data_size)
 {
 	return usbvirt_control_transfer(dev, setup, setup_size,
@@ -119,5 +119,5 @@
  * @return Error code.
  */
-int usbvirt_control_read(usbvirt_device_t *dev, void *setup, size_t setup_size,
+int usbvirt_control_read(usbvirt_device_t *dev, const void *setup, size_t setup_size,
     void *data, size_t data_size, size_t *data_size_sent)
 {
@@ -136,5 +136,5 @@
  */
 int usbvirt_data_out(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
-    usb_endpoint_t endpoint, void *data, size_t data_size)
+    usb_endpoint_t endpoint, const void *data, size_t data_size)
 {
 	if ((endpoint <= 0) || (endpoint >= USBVIRT_ENDPOINT_MAX)) {
Index: uspace/lib/usbvirt/src/virthub_base.c
===================================================================
--- uspace/lib/usbvirt/src/virthub_base.c	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
+++ uspace/lib/usbvirt/src/virthub_base.c	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
@@ -0,0 +1,175 @@
+/*
+ * 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 <macros.h>
+#include <str.h>
+#include <usb/classes/hub.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 usb_standard_endpoint_descriptor_t virthub_endpoint_descriptor;
+extern const usbvirt_device_configuration_extras_t virthub_interface_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, usb_endpoint_t ep)
+{
+	assert(instance);
+	assert(hub_desc);
+	assert(name);
+
+	if (!usb_endpoint_is_valid(ep) || (ep == USB_ENDPOINT_DEFAULT_CONTROL))
+		return EINVAL;
+
+	instance->config_descriptor =
+	    virthub_configuration_descriptor_without_hub_size;
+	instance->config_descriptor.total_length += hub_desc->length;
+
+	instance->endpoint_descriptor = virthub_endpoint_descriptor;
+	instance->endpoint_descriptor.endpoint_address = 128 | ep;
+	instance->endpoint_descriptor.max_packet_size =
+	    STATUS_BYTES(hub_desc->port_count);
+
+	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 = ARRAY_SIZE(instance->extra);
+
+	instance->extra[0] = virthub_interface_descriptor_ex;
+	instance->extra[1].data = (void *)hub_desc;
+	instance->extra[1].length = hub_desc->length;
+	instance->extra[2].data = (void*)&instance->endpoint_descriptor;
+	instance->extra[2].length = sizeof(instance->endpoint_descriptor);
+
+	instance->device.ops = ops;
+	instance->device.descriptors = &instance->descriptors;
+	instance->device.device_data = instance;
+	instance->device.address = 0;
+	instance->data = data;
+	instance->device.name = str_dup(name);
+
+	if (!instance->device.name)
+		return ENOMEM;
+
+	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[1].data, instance->extra[1].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 072607b7612718a490dd8854b8c3cbf320c67751)
+++ uspace/lib/usbvirt/src/virthub_descriptors.c	(revision 072607b7612718a490dd8854b8c3cbf320c67751)
@@ -0,0 +1,106 @@
+/*
+ * 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 = 1 | 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),
+};
+
+
+/**
+ * @}
+ */
