Index: uspace/app/virtusbkbd/Makefile
===================================================================
--- uspace/app/virtusbkbd/Makefile	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/app/virtusbkbd/Makefile	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -33,5 +33,5 @@
 
 LIBS = $(LIBUSB_PREFIX)/libusb.a $(LIBUSBVIRT_PREFIX)/libusbvirt.a
-EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -I$(LIB_PREFIX) -I$(LIBDRV_PREFIX)/include
+EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -I$(LIBUSBVIRT_PREFIX)/include -I$(LIBDRV_PREFIX)/include
 
 SOURCES = \
Index: uspace/app/virtusbkbd/stdreq.c
===================================================================
--- uspace/app/virtusbkbd/stdreq.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/app/virtusbkbd/stdreq.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -39,23 +39,5 @@
 #include "kbdconfig.h"
 
-static int on_get_descriptor(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data);
-
-usbvirt_standard_device_request_ops_t standard_request_ops = {
-	.on_get_status = NULL,
-	.on_clear_feature = NULL,
-	.on_set_feature = NULL,
-	.on_set_address = NULL,
-	.on_get_descriptor = on_get_descriptor,
-	.on_set_descriptor = NULL,
-	.on_get_configuration = NULL,
-	.on_set_configuration = NULL,
-	.on_get_interface = NULL,
-	.on_set_interface = NULL,
-	.on_synch_frame = NULL
-};
-
-
-static int on_get_descriptor(struct usbvirt_device *dev,
+int stdreq_on_get_descriptor(struct usbvirt_device *dev,
     usb_device_request_setup_packet_t *request, uint8_t *data)
 {
Index: uspace/app/virtusbkbd/stdreq.h
===================================================================
--- uspace/app/virtusbkbd/stdreq.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/app/virtusbkbd/stdreq.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -38,5 +38,6 @@
 #include <usbvirt/device.h>
 
-extern usbvirt_standard_device_request_ops_t standard_request_ops;
+int stdreq_on_get_descriptor(usbvirt_device_t *,
+    usb_device_request_setup_packet_t *, uint8_t *);
 
 #endif
Index: uspace/app/virtusbkbd/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/app/virtusbkbd/virtusbkbd.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -76,11 +76,4 @@
 }
 
-static int on_class_request(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{	
-	printf("%s: class request (%d)\n", NAME, (int) request->request);
-	
-	return EOK;
-}
 
 /** Compares current and last status of pressed keys.
@@ -138,4 +131,25 @@
 }
 
+static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
+	{
+		.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(
+		    USB_DIRECTION_IN,
+		    USBVIRT_REQUEST_TYPE_STANDARD,
+		    USBVIRT_REQUEST_RECIPIENT_DEVICE),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "GetDescriptor",
+		.callback = stdreq_on_get_descriptor
+	},
+	{
+		.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(
+		    USB_DIRECTION_IN,
+		    USBVIRT_REQUEST_TYPE_CLASS,
+		    USBVIRT_REQUEST_RECIPIENT_DEVICE),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "GetDescriptor",
+		.callback = stdreq_on_get_descriptor
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
+};
 
 /** Keyboard callbacks.
@@ -143,6 +157,5 @@
  */
 static usbvirt_device_ops_t keyboard_ops = {
-	.standard_request_ops = &standard_request_ops,
-	.on_class_device_request = on_class_request,
+	.control_transfer_handlers = endpoint_zero_handlers,
 	.on_data = on_incoming_data,
 	.on_data_request = on_request_for_data
@@ -257,4 +270,5 @@
 	
 	printf("%s: Simulating keyboard events...\n", NAME);
+	fibril_sleep(10);
 	while (1) {
 		kb_process_events(&status, keyboard_events, keyboard_events_count,
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/usbhub/utils.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -552,5 +552,5 @@
 		return;
 	}
-	printf("[usb_hub] new device address %d, handle %d\n",
+	printf("[usb_hub] new device address %d, handle %zu\n",
 	    new_device_address, child_handle);
 	
Index: uspace/drv/vhc/Makefile
===================================================================
--- uspace/drv/vhc/Makefile	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/Makefile	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -33,5 +33,5 @@
 	$(LIBDRV_PREFIX)/libdrv.a
 EXTRA_CFLAGS += \
-	-I$(LIB_PREFIX) \
+	-I$(LIBUSBVIRT_PREFIX)/include \
 	-I$(LIBUSB_PREFIX)/include \
 	-I$(LIBDRV_PREFIX)/include
@@ -39,4 +39,7 @@
 
 SOURCES = \
+	hub/hub.c \
+	hub/virthub.c \
+	hub/virthubops.c \
 	conndev.c \
 	connhost.c \
@@ -45,6 +48,5 @@
 	hc.c \
 	hcd.c \
-	hub.c \
-	hubops.c
+	hub.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/connhost.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -102,5 +102,5 @@
 	transfer->out_callback = callback;
 
-	hc_add_transaction_to_device(false, target, buffer, size,
+	hc_add_transaction_to_device(false, target, transfer_type, buffer, size,
 	    universal_callback, transfer);
 
@@ -122,5 +122,5 @@
 	transfer->out_callback = callback;
 
-	hc_add_transaction_to_device(true, target, buffer, size,
+	hc_add_transaction_to_device(true, target, transfer_type, buffer, size,
 	    universal_callback, transfer);
 
@@ -142,5 +142,5 @@
 	transfer->in_callback = callback;
 
-	hc_add_transaction_from_device(target, buffer, size,
+	hc_add_transaction_from_device(target, transfer_type, buffer, size,
 	    universal_callback, transfer);
 
Index: uspace/drv/vhc/devices.c
===================================================================
--- uspace/drv/vhc/devices.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/devices.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -47,4 +47,5 @@
 #include "devices.h"
 #include "hub.h"
+#include "hub/virthub.h"
 #include "vhcd.h"
 
@@ -69,5 +70,5 @@
 	list_append(&dev->link, &devices);
 	
-	hub_add_device(dev);
+	virthub_connect_device(&virtual_hub_device, dev);
 	
 	return dev;
@@ -78,5 +79,5 @@
 void virtdev_destroy_device(virtdev_connection_t *dev)
 {
-	hub_remove_device(dev);
+	virthub_disconnect_device(&virtual_hub_device, dev);
 	list_remove(&dev->link);
 	free(dev);
@@ -94,5 +95,5 @@
 		    = list_get_instance(pos, virtdev_connection_t, link);
 		
-		if (!hub_can_device_signal(dev)) {
+		if (!virthub_is_device_enabled(&virtual_hub_device, dev)) {
 			continue;
 		}
@@ -145,5 +146,5 @@
 	 * (if the address matches).
 	 */
-	if (virthub_dev.address == transaction->target.address) {
+	if (virtual_hub_device.address == transaction->target.address) {
 		size_t tmp;
 		dprintf(1, "sending `%s' transaction to hub",
@@ -151,5 +152,6 @@
 		switch (transaction->type) {
 			case USBVIRT_TRANSACTION_SETUP:
-				virthub_dev.transaction_setup(&virthub_dev,
+				virtual_hub_device.transaction_setup(
+				    &virtual_hub_device,
 				    transaction->target.endpoint,
 				    transaction->buffer, transaction->len);
@@ -157,5 +159,6 @@
 				
 			case USBVIRT_TRANSACTION_IN:
-				virthub_dev.transaction_in(&virthub_dev,
+				virtual_hub_device.transaction_in(
+				    &virtual_hub_device,
 				    transaction->target.endpoint,
 				    transaction->buffer, transaction->len,
@@ -167,5 +170,6 @@
 				
 			case USBVIRT_TRANSACTION_OUT:
-				virthub_dev.transaction_out(&virthub_dev,
+				virtual_hub_device.transaction_out(
+				    &virtual_hub_device,
 				    transaction->target.endpoint,
 				    transaction->buffer, transaction->len);
Index: uspace/drv/vhc/hc.c
===================================================================
--- uspace/drv/vhc/hc.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/hc.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -68,7 +68,8 @@
 static link_t transaction_list;
 
-#define TRANSACTION_FORMAT "T[%d:%d %s (%d)]"
+#define TRANSACTION_FORMAT "T[%d.%d %s/%s (%d)]"
 #define TRANSACTION_PRINTF(t) \
 	(t).target.address, (t).target.endpoint, \
+	usb_str_transfer_type((t).transfer_type), \
 	usbvirt_str_transaction_type((t).type), \
 	(int)(t).len
@@ -76,4 +77,6 @@
 #define transaction_get_instance(lnk) \
 	list_get_instance(lnk, transaction_t, link)
+
+#define HUB_STATUS_MAX_LEN (HUB_PORT_COUNT + 64)
 
 static inline unsigned int pseudo_random(unsigned int *seed)
@@ -99,5 +102,5 @@
 /** Host controller manager main function.
  */
-void hc_manager(void)
+static int hc_manager_fibril(void *arg)
 {
 	list_initialize(&transaction_list);
@@ -114,8 +117,6 @@
 		}
 		
-		char ports[HUB_PORT_COUNT + 2];
-		hub_get_port_statuses(ports, HUB_PORT_COUNT + 1);
-		dprintf(4, "virtual hub: addr=%d ports=%s",
-		    virthub_dev.address, ports);
+		char ports[HUB_STATUS_MAX_LEN + 1];
+		virthub_get_status(&virtual_hub_device, ports, HUB_STATUS_MAX_LEN);
 		
 		link_t *first_transaction_link = transaction_list.next;
@@ -125,5 +126,5 @@
 		
 
-		dprintf(0, "about to process " TRANSACTION_FORMAT " (vhub:%s)",
+		dprintf(0, "about to process " TRANSACTION_FORMAT " [%s]",
 		    TRANSACTION_PRINTF(*transaction), ports);
 
@@ -138,4 +139,17 @@
 		free(transaction);
 	}
+
+	assert(false && "unreachable");
+	return EOK;
+}
+
+void hc_manager(void)
+{
+	fid_t fid = fibril_create(hc_manager_fibril, NULL);
+	if (fid == 0) {
+		printf(NAME ": failed to start HC manager fibril\n");
+		return;
+	}
+	fibril_add_ready(fid);
 }
 
@@ -143,5 +157,5 @@
  */
 static transaction_t *transaction_create(usbvirt_transaction_type_t type,
-    usb_target_t target,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void * buffer, size_t len,
     hc_transaction_done_callback_t callback, void * arg)
@@ -151,4 +165,5 @@
 	list_initialize(&transaction->link);
 	transaction->type = type;
+	transaction->transfer_type = transfer_type;
 	transaction->target = target;
 	transaction->buffer = buffer;
@@ -166,9 +181,11 @@
  */
 void hc_add_transaction_to_device(bool setup, usb_target_t target,
+    usb_transfer_type_t transfer_type,
     void * buffer, size_t len,
     hc_transaction_done_callback_t callback, void * arg)
 {
 	transaction_t *transaction = transaction_create(
-	    setup ? USBVIRT_TRANSACTION_SETUP : USBVIRT_TRANSACTION_OUT, target,
+	    setup ? USBVIRT_TRANSACTION_SETUP : USBVIRT_TRANSACTION_OUT,
+	    target, transfer_type,
 	    buffer, len, callback, arg);
 	list_append(&transaction->link, &transaction_list);
@@ -178,9 +195,11 @@
  */
 void hc_add_transaction_from_device(usb_target_t target,
+    usb_transfer_type_t transfer_type,
     void * buffer, size_t len,
     hc_transaction_done_callback_t callback, void * arg)
 {
 	transaction_t *transaction = transaction_create(USBVIRT_TRANSACTION_IN,
-	    target, buffer, len, callback, arg);
+	    target, transfer_type,
+	    buffer, len, callback, arg);
 	list_append(&transaction->link, &transaction_list);
 }
Index: uspace/drv/vhc/hc.h
===================================================================
--- uspace/drv/vhc/hc.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/hc.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -55,4 +55,6 @@
 	/** Transaction type. */
 	usbvirt_transaction_type_t type;
+	/** Transfer type. */
+	usb_transfer_type_t transfer_type;
 	/** Device address. */
 	usb_target_t target;
@@ -71,9 +73,11 @@
 void hc_manager(void);
 
-void hc_add_transaction_to_device(bool setup, usb_target_t target,
+void hc_add_transaction_to_device(bool setup,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void * buffer, size_t len,
     hc_transaction_done_callback_t callback, void * arg);
 
-void hc_add_transaction_from_device(usb_target_t target,
+void hc_add_transaction_from_device(
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void * buffer, size_t len,
     hc_transaction_done_callback_t callback, void * arg);
Index: uspace/drv/vhc/hcd.c
===================================================================
--- uspace/drv/vhc/hcd.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/hcd.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -79,5 +79,5 @@
 	 * Initialize our hub and announce its presence.
 	 */
-	hub_init(dev);
+	virtual_hub_device_init(dev);
 
 	printf("%s: virtual USB host controller ready.\n", NAME);
@@ -95,33 +95,18 @@
 };
 
-/** Fibril wrapper for HC transaction manager.
- *
- * @param arg Not used.
- * @return Nothing, return argument is unreachable.
- */
-static int hc_manager_fibril(void *arg)
-{
-	hc_manager();
-	return EOK;
-}
 
 int main(int argc, char * argv[])
 {	
-	printf("%s: virtual USB host controller driver.\n", NAME);
-
-	usb_dprintf_enable(NAME, 0);
-
-	fid_t fid = fibril_create(hc_manager_fibril, NULL);
-	if (fid == 0) {
-		printf("%s: failed to start HC manager fibril\n", NAME);
-		return ENOMEM;
-	}
-	fibril_add_ready(fid);
-
 	/*
 	 * Temporary workaround. Wait a little bit to be the last driver
 	 * in devman output.
 	 */
-	sleep(4);
+	sleep(5);
+
+	usb_dprintf_enable(NAME, 0);
+
+	printf(NAME ": virtual USB host controller driver.\n");
+
+	hc_manager();
 
 	return driver_main(&vhc_driver);
Index: uspace/drv/vhc/hub.c
===================================================================
--- uspace/drv/vhc/hub.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/hub.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -40,270 +40,63 @@
 #include <stdlib.h>
 #include <driver.h>
+#include <usb/usbdrv.h>
 
+#include "hub.h"
+#include "hub/virthub.h"
 #include "vhcd.h"
-#include "hub.h"
-#include "hubintern.h"
-#include "conn.h"
 
+usbvirt_device_t virtual_hub_device;
 
-/** Standard device descriptor. */
-usb_standard_device_descriptor_t std_device_descriptor = {
-	.length = sizeof(usb_standard_device_descriptor_t),
-	.descriptor_type = USB_DESCTYPE_DEVICE,
-	.usb_spec_version = 0x110,
-	.device_class = USB_CLASS_HUB,
-	.device_subclass = 0,
-	.device_protocol = 0,
-	.max_packet_size = 64,
-	.configuration_count = 1
-};
+static int hub_register_in_devman_fibril(void *arg);
 
-/** Standard interface descriptor. */
-usb_standard_interface_descriptor_t std_interface_descriptor = {
-	.length = sizeof(usb_standard_interface_descriptor_t),
-	.descriptor_type = USB_DESCTYPE_INTERFACE,
-	.interface_number = 0,
-	.alternate_setting = 0,
-	.endpoint_count = 1,
-	.interface_class = USB_CLASS_HUB,
-	.interface_subclass = 0,
-	.interface_protocol = 0,
-	.str_interface = 0
-};
+void virtual_hub_device_init(device_t *hc_dev)
+{
+	virthub_init(&virtual_hub_device);
 
-hub_descriptor_t hub_descriptor = {
-	.length = sizeof(hub_descriptor_t),
-	.type = USB_DESCTYPE_HUB,
-	.port_count = HUB_PORT_COUNT,
-	.characteristics = 0, 
-	.power_on_warm_up = 50, /* Huh? */
-	.max_current = 100, /* Huh again. */
-	.removable_device = { 0 },
-	.port_power = { 0xFF }
-};
+	/*
+	 * We need to register the root hub.
+	 * This must be done in separate fibril because the device
+	 * we are connecting to are ourselves and we cannot connect
+	 * before leaving the add_device() function.
+	 */
+	fid_t root_hub_registration
+	    = fibril_create(hub_register_in_devman_fibril, hc_dev);
+	if (root_hub_registration == 0) {
+		printf(NAME ": failed to register root hub\n");
+		return;
+	}
 
-/** Endpoint descriptor. */
-usb_standard_endpoint_descriptor_t endpoint_descriptor = {
-	.length = sizeof(usb_standard_endpoint_descriptor_t),
-	.descriptor_type = USB_DESCTYPE_ENDPOINT,
-	.endpoint_address = HUB_STATUS_CHANGE_PIPE | 128,
-	.attributes = USB_TRANSFER_INTERRUPT,
-	.max_packet_size = 8,
-	.poll_interval = 0xFF
-};
-
-/** Standard configuration descriptor. */
-usb_standard_configuration_descriptor_t std_configuration_descriptor = {
-	.length = sizeof(usb_standard_configuration_descriptor_t),
-	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
-	.total_length = 
-		sizeof(usb_standard_configuration_descriptor_t)
-		+ sizeof(std_interface_descriptor)
-		+ sizeof(hub_descriptor)
-		+ sizeof(endpoint_descriptor)
-		,
-	.interface_count = 1,
-	.configuration_number = HUB_CONFIGURATION_ID,
-	.str_configuration = 0,
-	.attributes = 128, /* denotes bus-powered device */
-	.max_power = 50
-};
-
-/** All hub configuration descriptors. */
-static usbvirt_device_configuration_extras_t extra_descriptors[] = {
-	{
-		.data = (uint8_t *) &std_interface_descriptor,
-		.length = sizeof(std_interface_descriptor)
-	},
-	{
-		.data = (uint8_t *) &hub_descriptor,
-		.length = sizeof(hub_descriptor)
-	},
-	{
-		.data = (uint8_t *) &endpoint_descriptor,
-		.length = sizeof(endpoint_descriptor)
-	}
-};
-
-/** Hub configuration. */
-usbvirt_device_configuration_t configuration = {
-	.descriptor = &std_configuration_descriptor,
-	.extra = extra_descriptors,
-	.extra_count = sizeof(extra_descriptors)/sizeof(extra_descriptors[0])
-};
-
-/** Hub standard descriptors. */
-usbvirt_descriptors_t descriptors = {
-	.device = &std_device_descriptor,
-	.configuration = &configuration,
-	.configuration_count = 1,
-};
-
-/** Hub as a virtual device. */
-usbvirt_device_t virthub_dev = {
-	.ops = &hub_ops,
-	.descriptors = &descriptors,
-	.lib_debug_level = 0,
-	.lib_debug_enabled_tags = USBVIRT_DEBUGTAG_ALL
-};
-
-/** Hub device. */
-hub_device_t hub_dev;
-
-static usb_address_t hub_set_address(usbvirt_device_t *hub)
-{
-	usb_address_t new_address;
-	int rc = vhc_iface.request_address(NULL, &new_address);
-	if (rc != EOK) {
-		return rc;
-	}
-	
-	usb_device_request_setup_packet_t setup_packet = {
-		.request_type = 0,
-		.request = USB_DEVREQ_SET_ADDRESS,
-		.index = 0,
-		.length = 0,
-	};
-	setup_packet.value = new_address;
-
-	hub->transaction_setup(hub, 0, &setup_packet, sizeof(setup_packet));
-	hub->transaction_in(hub, 0, NULL, 0, NULL);
-	
-	return new_address;
+	fibril_add_ready(root_hub_registration);
 }
 
-/** Initialize virtual hub. */
-void hub_init(device_t *hc_dev)
+/** Register root hub in devman.
+ *
+ * @param arg Host controller device (type <code>device_t *</code>).
+ * @return Error code.
+ */
+int hub_register_in_devman_fibril(void *arg)
 {
-	size_t i;
-	
-	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		hub_port_t *port = &hub_dev.ports[i];
-		
-		port->index = (int) i + 1;
-		port->device = NULL;
-		port->state = HUB_PORT_STATE_NOT_CONFIGURED;
-		port->status_change = 0;
-		fibril_mutex_initialize(&port->guard);
-	}
-	
-	usbvirt_connect_local(&virthub_dev);
-	
-	dprintf(1, "virtual hub (%d ports) created", HUB_PORT_COUNT);
+	device_t *hc_dev = (device_t *) arg;
 
-	usb_address_t hub_address = hub_set_address(&virthub_dev);
-	if (hub_address < 0) {
-		dprintf(1, "problem changing hub address (%s)",
-		    str_error(hub_address));
+	int hc = usb_drv_hc_connect(hc_dev, IPC_FLAG_BLOCKING);
+	if (hc < 0) {
+		printf(NAME ": failed to register root hub\n");
+		return hc;
 	}
 
-	dprintf(2, "virtual hub address changed to %d", hub_address);
+	usb_drv_reserve_default_address(hc);
 
-	char *id;
-	int rc = asprintf(&id, "usb&hub");
-	if (rc <= 0) {
-		return;
-	}
+	usb_address_t hub_address = usb_drv_request_address(hc);
+	usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT, hub_address);
+
+	usb_drv_release_default_address(hc);
+
 	devman_handle_t hub_handle;
-	rc = child_device_register_wrapper(hc_dev, "hub", id, 10, &hub_handle);
-	if (rc != EOK) {
-		free(id);
-	}
+	usb_drv_register_child_in_devman(hc, hc_dev, hub_address, &hub_handle);
+	usb_drv_bind_address(hc, hub_address, hub_handle);
 
-	vhc_iface.bind_address(NULL, hub_address, hub_handle);	
-
-	dprintf(2, "virtual hub has devman handle %d", (int) hub_handle);
+	return EOK;
 }
-
-/** Connect device to the hub.
- *
- * @param device Device to be connected.
- * @return Port where the device was connected to.
- */
-size_t hub_add_device(virtdev_connection_t *device)
-{
-	size_t i;
-	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		hub_port_t *port = &hub_dev.ports[i];
-		fibril_mutex_lock(&port->guard);
-		
-		if (port->device != NULL) {
-			fibril_mutex_unlock(&port->guard);
-			continue;
-		}
-		
-		port->device = device;
-		
-		/*
-		 * TODO:
-		 * If the hub was configured, we can normally
-		 * announce the plug-in.
-		 * Otherwise, we will wait until hub is configured
-		 * and announce changes in single burst.
-		 */
-		//if (port->state == HUB_PORT_STATE_DISCONNECTED) {
-			port->state = HUB_PORT_STATE_DISABLED;
-			set_port_status_change_nl(port, HUB_STATUS_C_PORT_CONNECTION);
-		//}
-		
-		fibril_mutex_unlock(&port->guard);
-
-		return i;
-	}
 	
-	return (size_t)-1;
-}
-
-/** Disconnect device from the hub. */
-void hub_remove_device(virtdev_connection_t *device)
-{
-	size_t i;
-	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		hub_port_t *port = &hub_dev.ports[i];
-		
-		if (port->device != device) {
-			continue;
-		}
-		
-		port->device = NULL;
-		port->state = HUB_PORT_STATE_DISCONNECTED;
-		
-		set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
-	}
-}
-
-/** Tell whether device port is open.
- *
- * @return Whether communication to and from the device can go through the hub.
- */
-bool hub_can_device_signal(virtdev_connection_t * device)
-{
-	size_t i;
-	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		if (hub_dev.ports[i].device == device) {
-			return hub_dev.ports[i].state == HUB_PORT_STATE_ENABLED;
-		}
-	}
-	
-	return false;
-}
-
-/** Format hub port status.
- *
- * @param result Buffer where to store status string.
- * @param len Number of characters that is possible to store in @p result
- * 	(excluding trailing zero).
- */
-void hub_get_port_statuses(char *result, size_t len)
-{
-	if (len > HUB_PORT_COUNT) {
-		len = HUB_PORT_COUNT;
-	}
-	size_t i;
-	for (i = 0; i < len; i++) {
-		result[i] = hub_port_state_as_char(hub_dev.ports[i].state);
-	}
-	result[len] = 0;
-}
 
 /**
Index: uspace/drv/vhc/hub.h
===================================================================
--- uspace/drv/vhc/hub.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/drv/vhc/hub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -40,17 +40,10 @@
 
 #include "devices.h"
+#include "hub/hub.h"
+#include "hub/virthub.h"
 
-#define HUB_PORT_COUNT 2
+extern usbvirt_device_t virtual_hub_device;
 
-#define BITS2BYTES(bits) \
-    (bits ? ((((bits)-1)>>3)+1) : 0)
-
-extern usbvirt_device_t virthub_dev;
-
-void hub_init(device_t *);
-size_t hub_add_device(virtdev_connection_t *);
-void hub_remove_device(virtdev_connection_t *);
-bool hub_can_device_signal(virtdev_connection_t *);
-void hub_get_port_statuses(char *result, size_t len);
+void virtual_hub_device_init(device_t *);
 
 #endif
Index: uspace/drv/vhc/hub/hub.c
===================================================================
--- uspace/drv/vhc/hub/hub.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/drv/vhc/hub/hub.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief Representation of an USB hub (implementation).
+ */
+#include <usb/classes/classes.h>
+#include <usbvirt/hub.h>
+#include <usbvirt/device.h>
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <driver.h>
+#include <usb/usbdrv.h>
+
+#include "hub.h"
+
+
+/** Produce a byte from bit values.
+ */
+#define MAKE_BYTE(b0, b1, b2, b3, b4, b5, b6, b7) \
+	(( \
+		((b0) << 0) \
+		| ((b1) << 1) \
+		| ((b2) << 2) \
+		| ((b3) << 3) \
+		| ((b4) << 4) \
+		| ((b5) << 5) \
+		| ((b6) << 6) \
+		| ((b7) << 7) \
+	))
+
+/* Static functions. */
+static hub_port_t *get_hub_port(hub_t *, size_t);
+static void set_port_status_change(hub_port_t *, hub_status_change_t);
+static void clear_port_status_change(hub_port_t *, uint16_t);
+static int set_port_state_delayed_fibril(void *);
+static void set_port_state_delayed(hub_t *, size_t, suseconds_t,
+    hub_port_state_t, hub_port_state_t);
+
+/** Convert hub port state to a char. */
+char hub_port_state_to_char(hub_port_state_t state) {
+	switch (state) {
+		case HUB_PORT_STATE_NOT_CONFIGURED:
+			return '-';
+		case HUB_PORT_STATE_POWERED_OFF:
+			return 'O';
+		case HUB_PORT_STATE_DISCONNECTED:
+			return 'X';
+		case HUB_PORT_STATE_DISABLED:
+			return 'D';
+		case HUB_PORT_STATE_RESETTING:
+			return 'R';
+		case HUB_PORT_STATE_ENABLED:
+			return 'E';
+		case HUB_PORT_STATE_SUSPENDED:
+			return 'S';
+		case HUB_PORT_STATE_RESUMING:
+			return 'F';
+		default:
+			return '?';
+	}
+}
+
+/** Initialize single hub port.
+ *
+ * @param port Port to be initialized.
+ * @param index Port index (one based).
+ */
+static void hub_init_port(hub_port_t *port, size_t index)
+{
+	port->connected_device = NULL;
+	port->index = index;
+	port->state = HUB_PORT_STATE_NOT_CONFIGURED;
+	port->status_change = 0;
+}
+
+/** Initialize the hub.
+ *
+ * @param hub Hub to be initialized.
+ */
+void hub_init(hub_t *hub)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_init_port(&hub->ports[i], i + 1);
+	}
+	hub->custom_data = NULL;
+	fibril_mutex_initialize(&hub->guard);
+}
+
+/** Connect a device to the hub.
+ *
+ * @param hub Hub to connect device to.
+ * @param device Device to be connected.
+ * @return Index of port the device was connected to.
+ * @retval -1 No free port available.
+ */
+size_t hub_connect_device(hub_t *hub, void *device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub->ports[i];
+
+		if (port->connected_device != NULL) {
+			continue;
+		}
+
+		port->connected_device = device;
+
+		/*
+		 * TODO:
+		 * If the hub was configured, we can normally
+		 * announce the plug-in.
+		 * Otherwise, we will wait until hub is configured
+		 * and announce changes in single burst.
+		 */
+		//if (port->state == HUB_PORT_STATE_DISCONNECTED) {
+			port->state = HUB_PORT_STATE_DISABLED;
+			set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+		//}
+
+		return i;
+	}
+
+	return (size_t) -1;
+}
+
+/** Find port device is connected to.
+ *
+ * @param hub Hub in question.
+ * @param device Device in question.
+ * @return Port index (zero based).
+ * @retval -1 Device is not connected.
+ */
+size_t hub_find_device(hub_t *hub, void *device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub->ports[i];
+
+		if (port->connected_device == device) {
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+/** Acquire exclusive access to the hub.
+ *
+ * @param hub Hub in question.
+ */
+void hub_acquire(hub_t *hub)
+{
+	fibril_mutex_lock(&hub->guard);
+}
+
+/** Give up exclusive access to the hub.
+ *
+ * @param hub Hub in question.
+ */
+void hub_release(hub_t *hub)
+{
+	fibril_mutex_unlock(&hub->guard);
+}
+
+/** Change port state.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @param state New port state.
+ */
+void hub_set_port_state(hub_t *hub, size_t port_index, hub_port_state_t state)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return;
+	}
+
+	switch (state) {
+		case HUB_PORT_STATE_POWERED_OFF:
+			clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+			clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
+			clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
+			break;
+		case HUB_PORT_STATE_RESUMING:
+			set_port_state_delayed(hub, port_index,
+			    10, state, HUB_PORT_STATE_ENABLED);
+			break;
+		case HUB_PORT_STATE_RESETTING:
+			set_port_state_delayed(hub, port_index,
+			    10, state, HUB_PORT_STATE_ENABLED);
+			break;
+		case HUB_PORT_STATE_ENABLED:
+			if (port->state == HUB_PORT_STATE_RESETTING) {
+				set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
+			}
+			break;
+		default:
+			break;
+	}
+
+	port->state = state;
+}
+
+/** Change state of all ports.
+ *
+ * @param hub Hub in question.
+ * @param state New state for all ports.
+ */
+void hub_set_port_state_all(hub_t *hub, hub_port_state_t state)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_set_port_state(hub, i, state);
+	}
+}
+
+/** Get port state.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @return Port state.
+ */
+hub_port_state_t hub_get_port_state(hub_t *hub, size_t port_index)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return HUB_PORT_STATE_UNKNOWN;
+	}
+
+	return port->state;
+}
+
+/** Clear port status change bit.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @param change Change to be cleared.
+ */
+void hub_clear_port_status_change(hub_t *hub, size_t port_index,
+    hub_status_change_t change)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return;
+	}
+
+	clear_port_status_change(port, change);
+}
+
+/** Get port status change bits.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @return Port status change bitmap in standard format.
+ */
+uint16_t hub_get_port_status_change(hub_t *hub, size_t port_index)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return 0;
+	}
+
+	return port->status_change;
+}
+
+/** Get port status bits.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @return Port status bitmap in standard format.
+ */
+uint32_t hub_get_port_status(hub_t *hub, size_t port_index)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return 0;
+	}
+
+	uint32_t status;
+	status = MAKE_BYTE(
+	    /* Current connect status. */
+	    port->connected_device == NULL ? 0 : 1,
+	    /* Port enabled/disabled. */
+	    port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
+	    /* Suspend. */
+	    (port->state == HUB_PORT_STATE_SUSPENDED)
+		|| (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
+	    /* Over-current. */
+	    0,
+	    /* Reset. */
+	    port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
+	    /* Reserved. */
+	    0, 0, 0)
+
+	    | (MAKE_BYTE(
+	    /* Port power. */
+	    port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
+	    /* Full-speed device. */
+	    0,
+	    /* Reserved. */
+	    0, 0, 0, 0, 0, 0
+	    )) << 8;
+
+	status |= (port->status_change << 16);
+
+	return status;
+}
+
+/** Create hub status change bitmap.
+ *
+ * @warning This function assumes that the whole bitmap fits into 8 bits.
+ *
+ * @param hub Hub in question.
+ * @return Hub status change bitmap.
+ */
+uint8_t hub_get_status_change_bitmap(hub_t *hub)
+{
+	uint8_t change_map = 0;
+
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub->ports[i];
+
+		if (port->status_change != 0) {
+			change_map |= (1 << port->index);
+		}
+	}
+
+	return change_map;
+}
+
+
+/*
+ *
+ * STATIC (HELPER) FUNCTIONS
+ *
+ */
+
+/** Find a port in a hub.
+ *
+ * @param hub Hub in question.
+ * @param port Port index (zero based).
+ * @return Port structure.
+ * @retval NULL Invalid port index.
+ */
+static hub_port_t *get_hub_port(hub_t *hub, size_t port)
+{
+	if (port >= HUB_PORT_COUNT) {
+		return NULL;
+	}
+
+	return &hub->ports[port];
+}
+
+/** Adds a port status change to a port.
+ *
+ * @param port The port with status change.
+ * @param change Change to be added to the status.
+ */
+static void set_port_status_change(hub_port_t *port,
+    hub_status_change_t change)
+{
+	assert(port != NULL);
+	port->status_change |= change;
+}
+
+/** Clears a port status change on a port.
+ *
+ * @param port The port with status change.
+ * @param change Change to be removed from the status.
+ */
+static void clear_port_status_change(hub_port_t *port,
+    uint16_t change)
+{
+	assert(port != NULL);
+	port->status_change &= (~change);
+}
+
+/** Structure for automatic (delayed) port state change. */
+struct delay_port_state_change {
+	/** Delay in microseconds. */
+	suseconds_t delay;
+	/** Old state of the port. */
+	hub_port_state_t old_state;
+	/** New state of the port. */
+	hub_port_state_t new_state;
+	/** Port index (zero based). */
+	size_t port;
+	/** Hub. */
+	hub_t *hub;
+};
+
+/** Fibril responsible for delayed port state change.
+ *
+ * @param arg Pointer to delay_port_state_change.
+ * @return Always EOK.
+ */
+static int set_port_state_delayed_fibril(void *arg)
+{
+	struct delay_port_state_change *change
+	    = (struct delay_port_state_change *) arg;
+
+	async_usleep(change->delay);
+
+	hub_acquire(change->hub);
+
+	hub_port_t *port = get_hub_port(change->hub, change->port);
+	assert(port != NULL);
+
+	if (port->state == change->old_state) {
+		hub_set_port_state(change->hub, change->port,
+		    change->new_state);
+	}
+
+	hub_release(change->hub);
+
+	free(change);
+
+	return EOK;
+}
+
+/** Change port state with a delay.
+ *
+ * @warning If the port state changes during the waiting phase, the state
+ * is not changed.
+ *
+ * @param hub Hub in question.
+ * @param port_index Port index (zero based).
+ * @param delay_time_ms Delay time in miliseconds.
+ * @param old_state Old (current) state of the port.
+ * @param new_state New state of the port.
+ */
+static void set_port_state_delayed(hub_t *hub, size_t port_index,
+    suseconds_t delay_time_ms,
+    hub_port_state_t old_state, hub_port_state_t new_state)
+{
+	struct delay_port_state_change *change
+	    = malloc(sizeof(struct delay_port_state_change));
+
+	change->hub = hub;
+	change->port = port_index;
+	change->delay = delay_time_ms * 1000;
+	change->old_state = old_state;
+	change->new_state = new_state;
+	fid_t fibril = fibril_create(set_port_state_delayed_fibril, change);
+	if (fibril == 0) {
+		printf("Failed to create fibril\n");
+		free(change);
+		return;
+	}
+	fibril_add_ready(fibril);
+}
+
+
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/hub.h
===================================================================
--- uspace/drv/vhc/hub/hub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/drv/vhc/hub/hub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief Representation of an USB hub.
+ */
+#ifndef VHC_HUB_HUB_H_
+#define VHC_HUB_HUB_H_
+
+#include <fibril_synch.h>
+
+#define HUB_PORT_COUNT 2
+#define BITS2BYTES(bits) (bits ? ((((bits)-1)>>3)+1) : 0)
+
+/** Hub port internal state.
+ * Some states (e.g. port over current) are not covered as they are not
+ * simulated at all.
+ */
+typedef enum {
+	HUB_PORT_STATE_UNKNOWN,
+	HUB_PORT_STATE_NOT_CONFIGURED,
+	HUB_PORT_STATE_POWERED_OFF,
+	HUB_PORT_STATE_DISCONNECTED,
+	HUB_PORT_STATE_DISABLED,
+	HUB_PORT_STATE_RESETTING,
+	HUB_PORT_STATE_ENABLED,
+	HUB_PORT_STATE_SUSPENDED,
+	HUB_PORT_STATE_RESUMING,
+	/* HUB_PORT_STATE_, */
+} hub_port_state_t;
+
+char hub_port_state_to_char(hub_port_state_t);
+
+/** Hub status change mask bits. */
+typedef enum {
+	HUB_STATUS_C_PORT_CONNECTION = (1 << 0),
+	HUB_STATUS_C_PORT_ENABLE = (1 << 1),
+	HUB_STATUS_C_PORT_SUSPEND = (1 << 2),
+	HUB_STATUS_C_PORT_OVER_CURRENT = (1 << 3),
+	HUB_STATUS_C_PORT_RESET = (1 << 4),
+	/* HUB_STATUS_C_ = (1 << ), */
+} hub_status_change_t;
+
+/** Hub port information. */
+typedef struct {
+	/** Custom pointer to connected device. */
+	void *connected_device;
+	/** Port index (one based). */
+	size_t index;
+	/** Port state. */
+	hub_port_state_t state;
+	/** Status change bitmap. */
+	uint16_t status_change;
+} hub_port_t;
+
+/** Hub device type. */
+typedef struct {
+	/** Hub ports. */
+	hub_port_t ports[HUB_PORT_COUNT];
+	/** Custom hub data. */
+	void *custom_data;
+	/** Access guard to the whole hub. */
+	fibril_mutex_t guard;
+} hub_t;
+
+void hub_init(hub_t *);
+size_t hub_connect_device(hub_t *, void *);
+size_t hub_find_device(hub_t *, void *);
+void hub_acquire(hub_t *);
+void hub_release(hub_t *);
+void hub_set_port_state(hub_t *, size_t, hub_port_state_t);
+void hub_set_port_state_all(hub_t *, hub_port_state_t);
+hub_port_state_t hub_get_port_state(hub_t *, size_t);
+void hub_clear_port_status_change(hub_t *, size_t, hub_status_change_t);
+uint16_t hub_get_port_status_change(hub_t *, size_t);
+uint32_t hub_get_port_status(hub_t *, size_t);
+uint8_t hub_get_status_change_bitmap(hub_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/virthub.c
===================================================================
--- uspace/drv/vhc/hub/virthub.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/drv/vhc/hub/virthub.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief
+ */
+#include <usb/classes/classes.h>
+#include <usbvirt/hub.h>
+#include <usbvirt/device.h>
+#include <assert.h>
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <driver.h>
+#include <usb/usbdrv.h>
+
+#include "virthub.h"
+#include "hub.h"
+
+
+/** Standard device descriptor. */
+usb_standard_device_descriptor_t std_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_HUB,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+/** Standard interface descriptor. */
+usb_standard_interface_descriptor_t std_interface_descriptor = {
+	.length = sizeof(usb_standard_interface_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_INTERFACE,
+	.interface_number = 0,
+	.alternate_setting = 0,
+	.endpoint_count = 1,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.str_interface = 0
+};
+
+/** Hub descriptor. */
+hub_descriptor_t hub_descriptor = {
+	.length = sizeof(hub_descriptor_t),
+	.type = USB_DESCTYPE_HUB,
+	.port_count = HUB_PORT_COUNT,
+	.characteristics = 0, 
+	.power_on_warm_up = 50, /* Huh? */
+	.max_current = 100, /* Huh again. */
+	.removable_device = { 0 },
+	.port_power = { 0xFF }
+};
+
+/** Endpoint descriptor. */
+usb_standard_endpoint_descriptor_t endpoint_descriptor = {
+	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_ENDPOINT,
+	.endpoint_address = HUB_STATUS_CHANGE_PIPE | 128,
+	.attributes = USB_TRANSFER_INTERRUPT,
+	.max_packet_size = 8,
+	.poll_interval = 0xFF
+};
+
+/** Standard configuration descriptor. */
+usb_standard_configuration_descriptor_t std_configuration_descriptor = {
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	.total_length = 
+		sizeof(usb_standard_configuration_descriptor_t)
+		+ sizeof(std_interface_descriptor)
+		+ sizeof(hub_descriptor)
+		+ sizeof(endpoint_descriptor)
+		,
+	.interface_count = 1,
+	.configuration_number = HUB_CONFIGURATION_ID,
+	.str_configuration = 0,
+	.attributes = 128, /* denotes bus-powered device */
+	.max_power = 50
+};
+
+/** All hub configuration descriptors. */
+static usbvirt_device_configuration_extras_t extra_descriptors[] = {
+	{
+		.data = (uint8_t *) &std_interface_descriptor,
+		.length = sizeof(std_interface_descriptor)
+	},
+	{
+		.data = (uint8_t *) &hub_descriptor,
+		.length = sizeof(hub_descriptor)
+	},
+	{
+		.data = (uint8_t *) &endpoint_descriptor,
+		.length = sizeof(endpoint_descriptor)
+	}
+};
+
+/** Hub configuration. */
+usbvirt_device_configuration_t configuration = {
+	.descriptor = &std_configuration_descriptor,
+	.extra = extra_descriptors,
+	.extra_count = sizeof(extra_descriptors)/sizeof(extra_descriptors[0])
+};
+
+/** Hub standard descriptors. */
+usbvirt_descriptors_t descriptors = {
+	.device = &std_device_descriptor,
+	.configuration = &configuration,
+	.configuration_count = 1,
+};
+
+/** Initializes virtual hub device.
+ *
+ * @param dev Virtual USB device backend.
+ * @return Error code.
+ */
+int virthub_init(usbvirt_device_t *dev)
+{
+	if (dev == NULL) {
+		return EBADMEM;
+	}
+	dev->ops = &hub_ops;
+	dev->descriptors = &descriptors;
+	dev->lib_debug_level = 0;
+	dev->lib_debug_enabled_tags = USBVIRT_DEBUGTAG_ALL;
+
+	hub_t *hub = malloc(sizeof(hub_t));
+	if (hub == NULL) {
+		return ENOMEM;
+	}
+
+	hub_init(hub);
+	dev->device_data = hub;
+
+	usbvirt_connect_local(dev);
+
+	return EOK;
+}
+
+/** Connect a device to a virtual hub.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param conn Device to be connected.
+ * @return Port device was connected to.
+ */
+int virthub_connect_device(usbvirt_device_t *dev, virtdev_connection_t *conn)
+{
+	assert(dev != NULL);
+	assert(conn != NULL);
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+	size_t port = hub_connect_device(hub, conn);
+	hub_release(hub);
+
+	return port;
+}
+
+/** Disconnect a device from a virtual hub.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param conn Device to be disconnected.
+ * @return Error code.
+ */
+int virthub_disconnect_device(usbvirt_device_t *dev, virtdev_connection_t *conn)
+{
+	assert(dev != NULL);
+	assert(conn != NULL);
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+	/* TODO: implement. */
+	hub_release(hub);
+
+	return ENOTSUP;
+}
+
+/** Whether trafic is propagated to given device.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param conn Connected device.
+ * @return Whether port is signalling to the device.
+ */
+bool virthub_is_device_enabled(usbvirt_device_t *dev, virtdev_connection_t *conn)
+{
+	assert(dev != NULL);
+	assert(conn != NULL);
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	hub_port_state_t state = HUB_PORT_STATE_UNKNOWN;
+	size_t port = hub_find_device(hub, conn);
+	if (port != (size_t) -1) {
+		state = hub_get_port_state(hub, port);
+	}
+	hub_release(hub);
+
+	return state == HUB_PORT_STATE_ENABLED;
+}
+
+/** Format status of a virtual hub.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param[out] status Hub status information.
+ * @param[in] len Size of the @p status buffer.
+ */
+void virthub_get_status(usbvirt_device_t *dev, char *status, size_t len)
+{
+	assert(dev != NULL);
+	if (len == 0) {
+		return;
+	}
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	char port_status[HUB_PORT_COUNT + 1];
+
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		port_status[i] = hub_port_state_to_char(
+		    hub_get_port_state(hub, i));
+	}
+	port_status[HUB_PORT_COUNT] = 0;
+
+	snprintf(status, len, "vhub:%s", port_status);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/virthub.h
===================================================================
--- uspace/drv/vhc/hub/virthub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/drv/vhc/hub/virthub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief USB hub as a virtual USB device.
+ */
+#ifndef VHC_HUB_VIRTHUB_H_
+#define VHC_HUB_VIRTHUB_H_
+
+#include <usbvirt/device.h>
+#include "../devices.h"
+#include "hub.h"
+
+/** Endpoint number for status change pipe. */
+#define HUB_STATUS_CHANGE_PIPE 1
+/** Configuration value for hub configuration. */
+#define HUB_CONFIGURATION_ID 1
+
+
+/** Hub descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_HUB). */
+	uint8_t type;
+	/** Number of downstream ports. */
+	uint8_t port_count;
+	/** Hub characteristics. */
+	uint16_t characteristics;
+	/** Time from power-on to stabilized current.
+	 * Expressed in 2ms unit.
+	 */
+	uint8_t power_on_warm_up;
+	/** Maximum current (in mA). */
+	uint8_t max_current;
+	/** Whether device at given port is removable. */
+	uint8_t removable_device[BITS2BYTES(HUB_PORT_COUNT+1)];
+	/** Port power control.
+	 * This is USB1.0 compatibility field, all bits must be 1.
+	 */
+	uint8_t port_power[BITS2BYTES(HUB_PORT_COUNT+1)];
+} __attribute__ ((packed)) hub_descriptor_t;
+
+extern usbvirt_device_ops_t hub_ops;
+extern hub_descriptor_t hub_descriptor;
+
+int virthub_init(usbvirt_device_t *);
+int virthub_connect_device(usbvirt_device_t *, virtdev_connection_t *);
+int virthub_disconnect_device(usbvirt_device_t *, virtdev_connection_t *);
+bool virthub_is_device_enabled(usbvirt_device_t *, virtdev_connection_t *);
+void virthub_get_status(usbvirt_device_t *, char *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/virthubops.c
===================================================================
--- uspace/drv/vhc/hub/virthubops.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/drv/vhc/hub/virthubops.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub operations.
+ */
+#include <errno.h>
+#include <usb/classes/hub.h>
+#include "virthub.h"
+#include "hub.h"
+
+/** Callback when device changes states. */
+static void on_state_change(struct usbvirt_device *dev,
+    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state)
+{
+	hub_t *hub = (hub_t *)dev->device_data;
+
+	hub_acquire(hub);
+
+	switch (new_state) {
+		case USBVIRT_STATE_CONFIGURED:
+			hub_set_port_state_all(hub, HUB_PORT_STATE_POWERED_OFF);
+			break;
+		case USBVIRT_STATE_ADDRESS:
+			hub_set_port_state_all(hub, HUB_PORT_STATE_NOT_CONFIGURED);
+			break;
+		default:
+			break;
+	}
+
+	hub_release(hub);
+}
+
+/** Callback for data request. */
+static int req_on_data(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	if (endpoint != HUB_STATUS_CHANGE_PIPE) {
+		return EINVAL;
+	}
+	
+	hub_t *hub = (hub_t *)dev->device_data;
+
+	hub_acquire(hub);
+
+	uint8_t change_map = hub_get_status_change_bitmap(hub);
+		
+	uint8_t *b = (uint8_t *) buffer;
+	if (size > 0) {
+		*b = change_map;
+		*actual_size = 1;
+	}
+	
+	hub_release(hub);
+
+	return EOK;
+}
+
+/** Handle ClearHubFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_clear_hub_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return ENOTSUP;
+}
+
+/** Handle ClearPortFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_clear_port_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	int rc;
+	size_t port = request->index - 1;
+	usb_hub_class_feature_t feature = request->value;
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	hub_port_state_t port_state = hub_get_port_state(hub, port);
+
+	switch (feature) {
+		case USB_HUB_FEATURE_PORT_ENABLE:
+			if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED)
+			    && (port_state != HUB_PORT_STATE_POWERED_OFF)) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_DISABLED);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_SUSPEND:
+			if (port_state != HUB_PORT_STATE_SUSPENDED) {
+				rc = EOK;
+				break;
+			}
+			hub_set_port_state(hub, port, HUB_PORT_STATE_RESUMING);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_POWER:
+			if (port_state != HUB_PORT_STATE_NOT_CONFIGURED) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_POWERED_OFF);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_CONNECTION:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_CONNECTION);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_ENABLE:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_SUSPEND:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_OVER_CURRENT);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_RESET:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_RESET);
+			rc = EOK;
+			break;
+
+		default:
+			rc = ENOTSUP;
+			break;
+	}
+
+	hub_release(hub);
+
+	return rc;
+}
+
+/** Handle GetBusState request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_bus_state(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return ENOTSUP;
+}
+
+/** Handle GetDescriptor request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_descriptor(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	if (request->value_high == USB_DESCTYPE_HUB) {
+		int rc = dev->control_transfer_reply(dev, 0,
+		    &hub_descriptor, hub_descriptor.length);
+
+		return rc;
+	}
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+/** Handle GetHubStatus request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_hub_status(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	uint32_t hub_status = 0;
+
+	return dev->control_transfer_reply(dev, 0,
+	    &hub_status, sizeof(hub_status));
+}
+
+/** Handle GetPortStatus request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_port_status(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	uint32_t status = hub_get_port_status(hub, request->index - 1);
+
+	hub_release(hub);
+
+	return dev->control_transfer_reply(dev, 0, &status, 4);
+}
+
+/** Handle SetHubFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_set_hub_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	return ENOTSUP;
+}
+
+/** Handle SetPortFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_set_port_feature(usbvirt_device_t *dev,
+    usb_device_request_setup_packet_t *request,
+    uint8_t *data)
+{
+	int rc;
+	size_t port = request->index - 1;
+	usb_hub_class_feature_t feature = request->value;
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	hub_port_state_t port_state = hub_get_port_state(hub, port);
+
+	switch (feature) {
+		case USB_HUB_FEATURE_PORT_RESET:
+			if (port_state != HUB_PORT_STATE_POWERED_OFF) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_RESETTING);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_SUSPEND:
+			if (port_state == HUB_PORT_STATE_ENABLED) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_POWER:
+			if (port_state == HUB_PORT_STATE_POWERED_OFF) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_DISCONNECTED);
+			}
+			rc = EOK;
+			break;
+
+		default:
+			break;
+	}
+
+	hub_release(hub);
+
+	return rc;
+}
+
+
+/** IN class request. */
+#define CLASS_REQ_IN(recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_IN, \
+	USBVIRT_REQUEST_TYPE_CLASS, recipient)
+/** OUT class request. */
+#define CLASS_REQ_OUT(recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_OUT, \
+	USBVIRT_REQUEST_TYPE_CLASS, recipient)
+
+/** Recipient: other. */
+#define REC_OTHER USBVIRT_REQUEST_RECIPIENT_OTHER
+/** Recipient: device. */
+#define REC_DEVICE USBVIRT_REQUEST_RECIPIENT_DEVICE
+/** Direction: in. */
+#define DIR_IN USB_DIRECTION_IN
+/** Direction: out. */
+#define DIR_OUT USB_DIRECTION_OUT
+
+/** Create a class request.
+ *
+ * @param direction Request direction.
+ * @param recipient Request recipient.
+ * @param req Request code.
+ */
+#define CLASS_REQ(direction, recipient, req) \
+	.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_CLASS, recipient), \
+	.request = req
+
+/** Create a standard request.
+ *
+ * @param direction Request direction.
+ * @param recipient Request recipient.
+ * @param req Request code.
+ */
+#define STD_REQ(direction, recipient, req) \
+	.request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_STANDARD, recipient), \
+	.request = req
+
+/** Hub operations on control endpoint zero. */
+static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
+	{
+		STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.name = "GetDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.name = "GetDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
+		.name = "GetPortStatus",
+		.callback = req_get_port_status
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
+		.name = "ClearHubFeature",
+		.callback = req_clear_hub_feature
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
+		.name = "ClearPortFeature",
+		.callback = req_clear_port_feature
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATE),
+		.name = "GetBusState",
+		.callback = req_get_bus_state
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
+		.name = "GetHubDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_STATUS),
+		.name = "GetHubStatus",
+		.callback = req_get_hub_status
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
+		.name = "GetPortStatus",
+		.callback = req_get_port_status
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
+		.name = "SetHubFeature",
+		.callback = req_set_hub_feature
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_SET_FEATURE),
+		.name = "SetPortFeature",
+		.callback = req_set_port_feature
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
+};
+
+
+/** Hub operations. */
+usbvirt_device_ops_t hub_ops = {
+	.control_transfer_handlers = endpoint_zero_handlers,
+	.on_data = NULL,
+	.on_data_request = req_on_data,
+	.on_state_change = on_state_change,
+};
+
+/**
+ * @}
+ */
Index: pace/drv/vhc/hubintern.h
===================================================================
--- uspace/drv/vhc/hubintern.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,149 +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 usb
- * @{
- */
-/** @file
- * @brief
- */
-#ifndef VHCD_HUBINTERN_H_
-#define VHCD_HUBINTERN_H_
-
-#include "hub.h"
-#include <fibril_synch.h>
-
-/** Endpoint number for status change pipe. */
-#define HUB_STATUS_CHANGE_PIPE 1
-/** Configuration value for hub configuration. */
-#define HUB_CONFIGURATION_ID 1
-
-/** Hub descriptor.
- */
-typedef struct {
-	/** Size of this descriptor in bytes. */
-	uint8_t length;
-	/** Descriptor type (USB_DESCTYPE_HUB). */
-	uint8_t type;
-	/** Number of downstream ports. */
-	uint8_t port_count;
-	/** Hub characteristics. */
-	uint16_t characteristics;
-	/** Time from power-on to stabilized current.
-	 * Expressed in 2ms unit.
-	 */
-	uint8_t power_on_warm_up;
-	/** Maximum current (in mA). */
-	uint8_t max_current;
-	/** Whether device at given port is removable. */
-	uint8_t removable_device[BITS2BYTES(HUB_PORT_COUNT+1)];
-	/** Port power control.
-	 * This is USB1.0 compatibility field, all bits must be 1.
-	 */
-	uint8_t port_power[BITS2BYTES(HUB_PORT_COUNT+1)];
-} __attribute__ ((packed)) hub_descriptor_t;
-
-/** Hub port internal state.
- * Some states (e.g. port over current) are not covered as they are not
- * simulated at all.
- */
-typedef enum {
-	HUB_PORT_STATE_NOT_CONFIGURED,
-	HUB_PORT_STATE_POWERED_OFF,
-	HUB_PORT_STATE_DISCONNECTED,
-	HUB_PORT_STATE_DISABLED,
-	HUB_PORT_STATE_RESETTING,
-	HUB_PORT_STATE_ENABLED,
-	HUB_PORT_STATE_SUSPENDED,
-	HUB_PORT_STATE_RESUMING,
-	/* HUB_PORT_STATE_, */
-} hub_port_state_t;
-
-/** Convert hub port state to a char. */
-static inline char hub_port_state_as_char(hub_port_state_t state) {
-	switch (state) {
-		case HUB_PORT_STATE_NOT_CONFIGURED:
-			return '-';
-		case HUB_PORT_STATE_POWERED_OFF:
-			return 'O';
-		case HUB_PORT_STATE_DISCONNECTED:
-			return 'X';
-		case HUB_PORT_STATE_DISABLED:
-			return 'D';
-		case HUB_PORT_STATE_RESETTING:
-			return 'R';
-		case HUB_PORT_STATE_ENABLED:
-			return 'E';
-		case HUB_PORT_STATE_SUSPENDED:
-			return 'S';
-		case HUB_PORT_STATE_RESUMING:
-			return 'F';
-		default:
-			return '?';
-	}
-}
-
-/** Hub status change mask bits. */
-typedef enum {
-	HUB_STATUS_C_PORT_CONNECTION = (1 << 0),
-	HUB_STATUS_C_PORT_ENABLE = (1 << 1),
-	HUB_STATUS_C_PORT_SUSPEND = (1 << 2),
-	HUB_STATUS_C_PORT_OVER_CURRENT = (1 << 3),
-	HUB_STATUS_C_PORT_RESET = (1 << 4),
-	/* HUB_STATUS_C_ = (1 << ), */
-} hub_status_change_t;
-
-/** Hub port information. */
-typedef struct {
-	virtdev_connection_t *device;
-	int index;
-	hub_port_state_t state;
-	uint16_t status_change;
-	fibril_mutex_t guard;
-} hub_port_t;
-
-/** Hub device type. */
-typedef struct {
-	hub_port_t ports[HUB_PORT_COUNT];
-} hub_device_t;
-
-extern hub_device_t hub_dev;
-
-extern hub_descriptor_t hub_descriptor;
-
-extern usbvirt_device_ops_t hub_ops;
-
-void clear_port_status_change(hub_port_t *, uint16_t);
-void set_port_status_change(hub_port_t *, uint16_t);
-void set_port_status_change_nl(hub_port_t *, uint16_t);
-
-
-#endif
-/**
- * @}
- */
Index: pace/drv/vhc/hubops.c
===================================================================
--- uspace/drv/vhc/hubops.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,527 +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 usb
- * @{
- */
-/** @file
- * @brief Virtual USB hub operations.
- */
-#include <usb/classes/classes.h>
-#include <usb/classes/hub.h>
-#include <usbvirt/hub.h>
-#include <usbvirt/device.h>
-#include <errno.h>
-
-#include "vhcd.h"
-#include "hub.h"
-#include "hubintern.h"
-
-/** Produce a byte from bit values.
- */
-#define MAKE_BYTE(b0, b1, b2, b3, b4, b5, b6, b7) \
-	(( \
-		((b0) << 0) \
-		| ((b1) << 1) \
-		| ((b2) << 2) \
-		| ((b3) << 3) \
-		| ((b4) << 4) \
-		| ((b5) << 5) \
-		| ((b6) << 6) \
-		| ((b7) << 7) \
-	))
-
-static int on_get_descriptor(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data);
-static int on_set_configuration(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data);
-static int on_class_request(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data);
-static int on_data_request(struct usbvirt_device *dev,
-    usb_endpoint_t endpoint,
-    void *buffer, size_t size, size_t *actual_size);
-static void set_port_state(hub_port_t *, hub_port_state_t);
-static void clear_port_status_change_nl(hub_port_t *, uint16_t);
-static void set_port_state_nl(hub_port_t *, hub_port_state_t);
-
-/** Standard USB requests. */
-static usbvirt_standard_device_request_ops_t standard_request_ops = {
-	.on_get_status = NULL,
-	.on_clear_feature = NULL,
-	.on_set_feature = NULL,
-	.on_set_address = NULL,
-	.on_get_descriptor = on_get_descriptor,
-	.on_set_descriptor = NULL,
-	.on_get_configuration = NULL,
-	.on_set_configuration = on_set_configuration,
-	.on_get_interface = NULL,
-	.on_set_interface = NULL,
-	.on_synch_frame = NULL
-};
-
-/** Hub operations. */
-usbvirt_device_ops_t hub_ops = {
-	.standard_request_ops = &standard_request_ops,
-	.on_class_device_request = on_class_request,
-	.on_data = NULL,
-	.on_data_request = on_data_request
-};
-
-/** Callback for GET_DESCRIPTOR request. */
-static int on_get_descriptor(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{
-	if (request->value_high == USB_DESCTYPE_HUB) {
-		int rc = dev->control_transfer_reply(dev, 0,
-		    &hub_descriptor, hub_descriptor.length);
-		
-		return rc;
-	}
-	/* Let the framework handle all the rest. */
-	return EFORWARD;
-}
-
-/** Callback for SET_CONFIGURATION request. */
-int on_set_configuration(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{
-	/* We must suspend power source to all ports. */
-	size_t i;
-	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		hub_port_t *port = &hub_dev.ports[i];
-		
-		set_port_state(port, HUB_PORT_STATE_POWERED_OFF);
-	}
-	
-	/* Let the framework handle the rest of the job. */
-	return EFORWARD;
-}
-
-struct delay_port_state_change {
-	suseconds_t delay;
-	hub_port_state_t old_state;
-	hub_port_state_t new_state;
-	hub_port_t *port;
-};
-
-static int set_port_state_delayed_fibril(void *arg)
-{
-	struct delay_port_state_change *change
-	    = (struct delay_port_state_change *) arg;
-	
-	async_usleep(change->delay);
-	
-	fibril_mutex_lock(&change->port->guard);
-	if (change->port->state == change->old_state) {
-		set_port_state_nl(change->port, change->new_state);
-	}
-	fibril_mutex_unlock(&change->port->guard);
-	
-	free(change);
-	
-	return EOK;
-}
-
-static void set_port_state_delayed(hub_port_t *port,
-    suseconds_t delay_time,
-    hub_port_state_t old_state, hub_port_state_t new_state)
-{
-	struct delay_port_state_change *change
-	    = malloc(sizeof(struct delay_port_state_change));
-	change->port = port;
-	change->delay = delay_time;
-	change->old_state = old_state;
-	change->new_state = new_state;
-	fid_t fibril = fibril_create(set_port_state_delayed_fibril, change);
-	if (fibril == 0) {
-		printf("Failed to create fibril\n");
-		return;
-	}
-	fibril_add_ready(fibril);
-}
-
-/** Change port status and updates status change status fields.
- */
-void set_port_state(hub_port_t *port, hub_port_state_t state)
-{
-	fibril_mutex_lock(&port->guard);
-	set_port_state_nl(port, state);
-	fibril_mutex_unlock(&port->guard);
-}
-
-void set_port_state_nl(hub_port_t *port, hub_port_state_t state)
-{
-
-	dprintf(2, "setting port %d state to %d (%c) from %c (change=%u)",
-	    port->index,
-	    state, hub_port_state_as_char(state),
-	    hub_port_state_as_char(port->state),
-	    (unsigned int) port->status_change);
-	
-	if (state == HUB_PORT_STATE_POWERED_OFF) {
-		clear_port_status_change_nl(port, HUB_STATUS_C_PORT_CONNECTION);
-		clear_port_status_change_nl(port, HUB_STATUS_C_PORT_ENABLE);
-		clear_port_status_change_nl(port, HUB_STATUS_C_PORT_RESET);
-	}
-	if (state == HUB_PORT_STATE_RESUMING) {
-		set_port_state_delayed(port, 10*1000,
-		    HUB_PORT_STATE_RESUMING, HUB_PORT_STATE_ENABLED);
-	}
-	if (state == HUB_PORT_STATE_RESETTING) {
-		set_port_state_delayed(port, 10*1000,
-		    HUB_PORT_STATE_RESETTING, HUB_PORT_STATE_ENABLED);
-	}
-	if ((port->state == HUB_PORT_STATE_RESETTING)
-	    && (state == HUB_PORT_STATE_ENABLED)) {
-		set_port_status_change_nl(port, HUB_STATUS_C_PORT_RESET);
-	}
-	
-	port->state = state;
-}
-
-/** Get access to a port or return with EINVAL. */
-#define _GET_PORT(portvar, index) \
-	do { \
-		if (virthub_dev.state != USBVIRT_STATE_CONFIGURED) { \
-			return EINVAL; \
-		} \
-		if (((index) == 0) || ((index) > HUB_PORT_COUNT)) { \
-			return EINVAL; \
-		} \
-	} while (false); \
-	hub_port_t *portvar = &hub_dev.ports[index-1]
-
-
-static int clear_hub_feature(uint16_t feature)
-{
-	return ENOTSUP;
-}
-
-static int clear_port_feature(uint16_t feature, uint16_t portindex)
-{	
-	_GET_PORT(port, portindex);
-	
-	fibril_mutex_lock(&port->guard);
-	int rc = ENOTSUP;
-
-	switch (feature) {
-		case USB_HUB_FEATURE_PORT_ENABLE:
-			if ((port->state != HUB_PORT_STATE_NOT_CONFIGURED)
-			    && (port->state != HUB_PORT_STATE_POWERED_OFF)) {
-				set_port_state_nl(port, HUB_PORT_STATE_DISABLED);
-			}
-			rc = EOK;
-			break;
-		
-		case USB_HUB_FEATURE_PORT_SUSPEND:
-			if (port->state != HUB_PORT_STATE_SUSPENDED) {
-				rc = EOK;
-				break;
-			}
-			set_port_state_nl(port, HUB_PORT_STATE_RESUMING);
-			rc = EOK;
-			break;
-			
-		case USB_HUB_FEATURE_PORT_POWER:
-			if (port->state != HUB_PORT_STATE_NOT_CONFIGURED) {
-				set_port_state_nl(port, HUB_PORT_STATE_POWERED_OFF);
-			}
-			rc = EOK;
-			break;
-		
-		case USB_HUB_FEATURE_C_PORT_CONNECTION:
-			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_CONNECTION);
-			rc = EOK;
-			break;
-		
-		case USB_HUB_FEATURE_C_PORT_ENABLE:
-			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_ENABLE);
-			rc = EOK;
-			break;
-		
-		case USB_HUB_FEATURE_C_PORT_SUSPEND:
-			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_SUSPEND);
-			rc = EOK;
-			break;
-			
-		case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
-			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_OVER_CURRENT);
-			rc = EOK;
-			break;
-
-		case USB_HUB_FEATURE_C_PORT_RESET:
-			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_RESET);
-			rc = EOK;
-			break;
-	}
-	
-	fibril_mutex_unlock(&port->guard);
-
-	return rc;
-}
-
-static int get_bus_state(uint16_t portindex)
-{
-	return ENOTSUP;
-}
-
-static int get_hub_descriptor(struct usbvirt_device *dev,
-    uint8_t descriptor_index,
-    uint8_t descriptor_type, uint16_t length)
-{
-	if (descriptor_type == USB_DESCTYPE_HUB) {
-		int rc = dev->control_transfer_reply(dev, 0,
-		    &hub_descriptor, hub_descriptor.length);
-
-		return rc;
-
-	}
-
-	return ENOTSUP;
-}
-
-static int get_hub_status(void)
-{
-	uint32_t hub_status = 0;
-	
-	return virthub_dev.control_transfer_reply(&virthub_dev, 0,
-	    &hub_status, 4);
-}
-
-static int get_port_status(uint16_t portindex)
-{
-	_GET_PORT(port, portindex);
-	
-	fibril_mutex_lock(&port->guard);
-
-	uint32_t status;
-	status = MAKE_BYTE(
-	    /* Current connect status. */
-	    port->device == NULL ? 0 : 1,
-	    /* Port enabled/disabled. */
-	    port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
-	    /* Suspend. */
-	    (port->state == HUB_PORT_STATE_SUSPENDED)
-	        || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
-	    /* Over-current. */
-	    0,
-	    /* Reset. */
-	    port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
-	    /* Reserved. */
-	    0, 0, 0)
-	    
-	    | (MAKE_BYTE(
-	    /* Port power. */
-	    port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
-	    /* Full-speed device. */
-	    0,
-	    /* Reserved. */
-	    0, 0, 0, 0, 0, 0
-	    )) << 8;
-	    
-	status |= (port->status_change << 16);
-	
-	fibril_mutex_unlock(&port->guard);
-
-	dprintf(2, "GetPortStatus(port=%d, status=%u)\n", (int)portindex,
-	    (unsigned int) status);
-	return virthub_dev.control_transfer_reply(&virthub_dev, 0, &status, 4);
-}
-
-
-static int set_hub_feature(uint16_t feature)
-{
-	return ENOTSUP;
-}
-
-static int set_port_feature(uint16_t feature, uint16_t portindex)
-{
-	_GET_PORT(port, portindex);
-	
-	fibril_mutex_lock(&port->guard);
-
-	int rc = ENOTSUP;
-
-	switch (feature) {
-		case USB_HUB_FEATURE_PORT_RESET:
-			if (port->state != HUB_PORT_STATE_POWERED_OFF) {
-				set_port_state_nl(port, HUB_PORT_STATE_RESETTING);
-			}
-			rc = EOK;
-			break;
-		
-		case USB_HUB_FEATURE_PORT_SUSPEND:
-			if (port->state == HUB_PORT_STATE_ENABLED) {
-				set_port_state_nl(port, HUB_PORT_STATE_SUSPENDED);
-			}
-			rc = EOK;
-			break;
-		
-		case USB_HUB_FEATURE_PORT_POWER:
-			if (port->state == HUB_PORT_STATE_POWERED_OFF) {
-				set_port_state_nl(port, HUB_PORT_STATE_DISCONNECTED);
-			}
-			rc = EOK;
-			break;
-	}
-
-	fibril_mutex_unlock(&port->guard);
-	return rc;
-}
-
-#undef _GET_PORT
-
-
-/** Callback for class request. */
-static int on_class_request(struct usbvirt_device *dev,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{	
-	dprintf(2, "hub class request (%d)", (int) request->request);
-	
-	uint8_t recipient = request->request_type & 31;
-	uint8_t direction = request->request_type >> 7;
-	
-#define _VERIFY(cond) \
-	do { \
-		if (!(cond)) { \
-			dprintf(0, "WARN: invalid class request (%s not met).\n", \
-			    NAME, #cond); \
-			return EINVAL; \
-		} \
-	} while (0)
-	
-	switch (request->request) {
-		case USB_HUB_REQUEST_CLEAR_FEATURE:
-			_VERIFY(direction == 0);
-			_VERIFY(request->length == 0);
-			if (recipient == 0) {
-				_VERIFY(request->index == 0);
-				return clear_hub_feature(request->value);
-			} else {
-				_VERIFY(recipient == 3);
-				return clear_port_feature(request->value,
-				    request->index);
-			}
-			
-		case USB_HUB_REQUEST_GET_STATE:
-			return get_bus_state(request->index);
-			
-		case USB_HUB_REQUEST_GET_DESCRIPTOR:
-			return get_hub_descriptor(dev, request->value_low,
-			    request->value_high, request->length);
-			
-		case USB_HUB_REQUEST_GET_STATUS:
-			if (recipient == 0) {
-				return get_hub_status();
-			} else {
-				return get_port_status(request->index);
-			}
-			
-		case USB_HUB_REQUEST_SET_FEATURE:
-			if (recipient == 0) {
-				return set_hub_feature(request->value);
-			} else {
-				return set_port_feature(request->value, request->index);
-			}
-			
-		default:
-			dprintf(0, "WARN: unknown request (%d)!\n",
-			    request->request);
-			break;
-	}
-	
-#undef _VERIFY	
-
-
-	return EOK;
-}
-
-void clear_port_status_change_nl(hub_port_t *port, uint16_t change)
-{
-	port->status_change &= (~change);
-	dprintf(2, "cleared port %d status change %d (%u)", port->index,
-	    (int)change, (unsigned int) port->status_change);
-}
-
-void set_port_status_change_nl(hub_port_t *port, uint16_t change)
-{
-	port->status_change |= change;
-	dprintf(2, "set port %d status change %d (%u)", port->index,
-	    (int)change, (unsigned int) port->status_change);
-
-}
-
-void clear_port_status_change(hub_port_t *port, uint16_t change)
-{
-	fibril_mutex_lock(&port->guard);
-	clear_port_status_change_nl(port, change);
-	fibril_mutex_unlock(&port->guard);
-}
-
-void set_port_status_change(hub_port_t *port, uint16_t change)
-{
-	fibril_mutex_lock(&port->guard);
-	set_port_status_change_nl(port, change);
-	fibril_mutex_unlock(&port->guard);
-}
-
-/** Callback for data request. */
-static int on_data_request(struct usbvirt_device *dev,
-    usb_endpoint_t endpoint,
-    void *buffer, size_t size, size_t *actual_size)
-{
-	if (endpoint != HUB_STATUS_CHANGE_PIPE) {
-		return EINVAL;
-	}
-	
-	uint8_t change_map = 0;
-	
-	size_t i;
-	for (i = 0; i < HUB_PORT_COUNT; i++) {
-		hub_port_t *port = &hub_dev.ports[i];
-		
-		fibril_mutex_lock(&port->guard);
-		if (port->status_change != 0) {
-			change_map |= (1 << (i + 1));
-		}
-		fibril_mutex_unlock(&port->guard);
-	}
-	
-	uint8_t *b = (uint8_t *) buffer;
-	if (size > 0) {
-		*b = change_map;
-		*actual_size = 1;
-	}
-	
-	return EOK;
-}
-
-
-/**
- * @}
- */
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/lib/c/generic/devman.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -230,8 +230,8 @@
 	
 	if (flags & IPC_FLAG_BLOCKING) {
-		phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
+		phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
 		    DEVMAN_CONNECT_TO_DEVICE, handle);
 	} else {
-		phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
+		phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
 		    DEVMAN_CONNECT_TO_DEVICE, handle);
 	}
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/lib/usb/src/usbdrv.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -72,10 +72,10 @@
 	devman_handle_t handle;
 
