Index: uspace/lib/usbhost/src/bus.c
===================================================================
--- uspace/lib/usbhost/src/bus.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/lib/usbhost/src/bus.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -36,16 +36,116 @@
 #include <usb/host/bus.h>
 #include <usb/host/endpoint.h>
+#include <ddf/driver.h>
 
 #include <mem.h>
 #include <errno.h>
+#include <stdio.h>
 
 /**
  * Initializes the bus structure.
  */
-void bus_init(bus_t *bus)
-{
+void bus_init(bus_t *bus, size_t device_size)
+{
+	assert(bus);
+	assert(device_size >= sizeof(device_t));
 	memset(bus, 0, sizeof(bus_t));
 
 	fibril_mutex_initialize(&bus->guard);
+	bus->device_size = device_size;
+}
+
+int device_init(device_t *dev)
+{
+	memset(dev, 0, sizeof(*dev));
+
+	link_initialize(&dev->link);
+	list_initialize(&dev->devices);
+	fibril_mutex_initialize(&dev->guard);
+
+	return EOK;
+}
+
+int bus_add_ep(bus_t *bus, device_t *device, usb_endpoint_t endpoint,
+    usb_direction_t dir, usb_transfer_type_t type, size_t max_packet_size,
+    unsigned packets, size_t size)
+{
+	assert(bus);
+	assert(device);
+
+	/* Temporary reference */
+	endpoint_t *ep = bus_create_endpoint(bus);
+	if (!ep)
+		return ENOMEM;
+
+	ep->target = (usb_target_t) {
+		.address = device->address,
+		.endpoint = endpoint,
+	};
+
+	ep->device = device;
+	ep->direction = dir;
+	ep->transfer_type = type;
+	ep->max_packet_size = max_packet_size;
+	ep->packets = packets;
+
+	ep->bandwidth = bus_count_bw(ep, size);
+
+	const int err = bus_register_endpoint(bus, ep);
+
+	/* drop Temporary reference */
+	endpoint_del_ref(ep);
+
+	return err;
+}
+
+int bus_remove_ep(bus_t *bus, usb_target_t target, usb_direction_t dir)
+{
+	assert(bus);
+	endpoint_t *ep = bus_find_endpoint(bus, target, dir);
+	if (!ep)
+		return ENOENT;
+
+	return bus_release_endpoint(bus, ep);
+}
+
+int device_set_default_name(device_t *dev)
+{
+	assert(dev);
+	assert(dev->fun);
+
+	char buf[10] = { 0 }; /* usbxyz-ss */
+	snprintf(buf, sizeof(buf) - 1, "usb%u-%cs",
+	    dev->address, usb_str_speed(dev->speed)[0]);
+
+	return ddf_fun_set_name(dev->fun, buf);
+}
+
+int bus_enumerate_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(hcd);
+	assert(dev);
+
+	if (!bus->ops.enumerate_device)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.enumerate_device(bus, hcd, dev);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
+}
+
+int bus_remove_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	assert(bus);
+	assert(dev);
+
+	if (!bus->ops.remove_device)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = bus->ops.remove_device(bus, hcd, dev);
+	fibril_mutex_unlock(&bus->guard);
+	return r;
 }
 
@@ -141,18 +241,4 @@
 }
 
-int bus_get_speed(bus_t *bus, usb_address_t address, usb_speed_t *speed)
-{
-	assert(bus);
-	assert(speed);
-
-	if (!bus->ops.get_speed)
-		return ENOTSUP;
-
-	fibril_mutex_lock(&bus->guard);
-	const int r = bus->ops.get_speed(bus, address, speed);
-	fibril_mutex_unlock(&bus->guard);
-	return r;
-}
-
 int bus_reset_toggle(bus_t *bus, usb_target_t target, bool all)
 {
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -35,4 +35,5 @@
 
 #include <usb/classes/classes.h>
+#include <usb/host/bus.h>
 #include <usb/debug.h>
 #include <usb/descriptor.h>
@@ -50,5 +51,4 @@
 #include <fibril_synch.h>
 #include <macros.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <str_error.h>
@@ -56,18 +56,4 @@
 
 #include "ddf_helpers.h"
-
-#define CTRL_PIPE_MIN_PACKET_SIZE 8
-
-typedef struct usb_dev {
-	link_t link;
-	list_t devices;
-	fibril_mutex_t guard;
-	usb_address_t address;
-	usb_speed_t speed;
-	usb_tt_address_t tt;
-
-	/* This must be set iff the usb_dev is managed by ddf_fun. */
-	ddf_fun_t *fun;
-} usb_dev_t;
 
 typedef struct hc_dev {
@@ -92,6 +78,6 @@
 
 
-static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, usb_dev_t *hub_dev, unsigned port);
-static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
+static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port);
+static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, unsigned port);
 
 
@@ -115,10 +101,9 @@
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
+	assert(hcd->bus);
 	assert(dev);
 	const size_t size = max_packet_size;
