Index: uspace/drv/bus/usb/ehci/hw_struct/queue_head.c
===================================================================
--- uspace/drv/bus/usb/ehci/hw_struct/queue_head.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/ehci/hw_struct/queue_head.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -37,4 +37,5 @@
 #include <mem.h>
 #include <macros.h>
+#include <usb/host/bus.h>
 
 #include "mem_access.h"
@@ -81,6 +82,6 @@
 	if (ep->speed != USB_SPEED_HIGH) {
 		ep_cap |=
-		    QH_EP_CAP_TT_PORT_SET(ep->tt.port) |
-		    QH_EP_CAP_TT_ADDR_SET(ep->tt.address);
+		    QH_EP_CAP_TT_PORT_SET(ep->device->tt.port) |
+		    QH_EP_CAP_TT_ADDR_SET(ep->device->tt.address);
 	}
 	if (ep->transfer_type == USB_TRANSFER_INTERRUPT) {
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -57,5 +57,4 @@
 
 static const ddf_hc_driver_t ehci_hc_driver = {
-	.hc_speed = USB_SPEED_HIGH,
 	.name = "EHCI-PCI",
 	.init = ehci_driver_init,
Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -35,9 +35,12 @@
 #include <adt/hash_table.h>
 #include <adt/hash.h>
+#include <usb/host/ddf_helpers.h>
 #include <usb/host/endpoint.h>
+#include <usb/host/hcd.h>
 #include <usb/debug.h>
 
 #include <assert.h>
 #include <errno.h>
+#include <str_error.h>
 #include <macros.h>
 #include <stdbool.h>
@@ -53,4 +56,56 @@
 	xhci_device_t *device;
 } hashed_device_t;
+
+/** TODO: Still some copy-pasta left...
+ */
+int xhci_bus_enumerate_device(xhci_bus_t *bus, xhci_hc_t *hc, device_t *dev)
+{
+	int err;
+
+	/* TODO: get speed from the default address reservation */
+	dev->speed = USB_SPEED_FULL;
+
+	/* Manage TT */
+	if (dev->hub->speed == USB_SPEED_HIGH && usb_speed_is_11(dev->speed)) {
+		/* For LS devices under HS hub */
+		/* TODO: How about SS hubs? */
+		dev->tt.address = dev->hub->address;
+		dev->tt.port = dev->port;
+	}
+	else {
+		/* Inherit hub's TT */
+		dev->tt = dev->hub->tt;
+	}
+
+	/* Assign an address to the device */
+	if ((err = xhci_rh_address_device(&hc->rh, dev))) {
+		usb_log_error("Failed to setup address of the new device: %s", str_error(err));
+		return err;
+	}
+
+	/* Read the device descriptor, derive the match ids */
+	if ((err = hcd_ddf_device_explore(hc->hcd, dev))) {
+		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
+		bus_release_address(&bus->base, dev->address);
+		return err;
+	}
+
+	return EOK;
+}
+
+static int enumerate_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	return xhci_bus_enumerate_device((xhci_bus_t *) bus, hc, dev);
+}
+
+static int remove_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	// TODO: Implement me!
+
+	return ENOTSUP;
+}
 
 /** Ops receive generic bus_t pointer. */
@@ -214,14 +269,4 @@
 }
 
