Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision d7869d7e00b2e62dbfbb2c4a30abf9a95caa7e73)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
@@ -111,5 +111,5 @@
 	 * needs to be ready at this time.
 	 */
-	ret = hcd_setup_virtual_root_hub(dev);
+	ret = hcd_setup_virtual_root_hub(dev_to_hcd(dev), dev);
 	if (ret != EOK) {
 		usb_log_error("Failed to init VHC root hub: %s\n",
Index: uspace/drv/bus/usb/xhci/main.c
===================================================================
--- uspace/drv/bus/usb/xhci/main.c	(revision d7869d7e00b2e62dbfbb2c4a30abf9a95caa7e73)
+++ uspace/drv/bus/usb/xhci/main.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
@@ -42,4 +42,5 @@
 
 #include "hc.h"
+#include "rh.h"
 #include "endpoint.h"
 
@@ -50,7 +51,9 @@
 static int hcd_claim(hcd_t *, ddf_dev_t *);
 static int hcd_start(hcd_t *, bool);
+static int hcd_setup_root_hub(hcd_t *, ddf_dev_t *);
 static int hcd_status(hcd_t *, uint32_t *);
 static void hcd_interrupt(hcd_t *, uint32_t);
 static int hcd_schedule(hcd_t *, usb_transfer_batch_t *);
+static int hcd_address_device(hcd_t *, usb_speed_t, usb_tt_address_t, usb_address_t *);
 static void hc_driver_fini(hcd_t *);
 
@@ -62,4 +65,5 @@
 	.claim = hcd_claim,
 	.start = hcd_start,
+	.setup_root_hub = hcd_setup_root_hub,
 	.fini = hc_driver_fini,
 	.ops = {
@@ -67,4 +71,5 @@
 		.irq_hook       = hcd_interrupt,
 		.status_hook    = hcd_status,
+		.address_device = hcd_address_device,
 	}
 };
@@ -116,4 +121,13 @@
 }
 
+static int hcd_setup_root_hub(hcd_t *hcd, ddf_dev_t *dev)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	hc->rh.hcd_rh = hcd_roothub_create(hcd, dev, USB_SPEED_SUPER);
+	return hc->rh.hcd_rh ? EOK : ENOMEM;
+}
+
 static int hcd_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
 {
@@ -139,4 +153,12 @@
 
 	hc_interrupt(hc, status);
+}
+
+static int hcd_address_device(hcd_t *hcd, usb_speed_t speed, usb_tt_address_t tt, usb_address_t *address)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	return xhci_rh_address_device(&hc->rh, speed, tt, address);
 }
 
Index: uspace/drv/bus/usb/xhci/rh.c
===================================================================
--- uspace/drv/bus/usb/xhci/rh.c	(revision d7869d7e00b2e62dbfbb2c4a30abf9a95caa7e73)
+++ uspace/drv/bus/usb/xhci/rh.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
@@ -38,4 +38,6 @@
 #include <usb/debug.h>
 #include <usb/host/utils/malloc32.h>
+#include <usb/host/ddf_helpers.h>
+
 #include "debug.h"
 #include "commands.h"
@@ -69,12 +71,20 @@
 // TODO: Check device deallocation, we free device_ctx in hc.c, not
 //       sure about the other structs.
-static int alloc_dev(xhci_hc_t *hc, uint8_t port, uint32_t route_str)
+// TODO: This currently assumes the device is attached to rh directly.
+//       Also, we should consider moving a lot of functionailty to xhci bus
+int xhci_rh_address_device(xhci_rh_t *rh, usb_speed_t unused_speed, usb_tt_address_t tt, usb_address_t *address)
 {
 	int err;
+	xhci_hc_t *hc = rh->hc;
 
 	xhci_cmd_t cmd;
 	xhci_cmd_init(&cmd);
 
-	const xhci_port_speed_t *speed = xhci_rh_get_port_speed(&hc->rh, port);
+	uint8_t port = tt.port;
+
+	/* XXX Certainly not generic solution. */
+	uint32_t route_str = 0;
+
+	const xhci_port_speed_t *speed = xhci_rh_get_port_speed(rh, port);
 
 	xhci_send_enable_slot_command(hc, &cmd);
@@ -127,6 +137,5 @@
 	XHCI_EP_ERROR_COUNT_SET(ictx->endpoint_ctx[0], 3);
 
-	// TODO: What's the alignment?
-	xhci_device_ctx_t *dctx = malloc(sizeof(xhci_device_ctx_t));
+	xhci_device_ctx_t *dctx = malloc32(sizeof(xhci_device_ctx_t));
 	if (!dctx) {
 		err = ENOMEM;
@@ -149,6 +158,6 @@
 	xhci_cmd_fini(&cmd);
 
-	usb_address_t address = XHCI_SLOT_DEVICE_ADDRESS(dctx->slot_ctx);
-	usb_log_debug2("Obtained USB address: %d.\n", address);
+	*address = XHCI_SLOT_DEVICE_ADDRESS(dctx->slot_ctx);
+	usb_log_debug2("Obtained USB address: %d.\n", *address);
 
 	// TODO: Ask libusbhost to create a control endpoint for EP0.
@@ -174,4 +183,14 @@
 }
 
+static int rh_setup_device(xhci_rh_t *rh, uint8_t port_id)
+{
+	/** This should ideally use the libusbhost in a clean and elegant way,
+	 * to create child function. The refactoring of libusbhost is not over
+	 * yet, so for now it is still quirky.
+	 */
+
+	return hcd_roothub_new_device(rh->hcd_rh, port_id);
+}
+
 static int handle_connected_device(xhci_rh_t *rh, uint8_t port_id)
 {
@@ -186,5 +205,5 @@
 		if (link_state == 0) {
 			/* USB3 is automatically advanced to enabled. */
-			return alloc_dev(rh->hc, port_id, 0);
+			return rh_setup_device(rh, port_id);
 		}
 		else if (link_state == 5) {
@@ -270,5 +289,5 @@
 				 * every time USB2 port is reset. This is a
 				 * temporary workaround. */
-				alloc_dev(rh->hc, i, 0);
+				rh_setup_device(rh, i);
 			}
 		}
Index: uspace/drv/bus/usb/xhci/rh.h
===================================================================
--- uspace/drv/bus/usb/xhci/rh.h	(revision d7869d7e00b2e62dbfbb2c4a30abf9a95caa7e73)
+++ uspace/drv/bus/usb/xhci/rh.h	(revision 867b3757d6898c102509e02a34857fa95c832191)
@@ -51,4 +51,6 @@
 } xhci_port_speed_t;
 
+typedef struct hcd_roothub hcd_roothub_t;
+
 /* XHCI root hub instance */
 typedef struct {
@@ -64,4 +66,7 @@
 	/* Number of hub ports. */
 	uint8_t max_ports;
+
+	/* We need this to create child devices */
+	hcd_roothub_t *hcd_rh;
 } xhci_rh_t;
 
@@ -74,4 +79,6 @@
 void xhci_rh_handle_port_change(xhci_rh_t *);
 
+int xhci_rh_address_device(xhci_rh_t *, usb_speed_t, usb_tt_address_t, usb_address_t *);
+
 #endif
 