-	const usb_target_t target =
-	    {{.address = dev->address, .endpoint = endpoint}};
 
 	usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n",
@@ -126,6 +111,6 @@
 	    usb_str_direction(direction), max_packet_size, interval);
 
-	return hcd_add_ep(hcd, target, direction, transfer_type,
-	    max_packet_size, packets, size, dev->tt);
+	return bus_add_ep(hcd->bus, dev, endpoint, direction, transfer_type,
+	    max_packet_size, packets, size);
 }
 
@@ -142,12 +127,15 @@
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
+	assert(hcd->bus);
 	assert(dev);
-	const usb_target_t target =
-	    {{.address = dev->address, .endpoint = endpoint}};
+	const usb_target_t target = {{
+		.address = dev->address,
+		.endpoint = endpoint
+	}};
 	usb_log_debug("Unregister endpoint %d:%d %s.\n",
 	    dev->address, endpoint, usb_str_direction(direction));
-	return hcd_remove_ep(hcd, target, direction);
+	return bus_remove_ep(hcd->bus, target, direction);
 }
 
@@ -156,11 +144,12 @@
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
+	assert(hcd->bus);
 	assert(dev);
 
 	usb_log_debug("Device %d requested default address at %s speed\n",
 	    dev->address, usb_str_speed(speed));
-	return hcd_reserve_default_address(hcd, speed);
+	return bus_reserve_default_address(hcd->bus, speed);
 }
 
@@ -169,10 +158,11 @@
 	assert(fun);
 	hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(hcd);
+	assert(hcd->bus);
 	assert(dev);
 
 	usb_log_debug("Device %d released default address\n", dev->address);
-	return hcd_release_default_address(hcd);
+	return bus_release_default_address(hcd->bus);
 }
 
@@ -184,5 +174,5 @@
 	hcd_t *hcd = dev_to_hcd(hc);
 	assert(hcd);
-	usb_dev_t *hub = ddf_fun_data_get(fun);
+	device_t *hub = ddf_fun_data_get(fun);
 	assert(hub);
 
@@ -196,5 +186,5 @@
 	assert(fun);
 	ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
-	usb_dev_t *dev = ddf_fun_data_get(fun);
+	device_t *dev = ddf_fun_data_get(fun);
 	assert(ddf_dev);
 	assert(dev);