-static int get_speed(bus_t *bus_base, usb_address_t address, usb_speed_t *speed)
-{
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
-	assert(bus);
-
-	// TODO: Use `xhci_get_port_speed` once we find the port corresponding to `address`.
-	*speed = USB_SPEED_SUPER;
-	return EOK;
-}
-
 static int release_address(bus_t *bus_base, usb_address_t address)
 {
@@ -255,4 +300,7 @@
 
 static const bus_ops_t xhci_bus_ops = {
+	.enumerate_device = enumerate_device,
+	.remove_device = remove_device,
+
 	.create_endpoint = create_endpoint,
 	.destroy_endpoint = destroy_endpoint,
@@ -263,5 +311,4 @@
 
 	.request_address = request_address,
-	.get_speed = get_speed,
 	.release_address = release_address,
 	.reset_toggle = reset_toggle,
@@ -303,5 +350,5 @@
 	assert(bus);
 
-	bus_init(&bus->base);
+	bus_init(&bus->base, sizeof(device_t));
 
 	if (!hash_table_create(&bus->devices, 0, 0, &device_ht_ops)) {
@@ -320,4 +367,5 @@
 	hash_table_destroy(&bus->devices);
 }
+
 /**
  * @}
Index: uspace/drv/bus/usb/xhci/bus.h
===================================================================
--- uspace/drv/bus/usb/xhci/bus.h	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/bus.h	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -42,4 +42,6 @@
 #include <usb/host/bus.h>
 
+typedef struct xhci_hc xhci_hc_t;
+
 /** Endpoint management structure */
 typedef struct xhci_bus {
@@ -58,4 +60,6 @@
 void xhci_bus_fini(xhci_bus_t *);
 
+int xhci_bus_enumerate_device(xhci_bus_t *, xhci_hc_t *, device_t *);
+
 #endif
 /**
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -158,5 +158,5 @@
 		return err;
 
-	hc->base = base;
+	hc->reg_base = base;
 	hc->cap_regs = (xhci_cap_regs_t *)  base;
 	hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
@@ -180,5 +180,5 @@
 
 	if ((err = hc_parse_ec(hc))) {
-		pio_disable(hc->base, RNGSZ(hc->mmio_range));
+		pio_disable(hc->reg_base, RNGSZ(hc->mmio_range));
 		return err;
 	}
@@ -619,5 +619,5 @@
 	xhci_fini_commands(hc);
 	xhci_rh_fini(&hc->rh);
-	pio_disable(hc->base, RNGSZ(hc->mmio_range));
+	pio_disable(hc->reg_base, RNGSZ(hc->mmio_range));
 	usb_log_info("HC(%p): Finalized.", hc);
 }
Index: uspace/drv/bus/usb/xhci/hc.h
===================================================================
--- uspace/drv/bus/usb/xhci/hc.h	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/hc.h	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -53,7 +53,7 @@
 	/* MMIO range */
 	addr_range_t mmio_range;
-	void *base;
 
 	/* Mapped register sets */
+	void *reg_base;
 	xhci_cap_regs_t *cap_regs;
 	xhci_op_regs_t *op_regs;
@@ -83,4 +83,7 @@
 	list_t commands;
 	list_t transfers;
+
+	/* TODO: Hack. Figure out a better way. */
+	hcd_t *hcd;
 } xhci_hc_t;
 
Index: uspace/drv/bus/usb/xhci/main.c
===================================================================
--- uspace/drv/bus/usb/xhci/main.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/main.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -55,9 +55,7 @@
 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 *);
 
 static const ddf_hc_driver_t xhci_ddf_hc_driver = {
-	.hc_speed = USB_SPEED_SUPER,
 	.name = "XHCI-PCI",
 	.init = hc_driver_init,
@@ -71,5 +69,4 @@
 		.irq_hook       = hcd_interrupt,
 		.status_hook    = hcd_status,
-		.address_device = hcd_address_device,
 	}
 };
@@ -90,4 +87,5 @@
 
 	hcd_set_implementation(hcd, hc, &xhci_ddf_hc_driver.ops, &hc->bus.base);
+	hc->hcd = hcd;
 
 	return EOK;
@@ -126,6 +124,6 @@
 	assert(hc);
 
-	hc->rh.hcd_rh = hcd_roothub_create(hcd, dev, USB_SPEED_SUPER);
-	return hc->rh.hcd_rh ? EOK : ENOMEM;
+	hc->rh.hc_device = dev;
+	return device_init(&hc->rh.device);
 }
 
@@ -153,12 +151,4 @@
 
 	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 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/rh.c	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -38,4 +38,5 @@
 #include <usb/debug.h>
 #include <usb/host/utils/malloc32.h>
+#include <usb/host/bus.h>
 #include <usb/host/ddf_helpers.h>
 
