Index: uspace/drv/isa/isa.c
===================================================================
--- uspace/drv/isa/isa.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/isa/isa.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -282,5 +282,6 @@
 
 		printf(NAME ": added io range (addr=0x%x, size=0x%x) to "
-		    "device %s\n", addr, len, dev->name);
+		    "device %s\n", (unsigned int) addr, (unsigned int) len,
+		    dev->name);
 	}
 }
@@ -489,5 +490,6 @@
 static int isa_add_device(device_t *dev)
 {
-	printf(NAME ": isa_add_device, device handle = %d\n", dev->handle);
+	printf(NAME ": isa_add_device, device handle = %d\n",
+	    (int) dev->handle);
 
 	/* Add child devices. */
Index: uspace/drv/ns8250/ns8250.c
===================================================================
--- uspace/drv/ns8250/ns8250.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/ns8250/ns8250.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -274,5 +274,5 @@
 	
 	/* Gain control over port's registers. */
-	if (pio_enable((void *) data->io_addr, REG_COUNT,
+	if (pio_enable((void *)(uintptr_t) data->io_addr, REG_COUNT,
 	    (void **) &data->port)) {
 		printf(NAME ": error - cannot gain the port %#" PRIx32 " for device "
@@ -727,5 +727,5 @@
 {
 	printf(NAME ": ns8250_add_device %s (handle = %d)\n",
-	    dev->name, dev->handle);
+	    dev->name, (int) dev->handle);
 	
 	int res = ns8250_dev_initialize(dev);
Index: uspace/drv/pciintel/pci.c
===================================================================
--- uspace/drv/pciintel/pci.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/pciintel/pci.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -324,5 +324,5 @@
 		printf(NAME ": device %s : ", dev->name);
 		printf("address = %" PRIx64, range_addr);
-		printf(", size = %x\n", range_size);
+		printf(", size = %x\n", (unsigned int) range_size);
 	}
 	
@@ -489,5 +489,5 @@
 	    (uint32_t) hw_resources.resources[0].res.io_range.address;
 	
-	if (pio_enable((void *)bus_data->conf_io_addr, 8,
+	if (pio_enable((void *)(uintptr_t)bus_data->conf_io_addr, 8,
 	    &bus_data->conf_addr_port)) {
 		printf(NAME ": failed to enable configuration ports.\n");
Index: uspace/drv/root/root.c
===================================================================
--- uspace/drv/root/root.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/root/root.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2010 Vojtech Horky
  * All rights reserved.
  *
@@ -53,4 +54,12 @@
 #define NAME "root"
 
+#define PLATFORM_DEVICE_NAME "hw"
+#define PLATFORM_DEVICE_MATCH_ID STRING(UARCH)
+#define PLATFORM_DEVICE_MATCH_SCORE 100
+
+#define VIRTUAL_DEVICE_NAME "virt"
+#define VIRTUAL_DEVICE_MATCH_ID "rootvirt"
+#define VIRTUAL_DEVICE_MATCH_SCORE 100
+
 static int root_add_device(device_t *dev);
 
@@ -66,4 +75,22 @@
 };
 
+/** Create the device which represents the root of virtual device tree.
+ *
+ * @param parent Parent of the newly created device.
+ * @return Error code.
+ */
+static int add_virtual_root_child(device_t *parent)
+{
+	printf(NAME ": adding new child for virtual devices.\n");
+	printf(NAME ":   device node is `%s' (%d %s)\n", VIRTUAL_DEVICE_NAME,
+	    VIRTUAL_DEVICE_MATCH_SCORE, VIRTUAL_DEVICE_MATCH_ID);
+
+	int res = child_device_register_wrapper(parent, VIRTUAL_DEVICE_NAME,
+	    VIRTUAL_DEVICE_MATCH_ID, VIRTUAL_DEVICE_MATCH_SCORE,
+	    NULL);
+
+	return res;
+}
+
 /** Create the device which represents the root of HW device tree.
  *
@@ -74,102 +101,12 @@
 {
 	printf(NAME ": adding new child for platform device.\n");
+	printf(NAME ":   device node is `%s' (%d %s)\n", PLATFORM_DEVICE_NAME,
+	    PLATFORM_DEVICE_MATCH_SCORE, PLATFORM_DEVICE_MATCH_ID);
 	
-	int res = EOK;
-	device_t *platform = NULL;
-	match_id_t *match_id = NULL;
-	
-	/* Create new device. */
-	platform = create_device();
-	if (NULL == platform) {
-		res = ENOMEM;
-		goto failure;
-	}	
-	
-	platform->name = "hw";
-	printf(NAME ": the new device's name is %s.\n", platform->name);
-	
-	/* Initialize match id list. */
-	match_id = create_match_id();
-	if (NULL == match_id) {
-		res = ENOMEM;
-		goto failure;
-	}
-	
-	/* TODO - replace this with some better solution (sysinfo ?) */
-	match_id->id = STRING(UARCH);
-	match_id->score = 100;
-	add_match_id(&platform->match_ids, match_id);
-	
-	/* Register child device. */
-	res = child_device_register(platform, parent);
-	if (EOK != res)
-		goto failure;
-	
+	int res = child_device_register_wrapper(parent, PLATFORM_DEVICE_NAME,
+	    PLATFORM_DEVICE_MATCH_ID, PLATFORM_DEVICE_MATCH_SCORE,
+	    NULL);
+
 	return res;
-	
-failure:
-	if (NULL != match_id)
-		match_id->id = NULL;
-	
-	if (NULL != platform) {
-		platform->name = NULL;
-		delete_device(platform);
-	}
-	
-	return res;
-}
-
-/** Create virtual USB host controller device.
- * Note that the virtual HC is actually device and driver in one
- * task.
- *
- * @param parent Parent device.
- * @return Error code.
- */
-static int add_virtual_usb_host_controller(device_t *parent)
-{
-	printf(NAME ": adding virtual host contoller.\n");
-
-	int rc;
-	device_t *vhc = NULL;
-	match_id_t *match_id = NULL;
-
-	vhc = create_device();
-	if (vhc == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-
-	vhc->name = "vhc";
-	printf(NAME ": the new device's name is %s.\n", vhc->name);
-
-	/* Initialize match id list. */
-	match_id = create_match_id();
-	if (match_id == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-
-	match_id->id = "usb&hc=vhc";
-	match_id->score = 100;
-	add_match_id(&vhc->match_ids, match_id);
-
-	/* Register child device. */
-	rc = child_device_register(vhc, parent);
-	if (rc != EOK)
-		goto failure;
-
-	return EOK;
-
-failure:
-	if (match_id != NULL)
-		match_id->id = NULL;
-
-	if (vhc != NULL) {
-		vhc->name = NULL;
-		delete_device(vhc);
-	}
-
-	return rc;
 }
 
@@ -184,4 +121,11 @@
 	    dev->handle);
 	
+	/*
+	 * Register virtual devices root.
+	 * We ignore error occurrence because virtual devices shall not be
+	 * vital for the system.
+	 */
+	add_virtual_root_child(dev);
+
 	/* Register root device's children. */
 	int res = add_platform_child(dev);
@@ -189,10 +133,4 @@
 		printf(NAME ": failed to add child device for platform.\n");
 	
-	/* Register virtual USB host controller. */
-	int rc = add_virtual_usb_host_controller(dev);
-	if (EOK != rc) {
-		printf(NAME ": failed to add child device - virtual USB HC.\n");
-	}
-
 	return res;
 }
Index: uspace/drv/rootia32/Makefile
===================================================================
--- uspace/drv/rootia32/Makefile	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2010 Lenka Trochtova
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../..
-LIBS = $(LIBDRV_PREFIX)/libdrv.a
-EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
-BINARY = rootia32
-
-SOURCES = \
-	rootia32.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/rootia32/rootia32.c
===================================================================
--- uspace/drv/rootia32/rootia32.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(revision )
@@ -1,204 +1,0 @@
-/*
- * Copyright (c) 2010 Lenka Trochtova
- * 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.
- */
-
-/**
- * @defgroup root_ia32 Root HW device driver for ia32 platform.
- * @brief HelenOS root HW device driver for ia32 platform.
- * @{
- */
-
-/** @file
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <bool.h>
-#include <fibril_synch.h>
-#include <stdlib.h>
-#include <str.h>
-#include <ctype.h>
-#include <macros.h>
-
-#include <driver.h>
-#include <devman.h>
-#include <ipc/devman.h>
-#include <ipc/dev_iface.h>
-#include <resource.h>
-#include <device/hw_res.h>
-
-#define NAME "rootia32"
-
-typedef struct rootia32_child_dev_data {
-	hw_resource_list_t hw_resources;
-} rootia32_child_dev_data_t;
-
-static int rootia32_add_device(device_t *dev);
-static void root_ia32_init(void);
-
-/** The root device driver's standard operations. */
-static driver_ops_t rootia32_ops = {
-	.add_device = &rootia32_add_device
-};
-
-/** The root device driver structure. */
-static driver_t rootia32_driver = {
-	.name = NAME,
-	.driver_ops = &rootia32_ops
-};
-
-static hw_resource_t pci_conf_regs = {
-	.type = IO_RANGE,
-	.res.io_range = {
-		.address = 0xCF8,
-		.size = 8,
-		.endianness = LITTLE_ENDIAN
-	}
-};
-
-static rootia32_child_dev_data_t pci_data = {
-	.hw_resources = {
-		1,
-		&pci_conf_regs
-	}
-};
-
-static hw_resource_list_t *rootia32_get_child_resources(device_t *dev)
-{
-	rootia32_child_dev_data_t *data;
-	
-	data = (rootia32_child_dev_data_t *) dev->driver_data;
-	if (NULL == data)
-		return NULL;
-	
-	return &data->hw_resources;
-}
-
-static bool rootia32_enable_child_interrupt(device_t *dev)
-{
-	/* TODO */
-	
-	return false;
-}
-
-static resource_iface_t child_res_iface = {
-	&rootia32_get_child_resources,
-	&rootia32_enable_child_interrupt
-};
-
-/* Initialized in root_ia32_init() function. */
-static device_ops_t rootia32_child_ops;
-
-static bool
-rootia32_add_child(device_t *parent, const char *name, const char *str_match_id,
-    rootia32_child_dev_data_t *drv_data)
-{
-	printf(NAME ": adding new child device '%s'.\n", name);
-	
-	device_t *child = NULL;
-	match_id_t *match_id = NULL;
-	
-	/* Create new device. */
-	child = create_device();
-	if (NULL == child)
-		goto failure;
-	
-	child->name = name;
-	child->driver_data = drv_data;
-	
-	/* Initialize match id list */
-	match_id = create_match_id();
-	if (NULL == match_id)
-		goto failure;
-	
-	match_id->id = str_match_id;
-	match_id->score = 100;
-	add_match_id(&child->match_ids, match_id);
-	
-	/* Set provided operations to the device. */
-	child->ops = &rootia32_child_ops;
-	
-	/* Register child device. */
-	if (EOK != child_device_register(child, parent))
-		goto failure;
-	
-	return true;
-	
-failure:
-	if (NULL != match_id)
-		match_id->id = NULL;
-	
-	if (NULL != child) {
-		child->name = NULL;
-		delete_device(child);
-	}
-	
-	printf(NAME ": failed to add child device '%s'.\n", name);
-	
-	return false;
-}
-
-static bool rootia32_add_children(device_t *dev)
-{
-	return rootia32_add_child(dev, "pci0", "intel_pci", &pci_data);
-}
-
-/** Get the root device.
- *
- * @param dev		The device which is root of the whole device tree (both
- *			of HW and pseudo devices).
- * @return		Zero on success, negative error number otherwise.
- */
-static int rootia32_add_device(device_t *dev)
-{
-	printf(NAME ": rootia32_add_device, device handle = %d\n", dev->handle);
-	
-	/* Register child devices. */
-	if (!rootia32_add_children(dev)) {
-		printf(NAME ": failed to add child devices for platform "
-		    "ia32.\n");
-	}
-	
-	return EOK;
-}
-
-static void root_ia32_init(void)
-{
-	rootia32_child_ops.interfaces[HW_RES_DEV_IFACE] = &child_res_iface;
-}
-
-int main(int argc, char *argv[])
-{
-	printf(NAME ": HelenOS rootia32 device driver\n");
-	root_ia32_init();
-	return driver_main(&rootia32_driver);
-}
-
-/**
- * @}
- */
Index: uspace/drv/rootia32/rootia32.ma
===================================================================
--- uspace/drv/rootia32/rootia32.ma	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(revision )
@@ -1,1 +1,0 @@
-10 ia32
Index: uspace/drv/rootpc/Makefile
===================================================================
--- uspace/drv/rootpc/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootpc/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Lenka Trochtova
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = rootpc
+
+SOURCES = \
+	rootpc.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/rootpc/rootpc.c
===================================================================
--- uspace/drv/rootpc/rootpc.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootpc/rootpc.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * 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.
+ */
+
+/**
+ * @defgroup root_pc Root HW device driver for ia32 and amd64 platform.
+ * @brief HelenOS root HW device driver for ia32 and amd64 platform.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ctype.h>
+#include <macros.h>
+
+#include <driver.h>
+#include <devman.h>
+#include <ipc/devman.h>
+#include <ipc/dev_iface.h>
+#include <resource.h>
+#include <device/hw_res.h>
+
+#define NAME "rootpc"
+
+typedef struct rootpc_child_dev_data {
+	hw_resource_list_t hw_resources;
+} rootpc_child_dev_data_t;
+
+static int rootpc_add_device(device_t *dev);
+static void root_pc_init(void);
+
+/** The root device driver's standard operations. */
+static driver_ops_t rootpc_ops = {
+	.add_device = &rootpc_add_device
+};
+
+/** The root device driver structure. */
+static driver_t rootpc_driver = {
+	.name = NAME,
+	.driver_ops = &rootpc_ops
+};
+
+static hw_resource_t pci_conf_regs = {
+	.type = IO_RANGE,
+	.res.io_range = {
+		.address = 0xCF8,
+		.size = 8,
+		.endianness = LITTLE_ENDIAN
+	}
+};
+
+static rootpc_child_dev_data_t pci_data = {
+	.hw_resources = {
+		1,
+		&pci_conf_regs
+	}
+};
+
+static hw_resource_list_t *rootpc_get_child_resources(device_t *dev)
+{
+	rootpc_child_dev_data_t *data;
+	
+	data = (rootpc_child_dev_data_t *) dev->driver_data;
+	if (NULL == data)
+		return NULL;
+	
+	return &data->hw_resources;
+}
+
+static bool rootpc_enable_child_interrupt(device_t *dev)
+{
+	/* TODO */
+	
+	return false;
+}
+
+static resource_iface_t child_res_iface = {
+	&rootpc_get_child_resources,
+	&rootpc_enable_child_interrupt
+};
+
+/* Initialized in root_pc_init() function. */
+static device_ops_t rootpc_child_ops;
+
+static bool
+rootpc_add_child(device_t *parent, const char *name, const char *str_match_id,
+    rootpc_child_dev_data_t *drv_data)
+{
+	printf(NAME ": adding new child device '%s'.\n", name);
+	
+	device_t *child = NULL;
+	match_id_t *match_id = NULL;
+	
+	/* Create new device. */
+	child = create_device();
+	if (NULL == child)
+		goto failure;
+	
+	child->name = name;
+	child->driver_data = drv_data;
+	
+	/* Initialize match id list */
+	match_id = create_match_id();
+	if (NULL == match_id)
+		goto failure;
+	
+	match_id->id = str_match_id;
+	match_id->score = 100;
+	add_match_id(&child->match_ids, match_id);
+	
+	/* Set provided operations to the device. */
+	child->ops = &rootpc_child_ops;
+	
+	/* Register child device. */
+	if (EOK != child_device_register(child, parent))
+		goto failure;
+	
+	return true;
+	
+failure:
+	if (NULL != match_id)
+		match_id->id = NULL;
+	
+	if (NULL != child) {
+		child->name = NULL;
+		delete_device(child);
+	}
+	
+	printf(NAME ": failed to add child device '%s'.\n", name);
+	
+	return false;
+}
+
+static bool rootpc_add_children(device_t *dev)
+{
+	return rootpc_add_child(dev, "pci0", "intel_pci", &pci_data);
+}
+
+/** Get the root device.
+ *
+ * @param dev		The device which is root of the whole device tree (both
+ *			of HW and pseudo devices).
+ * @return		Zero on success, negative error number otherwise.
+ */
+static int rootpc_add_device(device_t *dev)
+{
+	printf(NAME ": rootpc_add_device, device handle = %d\n",
+	    (int)dev->handle);
+	
+	/* Register child devices. */
+	if (!rootpc_add_children(dev)) {
+		printf(NAME ": failed to add child devices for platform "
+		    "ia32.\n");
+	}
+	
+	return EOK;
+}
+
+static void root_pc_init(void)
+{
+	rootpc_child_ops.interfaces[HW_RES_DEV_IFACE] = &child_res_iface;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS rootpc device driver\n");
+	root_pc_init();
+	return driver_main(&rootpc_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/rootpc/rootpc.ma
===================================================================
--- uspace/drv/rootpc/rootpc.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootpc/rootpc.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,2 @@
+10 ia32
+10 amd64
Index: uspace/drv/rootvirt/Makefile
===================================================================
--- uspace/drv/rootvirt/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = rootvirt
+
+SOURCES = \
+	rootvirt.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/rootvirt/devices.def
===================================================================
--- uspace/drv/rootvirt/devices.def	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/devices.def	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,24 @@
+/*
+ * Add list of virtual devices you want to launch driver for here.
+ *
+ * Unless the list is empty, the last item shall be followed by a comma.
+ */
+#ifdef CONFIG_TEST_DRIVERS
+{
+	.name = "test1",
+	.match_id = "virtual&test1"
+},
+{
+	.name = "test2alpha",
+	.match_id = "virtual&test2"
+},
+{
+	.name = "test2bravo",
+	.match_id = "virtual&test2"
+},
+#endif
+/* Virtual USB host controller. */
+{
+	.name = "usbhc",
+	.match_id = "usb&hc=vhc"
+},
Index: uspace/drv/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/rootvirt/rootvirt.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/rootvirt.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup rootvirt Root device driver for virtual devices.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <driver.h>
+
+#define NAME "rootvirt"
+
+/** Virtual device entry. */
+typedef struct {
+	/** Device name. */
+	const char *name;
+	/** Device match id. */
+	const char *match_id;
+} virtual_device_t;
+
+/** List of existing virtual devices. */
+virtual_device_t virtual_devices[] = {
+#include "devices.def"
+	/* Terminating item. */
+	{
+		.name = NULL,
+		.match_id = NULL
+	}
+};
+
+static int add_device(device_t *dev);
+
+static driver_ops_t rootvirt_ops = {
+	.add_device = &add_device
+};
+
+static driver_t rootvirt_driver = {
+	.name = NAME,
+	.driver_ops = &rootvirt_ops
+};
+
+/** Add child device.
+ *
+ * @param parent Parent device.
+ * @param virt_dev Virtual device to add.
+ * @return Error code.
+ */
+static int add_child(device_t *parent, virtual_device_t *virt_dev)
+{
+	printf(NAME ": registering child device `%s' (match \"%s\")\n",
+	    virt_dev->name, virt_dev->match_id);
+
+	int rc = child_device_register_wrapper(parent, virt_dev->name,
+	    virt_dev->match_id, 10, NULL);
+
+	if (rc == EOK) {
+		printf(NAME ": registered child device `%s'\n",
+		    virt_dev->name);
+	} else {
+		printf(NAME ": failed to register child device `%s': %s\n",
+		    virt_dev->name, str_error(rc));
+	}
+
+	return rc;
+}
+
+static int add_device(device_t *dev)
+{
+	static int instances = 0;
+
+	/*
+	 * Allow only single instance of root virtual device.
+	 */
+	instances++;
+	if (instances > 1) {
+		return ELIMIT;
+	}
+
+	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	    dev->name, (int)dev->handle);
+	
+	/*
+	 * Go through all virtual devices and try to add them.
+	 * We silently ignore failures.
+	 */
+	virtual_device_t *virt_dev = virtual_devices;
+	while (virt_dev->name != NULL) {
+		(void) add_child(dev, virt_dev);
+		virt_dev++;
+	}
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS virtual devices root driver\n");
+	return driver_main(&rootvirt_driver);
+}
+
+/**
+ * @}
+ */
+
Index: uspace/drv/rootvirt/rootvirt.ma
===================================================================
--- uspace/drv/rootvirt/rootvirt.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/rootvirt.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,1 @@
+10 rootvirt
Index: uspace/drv/test1/Makefile
===================================================================
--- uspace/drv/test1/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test1/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = test1
+
+SOURCES = \
+	test1.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/test1/test1.c
===================================================================
--- uspace/drv/test1/test1.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test1/test1.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <driver.h>
+
+#define NAME "test1"
+
+static int add_device(device_t *dev);
+
+static driver_ops_t driver_ops = {
+	.add_device = &add_device
+};
+
+static driver_t the_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+/** Register child and inform user about it.
+ *
+ * @param parent Parent device.
+ * @param message Message for the user.
+ * @param name Device name.
+ * @param match_id Device match id.
+ * @param score Device match score.
+ */
+static void register_child_verbose(device_t *parent, const char *message,
+    const char *name, const char *match_id, int match_score)
+{
+	printf(NAME ": registering child device `%s': %s.\n",
+	   name, message);
+
+	int rc = child_device_register_wrapper(parent, name,
+	    match_id, match_score, NULL);
+
+	if (rc == EOK) {
+		printf(NAME ": registered child device `%s'.\n", name);
+	} else {
+		printf(NAME ": failed to register child `%s' (%s).\n",
+		    name, str_error(rc));
+	}
+}
+
+/** Callback when new device is passed to this driver.
+ * This function is the body of the test: it shall register new child
+ * (named `clone') that shall be driven by the same task. When the clone
+ * is added, it registers another child (named `child') that is also driven
+ * by this task. The conditions ensure that we do not recurse indefinitely.
+ * When successful, the device tree shall contain following fragment:
+ *
+ * /virtual/test1
+ * /virtual/test1/clone
+ * /virtual/test1/clone/child
+ *
+ * and devman shall not deadlock.
+ *
+ *
+ * @param dev New device.
+ * @return Error code reporting success of the operation.
+ */
+static int add_device(device_t *dev)
+{
+	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	    dev->name, (int) dev->handle);
+
+	add_device_to_class(dev, "virtual");
+
+	if (dev->parent == NULL) {
+		register_child_verbose(dev, "cloning myself ;-)", "clone",
+		    "virtual&test1", 10);
+	} else if (str_cmp(dev->name, "clone") == 0) {
+		register_child_verbose(dev, "run by the same task", "child",
+		    "virtual&test1&child", 10);
+	}
+
+	printf(NAME ": device `%s' accepted.\n", dev->name);
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS test1 virtual device driver\n");
+	return driver_main(&the_driver);
+}
+
+
Index: uspace/drv/test1/test1.ma
===================================================================
--- uspace/drv/test1/test1.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test1/test1.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,2 @@
+10 virtual&test1
+10 virtual&test1&child
Index: uspace/drv/test2/Makefile
===================================================================
--- uspace/drv/test2/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test2/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = test2
+
+SOURCES = \
+	test2.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/test2/test2.c
===================================================================
--- uspace/drv/test2/test2.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test2/test2.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <driver.h>
+
+#define NAME "test2"
+
+static int add_device(device_t *dev);
+
+static driver_ops_t driver_ops = {
+	.add_device = &add_device
+};
+
+static driver_t the_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+/** Register child and inform user about it.
+ *
+ * @param parent Parent device.
+ * @param message Message for the user.
+ * @param name Device name.
+ * @param match_id Device match id.
+ * @param score Device match score.
+ */
+static void register_child_verbose(device_t *parent, const char *message,
+    const char *name, const char *match_id, int match_score)
+{
+	printf(NAME ": registering child device `%s': %s.\n",
+	   name, message);
+
+	int rc = child_device_register_wrapper(parent, name,
+	    match_id, match_score, NULL);
+
+	if (rc == EOK) {
+		printf(NAME ": registered child device `%s'.\n", name);
+	} else {
+		printf(NAME ": failed to register child `%s' (%s).\n",
+		    name, str_error(rc));
+	}
+}
+
+/** Add child devices after some sleep.
+ *
+ * @param arg Parent device structure (device_t *).
+ * @return Always EOK.
+ */
+static int postponed_birth(void *arg)
+{
+	device_t *dev = (device_t *) arg;
+
+	async_usleep(1000);
+
+	register_child_verbose(dev, "child driven by the same task",
+	    "child", "virtual&test2", 10);
+	register_child_verbose(dev, "child driven by test1",
+	    "test1", "virtual&test1", 10);
+
+	add_device_to_class(dev, "virtual");
+
+	return EOK;
+}
+
+
+static int add_device(device_t *dev)
+{
+	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	    dev->name, (int) dev->handle);
+
+	if (dev->parent == NULL) {
+		fid_t postpone = fibril_create(postponed_birth, dev);
+		fibril_add_ready(postpone);
+	} else {
+		register_child_verbose(dev, "child without available driver",
+		    "ERROR", "non-existent.match.id", 10);
+	}
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS test2 virtual device driver\n");
+	return driver_main(&the_driver);
+}
+
+
Index: uspace/drv/test2/test2.ma
===================================================================
--- uspace/drv/test2/test2.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test2/test2.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,1 @@
+10 virtual&test2
Index: uspace/drv/uhci/Makefile
===================================================================
--- uspace/drv/uhci/Makefile	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/uhci/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -33,5 +33,6 @@
 
 SOURCES = \
-	main.c
+	main.c \
+	transfers.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/uhci/main.c
===================================================================
--- uspace/drv/uhci/main.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/uhci/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -27,55 +27,21 @@
  */
 #include <usb/hcdhubd.h>
+#include <usb/debug.h>
 #include <errno.h>
+#include "uhci.h"
 
-static int enqueue_transfer_out(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
-    void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf("UHCI: transfer OUT [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
-	    size);
-	return ENOTSUP;
-}
-
-static int enqueue_transfer_setup(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
-    void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf("UHCI: transfer SETUP [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
-	    size);
-	return ENOTSUP;
-}
-
-static int enqueue_transfer_in(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
-    void *buffer, size_t size,
-    usb_hcd_transfer_callback_in_t callback, void *arg)
-{
-	printf("UHCI: transfer IN [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
-	    size);
-	return ENOTSUP;
-}
-
-static usb_hcd_transfer_ops_t uhci_transfer_ops = {
-	.transfer_out = enqueue_transfer_out,
-	.transfer_in = enqueue_transfer_in,
-	.transfer_setup = enqueue_transfer_setup
+static device_ops_t uhci_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &uhci_iface,
 };
 
-static int uhci_add_hc(usb_hc_device_t *device)
+static int uhci_add_device(device_t *device)
 {
-	device->transfer_ops = &uhci_transfer_ops;
+	usb_dprintf(NAME, 1, "uhci_add_device() called\n");
+	device->ops = &uhci_ops;
 
 	/*
 	 * We need to announce the presence of our root hub.
 	 */
+	usb_dprintf(NAME, 2, "adding root hub\n");
 	usb_hcd_add_root_hub(device);
 
@@ -83,7 +49,11 @@
 }
 
-usb_hc_driver_t uhci_driver = {
-	.name = "uhci",
-	.add_hc = uhci_add_hc
+static driver_ops_t uhci_driver_ops = {
+	.add_device = uhci_add_device,
+};
+
+static driver_t uhci_driver = {
+	.name = NAME,
+	.driver_ops = &uhci_driver_ops
 };
 
@@ -93,5 +63,7 @@
 	 * Do some global initializations.
 	 */
+	sleep(5);
+	usb_dprintf_enable(NAME, 5);
 
-	return usb_hcd_main(&uhci_driver);
+	return driver_main(&uhci_driver);
 }
Index: uspace/drv/uhci/transfers.c
===================================================================
--- uspace/drv/uhci/transfers.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/uhci/transfers.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+#include <usb/hcdhubd.h>
+#include <errno.h>
+
+#include "uhci.h"
+
+static int enqueue_transfer_out(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
+	    size);
+
+	return ENOTSUP;
+}
+
+static int enqueue_transfer_setup(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
+	    size);
+
+	return ENOTSUP;
+}
+
+static int enqueue_transfer_in(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
+	    size);
+
+	return ENOTSUP;
+}
+
+
+static int get_address(device_t *dev, devman_handle_t handle,
+    usb_address_t *address)
+{
+	return ENOTSUP;
+}
+
+static int interrupt_out(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int interrupt_in(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+static int control_read_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+
+usbhc_iface_t uhci_iface = {
+	.tell_address = get_address,
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+	.control_write_setup = control_write_setup,
+	.control_write_data = control_write_data,
+	.control_write_status = control_write_status,
+	.control_read_setup = control_read_setup,
+	.control_read_data = control_read_data,
+	.control_read_status = control_read_status
+};
Index: uspace/drv/uhci/uhci.h
===================================================================
--- uspace/drv/uhci/uhci.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/uhci/uhci.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,47 @@
+/*
+ * 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 UHCI driver
+ */
+#ifndef DRV_UHCI_UHCI_H
+#define DRV_UHCI_UHCI_H
+
+#include <usbhc_iface.h>
+
+#define NAME "uhci"
+
+usbhc_iface_t uhci_iface;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci/uhci.ma
===================================================================
--- uspace/drv/uhci/uhci.ma	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/uhci/uhci.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -1,3 +1,2 @@
 10 pci/ven=8086&dev=7020
-10 usb&hc=uhci
-10 usb&hc=uhci&hub
+
Index: uspace/drv/usbhub/Makefile
===================================================================
--- uspace/drv/usbhub/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2010 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include
+BINARY = usbhub
+
+SOURCES = \
+	main.c \
+	utils.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbhub/main.c
===================================================================
--- uspace/drv/usbhub/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <usb/usbdrv.h>
+#include <driver.h>
+#include <errno.h>
+#include "usbhub.h"
+
+static driver_ops_t hub_driver_ops = {
+	.add_device = usb_add_hub_device,
+};
+
+static driver_t hub_driver = {
+	.name = "usbhub",
+	.driver_ops = &hub_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	return driver_main(&hub_driver);
+}
Index: uspace/drv/usbhub/usbhub.h
===================================================================
--- uspace/drv/usbhub/usbhub.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/usbhub.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief Hub driver.
+ */
+#ifndef DRV_USBHUB_USBHUB_H
+#define DRV_USBHUB_USBHUB_H
+
+#define NAME "usbhub"
+
+int usb_add_hub_device(device_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/usbhub.ma
===================================================================
--- uspace/drv/usbhub/usbhub.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/usbhub.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,1 @@
+10 usb&hub
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/utils.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libusb usb
+ * @{
+ */
+/** @file
+ * @brief Hub driver.
+ */
+#include <driver.h>
+#include <usb/devreq.h>
+#include <usbhc_iface.h>
+#include <usb/usbdrv.h>
+#include <usb/descriptor.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+#include <usb/classes/hub.h>
+#include "usbhub.h"
+
+static void check_hub_changes(void);
+
+size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
+
+//*********************************************
+//
+//  various utils
+//
+//*********************************************
+
+void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
+	//base size
+	size_t size = 7;
+	//variable size according to port count
+	size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
+	size += 2 * var_size;
+	uint8_t * result = (uint8_t*) malloc(size);
+	//size
+	result[0] = size;
+	//descriptor type
+	result[1] = USB_DESCTYPE_HUB;
+	result[2] = descriptor->ports_count;
+	/// @fixme handling of endianness??
+	result[3] = descriptor->hub_characteristics / 256;
+	result[4] = descriptor->hub_characteristics % 256;
+	result[5] = descriptor->pwr_on_2_good_time;
+	result[6] = descriptor->current_requirement;
+
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		result[7 + i] = descriptor->devices_removable[i];
+	}
+	for (i = 0; i < var_size; ++i) {
+		result[7 + var_size + i] = 255;
+	}
+	return result;
+}
+
+usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
+	uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
+	if (sdescriptor[1] != USB_DESCTYPE_HUB) return NULL;
+	usb_hub_descriptor_t * result = (usb_hub_descriptor_t*) malloc(sizeof (usb_hub_descriptor_t));
+	//uint8_t size = sdescriptor[0];
+	result->ports_count = sdescriptor[2];
+	/// @fixme handling of endianness??
+	result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
+	result->pwr_on_2_good_time = sdescriptor[5];
+	result->current_requirement = sdescriptor[6];
+	size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
+	result->devices_removable = (uint8_t*) malloc(var_size);
+
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		result->devices_removable[i] = sdescriptor[7 + i];
+	}
+	return result;
+}
+
+
+//*********************************************
+//
+//  hub driver code
+//
+//*********************************************
+
+usb_hcd_hub_info_t * usb_create_hub_info(device_t * device) {
+	usb_hcd_hub_info_t* result = (usb_hcd_hub_info_t*) malloc(sizeof (usb_hcd_hub_info_t));
+
+	return result;
+}
+
+/** Callback when new hub device is detected.
+ *
+ * @param dev New device.
+ * @return Error code.
+ */
+int usb_add_hub_device(device_t *dev) {
+	printf(NAME ": add_hub_device(handle=%d)\n", (int) dev->handle);
+
+	check_hub_changes();
+
+	/*
+	 * We are some (probably deeply nested) hub.
+	 * Thus, assign our own operations and explore already
+	 * connected devices.
+	 */
+
+	//create the hub structure
+	usb_hcd_hub_info_t * hub_info = usb_create_hub_info(dev);
+	(void)hub_info;
+
+	return EOK;
+	//return ENOTSUP;
+}
+
+
+/** Check changes on all known hubs.
+ */
+static void check_hub_changes(void) {
+	/*
+	 * Iterate through all hubs.
+	 */
+	for (; false; ) {
+		/*
+		 * Check status change pipe of this hub.
+		 */
+		usb_target_t target = {
+			.address = 5,
+			.endpoint = 1
+		};
+
+		size_t port_count = 7;
+
+		/*
+		 * Connect to respective HC.
+		 */
+		int hc = usb_drv_hc_connect(NULL, 0);
+		if (hc < 0) {
+			continue;
+		}
+
+		// FIXME: count properly
+		size_t byte_length = (port_count / 8) + 1;
+
+		void *change_bitmap = malloc(byte_length);
+		size_t actual_size;
+		usb_handle_t handle;
+
+		/*
+		 * Send the request.
+		 * FIXME: check returned value for possible errors
+		 */
+		usb_drv_async_interrupt_in(hc, target,
+				change_bitmap, byte_length, &actual_size,
+				&handle);
+
+		usb_drv_async_wait_for(handle);
+
+		/*
+		 * TODO: handle the changes.
+		 */
+
+		/*
+		 * WARNING: sample code, will not work out of the box.
+		 * And does not contain code for checking for errors.
+		 */
+#if 0
+		/*
+		 * Before opening the port, we must acquire the default
+		 * address.
+		 */
+		usb_drv_reserve_default_address(hc);
+
+		usb_address_t new_device_address = usb_drv_request_address(hc);
+
+		// TODO: open the port
+
+		// TODO: send request for setting address to new_device_address
+
+		/*
+		 * Once new address is set, we can release the default
+		 * address.
+		 */
+		usb_drv_release_default_address(hc);
+
+		/*
+		 * Obtain descriptors and create match ids for devman.
+		 */
+
+		// TODO: get device descriptors
+
+		// TODO: create match ids
+
+		// TODO: add child device
+
+		// child_device_register sets the device handle
+		// TODO: store it here
+		devman_handle_t new_device_handle = 0;
+
+		/*
+		 * Inform the HC that the new device has devman handle
+		 * assigned.
+		 */
+		usb_drv_bind_address(hc, new_device_address, new_device_handle);
+
+		/*
+		 * That's all.
+		 */
+#endif
+
+
+		/*
+		 * Hang-up the HC-connected phone.
+		 */
+		ipc_hangup(hc);
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/usbkbd/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -32,4 +32,6 @@
 #include <fibril.h>
 #include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <usb/devreq.h>
 
 #define BUFFER_SIZE 32
@@ -37,4 +39,47 @@
 
 static const usb_endpoint_t CONTROL_EP = 0;
+
+/*
+ * Callbacks for parser
+ */
+static void usbkbd_process_keycodes(const uint16_t *key_codes, size_t count,
+                                    void *arg)
+{
+
+}
+
+/*
+ * Kbd functions
+ */
+static int usbkbd_get_descriptors()
+{
+	// copy-pasted:
+	
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_device_descriptor_t)
+	};
+	
+	setup_packet.value_high = USB_DESCTYPE_DEVICE;
+	setup_packet.value_low = 0;
+
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_device_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	// end of copy-paste
+}
 
 static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev)