@@ -233,8 +223,8 @@
 {
 	assert(fun);
-	usb_dev_t *usb_dev = ddf_fun_data_get(fun);
-	assert(usb_dev);
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
 	const usb_target_t target = {{
-	    .address =  usb_dev->address,
+	    .address  = dev->address,
 	    .endpoint = endpoint,
 	}};
@@ -259,8 +249,8 @@
 {
 	assert(fun);
-	usb_dev_t *usb_dev = ddf_fun_data_get(fun);
-	assert(usb_dev);
+	device_t *dev = ddf_fun_data_get(fun);
+	assert(dev);
 	const usb_target_t target = {{
-	    .address =  usb_dev->address,
+	    .address  = dev->address,
 	    .endpoint = endpoint,
 	}};
@@ -343,5 +333,5 @@
 }
 
-static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub,
+static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub,
     unsigned port)
 {
@@ -350,4 +340,5 @@
 	hcd_t *hcd = dev_to_hcd(device);
 	assert(hcd);
+	assert(hcd->bus);
 
 	hc_dev_t *hc_dev = dev_to_hc_dev(device);
@@ -356,8 +347,8 @@
 	fibril_mutex_lock(&hub->guard);
 
-	usb_dev_t *victim = NULL;
-
-	list_foreach(hub->devices, link, usb_dev_t, it) {
-		if (it->tt.port == port) {
+	device_t *victim = NULL;
+
+	list_foreach(hub->devices, link, device_t, it) {
+		if (it->port == port) {
 			victim = it;
 			break;
@@ -366,5 +357,6 @@
 	if (victim) {
 		assert(victim->fun);
-		assert(victim->tt.port == port);
+		assert(victim->port == port);
+		assert(victim->hub == hub);
 		list_remove(&victim->link);
 		fibril_mutex_unlock(&hub->guard);
@@ -372,6 +364,7 @@
 		if (ret == EOK) {
 			usb_address_t address = victim->address;
+			bus_remove_device(hcd->bus, hcd, victim);
 			ddf_fun_destroy(victim->fun);
-			hcd_release_address(hcd, address);
+			bus_release_address(hcd->bus, address);
 		} else {
 			usb_log_warning("Failed to unbind device `%s': %s\n",
@@ -384,130 +377,5 @@
 }
 
-#define GET_DEVICE_DESC(size) \
-{ \
-	.request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \
-	    | (USB_REQUEST_TYPE_STANDARD << 5) \
-	    | USB_REQUEST_RECIPIENT_DEVICE, \
-	.request = USB_DEVREQ_GET_DESCRIPTOR, \
-	.value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \
-	.index = uint16_host2usb(0), \
-	.length = uint16_host2usb(size), \
-};
-
-#define SET_ADDRESS(address) \
-{ \
-	.request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \
-	    | (USB_REQUEST_TYPE_STANDARD << 5) \
-	    | USB_REQUEST_RECIPIENT_DEVICE, \
-	.request = USB_DEVREQ_SET_ADDRESS, \
-	.value = uint16_host2usb(address), \
-	.index = uint16_host2usb(0), \
-	.length = uint16_host2usb(0), \
-};
-
-static int hcd_usb2_address_device(hcd_t *hcd, usb_speed_t speed,
-    usb_tt_address_t tt, usb_address_t *out_address)
-{
-	int err;
-
-	static const usb_target_t default_target = {{
-		.address = USB_ADDRESS_DEFAULT,
-		.endpoint = 0,
-	}};
-
-	/** Reserve address early, we want pretty log messages */
-	const usb_address_t address = hcd_request_address(hcd, speed);
-	if (address < 0) {
-		usb_log_error("Failed to reserve new address: %s.",
-		    str_error(address));
-		return address;
-	}
-	usb_log_debug("Device(%d): Reserved new address.", address);
-
-	/* Add default pipe on default address */
-	usb_log_debug("Device(%d): Adding default target (0:0)", address);
-	err = hcd_add_ep(hcd,
-	    default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
-	    CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1, tt);
-	if (err != EOK) {
-		usb_log_error("Device(%d): Failed to add default target: %s.",
-		    address, str_error(err));
-		goto err_address;
-	}
-
-	/* Get max packet size for default pipe */
-	usb_standard_device_descriptor_t desc = { 0 };
-	const usb_device_request_setup_packet_t get_device_desc_8 =
-	    GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
-
-	usb_log_debug("Device(%d): Requesting first 8B of device descriptor.",
-	    address);
-	ssize_t got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN,
-	    &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
-	    "read first 8 bytes of dev descriptor");
-
-	if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
-		err = got < 0 ? got : EOVERFLOW;
-		usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.",
-		    address, str_error(err));
-		goto err_default_target;
-	}
-
-	/* Set new address */
-	const usb_device_request_setup_packet_t set_address = SET_ADDRESS(address);
-
-	usb_log_debug("Device(%d): Setting USB address.", address);
-	err = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT,
-	    NULL, 0, *(uint64_t *)&set_address, "set address");
-	if (err != 0) {
-		usb_log_error("Device(%d): Failed to set new address: %s.",
-		    address, str_error(got));
-		goto err_default_target;
-	}
-
-	*out_address = address;
-
-	usb_target_t control_ep = {
-		.address = address,
-		.endpoint = 0
-	};
-
-	/* Register EP on the new address */
-	usb_log_debug("Device(%d): Registering control EP.", address);
-	err = hcd_add_ep(hcd, control_ep, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
-	    ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
-	    ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)),
-	    ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)), tt);
-	if (err != EOK) {
-		usb_log_error("Device(%d): Failed to register EP0: %s",
-		    address, str_error(err));
-		goto err_default_target;
-	}
-
-	hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
-	return EOK;
-
-
-err_default_target:
-	hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
-err_address:
-	hcd_release_address(hcd, address);
-	return err;
-}
-
-static int usb_dev_init(usb_dev_t *usb_dev, usb_speed_t speed)
-{
-	memset(usb_dev, 0, sizeof(*usb_dev));
-
-	link_initialize(&usb_dev->link);
-	list_initialize(&usb_dev->devices);
-	fibril_mutex_initialize(&usb_dev->guard);
-
-	usb_dev->speed = speed;
-
-	return EOK;
-}
-
-static usb_dev_t *usb_dev_create(ddf_dev_t *hc, usb_speed_t speed)
+device_t *hcd_ddf_device_create(ddf_dev_t *hc, size_t device_size)
 {
 	/* Create DDF function for the new device */
@@ -519,16 +387,16 @@
 
 	/* Create USB device node for the new device */
-	usb_dev_t *usb_dev = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));
-	if (!usb_dev) {
+	device_t *dev = ddf_fun_data_alloc(fun, device_size);
+	if (!dev) {
 		ddf_fun_destroy(fun);
 		return NULL;
 	}
 
-	usb_dev_init(usb_dev, speed);
-	usb_dev->fun = fun;
-	return usb_dev;
-}
-
-static void usb_dev_destroy(usb_dev_t *dev)
+	device_init(dev);
+	dev->fun = fun;
+	return dev;
+}
+
+void hcd_ddf_device_destroy(device_t *dev)
 {
 	assert(dev);
@@ -537,16 +405,5 @@
 }
 