-	rc = devman_device_get_handle("/virt/usbhc", &handle, 0);
+	rc = devman_device_get_handle("/virt/usbhc", &handle, flags);
 	if (rc != EOK) {
 		return rc;
 	}
 	
-	int phone = devman_device_connect(handle, 0);
+	int phone = devman_device_connect(handle, flags);
 
 	return phone;
Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ uspace/lib/usbvirt/Makefile	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -31,13 +31,13 @@
 
 LIBS = $(LIBUSB_PREFIX)/libusb.a
-EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include
+EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -Iinclude
 
 SOURCES = \
-	callback.c \
-	ctrlpipe.c \
-	debug.c \
-	main.c \
-	stdreq.c \
-	transaction.c
+	src/callback.c \
+	src/ctrlpipe.c \
+	src/debug.c \
+	src/main.c \
+	src/stdreq.c \
+	src/transaction.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: pace/lib/usbvirt/callback.c
===================================================================
--- uspace/lib/usbvirt/callback.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,236 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Callback connection handling.
- */
-#include <devmap.h>
-#include <fcntl.h>
-#include <vfs/vfs.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <mem.h>
-
-#include "hub.h"
-#include "device.h"
-#include "private.h"
-
-#define NAMESPACE "usb"
-#define USB_MAX_PAYLOAD_SIZE 1020
-
-/** Wrapper for SETUP transaction over telephone. */
-static void handle_setup_transaction(usbvirt_device_t *device,
-    ipc_callid_t iid, ipc_call_t icall)
-{
-	usb_address_t address = IPC_GET_ARG1(icall);
-	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
-	size_t expected_len = IPC_GET_ARG3(icall);
-	
-	if (address != device->address) {
-		ipc_answer_0(iid, EADDRNOTAVAIL);
-		return;
-	}
-	
-	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
-		ipc_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	if (expected_len == 0) {
-		ipc_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	size_t len = 0;
-	void * buffer = NULL;
-	int rc = async_data_write_accept(&buffer, false,
-	    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
-		
-	if (rc != EOK) {
-		ipc_answer_0(iid, rc);
-		return;
-	}
-	
-	rc = device->transaction_setup(device, endpoint, buffer, len);
-	
-	ipc_answer_0(iid, rc);
-}
-
-/** Wrapper for OUT transaction over telephone. */
-static void handle_out_transaction(usbvirt_device_t *device,
-    ipc_callid_t iid, ipc_call_t icall)
-{
-	usb_address_t address = IPC_GET_ARG1(icall);
-	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
-	size_t expected_len = IPC_GET_ARG3(icall);
-	
-	if (address != device->address) {
-		ipc_answer_0(iid, EADDRNOTAVAIL);
-		return;
-	}
-	
-	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
-		ipc_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	int rc = EOK;
-	
-	size_t len = 0;
-	void *buffer = NULL;
-	
-	if (expected_len > 0) {
-		rc = async_data_write_accept(&buffer, false,
-		    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
-			
-		if (rc != EOK) {
-			ipc_answer_0(iid, rc);
-			return;
-		}
-	}
-	
-	rc = device->transaction_out(device, endpoint, buffer, len);
-	
-	if (buffer != NULL) {
-		free(buffer);
-	}
-	
-	ipc_answer_0(iid, rc);
-}
-
-
-/** Wrapper for IN transaction over telephone. */
-static void handle_in_transaction(usbvirt_device_t *device,
-    ipc_callid_t iid, ipc_call_t icall)
-{
-	usb_address_t address = IPC_GET_ARG1(icall);
-	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
-	size_t expected_len = IPC_GET_ARG3(icall);
-	
-	if (address != device->address) {
-		ipc_answer_0(iid, EADDRNOTAVAIL);
-		return;
-	}
-	
-	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
-		ipc_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	int rc = EOK;
-	
-	void *buffer = expected_len > 0 ? malloc(expected_len) : NULL;
-	size_t len;
-	
-	rc = device->transaction_in(device, endpoint, buffer, expected_len, &len);
-	/*
-	 * If the request was processed, we will send data back.
-	 */
-	if ((rc == EOK) && (expected_len > 0)) {
-		size_t receive_len;
-		ipc_callid_t callid;
-		if (!async_data_read_receive(&callid, &receive_len)) {
-			ipc_answer_0(iid, EINVAL);
-			return;
-		}
-		async_data_read_finalize(callid, buffer, receive_len);
-	}
-	
-	ipc_answer_0(iid, rc);
-}
-
-/** Wrapper for getting device name. */
-static void handle_get_name(usbvirt_device_t *device,
-    ipc_callid_t iid, ipc_call_t icall)
-{
-	if (device->name == NULL) {
-		ipc_answer_0(iid, ENOENT);
-	}
-	
-	size_t size = str_size(device->name);
-	
-	ipc_callid_t callid;
-	size_t accepted_size;
-	if (!async_data_read_receive(&callid, &accepted_size)) {
-		ipc_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	if (accepted_size > size) {
-		accepted_size = size;
-	}
-	async_data_read_finalize(callid, device->name, accepted_size);
-	
-	ipc_answer_1(iid, EOK, accepted_size);
-}
-
-/** Callback connection for a given device. */
-void device_callback_connection(usbvirt_device_t *device, ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_callid_t callid; 
-		ipc_call_t call; 
-		
-		callid = async_get_call(&call);
-		switch (IPC_GET_IMETHOD(call)) {
-			case IPC_M_PHONE_HUNGUP:
-				ipc_answer_0(callid, EOK);
-				return;
-			
-			case IPC_M_USBVIRT_GET_NAME:
-				handle_get_name(device, callid, call);
-				break;
-			
-			case IPC_M_USBVIRT_TRANSACTION_SETUP:
-				handle_setup_transaction(device, callid, call);
-				break;
-			
-			case IPC_M_USBVIRT_TRANSACTION_OUT:
-				handle_out_transaction(device, callid, call);
-				break;
-				
-			case IPC_M_USBVIRT_TRANSACTION_IN:
-				handle_in_transaction(device, callid, call);
-				break;
-			
-			default:
-				ipc_answer_0(callid, EINVAL);
-				break;
-		}
-	}
-}
-
-
-/**
- * @}
- */
Index: pace/lib/usbvirt/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/ctrlpipe.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,127 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Device control pipe.
- */
-#include <errno.h>
-
-#include "private.h"
-
-#define REQUEST_TYPE_STANDARD 0 
-#define REQUEST_TYPE_CLASS 1
-
-#define GET_MIDBITS_MASK(size, shift) \
-	(((1 << size) - 1) << shift)
-#define GET_MIDBITS(value, size, shift) \
-	((value & GET_MIDBITS_MASK(size, shift)) >> shift)
-
-
-static const char *str_request_type(int type)
-{
-	switch (type) {
-		case REQUEST_TYPE_STANDARD:
-			return "standard";
-		case REQUEST_TYPE_CLASS:
-			return "class";
-		default:
-			return "unknown";
-	}
-}
-
-/** Tell request type.
- * By type is meant either standard, class, vendor or other.
- */
-static int request_get_type(uint8_t request_type)
-{
-	return GET_MIDBITS(request_type, 2, 5);
-}
-
-/** Handle communication over control pipe zero.
- */
-int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer)
-{
-	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
-	    "op on control pipe zero (request_size=%u)", transfer->request_size);
-	
-	if (transfer->request_size < sizeof(usb_device_request_setup_packet_t)) {
-		return ENOMEM;
-	}
-	
-	usb_device_request_setup_packet_t *request = (usb_device_request_setup_packet_t *) transfer->request;
-	uint8_t *remaining_data = transfer->data;
-	
-	int type = request_get_type(request->request_type);
-	
-	int rc = EOK;
-	
-	device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
-	    "request type: %s", str_request_type(type));
-	
-	switch (type) {
-		case REQUEST_TYPE_STANDARD:
-			rc = handle_std_request(device, request, remaining_data);
-			break;
-		case REQUEST_TYPE_CLASS:
-			if (DEVICE_HAS_OP(device, on_class_device_request)) {
-				rc = device->ops->on_class_device_request(device,
-				    request, remaining_data);
-			}
-			break;
-		default:
-			break;
-	}
-	
-	if (device->new_address != -1) {
-		/*
-		 * TODO: handle when this request is invalid (e.g.
-		 * setting address when in configured state).
-		 */
-		if (device->new_address == 0) {
-			device->state = USBVIRT_STATE_DEFAULT;
-		} else {
-			device->state = USBVIRT_STATE_ADDRESS;
-		}
-		device->address = device->new_address;
-		
-		device->new_address = -1;
-		
-		device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
-		    "device address changed to %d (state %s)",
-		    device->address, str_device_state(device->state));
-	}
-	
-	return rc;
-}
-
-/**
- * @}
- */
Index: pace/lib/usbvirt/debug.c
===================================================================
--- uspace/lib/usbvirt/debug.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,104 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Debugging support.
- */
-#include <stdio.h>
-#include <bool.h>
-
-#include "device.h"
-#include "private.h"
-
-
-static void debug_print(int level, uint8_t tag,
-    int current_level, uint8_t enabled_tags,
-    const char *format, va_list args)
-{
-	if (level > current_level) {
-		return;
-	}
-	
-	if ((tag & enabled_tags) == 0) {
-		return;
-	}
-	
-	bool print_prefix = true;
-	
-	if ((format[0] == '%') && (format[1] == 'M')) {
-		format += 2;
-		print_prefix = false;
-	}
-	
-	if (print_prefix) {
-		printf("[vusb]: ");
-		while (--level > 0) {
-			printf(" ");
-		}
-	}
-	
-	vprintf(format, args);
-	
-	if (print_prefix) {
-		printf("\n");
-	}
-}
-
-
-void user_debug(usbvirt_device_t *device, int level, uint8_t tag,
-    const char *format, ...)
-{
-	va_list args;
-	va_start(args, format);
-	
-	debug_print(level, tag,
-	    device->debug_level, device->debug_enabled_tags,
-	    format, args);
-	
-	va_end(args);
-}
-
-void lib_debug(usbvirt_device_t *device, int level, uint8_t tag,
-    const char *format, ...)
-{
-	va_list args;
-	va_start(args, format);
-	
-	debug_print(level, tag,
-	    device->lib_debug_level, device->lib_debug_enabled_tags,
-	    format, args);
-	
-	va_end(args);
-}
-
-/**
- * @}
- */
Index: pace/lib/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/device.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,224 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Virtual USB device.
- */
-#ifndef LIBUSBVIRT_DEVICE_H_
-#define LIBUSBVIRT_DEVICE_H_
-
-#include <usb/usb.h>
-#include <usb/descriptor.h>
-#include <usb/devreq.h>
-
-typedef struct usbvirt_device usbvirt_device_t;
-struct usbvirt_control_transfer;
-
-typedef int (*usbvirt_on_device_request_t)(usbvirt_device_t *dev,
-	usb_device_request_setup_packet_t *request,
-	uint8_t *data);
-
-/** Callbacks for standard device requests.
- * When these functions are NULL or return EFORWARD, this
- * framework will try to satisfy the request by itself.
- */
-typedef struct {
-	usbvirt_on_device_request_t on_get_status;
-	usbvirt_on_device_request_t on_clear_feature;
-	usbvirt_on_device_request_t on_set_feature;
-	usbvirt_on_device_request_t on_set_address;
-	usbvirt_on_device_request_t on_get_descriptor;
-	usbvirt_on_device_request_t on_set_descriptor;
-	usbvirt_on_device_request_t on_get_configuration;
-	usbvirt_on_device_request_t on_set_configuration;
-	usbvirt_on_device_request_t on_get_interface;
-	usbvirt_on_device_request_t on_set_interface;
-	usbvirt_on_device_request_t on_synch_frame;
-} usbvirt_standard_device_request_ops_t;
-
-/** Device operations. */
-typedef struct {
-	/** Callbacks for standard deivce requests. */
-	usbvirt_standard_device_request_ops_t *standard_request_ops;
-	/** Callback for class-specific USB request. */
-	usbvirt_on_device_request_t on_class_device_request;
-	
-	int (*on_control_transfer)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, struct usbvirt_control_transfer *transfer);
-	
-	/** Callback for all other incoming data. */
-	int (*on_data)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, void *buffer, size_t size);
-	
-	/** Callback for host request for data. */
-	int (*on_data_request)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *actual_size);
-	
-	/** Decides direction of control transfer. */
-	usb_direction_t (*decide_control_transfer_direction)(
-	    usb_endpoint_t endpoint, void *buffer, size_t size);
-} usbvirt_device_ops_t;
-
-/** Extra configuration data for GET_CONFIGURATION request. */
-typedef struct {
-	/** Actual data. */
-	uint8_t *data;
-	/** Data length. */
-	size_t length;
-} usbvirt_device_configuration_extras_t;
-
-/** Single device configuration. */
-typedef struct {
-	/** Standard configuration descriptor. */
-	usb_standard_configuration_descriptor_t *descriptor;
-	/** Array of extra data. */
-	usbvirt_device_configuration_extras_t *extra;
-	/** Length of @c extra array. */
-	size_t extra_count;
-} usbvirt_device_configuration_t;
-
-/** Standard USB descriptors. */
-typedef struct {
-	/** Standard device descriptor.
-	 * There is always only one such descriptor for the device.
-	 */
-	usb_standard_device_descriptor_t *device;
-	
-	/** Configurations. */
-	usbvirt_device_configuration_t *configuration;
-	/** Number of configurations. */
-	size_t configuration_count;
-	/** Index of currently selected configuration. */
-	uint8_t current_configuration;
-} usbvirt_descriptors_t;
-
-/** Possible states of virtual USB device.
- * Notice that these are not 1:1 mappings to those in USB specification.
- */
-typedef enum {
-	USBVIRT_STATE_DEFAULT,
-	USBVIRT_STATE_ADDRESS,
-	USBVIRT_STATE_CONFIGURED
-} usbvirt_device_state_t;
-
-/** Information about on-going control transfer.
- */
-typedef struct usbvirt_control_transfer {
-	/** Transfer direction (read/write control transfer). */
-	usb_direction_t direction;
-	/** Request data. */
-	void *request;
-	/** Size of request data. */
-	size_t request_size;
-	/** Payload. */
-	void *data;
-	/** Size of payload. */
-	size_t data_size;
-} usbvirt_control_transfer_t;
-
-typedef enum {
-	USBVIRT_DEBUGTAG_BASE = 1,
-	USBVIRT_DEBUGTAG_TRANSACTION = 2,
-	USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO = 4,
-	USBVIRT_DEBUGTAG_ALL = 255
-} usbvirt_debug_tags_t;
-
-/** Virtual USB device. */
-struct usbvirt_device {
-	/** Callback device operations. */
-	usbvirt_device_ops_t *ops;
-	
-	/** Reply onto control transfer.
-	 */
-	int (*control_transfer_reply)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, void *buffer, size_t size);
-	
-	/** Device name.
-	 * Used in debug prints and sent to virtual host controller.
-	 */
-	const char *name;
-	
-	/** Standard descriptors. */
-	usbvirt_descriptors_t *descriptors;
-	
-	/** Current device state. */
-	usbvirt_device_state_t state;
-	
-	/** Device address. */
-	usb_address_t address;
-	/** New device address.
-	 * This field is used during SET_ADDRESS request.
-	 * On all other occasions, it holds invalid address (e.g. -1).
-	 */
-	usb_address_t new_address;
-	
-	/** Process OUT transaction. */
-	int (*transaction_out)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, void *buffer, size_t size);
-	/** Process SETUP transaction. */
-	int (*transaction_setup)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, void *buffer, size_t size);
-	/** Process IN transaction. */
-	int (*transaction_in)(usbvirt_device_t *dev,
-	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *data_size);
-	
-	/** State information on control-transfer endpoints. */
-	usbvirt_control_transfer_t current_control_transfers[USB11_ENDPOINT_MAX];
-	
-	/* User debugging. */
-	
-	/** Debug print. */
-	void (*debug)(usbvirt_device_t *dev, int level, uint8_t tag,
-	    const char *format, ...);
-	
-	/** Current debug level. */
-	int debug_level;
-	
-	/** Bitmap of currently enabled tags. */
-	uint8_t debug_enabled_tags;
-	
-	/* Library debugging. */
-	
-	/** Debug print. */
-	void (*lib_debug)(usbvirt_device_t *dev, int level, uint8_t tag,
-	    const char *format, ...);
-	
-	/** Current debug level. */
-	int lib_debug_level;
-	
-	/** Bitmap of currently enabled tags. */
-	uint8_t lib_debug_enabled_tags;
-};
-
-#endif
-/**
- * @}
- */
Index: pace/lib/usbvirt/hub.h
===================================================================
--- uspace/lib/usbvirt/hub.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,68 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Virtual USB device.
- */
-#ifndef LIBUSBVIRT_HUB_H_
-#define LIBUSBVIRT_HUB_H_
-
-#include "device.h"
-
-/** USB transaction type.
- * This types does not correspond directly to types in USB specification,
- * as actually DATA transactions are marked with these types to identify
- * their direction (and tag).
- */
-typedef enum {
-	USBVIRT_TRANSACTION_SETUP,
-	USBVIRT_TRANSACTION_IN,
-	USBVIRT_TRANSACTION_OUT
-} usbvirt_transaction_type_t;
-
-const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type);
-
-/** Telephony methods of virtual devices. */
-typedef enum {
-	IPC_M_USBVIRT_GET_NAME = IPC_FIRST_USER_METHOD,
-	IPC_M_USBVIRT_TRANSACTION_SETUP,
-	IPC_M_USBVIRT_TRANSACTION_OUT,
-	IPC_M_USBVIRT_TRANSACTION_IN,
-} usbvirt_device_method_t;
-
-int usbvirt_connect(usbvirt_device_t *);
-int usbvirt_connect_local(usbvirt_device_t *);
-int usbvirt_disconnect(usbvirt_device_t *dev);
-
-#endif
-/**
- * @}
- */
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB device.
+ */
+#ifndef LIBUSBVIRT_DEVICE_H_
+#define LIBUSBVIRT_DEVICE_H_
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/devreq.h>
+
+/** Request type of a control transfer. */
+typedef enum {
+	/** Standard USB request. */
+	USBVIRT_REQUEST_TYPE_STANDARD = 0,
+	/** Standard class USB request. */
+	USBVIRT_REQUEST_TYPE_CLASS = 1
+} usbvirt_request_type_t;
+
+/** Recipient of control request. */
+typedef enum {
+	/** Device is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_DEVICE = 0,
+	/** Interface is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_INTERFACE = 1,
+	/** Endpoint is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_ENDPOINT = 2,
+	/** Other part of the device is the recipient of the control request. */
+	USBVIRT_REQUEST_RECIPIENT_OTHER = 3
+} usbvirt_request_recipient_t;
+
+/** Possible states of virtual USB device.
+ * Notice that these are not 1:1 mappings to those in USB specification.
+ */
+typedef enum {
+	/** Default state, device listens at default address. */
+	USBVIRT_STATE_DEFAULT,
+	/** Device has non-default address assigned. */
+	USBVIRT_STATE_ADDRESS,
+	/** Device is configured. */
+	USBVIRT_STATE_CONFIGURED
+} usbvirt_device_state_t;
+
+typedef struct usbvirt_device usbvirt_device_t;
+struct usbvirt_control_transfer;
+
+typedef int (*usbvirt_on_device_request_t)(usbvirt_device_t *dev,
+	usb_device_request_setup_packet_t *request,
+	uint8_t *data);
+
+/** Callback for control request over pipe zero.
+ *
+ * @param dev Virtual device answering the call.
+ * @param request Request setup packet.
+ * @param data Data when DATA stage is present.
+ * @return Error code.
+ */
+typedef int (*usbvirt_control_request_callback_t)(usbvirt_device_t *dev,
+	usb_device_request_setup_packet_t *request,
+	uint8_t *data);
+
+/** Handler for control transfer on endpoint zero. */
+typedef struct {
+	/** Request type bitmap.
+	 * Use USBVIRT_MAKE_CONTROL_REQUEST_TYPE for creating the bitmap.
+	 */
+	uint8_t request_type;
+	/** Request code. */
+	uint8_t request;
+	/** Request name for debugging. */
+	const char *name;
+	/** Callback for the request.
+	 * NULL value here announces end of a list.
+	 */
+	usbvirt_control_request_callback_t callback;
+} usbvirt_control_transfer_handler_t;
+
+/** Create control request type bitmap.
+ *
+ * @param direction Transfer direction (use usb_direction_t).
+ * @param type Request type (use usbvirt_request_type_t).
+ * @param recipient Recipient of the request (use usbvirt_request_recipient_t).
+ * @return Request type bitmap.
+ */
+#define USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, type, recipient) \
+	((((direction) == USB_DIRECTION_IN) ? 1 : 0) << 7) \
+	| (((type) & 3) << 5) \
+	| (((recipient) & 31))
+
+/** Create last item in an array of control request handlers. */
+#define USBVIRT_CONTROL_TRANSFER_HANDLER_LAST { 0, 0, NULL, NULL }
+
+/** Device operations. */
+typedef struct {
+	/** Callbacks for transfers over control pipe zero. */
+	usbvirt_control_transfer_handler_t *control_transfer_handlers;
+
+	int (*on_control_transfer)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, struct usbvirt_control_transfer *transfer);
+	
+	/** Callback for all other incoming data. */
+	int (*on_data)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	
+	/** Callback for host request for data. */
+	int (*on_data_request)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *actual_size);
+	
+	/** Decides direction of control transfer. */
+	usb_direction_t (*decide_control_transfer_direction)(
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+	/** Callback when device changes its state.
+	 *
+	 * It is correct that this function is called when both states
+	 * are equal (e.g. this function is called during SET_CONFIGURATION
+	 * request done on already configured device).
+	 *
+	 * @warning The value of <code>dev->state</code> before calling
+	 * this function is not specified (i.e. can be @p old_state or
+	 * @p new_state).
+	 */
+	void (*on_state_change)(usbvirt_device_t *dev,
+	    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state);
+} usbvirt_device_ops_t;
+
+/** Extra configuration data for GET_CONFIGURATION request. */
+typedef struct {
+	/** Actual data. */
+	uint8_t *data;
+	/** Data length. */
+	size_t length;
+} usbvirt_device_configuration_extras_t;
+
+/** Single device configuration. */
+typedef struct {
+	/** Standard configuration descriptor. */
+	usb_standard_configuration_descriptor_t *descriptor;
+	/** Array of extra data. */
+	usbvirt_device_configuration_extras_t *extra;
+	/** Length of @c extra array. */
+	size_t extra_count;
+} usbvirt_device_configuration_t;
+
+/** Standard USB descriptors. */
+typedef struct {
+	/** Standard device descriptor.
+	 * There is always only one such descriptor for the device.
+	 */
+	usb_standard_device_descriptor_t *device;
+	
+	/** Configurations. */
+	usbvirt_device_configuration_t *configuration;
+	/** Number of configurations. */
+	size_t configuration_count;
+	/** Index of currently selected configuration. */
+	uint8_t current_configuration;
+} usbvirt_descriptors_t;
+
+/** Information about on-going control transfer.
+ */
+typedef struct usbvirt_control_transfer {
+	/** Transfer direction (read/write control transfer). */
+	usb_direction_t direction;
+	/** Request data. */
+	void *request;
+	/** Size of request data. */
+	size_t request_size;
+	/** Payload. */
+	void *data;
+	/** Size of payload. */
+	size_t data_size;
+} usbvirt_control_transfer_t;
+
+typedef enum {
+	USBVIRT_DEBUGTAG_BASE = 1,
+	USBVIRT_DEBUGTAG_TRANSACTION = 2,
+	USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO = 4,
+	USBVIRT_DEBUGTAG_ALL = 255
+} usbvirt_debug_tags_t;
+
+/** Virtual USB device. */
+struct usbvirt_device {
+	/** Callback device operations. */
+	usbvirt_device_ops_t *ops;
+	
+	/** Custom device data. */
+	void *device_data;
+
+	/** Reply onto control transfer.
+	 */
+	int (*control_transfer_reply)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	
+	/** Device name.
+	 * Used in debug prints and sent to virtual host controller.
+	 */
+	const char *name;
+	
+	/** Standard descriptors. */
+	usbvirt_descriptors_t *descriptors;
+	
+	/** Current device state. */
+	usbvirt_device_state_t state;
+	
+	/** Device address. */
+	usb_address_t address;
+	/** New device address.
+	 * This field is used during SET_ADDRESS request.
+	 * On all other occasions, it holds invalid address (e.g. -1).
+	 */
+	usb_address_t new_address;
+	
+	/** Process OUT transaction. */
+	int (*transaction_out)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	/** Process SETUP transaction. */
+	int (*transaction_setup)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size);
+	/** Process IN transaction. */
+	int (*transaction_in)(usbvirt_device_t *dev,
+	    usb_endpoint_t endpoint, void *buffer, size_t size, size_t *data_size);
+	
+	/** State information on control-transfer endpoints. */
+	usbvirt_control_transfer_t current_control_transfers[USB11_ENDPOINT_MAX];
+	
+	/* User debugging. */
+	
+	/** Debug print. */
+	void (*debug)(usbvirt_device_t *dev, int level, uint8_t tag,
+	    const char *format, ...);
+	
+	/** Current debug level. */
+	int debug_level;
+	
+	/** Bitmap of currently enabled tags. */
+	uint8_t debug_enabled_tags;
+	
+	/* Library debugging. */
+	
+	/** Debug print. */
+	void (*lib_debug)(usbvirt_device_t *dev, int level, uint8_t tag,
+	    const char *format, ...);
+	
+	/** Current debug level. */
+	int lib_debug_level;
+	
+	/** Bitmap of currently enabled tags. */
+	uint8_t lib_debug_enabled_tags;
+};
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/include/usbvirt/hub.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/hub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/include/usbvirt/hub.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB device.
+ */
+#ifndef LIBUSBVIRT_HUB_H_
+#define LIBUSBVIRT_HUB_H_
+
+#include "device.h"
+
+/** USB transaction type.
+ * This types does not correspond directly to types in USB specification,
+ * as actually DATA transactions are marked with these types to identify
+ * their direction (and tag).
+ */
+typedef enum {
+	USBVIRT_TRANSACTION_SETUP,
+	USBVIRT_TRANSACTION_IN,
+	USBVIRT_TRANSACTION_OUT
+} usbvirt_transaction_type_t;
+
+const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type);
+
+/** Telephony methods of virtual devices. */
+typedef enum {
+	IPC_M_USBVIRT_GET_NAME = IPC_FIRST_USER_METHOD,
+	IPC_M_USBVIRT_TRANSACTION_SETUP,
+	IPC_M_USBVIRT_TRANSACTION_OUT,
+	IPC_M_USBVIRT_TRANSACTION_IN,
+} usbvirt_device_method_t;
+
+int usbvirt_connect(usbvirt_device_t *);
+int usbvirt_connect_local(usbvirt_device_t *);
+int usbvirt_disconnect(usbvirt_device_t *dev);
+
+#endif
+/**
+ * @}
+ */
Index: pace/lib/usbvirt/main.c
===================================================================
--- uspace/lib/usbvirt/main.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,289 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Device registration with virtual USB framework.
- */
-#include <devman.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <mem.h>
-#include <assert.h>
-
-#include "hub.h"
-#include "device.h"
-#include "private.h"
-
-#define NAMESPACE "usb"
-
-/** Virtual device wrapper. */
-typedef struct {
-	/** Actual device. */
-	usbvirt_device_t *device;
-	/** Phone to host controller. */
-	int vhcd_phone;
-	/** Device id. */
-	sysarg_t id;
-	/** Linked-list member. */
-	link_t link;
-} virtual_device_t;
-
-/*** List of known device. */
-static LIST_INITIALIZE(device_list);
-
-/** Find virtual device wrapper based on the contents. */
-static virtual_device_t *find_device(usbvirt_device_t *device)
-{
-	if (list_empty(&device_list)) {
-		return NULL;
-	}
-	
-	link_t *pos;
-	for (pos = device_list.next; pos != &device_list; pos = pos->next) {
-		virtual_device_t *dev
-		    = list_get_instance(pos, virtual_device_t, link);
-		if (dev->device == device) {
-			return dev;
-		}
-	}
-	
-	return NULL;
-}
-
-/** Find virtual device wrapper by its id. */
-static virtual_device_t *find_device_by_id(sysarg_t id)
-{
-	if (list_empty(&device_list)) {
-		return NULL;
-	}
-	
-	link_t *pos;
-	for (pos = device_list.next; pos != &device_list; pos = pos->next) {
-		virtual_device_t *dev
-		    = list_get_instance(pos, virtual_device_t, link);
-		if (dev->id == id) {
-			return dev;
-		}
-	}
-	
-	return NULL;
-}
-
-/** Reply to a control transfer. */
-static int control_transfer_reply(usbvirt_device_t *device,
-	    usb_endpoint_t endpoint, void *buffer, size_t size)
-{
-	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
-	if (transfer->data != NULL) {
-		free(transfer->data);
-	}
-	transfer->data = malloc(size);
-	memcpy(transfer->data, buffer, size);
-	transfer->data_size = size;
-	
-	return EOK;
-}
-
-/** Initialize virtual device. */
-static void device_init(usbvirt_device_t *dev)
-{
-	dev->transaction_out = transaction_out;
-	dev->transaction_setup = transaction_setup;
-	dev->transaction_in = transaction_in;
-	
-	dev->control_transfer_reply = control_transfer_reply;
-	
-	dev->debug = user_debug;
-	dev->lib_debug = lib_debug;
-	
-	dev->state = USBVIRT_STATE_DEFAULT;
-	dev->address = 0;
-	dev->new_address = -1;
-	
-	size_t i;
-	for (i = 0; i < USB11_ENDPOINT_MAX; i++) {
-		usbvirt_control_transfer_t *transfer = &dev->current_control_transfers[i];
-		transfer->direction = 0;
-		transfer->request = NULL;
-		transfer->request_size = 0;
-		transfer->data = NULL;
-		transfer->data_size = 0;
-	}
-}
-
-/** Add a virtual device.
- * The returned device (if not NULL) shall be destroy via destroy_device().
- */
-static virtual_device_t *add_device(usbvirt_device_t *dev)
-{
-	assert(find_device(dev) == NULL);
-	virtual_device_t *new_device
-	    = (virtual_device_t *) malloc(sizeof(virtual_device_t));
-	
-	new_device->device = dev;
-	link_initialize(&new_device->link);
-	
-	list_append(&new_device->link, &device_list);
-	
-	return new_device;
-}
-
-/** Destroy virtual device. */
-static void destroy_device(virtual_device_t *dev)
-{
-	if (dev->vhcd_phone > 0) {
-		ipc_hangup(dev->vhcd_phone);
-	}
-	
-	list_remove(&dev->link);
-	
-	free(dev);
-}
-
-/** Callback connection handler. */
-static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	// FIXME - determine which device just called back
-	virtual_device_t *dev = find_device_by_id(0);
-	if (dev == NULL) {
-		ipc_answer_0(iid, EINVAL);
-		printf("Ooops\n");
-		return;
-	}
-
-	device_callback_connection(dev->device, iid, icall);
-}
-
-/** Create necessary phones for communication with virtual HCD.
- * This function wraps following calls:
- * -# open <code>/dev/devices/\\virt\\usbhc for reading
- * -# access phone of file opened in previous step
- * -# create callback through just opened phone
- * -# create handler for calling on data from host to function
- * -# return the (outgoing) phone
- *
- * @warning This function is wrapper for several actions and therefore
- * it is not possible - in case of error - to determine at which point
- * error occurred.
- *
- * @param dev Device to connect.
- * @return EOK on success or error code from errno.h.
- */
-int usbvirt_connect(usbvirt_device_t *dev)
-{
-	virtual_device_t *virtual_device = find_device(dev);
-	if (virtual_device != NULL) {
-		return EEXISTS;
-	}
-	
-	const char *vhc_path = "/virt/usbhc";
-	int rc;
-	devman_handle_t handle;
-
-	rc = devman_device_get_handle(vhc_path, &handle, 0);
-	if (rc != EOK) {
-		printf("devman_device_get_handle() failed\n");
-		return rc;
-	}
-	
-	int hcd_phone = devman_device_connect(handle, 0);
-	
-	if (hcd_phone < 0) {
-		printf("devman_device_connect() failed\n");
-		return hcd_phone;
-	}
-	
-	sysarg_t phonehash;
-	rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
-	if (rc != EOK) {
-		printf("ipc_connect_to_me() failed\n");
-		return rc;
-	}
-	
-	device_init(dev);
-	
-	virtual_device = add_device(dev);
-	virtual_device->vhcd_phone = hcd_phone;
-	virtual_device->id = 0;
-	
-	async_new_connection(phonehash, 0, NULL, callback_connection);
-	
-	return EOK;
-}
-
-/** Prepares device as local.
- * This is useful if you want to have a virtual device in the same task
- * as HCD.
- *
- * @param dev Device to connect.
- * @return Error code.
- * @retval EOK Device connected.
- * @retval EEXISTS This device is already connected.
- */
-int usbvirt_connect_local(usbvirt_device_t *dev)
-{
-	virtual_device_t *virtual_device = find_device(dev);
-	if (virtual_device != NULL) {
-		return EEXISTS;
-	}
-	
-	device_init(dev);
-	
-	virtual_device = add_device(dev);
-	virtual_device->vhcd_phone = -1;
-	virtual_device->id = 0;
-	
-	return EOK;
-}
-
-/** Disconnects device from HCD.
- *
- * @param dev Device to be disconnected.
- * @return Error code.
- * @retval EOK Device connected.
- * @retval ENOENT This device is not connected.
- */
-int usbvirt_disconnect(usbvirt_device_t *dev)
-{
-	virtual_device_t *virtual_device = find_device(dev);
-	if (virtual_device == NULL) {
-		return ENOENT;
-	}
-	
-	destroy_device(virtual_device);
-	
-	return EOK;
-}
-
-
-/**
- * @}
- */
Index: pace/lib/usbvirt/private.h
===================================================================
--- uspace/lib/usbvirt/private.h	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,91 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Virtual USB private header.
- */
-#ifndef LIBUSBVIRT_PRIVATE_H_
-#define LIBUSBVIRT_PRIVATE_H_
-
-#include "device.h"
-#include "hub.h"
-
-
-#define DEVICE_HAS_OP(dev, op) \
-	( \
-		(  ((dev)->ops) != NULL  ) \
-		&& \
-		(  ((dev)->ops->op) != NULL  ) \
-	)
-
-int usbvirt_data_to_host(struct usbvirt_device *dev,
-    usb_endpoint_t endpoint, void *buffer, size_t size);
-
-int handle_incoming_data(struct usbvirt_device *dev,
-    usb_endpoint_t endpoint, void *buffer, size_t size);
-
-int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer);
-
-int handle_std_request(usbvirt_device_t *device, usb_device_request_setup_packet_t *request, uint8_t *data);
-
-void device_callback_connection(usbvirt_device_t *device, ipc_callid_t iid, ipc_call_t *icall);
-
-int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
-    void *buffer, size_t size);
-int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
-    void *buffer, size_t size);
-int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
-    void *buffer, size_t size, size_t *data_size);
-
-
-void user_debug(usbvirt_device_t *device, int level, uint8_t tag,
-    const char *format, ...);
-void lib_debug(usbvirt_device_t *device, int level, uint8_t tag,
-    const char *format, ...);
-    
-static inline const char *str_device_state(usbvirt_device_state_t state)
-{
-	switch (state) {
-		case USBVIRT_STATE_DEFAULT:
-			return "default";
-		case USBVIRT_STATE_ADDRESS:
-			return "address";
-		case USBVIRT_STATE_CONFIGURED:
-			return "configured";
-		default:
-			return "unknown";
-	}
-}
-
-#endif
-/**
- * @}
- */
Index: uspace/lib/usbvirt/src/callback.c
===================================================================
--- uspace/lib/usbvirt/src/callback.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/callback.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Callback connection handling.
+ */
+#include <devmap.h>
+#include <fcntl.h>
+#include <vfs/vfs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+
+#include "private.h"
+
+#define NAMESPACE "usb"
+#define USB_MAX_PAYLOAD_SIZE 1020
+
+/** Wrapper for SETUP transaction over telephone. */
+static void handle_setup_transaction(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	if (expected_len == 0) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	size_t len = 0;
+	void * buffer = NULL;
+	int rc = async_data_write_accept(&buffer, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
+		
+	if (rc != EOK) {
+		ipc_answer_0(iid, rc);
+		return;
+	}
+	
+	rc = device->transaction_setup(device, endpoint, buffer, len);
+	
+	ipc_answer_0(iid, rc);
+}
+
+/** Wrapper for OUT transaction over telephone. */
+static void handle_out_transaction(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	int rc = EOK;
+	
+	size_t len = 0;
+	void *buffer = NULL;
+	
+	if (expected_len > 0) {
+		rc = async_data_write_accept(&buffer, false,
+		    1, USB_MAX_PAYLOAD_SIZE, 0, &len);
+			
+		if (rc != EOK) {
+			ipc_answer_0(iid, rc);
+			return;
+		}
+	}
+	
+	rc = device->transaction_out(device, endpoint, buffer, len);
+	
+	if (buffer != NULL) {
+		free(buffer);
+	}
+	
+	ipc_answer_0(iid, rc);
+}
+
+
+/** Wrapper for IN transaction over telephone. */
+static void handle_in_transaction(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	usb_address_t address = IPC_GET_ARG1(icall);
+	usb_endpoint_t endpoint = IPC_GET_ARG2(icall);
+	size_t expected_len = IPC_GET_ARG3(icall);
+	
+	if (address != device->address) {
+		ipc_answer_0(iid, EADDRNOTAVAIL);
+		return;
+	}
+	
+	if ((endpoint < 0) || (endpoint >= USB11_ENDPOINT_MAX)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	int rc = EOK;
+	
+	void *buffer = expected_len > 0 ? malloc(expected_len) : NULL;
+	size_t len;
+	
+	rc = device->transaction_in(device, endpoint, buffer, expected_len, &len);
+	/*
+	 * If the request was processed, we will send data back.
+	 */
+	if ((rc == EOK) && (expected_len > 0)) {
+		size_t receive_len;
+		ipc_callid_t callid;
+		if (!async_data_read_receive(&callid, &receive_len)) {
+			ipc_answer_0(iid, EINVAL);
+			return;
+		}
+		async_data_read_finalize(callid, buffer, receive_len);
+	}
+	
+	ipc_answer_0(iid, rc);
+}
+
+/** Wrapper for getting device name. */
+static void handle_get_name(usbvirt_device_t *device,
+    ipc_callid_t iid, ipc_call_t icall)
+{
+	if (device->name == NULL) {
+		ipc_answer_0(iid, ENOENT);
+	}
+	
+	size_t size = str_size(device->name);
+	
+	ipc_callid_t callid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&callid, &accepted_size)) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	if (accepted_size > size) {
+		accepted_size = size;
+	}
+	async_data_read_finalize(callid, device->name, accepted_size);
+	
+	ipc_answer_1(iid, EOK, accepted_size);
+}
+
+/** Callback connection for a given device. */
+void device_callback_connection(usbvirt_device_t *device, ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_answer_0(iid, EOK);
+	
+	while (true) {
+		ipc_callid_t callid; 
+		ipc_call_t call; 
+		
+		callid = async_get_call(&call);
+		switch (IPC_GET_IMETHOD(call)) {
+			case IPC_M_PHONE_HUNGUP:
+				ipc_answer_0(callid, EOK);
+				return;
+			
+			case IPC_M_USBVIRT_GET_NAME:
+				handle_get_name(device, callid, call);
+				break;
+			
+			case IPC_M_USBVIRT_TRANSACTION_SETUP:
+				handle_setup_transaction(device, callid, call);
+				break;
+			
+			case IPC_M_USBVIRT_TRANSACTION_OUT:
+				handle_out_transaction(device, callid, call);
+				break;
+				
+			case IPC_M_USBVIRT_TRANSACTION_IN:
+				handle_in_transaction(device, callid, call);
+				break;
+			
+			default:
+				ipc_answer_0(callid, EINVAL);
+				break;
+		}
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ctrlpipe.c
===================================================================
--- uspace/lib/usbvirt/src/ctrlpipe.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/ctrlpipe.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Device control pipe.
+ */
+#include <errno.h>
+
+#include "private.h"
+
+/** Compares handler type with request packet type.
+ *
+ * @param handler Handler.
+ * @param request_packet Request packet.
+ * @return Whether handler can serve this packet.
+ */
+static bool is_suitable_handler(usbvirt_control_transfer_handler_t *handler,
+    usb_device_request_setup_packet_t *request_packet)
+{
+	return (
+	    (handler->request_type == request_packet->request_type)
+	    && (handler->request == request_packet->request));
+
+}
+
+/** Find suitable transfer handler for given request packet.
+ *
+ * @param handlers Array of available handlers.
+ * @param request_packet Request SETUP packet.
+ * @return Handler or NULL.
+ */
+static usbvirt_control_transfer_handler_t *find_handler(
+    usbvirt_control_transfer_handler_t *handlers,
+    usb_device_request_setup_packet_t *request_packet)
+{
+	if (handlers == NULL) {
+		return NULL;
+	}
+
+	while (handlers->callback != NULL) {
+		if (is_suitable_handler(handlers, request_packet)) {
+			return handlers;
+		}
+		handlers++;
+	}
+
+	return NULL;
+}
+
+#define _GET_BIT(byte, bit) \
+	(((byte) & (1 << (bit))) ? '1' : '0')
+#define _GET_BITS(byte) \
+	_GET_BIT(byte, 7), _GET_BIT(byte, 6), _GET_BIT(byte, 5), \
+	_GET_BIT(byte, 4), _GET_BIT(byte, 3), _GET_BIT(byte, 2), \
+	_GET_BIT(byte, 1), _GET_BIT(byte, 0)
+
+static int find_and_run_handler(usbvirt_device_t *device,
+    usbvirt_control_transfer_handler_t *handlers,
+    usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data)
+{
+	int rc = EFORWARD;
+	usbvirt_control_transfer_handler_t *suitable_handler
+	    = find_handler(handlers, setup_packet);
+	if (suitable_handler != NULL) {
+		const char *callback_name = "user handler";
+		if (suitable_handler->name != NULL) {
+			callback_name = suitable_handler->name;
+		}
+		device->lib_debug(device, 1, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+		    "pipe #0 - calling %s " \
+		        "[%c.%c%c.%c%c%c%c%c, R%d, V%d, I%d, L%d]",
+		    callback_name,
+		    _GET_BITS(setup_packet->request_type),
+		    setup_packet->request, setup_packet->value,
+		    setup_packet->index, setup_packet->length);
+		rc = suitable_handler->callback(device, setup_packet, data);
+	}
+
+	return rc;
+}
+#undef _GET_BITS
+#undef _GET_BIT
+
+
+/** Handle communication over control pipe zero.
+ */
+int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer)
+{
+	device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+	    "op on control pipe zero (request_size=%u)", transfer->request_size);
+	
+	if (transfer->request_size < sizeof(usb_device_request_setup_packet_t)) {
+		return ENOMEM;
+	}
+	
+	usb_device_request_setup_packet_t *request
+	    = (usb_device_request_setup_packet_t *) transfer->request;
+
+	/*
+	 * First, see whether user provided its own callback.
+	 */
+	int rc = EFORWARD;
+	if (device->ops) {
+		rc = find_and_run_handler(device,
+		    device->ops->control_transfer_handlers,
+		    request, transfer->data);
+	}
+
+	/*
+	 * If there was no user callback or the callback returned EFORWARD,
+	 * we need to run a local handler.
+	 */
+	if (rc == EFORWARD) {
+		rc = find_and_run_handler(device,
+		    control_pipe_zero_local_handlers,
+		    request, transfer->data);
+	}
+	
+	/*
+	 * Check for SET_ADDRESS finalization.
+	 */
+	if (device->new_address != -1) {
+		/*
+		 * TODO: handle when this request is invalid (e.g.
+		 * setting address when in configured state).
+		 */
+		usbvirt_device_state_t new_state;
+		if (device->new_address == 0) {
+			new_state = USBVIRT_STATE_DEFAULT;
+		} else {
+			new_state = USBVIRT_STATE_ADDRESS;
+		}
+		device->address = device->new_address;
+		
+		device->new_address = -1;
+		
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    new_state);
+		}
+		device->state = new_state;
+
+		device->lib_debug(device, 2, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
+		    "device address changed to %d (state %s)",
+		    device->address, str_device_state(device->state));
+	}
+	
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/debug.c
===================================================================
--- uspace/lib/usbvirt/src/debug.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/debug.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Debugging support.
+ */
+#include <stdio.h>
+#include <bool.h>
+
+#include "private.h"
+
+
+static void debug_print(int level, uint8_t tag,
+    int current_level, uint8_t enabled_tags,
+    const char *format, va_list args)
+{
+	if (level > current_level) {
+		return;
+	}
+	
+	if ((tag & enabled_tags) == 0) {
+		return;
+	}
+	
+	bool print_prefix = true;
+	
+	if ((format[0] == '%') && (format[1] == 'M')) {
+		format += 2;
+		print_prefix = false;
+	}
+	
+	if (print_prefix) {
+		printf("[vusb]: ");
+		while (--level > 0) {
+			printf(" ");
+		}
+	}
+	
+	vprintf(format, args);
+	
+	if (print_prefix) {
+		printf("\n");
+	}
+}
+
+
+void user_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	
+	debug_print(level, tag,
+	    device->debug_level, device->debug_enabled_tags,
+	    format, args);
+	
+	va_end(args);
+}
+
+void lib_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	
+	debug_print(level, tag,
+	    device->lib_debug_level, device->lib_debug_enabled_tags,
+	    format, args);
+	
+	va_end(args);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/main.c
===================================================================
--- uspace/lib/usbvirt/src/main.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/main.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Device registration with virtual USB framework.
+ */
+#include <devman.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <assert.h>
+
+#include "private.h"
+
+#define NAMESPACE "usb"
+
+/** Virtual device wrapper. */
+typedef struct {
+	/** Actual device. */
+	usbvirt_device_t *device;
+	/** Phone to host controller. */
+	int vhcd_phone;
+	/** Device id. */
+	sysarg_t id;
+	/** Linked-list member. */
+	link_t link;
+} virtual_device_t;
+
+/*** List of known device. */
+static LIST_INITIALIZE(device_list);
+
+/** Find virtual device wrapper based on the contents. */
+static virtual_device_t *find_device(usbvirt_device_t *device)
+{
+	if (list_empty(&device_list)) {
+		return NULL;
+	}
+	
+	link_t *pos;
+	for (pos = device_list.next; pos != &device_list; pos = pos->next) {
+		virtual_device_t *dev
+		    = list_get_instance(pos, virtual_device_t, link);
+		if (dev->device == device) {
+			return dev;
+		}
+	}
+	
+	return NULL;
+}
+
+/** Find virtual device wrapper by its id. */
+static virtual_device_t *find_device_by_id(sysarg_t id)
+{
+	if (list_empty(&device_list)) {
+		return NULL;
+	}
+	
+	link_t *pos;
+	for (pos = device_list.next; pos != &device_list; pos = pos->next) {
+		virtual_device_t *dev
+		    = list_get_instance(pos, virtual_device_t, link);
+		if (dev->id == id) {
+			return dev;
+		}
+	}
+	
+	return NULL;
+}
+
+/** Reply to a control transfer. */
+static int control_transfer_reply(usbvirt_device_t *device,
+	    usb_endpoint_t endpoint, void *buffer, size_t size)
+{
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->data != NULL) {
+		free(transfer->data);
+	}
+	transfer->data = malloc(size);
+	memcpy(transfer->data, buffer, size);
+	transfer->data_size = size;
+	
+	return EOK;
+}
+
+/** Initialize virtual device. */
+static void device_init(usbvirt_device_t *dev)
+{
+	dev->transaction_out = transaction_out;
+	dev->transaction_setup = transaction_setup;
+	dev->transaction_in = transaction_in;
+	
+	dev->control_transfer_reply = control_transfer_reply;
+	
+	dev->debug = user_debug;
+	dev->lib_debug = lib_debug;
+	
+	dev->state = USBVIRT_STATE_DEFAULT;
+	dev->address = 0;
+	dev->new_address = -1;
+	
+	size_t i;
+	for (i = 0; i < USB11_ENDPOINT_MAX; i++) {
+		usbvirt_control_transfer_t *transfer = &dev->current_control_transfers[i];
+		transfer->direction = 0;
+		transfer->request = NULL;
+		transfer->request_size = 0;
+		transfer->data = NULL;
+		transfer->data_size = 0;
+	}
+}
+
+/** Add a virtual device.
+ * The returned device (if not NULL) shall be destroy via destroy_device().
+ */
+static virtual_device_t *add_device(usbvirt_device_t *dev)
+{
+	assert(find_device(dev) == NULL);
+	virtual_device_t *new_device
+	    = (virtual_device_t *) malloc(sizeof(virtual_device_t));
+	
+	new_device->device = dev;
+	link_initialize(&new_device->link);
+	
+	list_append(&new_device->link, &device_list);
+	
+	return new_device;
+}
+
+/** Destroy virtual device. */
+static void destroy_device(virtual_device_t *dev)
+{
+	if (dev->vhcd_phone > 0) {
+		ipc_hangup(dev->vhcd_phone);
+	}
+	
+	list_remove(&dev->link);
+	
+	free(dev);
+}
+
+/** Callback connection handler. */
+static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	// FIXME - determine which device just called back
+	virtual_device_t *dev = find_device_by_id(0);
+	if (dev == NULL) {
+		ipc_answer_0(iid, EINVAL);
+		printf("Ooops\n");
+		return;
+	}
+
+	device_callback_connection(dev->device, iid, icall);
+}
+
+/** Create necessary phones for communication with virtual HCD.
+ * This function wraps following calls:
+ * -# open <code>/dev/devices/\\virt\\usbhc for reading
+ * -# access phone of file opened in previous step
+ * -# create callback through just opened phone
+ * -# create handler for calling on data from host to function
+ * -# return the (outgoing) phone
+ *
+ * @warning This function is wrapper for several actions and therefore
+ * it is not possible - in case of error - to determine at which point
+ * error occurred.
+ *
+ * @param dev Device to connect.
+ * @return EOK on success or error code from errno.h.
+ */
+int usbvirt_connect(usbvirt_device_t *dev)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device != NULL) {
+		return EEXISTS;
+	}
+	
+	const char *vhc_path = "/virt/usbhc";
+	int rc;
+	devman_handle_t handle;
+
+	rc = devman_device_get_handle(vhc_path, &handle, 0);
+	if (rc != EOK) {
+		printf("devman_device_get_handle() failed\n");
+		return rc;
+	}
+	
+	int hcd_phone = devman_device_connect(handle, 0);
+	
+	if (hcd_phone < 0) {
+		printf("devman_device_connect() failed\n");
+		return hcd_phone;
+	}
+	
+	sysarg_t phonehash;
+	rc = ipc_connect_to_me(hcd_phone, 0, 0, 0, &phonehash);
+	if (rc != EOK) {
+		printf("ipc_connect_to_me() failed\n");
+		return rc;
+	}
+	
+	device_init(dev);
+	
+	virtual_device = add_device(dev);
+	virtual_device->vhcd_phone = hcd_phone;
+	virtual_device->id = 0;
+	
+	async_new_connection(phonehash, 0, NULL, callback_connection);
+	
+	return EOK;
+}
+
+/** Prepares device as local.
+ * This is useful if you want to have a virtual device in the same task
+ * as HCD.
+ *
+ * @param dev Device to connect.
+ * @return Error code.
+ * @retval EOK Device connected.
+ * @retval EEXISTS This device is already connected.
+ */
+int usbvirt_connect_local(usbvirt_device_t *dev)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device != NULL) {
+		return EEXISTS;
+	}
+	
+	device_init(dev);
+	
+	virtual_device = add_device(dev);
+	virtual_device->vhcd_phone = -1;
+	virtual_device->id = 0;
+	
+	return EOK;
+}
+
+/** Disconnects device from HCD.
+ *
+ * @param dev Device to be disconnected.
+ * @return Error code.
+ * @retval EOK Device connected.
+ * @retval ENOENT This device is not connected.
+ */
+int usbvirt_disconnect(usbvirt_device_t *dev)
+{
+	virtual_device_t *virtual_device = find_device(dev);
+	if (virtual_device == NULL) {
+		return ENOENT;
+	}
+	
+	destroy_device(virtual_device);
+	
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/private.h	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Virtual USB private header.
+ */
+#ifndef LIBUSBVIRT_PRIVATE_H_
+#define LIBUSBVIRT_PRIVATE_H_
+
+#include <usbvirt/device.h>
+#include <usbvirt/hub.h>
+#include <assert.h>
+
+
+#define DEVICE_HAS_OP(dev, op) \
+	( \
+		(  ((dev)->ops) != NULL  ) \
+		&& \
+		(  ((dev)->ops->op) != NULL  ) \
+	)
+
+int usbvirt_data_to_host(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+int handle_incoming_data(struct usbvirt_device *dev,
+    usb_endpoint_t endpoint, void *buffer, size_t size);
+
+int control_pipe(usbvirt_device_t *device, usbvirt_control_transfer_t *transfer);
+
+int handle_std_request(usbvirt_device_t *device, usb_device_request_setup_packet_t *request, uint8_t *data);
+
+void device_callback_connection(usbvirt_device_t *device, ipc_callid_t iid, ipc_call_t *icall);
+
+int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size);
+int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size);
+int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *data_size);
+
+
+void user_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...);
+void lib_debug(usbvirt_device_t *device, int level, uint8_t tag,
+    const char *format, ...);
+    
+static inline const char *str_device_state(usbvirt_device_state_t state)
+{
+	switch (state) {
+		case USBVIRT_STATE_DEFAULT:
+			return "default";
+		case USBVIRT_STATE_ADDRESS:
+			return "address";
+		case USBVIRT_STATE_CONFIGURED:
+			return "configured";
+		default:
+			return "unknown";
+	}
+}
+
+extern usbvirt_control_transfer_handler_t control_pipe_zero_local_handlers[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Preprocessing of standard device requests.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <usb/devreq.h>
+
+#include "private.h"
+
+/*
+ * All sub handlers must return EFORWARD to inform the caller that
+ * they were not able to process the request (yes, it is abuse of
+ * this error code but such error code shall not collide with anything
+ * else in this context).
+ */
+ 
+/** GET_DESCRIPTOR handler. */
+static int handle_get_descriptor(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
+{
+	uint8_t type = setup_packet->value_high;
+	uint8_t index = setup_packet->value_low;
+
+	/* 
+	 * Standard device descriptor.
+	 */
+	if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
+		if (device->descriptors && device->descriptors->device) {
+			return device->control_transfer_reply(device, 0,
+			    device->descriptors->device,
+			    device->descriptors->device->length);
+		} else {
+			return EFORWARD;
+		}
+	}
+	
+	/*
+	 * Configuration descriptor together with interface, endpoint and
+	 * class-specific descriptors.
+	 */
+	if (type == USB_DESCTYPE_CONFIGURATION) {
+		if (!device->descriptors) {
+			return EFORWARD;
+		}
+		if (index >= device->descriptors->configuration_count) {
+			return EFORWARD;
+		}
+		/* Copy the data. */
+		usbvirt_device_configuration_t *config = &device->descriptors
+		    ->configuration[index];
+		uint8_t *all_data = malloc(config->descriptor->total_length);
+		if (all_data == NULL) {
+			return ENOMEM;
+		}
+		
+		uint8_t *ptr = all_data;
+		memcpy(ptr, config->descriptor, config->descriptor->length);
+		ptr += config->descriptor->length;
+		size_t i;
+		for (i = 0; i < config->extra_count; i++) {
+			usbvirt_device_configuration_extras_t *extra
+			    = &config->extra[i];
+			memcpy(ptr, extra->data, extra->length);
+			ptr += extra->length;
+		}
+		
+		int rc = device->control_transfer_reply(device, 0,
+		    all_data, config->descriptor->total_length);
+		
+		free(all_data);
+		
+		return rc;
+	}
+	
+	return EFORWARD;
+}
+
+/** SET_ADDRESS handler. */
+static int handle_set_address(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
+{
+	uint16_t new_address = setup_packet->value;
+	uint16_t zero1 = setup_packet->index;
+	uint16_t zero2 = setup_packet->length;
+
+	if ((zero1 != 0) || (zero2 != 0)) {
+		return EINVAL;
+	}
+	
+	if (new_address > 127) {
+		return EINVAL;
+	}
+	
+	device->new_address = new_address;
+	
+	return EOK;
+}
+
+/** SET_CONFIGURATION handler. */
+static int handle_set_configuration(usbvirt_device_t *device,
+    usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
+{
+	uint16_t configuration_value = setup_packet->value;
+	uint16_t zero1 = setup_packet->index;
+	uint16_t zero2 = setup_packet->length;
+
+	if ((zero1 != 0) || (zero2 != 0)) {
+		return EINVAL;
+	}
+	
+	/*
+	 * Configuration value is 1 byte information.
+	 */
+	if (configuration_value > 255) {
+		return EINVAL;
+	}
+	
+	/*
+	 * Do nothing when in default state. According to specification,
+	 * this is not specified.
+	 */
+	if (device->state == USBVIRT_STATE_DEFAULT) {
+		return EOK;
+	}
+	
+	if (configuration_value == 0) {
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    USBVIRT_STATE_ADDRESS);
+		}
+		device->state = USBVIRT_STATE_ADDRESS;
+	} else {
+		/*
+		* TODO: browse provided configurations and verify that
+		* user selected existing configuration.
+		*/
+		if (DEVICE_HAS_OP(device, on_state_change)) {
+			device->ops->on_state_change(device, device->state,
+			    USBVIRT_STATE_CONFIGURED);
+		}
+		device->state = USBVIRT_STATE_CONFIGURED;
+		if (device->descriptors) {
+			device->descriptors->current_configuration
+			    = configuration_value;
+		}
+	}
+		
+	return EOK;
+}
+
+
+#define MAKE_BM_REQUEST(direction, recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
+	    USBVIRT_REQUEST_TYPE_STANDARD, recipient)
+#define MAKE_BM_REQUEST_DEV(direction) \
+	MAKE_BM_REQUEST(direction, USBVIRT_REQUEST_RECIPIENT_DEVICE)
+
+usbvirt_control_transfer_handler_t control_pipe_zero_local_handlers[] = {
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_IN),
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "GetDescriptor()",
+		.callback = handle_get_descriptor
+	},
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_OUT),
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.name = "SetAddress()",
+		.callback = handle_set_address
+	},
+	{
+		.request_type = MAKE_BM_REQUEST_DEV(USB_DIRECTION_OUT),
+		.request = USB_DEVREQ_SET_CONFIGURATION,
+		.name = "SetConfiguration()",
+		.callback = handle_set_configuration
+	},
+	USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
+};
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/transaction.c
===================================================================
--- uspace/lib/usbvirt/src/transaction.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
+++ uspace/lib/usbvirt/src/transaction.c	(revision 11658b6402ef30f4b33c870d53939c869485ae26)
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusbvirt usb
+ * @{
+ */
+/** @file
+ * @brief Transaction processing.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+
+#include "private.h"
+
+static usb_direction_t setup_transaction_direction(usbvirt_device_t *,
+    usb_endpoint_t, void *, size_t);
+static void process_control_transfer(usbvirt_device_t *,
+    usb_endpoint_t, usbvirt_control_transfer_t *);
+
+/** Convert virtual USB transaction type to string.
+ */
+const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type)
+{
+	switch (type) {
+		case USBVIRT_TRANSACTION_SETUP:
+			return "setup";
+		case USBVIRT_TRANSACTION_IN:
+			return "in";
+		case USBVIRT_TRANSACTION_OUT:
+			return "out";
+		default:
+			return "unknown";
+	}
+}
+
+/** SETUP transaction handling.
+ * The setup transaction only prepares control transfer on given endpoint.
+ */
+int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size)
+{
+	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+	    "setup transaction: endpoint=%d, size=%u", endpoint, size);
+	
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	
+	if (transfer->request != NULL) {
+		free(transfer->request);
+	}
+	if (transfer->data != NULL) {
+		free(transfer->data);
+	}
+	
+	transfer->direction = setup_transaction_direction(device, endpoint,
+	    buffer, size);
+	transfer->request = malloc(size);
+	memcpy(transfer->request, buffer, size);
+	transfer->request_size = size;
+	transfer->data = NULL;
+	transfer->data_size = 0;
+	
+	if (transfer->direction == USB_DIRECTION_IN) {
+		process_control_transfer(device, endpoint, transfer);
+	}
+	
+	return EOK;
+}
+
+/** OUT transaction handling.
+ * The OUT transaction can trigger processing of a control transfer.
+ */
+int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size)
+{
+	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+	    "out transaction: endpoint=%d, size=%u", endpoint, size);
+	
+	/*
+	 * First check whether it is a transaction over control pipe.
+	 */
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->request != NULL) {
+		if (transfer->direction == USB_DIRECTION_OUT) {
+			/*
+			 * For out transactions, append the data to the buffer.
+			 */
+			uint8_t *new_buffer = (uint8_t *) malloc(transfer->data_size + size);
+			if (transfer->data) {
+				memcpy(new_buffer, transfer->data, transfer->data_size);
+			}
+			memcpy(new_buffer + transfer->data_size, buffer, size);
+			
+			if (transfer->data) {
+				free(transfer->data);
+			}
+			transfer->data = new_buffer;
+			transfer->data_size += size;
+		} else {
+			/*
+			 * For in transactions, this means end of the
+			 * transaction.
+			 */
+			free(transfer->request);
+			if (transfer->data) {
+				free(transfer->data);
+			}
+			transfer->request = NULL;
+			transfer->request_size = 0;
+			transfer->data = NULL;
+			transfer->data_size = 0;
+		}
+		
+		return EOK;
+	}
+	
+	/*
+	 * Otherwise, announce that some data has come.
+	 */
+	if (device->ops && device->ops->on_data) {
+		return device->ops->on_data(device, endpoint, buffer, size);
+	} else {
+		return ENOTSUP;
+	}
+}
+
+/** IN transaction handling.
+ * The IN transaction can trigger processing of a control transfer.
+ */
+int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
+    void *buffer, size_t size, size_t *data_size)
+{
+	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+	    "in transaction: endpoint=%d, size=%u", endpoint, size);
+	
+	/*
+	 * First check whether it is a transaction over control pipe.
+	 */
+	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
+	if (transfer->request != NULL) {
+		if (transfer->direction == USB_DIRECTION_OUT) {
+			/*
+			 * This means end of input data.
+			 */
+			process_control_transfer(device, endpoint, transfer);
+		} else {
+			/*
+			 * For in transactions, this means sending next part
+			 * of the buffer.
+			 */
+			// FIXME: handle when the HC wants the data back
+			// in more chunks
+			size_t actual_size = 0;
+			if (transfer->data) {
+				actual_size = transfer->data_size;
+			}
+			if (actual_size > size) {
+				actual_size = size;
+			}
+			device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+			    "in transaction: will copy %zu bytes", actual_size);
+			if (actual_size > 0) {
+				memcpy(buffer, transfer->data, actual_size);
+				if (data_size) {
+					*data_size = actual_size;
+				}
+			}
+		}
+		
+		return EOK;
+	}
+	
+	if (size == 0) {
+		return EINVAL;
+	}
+	
+	int rc = 1;
+	
+	if (device->ops && device->ops->on_data_request) {
+		rc = device->ops->on_data_request(device, endpoint, buffer, size, data_size);
+	}
+	
+	return rc;
+}
+
+/** Determine direction of control transfer.
+ * First, try the user provided callback, otherwise guess, believing that
+ * it uses the same format as control pipe 0.
+ */
+static usb_direction_t setup_transaction_direction(usbvirt_device_t *device,
+    usb_endpoint_t endpoint,
+    void *data, size_t size)
+{
+	int direction = -1;
+	if (device->ops && device->ops->decide_control_transfer_direction) {
+		direction = device->ops->decide_control_transfer_direction(endpoint,
+		    data, size);
+	}
+	
+	/*
+	 * If the user-supplied routine have not handled the direction
+	 * (or simply was not provided) we will guess, hoping that it 
+	 * uses same format as standard request on control pipe zero.
+	 */
+	if (direction < 0) {
+		if (size > 0) {
+			uint8_t *ptr = (uint8_t *) data;
+			if ((ptr[0] & 128) == 128) {
+				direction = USB_DIRECTION_IN;
+			} else {
+				direction = USB_DIRECTION_OUT;
+			}
+		} else {
+			/* This shall not happen anyway. */
+			direction = USB_DIRECTION_OUT;
+		}
+	}
+	
+	return (usb_direction_t) direction;
+}
+
+/** Process control transfer.
+ */
+static void process_control_transfer(usbvirt_device_t *device,
+    usb_endpoint_t endpoint,
+    usbvirt_control_transfer_t *transfer)
+{
+	int rc = EFORWARD;
+	
+	if (device->ops && device->ops->on_control_transfer) {
+		rc = device->ops->on_control_transfer(device, endpoint, transfer);
+	}
+	
+	if (rc == EFORWARD) {
+		if (endpoint == 0) {
+			rc = control_pipe(device, transfer);
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: pace/lib/usbvirt/stdreq.c
===================================================================
--- uspace/lib/usbvirt/stdreq.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,212 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Preprocessing of standard device requests.
- */
-#include <errno.h>
-#include <stdlib.h>
-#include <mem.h>
-#include <usb/devreq.h>
-
-#include "private.h"
-
-
-
-/*
- * All sub handlers must return EFORWARD to inform the caller that
- * they were not able to process the request (yes, it is abuse of
- * this error code but such error code shall not collide with anything
- * else in this context).
- */
- 
-/** GET_DESCRIPTOR handler. */
-static int handle_get_descriptor(usbvirt_device_t *device,
-    uint8_t type, uint8_t index, uint16_t language,
-    uint16_t length)
-{
-	/* 
-	 * Standard device descriptor.
-	 */
-	if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
-		if (device->descriptors && device->descriptors->device) {
-			return device->control_transfer_reply(device, 0,
-			    device->descriptors->device,
-			    device->descriptors->device->length);
-		} else {
-			return EFORWARD;
-		}
-	}
-	
-	/*
-	 * Configuration descriptor together with interface, endpoint and
-	 * class-specific descriptors.
-	 */
-	if (type == USB_DESCTYPE_CONFIGURATION) {
-		if (!device->descriptors) {
-			return EFORWARD;
-		}
-		if (index >= device->descriptors->configuration_count) {
-			return EFORWARD;
-		}
-		/* Copy the data. */
-		usbvirt_device_configuration_t *config = &device->descriptors
-		    ->configuration[index];
-		uint8_t *all_data = malloc(config->descriptor->total_length);
-		if (all_data == NULL) {
-			return ENOMEM;
-		}
-		
-		uint8_t *ptr = all_data;
-		memcpy(ptr, config->descriptor, config->descriptor->length);
-		ptr += config->descriptor->length;
-		size_t i;
-		for (i = 0; i < config->extra_count; i++) {
-			usbvirt_device_configuration_extras_t *extra
-			    = &config->extra[i];
-			memcpy(ptr, extra->data, extra->length);
-			ptr += extra->length;
-		}
-		
-		int rc = device->control_transfer_reply(device, 0,
-		    all_data, config->descriptor->total_length);
-		
-		free(all_data);
-		
-		return rc;
-	}
-	
-	return EFORWARD;
-}
-
-/** SET_ADDRESS handler. */
-static int handle_set_address(usbvirt_device_t *device,
-    uint16_t new_address,
-    uint16_t zero1, uint16_t zero2)
-{
-	if ((zero1 != 0) || (zero2 != 0)) {
-		return EINVAL;
-	}
-	
-	if (new_address > 127) {
-		return EINVAL;
-	}
-	
-	device->new_address = new_address;
-	
-	return EOK;
-}
-
-/** SET_CONFIGURATION handler. */
-static int handle_set_configuration(usbvirt_device_t *device,
-    uint16_t configuration_value,
-    uint16_t zero1, uint16_t zero2)
-{
-	if ((zero1 != 0) || (zero2 != 0)) {
-		return EINVAL;
-	}
-	
-	/*
-	 * Configuration value is 1 byte information.
-	 */
-	if (configuration_value > 255) {
-		return EINVAL;
-	}
-	
-	/*
-	 * Do nothing when in default state. According to specification,
-	 * this is not specified.
-	 */
-	if (device->state == USBVIRT_STATE_DEFAULT) {
-		return EOK;
-	}
-	
-	if (configuration_value == 0) {
-		device->state = USBVIRT_STATE_ADDRESS;
-	} else {
-		/*
-		* TODO: browse provided configurations and verify that
-		* user selected existing configuration.
-		*/
-		device->state = USBVIRT_STATE_CONFIGURED;
-		if (device->descriptors) {
-			device->descriptors->current_configuration
-			    = configuration_value;
-		}
-	}
-		
-	return EOK;
-}
-
-#define HANDLE_REQUEST(request, data, type, dev, user_callback, default_handler) \
-	do { \
-		if ((request)->request == (type)) { \
-			int _rc = EFORWARD; \
-			if (((dev)->ops) && ((dev)->ops->standard_request_ops) \
-			    && ((dev)->ops->standard_request_ops->user_callback)) { \
-				_rc = (dev)->ops->standard_request_ops->\
-				    user_callback(dev, request, data); \
-			} \
-			if (_rc == EFORWARD) { \
-				default_handler; \
-			} \
-			return _rc; \
-		} \
-	} while (false)
-
-/** Handle standard device request. */
-int handle_std_request(usbvirt_device_t *device,
-    usb_device_request_setup_packet_t *request, uint8_t *data)
-{
-	device->lib_debug(device, 3, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
-	    "handling standard request %d", request->request);
-	
-	HANDLE_REQUEST(request, data, USB_DEVREQ_GET_DESCRIPTOR,
-	    device, on_get_descriptor,
-	    handle_get_descriptor(device, request->value_high, request->value_low,
-	        request->index, request->length));
-	
-	HANDLE_REQUEST(request, data, USB_DEVREQ_SET_ADDRESS,
-	    device, on_set_address,
-	    handle_set_address(device, request->value,
-	        request->index, request->length));
-	
-	HANDLE_REQUEST(request, data, USB_DEVREQ_SET_CONFIGURATION,
-	    device, on_set_configuration,
-	    handle_set_configuration(device, request->value,
-	        request->index, request->length));
-	
-	return ENOTSUP;
-}
-
-/**
- * @}
- */
Index: pace/lib/usbvirt/transaction.c
===================================================================
--- uspace/lib/usbvirt/transaction.c	(revision a9b6bec345bf507ad3bd659aecd9e5f287828514)
+++ 	(revision )
@@ -1,269 +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 libusbvirt usb
- * @{
- */
-/** @file
- * @brief Transaction processing.
- */
-#include <errno.h>
-#include <stdlib.h>
-#include <mem.h>
-
-#include "hub.h"
-#include "private.h"
-
-static usb_direction_t setup_transaction_direction(usbvirt_device_t *,
-    usb_endpoint_t, void *, size_t);
-static void process_control_transfer(usbvirt_device_t *,
-    usb_endpoint_t, usbvirt_control_transfer_t *);
-
-/** Convert virtual USB transaction type to string.
- */
-const char *usbvirt_str_transaction_type(usbvirt_transaction_type_t type)
-{
-	switch (type) {
-		case USBVIRT_TRANSACTION_SETUP:
-			return "setup";
-		case USBVIRT_TRANSACTION_IN:
-			return "in";
-		case USBVIRT_TRANSACTION_OUT:
-			return "out";
-		default:
-			return "unknown";
-	}
-}
-
-/** SETUP transaction handling.
- * The setup transaction only prepares control transfer on given endpoint.
- */
-int transaction_setup(usbvirt_device_t *device, usb_endpoint_t endpoint,
-    void *buffer, size_t size)
-{
-	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
-	    "setup transaction: endpoint=%d, size=%u", endpoint, size);
-	
-	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
-	
-	if (transfer->request != NULL) {
-		free(transfer->request);
-	}
-	if (transfer->data != NULL) {
-		free(transfer->data);
-	}
-	
-	transfer->direction = setup_transaction_direction(device, endpoint,
-	    buffer, size);
-	transfer->request = malloc(size);
-	memcpy(transfer->request, buffer, size);
-	transfer->request_size = size;
-	transfer->data = NULL;
-	transfer->data_size = 0;
-	
-	if (transfer->direction == USB_DIRECTION_IN) {
-		process_control_transfer(device, endpoint, transfer);
-	}
-	
-	return EOK;
-}
-
-/** OUT transaction handling.
- * The OUT transaction can trigger processing of a control transfer.
- */
-int transaction_out(usbvirt_device_t *device, usb_endpoint_t endpoint,
-    void *buffer, size_t size)
-{
-	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
-	    "out transaction: endpoint=%d, size=%u", endpoint, size);
-	
-	/*
-	 * First check whether it is a transaction over control pipe.
-	 */
-	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
-	if (transfer->request != NULL) {
-		if (transfer->direction == USB_DIRECTION_OUT) {
-			/*
-			 * For out transactions, append the data to the buffer.
-			 */
-			uint8_t *new_buffer = (uint8_t *) malloc(transfer->data_size + size);
-			if (transfer->data) {
-				memcpy(new_buffer, transfer->data, transfer->data_size);
-			}
-			memcpy(new_buffer + transfer->data_size, buffer, size);
-			
-			if (transfer->data) {
-				free(transfer->data);
-			}
-			transfer->data = new_buffer;
-			transfer->data_size += size;
-		} else {
-			/*
-			 * For in transactions, this means end of the
-			 * transaction.
-			 */
-			free(transfer->request);
-			if (transfer->data) {
-				free(transfer->data);
-			}
-			transfer->request = NULL;
-			transfer->request_size = 0;
-			transfer->data = NULL;
-			transfer->data_size = 0;
-		}
-		
-		return EOK;
-	}
-	
-	/*
-	 * Otherwise, announce that some data has come.
-	 */
-	if (device->ops && device->ops->on_data) {
-		return device->ops->on_data(device, endpoint, buffer, size);
-	} else {
-		return ENOTSUP;
-	}
-}
-
-/** IN transaction handling.
- * The IN transaction can trigger processing of a control transfer.
- */
-int transaction_in(usbvirt_device_t *device, usb_endpoint_t endpoint,
-    void *buffer, size_t size, size_t *data_size)
-{
-	device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
-	    "in transaction: endpoint=%d, size=%u", endpoint, size);
-	
-	/*
-	 * First check whether it is a transaction over control pipe.
-	 */
-	usbvirt_control_transfer_t *transfer = &device->current_control_transfers[endpoint];
-	if (transfer->request != NULL) {
-		if (transfer->direction == USB_DIRECTION_OUT) {
-			/*
-			 * This means end of input data.
-			 */
-			process_control_transfer(device, endpoint, transfer);
-		} else {
-			/*
-			 * For in transactions, this means sending next part
-			 * of the buffer.
-			 */
-			// FIXME: handle when the HC wants the data back
-			// in more chunks
-			size_t actual_size = 0;
-			if (transfer->data) {
-				actual_size = transfer->data_size;
-			}
-			if (actual_size > size) {
-				actual_size = size;
-			}
-			device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
-			    "in transaction: will copy %zu bytes", actual_size);
-			if (actual_size > 0) {
-				memcpy(buffer, transfer->data, actual_size);
-				if (data_size) {
-					*data_size = actual_size;
-				}
-			}
-		}
-		
-		return EOK;
-	}
-	
-	if (size == 0) {
-		return EINVAL;
-	}
-	
-	int rc = 1;
-	
-	if (device->ops && device->ops->on_data_request) {
-		rc = device->ops->on_data_request(device, endpoint, buffer, size, data_size);
-	}
-	
-	return rc;
-}
-
-/** Determine direction of control transfer.
- * First, try the user provided callback, otherwise guess, believing that
- * it uses the same format as control pipe 0.
- */
-static usb_direction_t setup_transaction_direction(usbvirt_device_t *device,
-    usb_endpoint_t endpoint,
-    void *data, size_t size)
-{
-	int direction = -1;
-	if (device->ops && device->ops->decide_control_transfer_direction) {
-		direction = device->ops->decide_control_transfer_direction(endpoint,
-		    data, size);
-	}
-	
-	/*
-	 * If the user-supplied routine have not handled the direction
-	 * (or simply was not provided) we will guess, hoping that it 
-	 * uses same format as standard request on control pipe zero.
-	 */
-	if (direction < 0) {
-		if (size > 0) {
-			uint8_t *ptr = (uint8_t *) data;
-			if ((ptr[0] & 128) == 128) {
-				direction = USB_DIRECTION_IN;
-			} else {
-				direction = USB_DIRECTION_OUT;
-			}
-		} else {
-			/* This shall not happen anyway. */
-			direction = USB_DIRECTION_OUT;
-		}
-	}
-	
-	return (usb_direction_t) direction;
-}
-
-/** Process control transfer.
- */
-static void process_control_transfer(usbvirt_device_t *device,
-    usb_endpoint_t endpoint,
-    usbvirt_control_transfer_t *transfer)
-{
-	int rc = EFORWARD;
-	
-	if (device->ops && device->ops->on_control_transfer) {
-		rc = device->ops->on_control_transfer(device, endpoint, transfer);
-	}
-	
-	if (rc == EFORWARD) {
-		if (endpoint == 0) {
-			rc = control_pipe(device, transfer);
-		}
-	}
-}
-
-/**
- * @}
- */