@@ -68,5 +113,5 @@
 
 	// TODO: get descriptors
-
+	usbkbd_get_descriptors();
 	// TODO: parse descriptors and save endpoints
 
@@ -75,5 +120,5 @@
 
 static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev,
-					char *buffer, size_t actual_size)
+                                        uint8_t *buffer, size_t actual_size)
 {
 	/*
@@ -81,4 +126,11 @@
 	 * now only take last 6 bytes and process, i.e. send to kbd
 	 */
+
+	usb_hid_report_in_callbacks_t *callbacks =
+	    (usb_hid_report_in_callbacks_t *)malloc(
+		sizeof(usb_hid_report_in_callbacks_t));
+	callbacks->keyboard = usbkbd_process_keycodes;
+
+	usb_hid_parse_report(kbd_dev->parser, buffer, callbacks, NULL);
 }
 
@@ -87,5 +139,5 @@
 	int rc;
 	usb_handle_t handle;
-	char buffer[BUFFER_SIZE];
+	uint8_t buffer[BUFFER_SIZE];
 	size_t actual_size;
 	//usb_endpoint_t poll_endpoint = 1;
Index: uspace/drv/vhc/conn.h
===================================================================
--- uspace/drv/vhc/conn.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/conn.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -38,4 +38,5 @@
 #include <usb/usb.h>
 #include <usb/hcdhubd.h>