-static int usb_dev_set_default_name(usb_dev_t *usb_dev)
-{
-	assert(usb_dev);
-
-	char buf[10] = { 0 }; /* usbxyz-ss */
-	snprintf(buf, sizeof(buf) - 1, "usb%u-%cs",
-	    usb_dev->address, usb_str_speed(usb_dev->speed)[0]);
-
-	return ddf_fun_set_name(usb_dev->fun, buf);
-}
-
-static int usb_dev_explore(hcd_t *hcd, usb_dev_t *usb_dev)
+int hcd_ddf_device_explore(hcd_t *hcd, device_t *device)
 {
 	int err;
@@ -556,8 +413,8 @@
 	init_match_ids(&mids);
 
-	usb_target_t control_ep = {
-		.address = usb_dev->address,
+	usb_target_t control_ep = {{
+		.address = device->address,
 		.endpoint = 0
-	};
+	}};
 
 	/* Get std device descriptor */
@@ -566,5 +423,5 @@
 
 	usb_log_debug("Device(%d): Requesting full device descriptor.",
-	    usb_dev->address);
+	    device->address);
 	ssize_t got = hcd_send_batch_sync(hcd, control_ep, USB_DIRECTION_IN,
 	    &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
@@ -573,17 +430,17 @@
 		err = got < 0 ? got : EOVERFLOW;
 		usb_log_error("Device(%d): Failed to set get dev descriptor: %s",
-		    usb_dev->address, str_error(err));
+		    device->address, str_error(err));
 		goto out;
 	}
 
 	/* Create match ids from the device descriptor */
-	usb_log_debug("Device(%d): Creating match IDs.", usb_dev->address);
+	usb_log_debug("Device(%d): Creating match IDs.", device->address);
 	if ((err = create_match_ids(&mids, &desc))) {
-		usb_log_error("Device(%d): Failed to create match ids: %s", usb_dev->address, str_error(err));
+		usb_log_error("Device(%d): Failed to create match ids: %s", device->address, str_error(err));
 		goto out;
 	}
 
 	list_foreach(mids.ids, link, const match_id_t, mid) {
-		ddf_fun_add_match_id(usb_dev->fun, mid->id, mid->score);
+		ddf_fun_add_match_id(device->fun, mid->id, mid->score);
 	}
 
@@ -593,78 +450,46 @@
 }
 