@@ -73,5 +74,5 @@
 // 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 xhci_rh_address_device(xhci_rh_t *rh, device_t *dev)
 {
 	int err;
@@ -81,10 +82,8 @@
 	xhci_cmd_init(&cmd);
 
-	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);
+	const xhci_port_speed_t *speed = xhci_rh_get_port_speed(rh, dev->port);
 
 	xhci_send_enable_slot_command(hc, &cmd);
@@ -109,5 +108,5 @@
 	/* Initialize slot_ctx according to section 4.3.3 point 3. */
 	/* Attaching to root hub port, root string equals to 0. */
-	XHCI_SLOT_ROOT_HUB_PORT_SET(ictx->slot_ctx, port);
+	XHCI_SLOT_ROOT_HUB_PORT_SET(ictx->slot_ctx, dev->port);
 	XHCI_SLOT_CTX_ENTRIES_SET(ictx->slot_ctx, 1);
 	XHCI_SLOT_ROUTE_STRING_SET(ictx->slot_ctx, route_str);
@@ -158,6 +157,6 @@
 	xhci_cmd_fini(&cmd);
 
-	*address = XHCI_SLOT_DEVICE_ADDRESS(dctx->slot_ctx);
-	usb_log_debug2("Obtained USB address: %d.\n", *address);
+	dev->address = XHCI_SLOT_DEVICE_ADDRESS(dctx->slot_ctx);
+	usb_log_debug2("Obtained USB address: %d.\n", dev->address);
 
 	// TODO: Ask libusbhost to create a control endpoint for EP0.
@@ -183,12 +182,45 @@
 }
 
+/** Create a device node for device directly connected to RH.
+ */
 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);
+	int err;
+	assert(rh);
+
+	xhci_bus_t *bus = &rh->hc->bus;
+
+	device_t *dev = hcd_ddf_device_create(rh->hc_device, bus->base.device_size);
+	if (!dev) {
+		usb_log_error("Failed to create USB device function.");
+		return ENOMEM;
+	}
+
+	dev->hub = &rh->device;
+	dev->port = port_id;
+
+	if ((err = xhci_bus_enumerate_device(bus, rh->hc, dev))) {
+		usb_log_error("Failed to enumerate USB device: %s", str_error(err));
+		return err;
+	}
+
+	if (!ddf_fun_get_name(dev->fun)) {
+		device_set_default_name(dev);
+	}
+
+	if ((err = ddf_fun_bind(dev->fun))) {
+		usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err));
+		goto err_usb_dev;
+	}
+
+	fibril_mutex_lock(&rh->device.guard);
+	list_append(&dev->link, &rh->device.devices);
+	fibril_mutex_unlock(&rh->device.guard);
+
+	return EOK;
+
+err_usb_dev:
+	hcd_ddf_device_destroy(dev);
+	return err;
 }
 
Index: uspace/drv/bus/usb/xhci/rh.h
===================================================================
--- uspace/drv/bus/usb/xhci/rh.h	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/drv/bus/usb/xhci/rh.h	(revision 20eaa82bcd1e1ed452c2148cd68afde550e29457)
@@ -38,7 +38,9 @@
 
 #include <usb/host/usb_transfer_batch.h>
+#include <usb/host/bus.h>
 #include "hw_struct/regs.h"
 
 typedef struct xhci_hc xhci_hc_t;
+typedef struct ddf_dev ddf_dev_t;
 
 /**
@@ -58,4 +60,10 @@
 	xhci_hc_t *hc;
 
+	/* Root for the device tree */
+	device_t device;
+
+	/* We need this to attach children to */
+	ddf_dev_t *hc_device;
+
 	/** Port speeds reported from HC */
 	xhci_port_speed_t speeds [16];
@@ -66,7 +74,4 @@
 	/* Number of hub ports. */
 	uint8_t max_ports;
-
-	/* We need this to create child devices */
-	hcd_roothub_t *hcd_rh;
 } xhci_rh_t;
 
@@ -79,5 +84,5 @@
 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 *);
+int xhci_rh_address_device(xhci_rh_t *rh, device_t *dev);
 
 #endif