+#include <usbhc_iface.h>
 #include "vhcd.h"
 #include "devices.h"
@@ -44,4 +45,8 @@
 
 usb_hcd_transfer_ops_t vhc_transfer_ops;
+usbhc_iface_t vhc_iface;
+
+void address_init(void);
+
 
 void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/connhost.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -36,4 +36,5 @@
 #include <errno.h>
 #include <usb/usb.h>
+#include <usb/hcd.h>
 
 #include "vhcd.h"
@@ -43,7 +44,7 @@
 typedef struct {
 	usb_direction_t direction;
-	usb_hcd_transfer_callback_out_t out_callback;
-	usb_hcd_transfer_callback_in_t in_callback;
-	usb_hc_device_t *hc;
+	usbhc_iface_transfer_out_callback_t out_callback;
+	usbhc_iface_transfer_in_callback_t in_callback;
+	device_t *dev;
 	void *arg;
 } transfer_info_t;
@@ -56,10 +57,10 @@
 	switch (transfer->direction) {
 		case USB_DIRECTION_IN:
-			transfer->in_callback(transfer->hc,
-			    size, outcome,
+			transfer->in_callback(transfer->dev,
+			    outcome, size,
 			    transfer->arg);
 			break;
 		case USB_DIRECTION_OUT:
-			transfer->out_callback(transfer->hc,
+			transfer->out_callback(transfer->dev,
 			    outcome,
 			    transfer->arg);
@@ -73,5 +74,5 @@
 }
 
-static transfer_info_t *create_transfer_info(usb_hc_device_t *hc,
+static transfer_info_t *create_transfer_info(device_t *dev,
     usb_direction_t direction, void *arg)
 {
@@ -82,27 +83,22 @@
 	transfer->out_callback = NULL;
 	transfer->arg = arg;
-	transfer->hc = hc;
+	transfer->dev = dev;
 
 	return transfer;
 }
 
-static int enqueue_transfer_out(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
+static int enqueue_transfer_out(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer OUT [%d.%d (%s); %zu]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
 	    size);
 
 	transfer_info_t *transfer
-	    = create_transfer_info(hc, USB_DIRECTION_OUT, arg);
+	    = create_transfer_info(dev, USB_DIRECTION_OUT, arg);
 	transfer->out_callback = callback;
-
-	usb_target_t target = {
-		.address = dev->address,
-		.endpoint = endpoint->endpoint
-	};
 
 	hc_add_transaction_to_device(false, target, buffer, size,
@@ -112,22 +108,17 @@
 }
 
-static int enqueue_transfer_setup(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
+static int enqueue_transfer_setup(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer SETUP [%d.%d (%s); %zu]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
 	    size);
 
 	transfer_info_t *transfer
-	    = create_transfer_info(hc, USB_DIRECTION_OUT, arg);
+	    = create_transfer_info(dev, USB_DIRECTION_OUT, arg);
 	transfer->out_callback = callback;
-
-	usb_target_t target = {
-		.address = dev->address,
-		.endpoint = endpoint->endpoint
-	};
 
 	hc_add_transaction_to_device(true, target, buffer, size,
@@ -137,22 +128,17 @@
 }
 
-static int enqueue_transfer_in(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
+static int enqueue_transfer_in(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void *buffer, size_t size,
-    usb_hcd_transfer_callback_in_t callback, void *arg)
-{
-	printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer IN [%d.%d (%s); %zu]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
 	    size);
 
 	transfer_info_t *transfer
-	    = create_transfer_info(hc, USB_DIRECTION_IN, arg);
+	    = create_transfer_info(dev, USB_DIRECTION_IN, arg);
 	transfer->in_callback = callback;
-
-	usb_target_t target = {
-		.address = dev->address,
-		.endpoint = endpoint->endpoint
-	};
 
 	hc_add_transaction_from_device(target, buffer, size,
@@ -163,8 +149,148 @@
 
 
-usb_hcd_transfer_ops_t vhc_transfer_ops = {
-	.transfer_out = enqueue_transfer_out,
-	.transfer_in = enqueue_transfer_in,
-	.transfer_setup = enqueue_transfer_setup
+static int interrupt_out(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int interrupt_in(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+static int control_read_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+static usb_address_keeping_t addresses;
+
+
+static int reserve_default_address(device_t *dev)
+{
+	usb_address_keeping_reserve_default(&addresses);
+	return EOK;
+}
+
+static int release_default_address(device_t *dev)
+{
+	usb_address_keeping_release_default(&addresses);
+	return EOK;
+}
+
+static int request_address(device_t *dev, usb_address_t *address)
+{
+	usb_address_t addr = usb_address_keeping_request(&addresses);
+	if (addr < 0) {
+		return (int)addr;
+	}
+
+	*address = addr;
+	return EOK;
+}
+
+static int release_address(device_t *dev, usb_address_t address)
+{
+	return usb_address_keeping_release(&addresses, address);
+}
+
+static int bind_address(device_t *dev, usb_address_t address,
+    devman_handle_t handle)
+{
+	usb_address_keeping_devman_bind(&addresses, address, handle);
+	return EOK;
+}
+
+static int tell_address(device_t *dev, devman_handle_t handle,
+    usb_address_t *address)
+{
+	usb_address_t addr = usb_address_keeping_find(&addresses, handle);
+	if (addr < 0) {
+		return addr;
+	}
+
+	*address = addr;
+	return EOK;
+}
+
+void address_init(void)
+{
+	usb_address_keeping_init(&addresses, 50);
+}
+
+usbhc_iface_t vhc_iface = {
+	.tell_address = tell_address,
+
+	.reserve_default_address = reserve_default_address,
+	.release_default_address = release_default_address,
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.release_address = release_address,
+
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+
+	.control_write_setup = control_write_setup,
+	.control_write_data = control_write_data,
+	.control_write_status = control_write_status,
+
+	.control_read_setup = control_read_setup,
+	.control_read_data = control_read_data,
+	.control_read_status = control_read_status
 };
 
Index: uspace/drv/vhc/debug.c
===================================================================
--- uspace/drv/vhc/debug.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/debug.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -35,31 +35,8 @@
 #include <stdio.h>
 #include <ipc/ipc.h>
+#include <usb/debug.h>
 
 #include "vhcd.h"
 
-/** Current debug level. */
-int debug_level = 0;
-
-/** Debugging printf.
- * This function is intended for single-line messages as it
- * automatically prints debugging prefix at the beginning of the
- * line.
- *
- * @see printf
- * @param level Debugging level.
- */
-void dprintf(int level, const char *format, ...)
-{
-	if (level > debug_level) {
-		return;
-	}
-	
-	printf("%s(%d): ", NAME, level);
-	va_list args;
-	va_start(args, format);
-	vprintf(format, args);
-	va_end(args);
-	printf("\n");
-}
 
 /** Debug print informing of invalid call.
Index: uspace/drv/vhc/hcd.c
===================================================================
--- uspace/drv/vhc/hcd.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/hcd.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -52,7 +52,11 @@
 #include "conn.h"
 
+static device_ops_t vhc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &vhc_iface,
+	.default_handler = default_connection_handler
+};
 
 static int vhc_count = 0;
-static int vhc_add_device(usb_hc_device_t *dev)
+static int vhc_add_device(device_t *dev)
 {
 	/*
@@ -65,12 +69,15 @@
 	vhc_count++;
 
-	dev->transfer_ops = &vhc_transfer_ops;
-	dev->generic->ops->default_handler = default_connection_handler;
+	dev->ops = &vhc_ops;
+
+	/*
+	 * Initialize address management.
+	 */
+	address_init();
 
 	/*
 	 * Initialize our hub and announce its presence.
 	 */
-	hub_init();
-	usb_hcd_add_root_hub(dev);
+	hub_init(dev);
 
 	printf("%s: virtual USB host controller ready.\n", NAME);
@@ -79,7 +86,11 @@
 }
 
-static usb_hc_driver_t vhc_driver = {
+static driver_ops_t vhc_driver_ops = {
+	.add_device = vhc_add_device,
+};
+
+static driver_t vhc_driver = {
 	.name = NAME,
-	.add_hc = &vhc_add_device
+	.driver_ops = &vhc_driver_ops
 };
 
@@ -99,5 +110,5 @@
 	printf("%s: virtual USB host controller driver.\n", NAME);
 
-	debug_level = 10;
+	usb_dprintf_enable(NAME, 10);
 
 	fid_t fid = fibril_create(hc_manager_fibril, NULL);
@@ -114,5 +125,5 @@
 	sleep(4);
 
-	return usb_hcd_main(&vhc_driver);
+	return driver_main(&vhc_driver);
 }
 
Index: uspace/drv/vhc/hub.c
===================================================================
--- uspace/drv/vhc/hub.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/hub.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -37,9 +37,12 @@
 #include <usbvirt/device.h>
 #include <errno.h>
+#include <str_error.h>
 #include <stdlib.h>
+#include <driver.h>
 
 #include "vhcd.h"
 #include "hub.h"
 #include "hubintern.h"
+#include "conn.h"
 
 
@@ -148,6 +151,28 @@
 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;
+}
+
 /** Initialize virtual hub. */
-void hub_init(void)
+void hub_init(device_t *hc_dev)
 {
 	size_t i;
@@ -163,4 +188,27 @@
 	
 	dprintf(1, "virtual hub (%d ports) created", HUB_PORT_COUNT);
+
+	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));
+	}
+
+	dprintf(2, "virtual hub address changed to %d", hub_address);
+
+	char *id;
+	int rc = asprintf(&id, "usb&hub");
+	if (rc <= 0) {
+		return;
+	}
+	devman_handle_t hub_handle;
+	rc = child_device_register_wrapper(hc_dev, "hub", id, 10, &hub_handle);
+	if (rc != EOK) {
+		free(id);
+	}
+
+	vhc_iface.bind_address(NULL, hub_address, hub_handle);	
+
+	dprintf(2, "virtual hub has devman handle %d", (int) hub_handle);
 }
 
Index: uspace/drv/vhc/hub.h
===================================================================
--- uspace/drv/vhc/hub.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/hub.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -37,4 +37,5 @@
 
 #include <usbvirt/device.h>
+#include <driver.h>
 
 #include "devices.h"
@@ -47,5 +48,5 @@
 extern usbvirt_device_t virthub_dev;
 
-void hub_init(void);
+void hub_init(device_t *);
 size_t hub_add_device(virtdev_connection_t *);
 void hub_remove_device(virtdev_connection_t *);
Index: uspace/drv/vhc/vhc.ma
===================================================================
--- uspace/drv/vhc/vhc.ma	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/vhc.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -1,2 +1,2 @@
 10 usb&hc=vhc
-10 usb&hc=vhc&hub
+
Index: uspace/drv/vhc/vhcd.h
===================================================================
--- uspace/drv/vhc/vhcd.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/vhcd.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -36,4 +36,6 @@
 #define VHCD_VHCD_H_
 
+#include <usb/debug.h>
+
 #define NAME "vhc"
 #define NAME_DEV "hcd-virt-dev"
@@ -43,6 +45,6 @@
 #define DEVMAP_PATH_DEV NAMESPACE "/" NAME_DEV
 
-extern int debug_level;
-void dprintf(int, const char *, ...);
+#define dprintf(level, format, ...) \
+	usb_dprintf(NAME, (level), format "\n", ##__VA_ARGS__)
 void dprintf_inval_call(int, ipc_call_t, ipcarg_t);
 