-static int hcd_address_device(hcd_t *hcd, usb_dev_t *usb_dev)
-{
-	if (hcd->ops.address_device)
-		return hcd->ops.address_device(hcd, usb_dev->speed, usb_dev->tt, &usb_dev->address);
-	else
-		return hcd_usb2_address_device(hcd, usb_dev->speed, usb_dev->tt, &usb_dev->address);
-}
-
-static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, usb_dev_t *hub_dev, unsigned port)
+static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port)
 {
 	int err;
 	assert(hcd);
-	assert(hub_dev);
+	assert(hcd->bus);
+	assert(hub);
 	assert(hc);
 
-	usb_speed_t speed = USB_SPEED_MAX;
-	/* The speed of the new device was reported by the hub when reserving
-	 * default address.
+	device_t *dev = hcd_ddf_device_create(hc, hcd->bus->device_size);
+	if (!dev) {
+		usb_log_error("Failed to create USB device function.");
+		return ENOMEM;
+	}
+
+	dev->hub = hub;
+	dev->port = port;
+
+	if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) {
+		usb_log_error("Failed to initialize USB dev memory structures.");
+		return err;
+	}
+
+	/* If the driver didn't name the dev when enumerating,
+	 * do it in some generic way.
 	 */
-	if ((err = bus_get_speed(hcd->bus, USB_ADDRESS_DEFAULT, &speed))) {
-		usb_log_error("Failed to verify speed: %s.", str_error(err));
-		return err;
-	}
-	usb_log_debug("Found new %s speed USB device.", usb_str_speed(speed));
-
-	usb_dev_t *usb_dev = usb_dev_create(hc, speed);
-	if (!usb_dev) {
-		usb_log_error("Failed to create USB device function.");
-		return err;
-	}
-
-	/* For devices under HS hub */
-	/* TODO: How about SS hubs? */
-	if (hub_dev->speed == USB_SPEED_HIGH && usb_speed_is_11(speed)) {
-		usb_dev->tt.address = hub_dev->address;
-	}
-	else {
-		/* Inherit hub's TT */
-		usb_dev->tt.address = hub_dev->tt.address;
-	}
-	usb_dev->tt.port = port;
-
-	/* Assign an address to the device */
-	if ((err = hcd_address_device(hcd, usb_dev))) {
-		usb_log_error("Failed to setup address of the new device: %s", str_error(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;
 	}
 
-	/* Read the device descriptor, derive the match ids */
-	if ((err = usb_dev_explore(hcd, usb_dev))) {
-		usb_log_error("Device(%d): Failed to explore device: %s", usb_dev->address, str_error(err));
-		goto err_usb_dev;
-	}
-
-	/* If the driver didn't name the device when addressing/exploring,
-	 * do it insome generic way.
-	 */
-	if (!ddf_fun_get_name(usb_dev->fun)) {
-		usb_dev_set_default_name(usb_dev);
-	}
-
-	if ((err = ddf_fun_bind(usb_dev->fun))) {
-		usb_log_error("Device(%d): Failed to register: %s.", usb_dev->address, str_error(err));
-		goto err_usb_dev;
-	}
-
-	fibril_mutex_lock(&hub_dev->guard);
-	list_append(&usb_dev->link, &hub_dev->devices);
-	fibril_mutex_unlock(&hub_dev->guard);
+	fibril_mutex_lock(&hub->guard);
+	list_append(&dev->link, &hub->devices);
+	fibril_mutex_unlock(&hub->guard);
 
 	return EOK;
 
 err_usb_dev:
-	usb_dev_destroy(usb_dev);
+	hcd_ddf_device_destroy(dev);
 	return err;
 }
@@ -681,45 +506,42 @@
 	assert(hc);
 	assert(hcd);
-
-	if ((err = hcd_reserve_default_address(hcd, USB_SPEED_MAX))) {
+	assert(hcd->bus);
+
+	if ((err = bus_reserve_default_address(hcd->bus, USB_SPEED_MAX))) {
 		usb_log_error("Failed to reserve default address for roothub setup: %s", str_error(err));
 		return err;
 	}
 
-	usb_dev_t *usb_dev = usb_dev_create(hc, USB_SPEED_MAX);
-	if (!usb_dev) {
+	device_t *dev = hcd_ddf_device_create(hc, USB_SPEED_MAX);
+	if (!dev) {
 		usb_log_error("Failed to create function for the root hub.");
 		goto err_default_address;
 	}
 
-	usb_dev->tt.address = -1;
-	usb_dev->tt.port = 0;
+	ddf_fun_set_name(dev->fun, "roothub");
+
+	dev->tt = (usb_tt_address_t) {
+		.address = -1,
+		.port = 0,
+	};
 
 	/* Assign an address to the device */
-	if ((err = hcd_address_device(hcd, usb_dev))) {
-		usb_log_error("Failed to setup roothub address: %s", str_error(err));
+	if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) {
+		usb_log_error("Failed to enumerate roothub device: %s", str_error(err));
 		goto err_usb_dev;
 	}
 
-	/* Read the device descriptor, derive the match ids */
-	if ((err = usb_dev_explore(hcd, usb_dev))) {
-		usb_log_error("Failed to explore roothub: %s", str_error(err));
-		goto err_usb_dev;
-	}
-
-	ddf_fun_set_name(usb_dev->fun, "roothub");
-
-	if ((err = ddf_fun_bind(usb_dev->fun))) {
+	if ((err = ddf_fun_bind(dev->fun))) {
 		usb_log_error("Failed to register roothub: %s.", str_error(err));
 		goto err_usb_dev;
 	}
 
-	hcd_release_default_address(hcd);
+	bus_release_default_address(hcd->bus);
 	return EOK;
 
 err_usb_dev:
-	usb_dev_destroy(usb_dev);
+	hcd_ddf_device_destroy(dev);
 err_default_address:
-	hcd_release_default_address(hcd);
+	bus_release_default_address(hcd->bus);
 	return err;
 }
@@ -1043,25 +865,4 @@
 }
 
-struct hcd_roothub {
-	hcd_t *hcd;
-	ddf_dev_t *hc_dev;
-	usb_dev_t rh_usb;
-};
-
-hcd_roothub_t *hcd_roothub_create(hcd_t *hcd, ddf_dev_t *dev, usb_speed_t speed)
-{
-	hcd_roothub_t *rh = malloc(sizeof(*rh));
-
-	rh->hcd = hcd;
-	rh->hc_dev = dev;
-	usb_dev_init(&rh->rh_usb, speed);
-
-	rh->rh_usb.tt.address = -1;
-	return rh;
-}
-
-int hcd_roothub_new_device(hcd_roothub_t *rh, unsigned port) {
-	return hcd_ddf_new_device(rh->hcd, rh->hc_dev, &rh->rh_usb, port);
-}
 /**
  * @}
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/lib/usbhost/src/hcd.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -45,48 +45,4 @@
 
 
-/*[>* Calls ep_add_hook upon endpoint registration.
- * @param ep Endpoint to be registered.
- * @param arg hcd_t in disguise.
- * @return Error code.
- * OH TODO: remove
- <]
-static int register_helper(endpoint_t *ep, void *arg)
-{
-	hcd_t *hcd = arg;
-	assert(ep);
-	assert(hcd);
-	if (hcd->ops.ep_add_hook)
-		return hcd->ops.ep_add_hook(hcd, ep);
-	return EOK;
-}
-
-[>* Calls ep_remove_hook upon endpoint removal.
- * @param ep Endpoint to be unregistered.
- * @param arg hcd_t in disguise.
- * OH TODO: remove
- <]
-static void unregister_helper(endpoint_t *ep, void *arg)
-{
-	hcd_t *hcd = arg;
-	assert(ep);
-	assert(hcd);
-	if (hcd->ops.ep_remove_hook)
-		hcd->ops.ep_remove_hook(hcd, ep);
-}
-
-[>* Calls ep_remove_hook upon endpoint removal. Prints warning.
- *  * @param ep Endpoint to be unregistered.
- *   * @param arg hcd_t in disguise.
- * OH TODO: remove
- *    <]
-static void unregister_helper_warn(endpoint_t *ep, void *arg)
-{
-        assert(ep);
-        usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
-            ep->target.address, ep->target.endpoint, usb_str_direction(ep->direction));
-	unregister_helper(ep, arg);
-}
-*/
-
 /** Initialize hcd_t structure.
  * Initializes device and endpoint managers. Sets data and hook pointer to NULL.
@@ -112,58 +68,4 @@
 	return address;
 }
-
-int hcd_release_address(hcd_t *hcd, usb_address_t address)
-{
-	assert(hcd);
-	return bus_release_address(hcd->bus, address);
-	// OH TODO removed helper
-}
-
-int hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed)
-{
-	assert(hcd);
-	usb_address_t address = 0;
-	return bus_request_address(hcd->bus, &address, true, speed);
-}
-
-int hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir,
-    usb_transfer_type_t type, size_t max_packet_size, unsigned packets,
-    size_t size, usb_tt_address_t tt)
-{
-	assert(hcd);
-
-	/* Temporary reference */
-	endpoint_t *ep = bus_create_endpoint(hcd->bus);
-	if (!ep)
-		return ENOMEM;
-
-	ep->target = target;
-	ep->direction = dir;
-	ep->transfer_type = type;
-	ep->max_packet_size = max_packet_size;
-	ep->packets = packets;
-	ep->tt = tt;
-
-	ep->bandwidth = bus_count_bw(ep, size);
-
-	const int err = bus_register_endpoint(hcd->bus, ep);
-
-	/* drop Temporary reference */
-	endpoint_del_ref(ep);
-
-	return err;
-}
-
-int hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir)
-{
-	assert(hcd);
-	endpoint_t *ep = bus_find_endpoint(hcd->bus, target, dir);
-	if (!ep)
-		return ENOENT;
-
-	return bus_release_endpoint(hcd->bus, ep);
-	// OH TODO removed helper
-}
-
 
 typedef struct {
Index: uspace/lib/usbhost/src/usb2_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb2_bus.c	(revision 867b3757d6898c102509e02a34857fa95c832191)
+++ uspace/lib/usbhost/src/usb2_bus.c	(revision 2770b669432a0a3478940311f193e80df63b07b8)
@@ -36,9 +36,14 @@
 #include <usb/host/usb2_bus.h>
 #include <usb/host/endpoint.h>
+#include <usb/host/ddf_helpers.h>
 #include <usb/debug.h>
+#include <usb/request.h>
+#include <usb/descriptor.h>
+#include <usb/usb.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <macros.h>
+#include <str_error.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -61,4 +66,152 @@
 	assert(addr >= 0);
 	return &bus->devices[addr % ARRAY_SIZE(bus->devices)].endpoint_list;
+}
+
+/** Get speed assigned to USB address.
+ *
+ * @param[in] bus Device manager structure to use.
+ * @param[in] address Address the caller wants to find.
+ * @param[out] speed Assigned speed.
+ * @return Error code.
+ */
+static int usb2_bus_get_speed(bus_t *bus_base, usb_address_t address, usb_speed_t *speed)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+
+	if (!usb_address_is_valid(address)) {
+		return EINVAL;
+	}
+
+	const int ret = bus->devices[address].occupied ? EOK : ENOENT;
+	if (speed && bus->devices[address].occupied) {
+		*speed = bus->devices[address].speed;
+	}
+
+	return ret;
+}
+
+static int usb2_bus_address_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	int err;
+
+	static const usb_target_t default_target = {{
+		.address = USB_ADDRESS_DEFAULT,
+		.endpoint = 0,
+	}};
+
+	/** Reserve address early, we want pretty log messages */
+	const usb_address_t address = bus_reserve_default_address(bus, dev->speed);
+	if (address < 0) {
+		usb_log_error("Failed to reserve new address: %s.",
+		    str_error(address));
+		return address;
+	}
+	usb_log_debug("Device(%d): Reserved new address.", address);
+
+	/* Add default pipe on default address */
+	usb_log_debug("Device(%d): Adding default target (0:0)", address);
+	err = bus_add_ep(bus, dev, 0, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
+	    CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1);
+	if (err != EOK) {
+		usb_log_error("Device(%d): Failed to add default target: %s.",
+		    address, str_error(err));
+		goto err_address;
+	}
+
+	/* Get max packet size for default pipe */
+	usb_standard_device_descriptor_t desc = { 0 };
+	const usb_device_request_setup_packet_t get_device_desc_8 =
+	    GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
+
+	usb_log_debug("Device(%d): Requesting first 8B of device descriptor.",
+	    address);
+	ssize_t got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN,
+	    &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
+	    "read first 8 bytes of dev descriptor");
+
+	if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
+		err = got < 0 ? got : EOVERFLOW;
+		usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.",
+		    address, str_error(err));
+		goto err_default_target;
+	}
+
+	/* Set new address */
+	const usb_device_request_setup_packet_t set_address = SET_ADDRESS(address);
+
+	usb_log_debug("Device(%d): Setting USB address.", address);
+	err = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT,
+	    NULL, 0, *(uint64_t *)&set_address, "set address");
+	if (err != 0) {
+		usb_log_error("Device(%d): Failed to set new address: %s.",
+		    address, str_error(got));
+		goto err_default_target;
+	}
+
+	dev->address = address;
+
+	/* Register EP on the new address */
+	usb_log_debug("Device(%d): Registering control EP.", address);
+	err = bus_add_ep(bus, dev, 0, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
+	    ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),
+	    ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)),
+	    ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)));
+	if (err != EOK) {
+		usb_log_error("Device(%d): Failed to register EP0: %s",
+		    address, str_error(err));
+		goto err_default_target;
+	}
+
+	bus_remove_ep(bus, default_target, USB_DIRECTION_BOTH);
+	return EOK;
+
+err_default_target:
+	bus_remove_ep(bus, default_target, USB_DIRECTION_BOTH);
+err_address:
+	bus_release_address(bus, address);
+	return err;
+}
+
+/** Enumerate a new USB device
+ */
+static int usb2_bus_enumerate_device(bus_t *bus, hcd_t *hcd, device_t *dev)
+{
+	int err;
+
+	/* The speed of the new device was reported by the hub when reserving
+	 * default address.
+	 */
+	if ((err = usb2_bus_get_speed(bus, USB_ADDRESS_DEFAULT, &dev->speed))) {
+		usb_log_error("Failed to verify speed: %s.", str_error(err));
+		return err;
+	}
+	usb_log_debug("Found new %s speed USB device.", usb_str_speed(dev->speed));
+
+	/* 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 = usb2_bus_address_device(bus, hcd, 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(hcd, dev))) {
+		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
+		bus_release_address(bus, dev->address);
+		return err;
+	}
+
+	return EOK;
 }
 
@@ -190,6 +343,4 @@
  * @param endpoint USB endpoint number.
  * @param direction Communication direction.
- * @param callback Function to call after unregister, before destruction.
- * @arg Argument to pass to the callback function.
  * @return Error code.
  */
@@ -211,4 +362,7 @@
 		list_remove(&ep->link);
 
+		usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
+		    ep->target.address, ep->target.endpoint, usb_str_direction(ep->direction));
+
 		/* Drop bus reference */
 		endpoint_del_ref(ep);
@@ -258,28 +412,6 @@
 }
 
-/** Get speed assigned to USB address.
- *
- * @param[in] bus Device manager structure to use.
- * @param[in] address Address the caller wants to find.
- * @param[out] speed Assigned speed.
- * @return Error code.
- */
-static int usb2_bus_get_speed(bus_t *bus_base, usb_address_t address, usb_speed_t *speed)
-{
-	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
-
-	if (!usb_address_is_valid(address)) {
-		return EINVAL;
-	}
-
-	const int ret = bus->devices[address].occupied ? EOK : ENOENT;
-	if (speed && bus->devices[address].occupied) {
-		*speed = bus->devices[address].speed;
-	}
-
-	return ret;
-}
-
 static const bus_ops_t usb2_bus_ops = {
+	.enumerate_device = usb2_bus_enumerate_device,
 	.create_endpoint = usb2_bus_create_ep,
 	.find_endpoint = usb2_bus_find_ep,
@@ -289,5 +421,4 @@
 	.release_address = usb2_bus_release_address,
 	.reset_toggle = usb2_bus_reset_toggle,
-	.get_speed = usb2_bus_get_speed,
 };
 
@@ -303,5 +434,5 @@
 	assert(bus);
 
-	bus_init(&bus->base);
+	bus_init(&bus->base, sizeof(device_t));
 
 	bus->base.ops = usb2_bus_ops;
