Index: uspace/drv/bus/usb/ehci/ehci_bus.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.c	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/ehci/ehci_bus.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -57,4 +57,9 @@
 }
 
+static int ehci_device_enumerate(device_t *dev)
+{
+	ehci_bus_t *bus = (ehci_bus_t *) dev->bus;
+	return usb2_bus_device_enumerate(&bus->helper, dev);
+}
 
 /** Creates new hcd endpoint representation.
@@ -101,5 +106,5 @@
 	ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);
 
-	const int err = usb2_bus_ops.endpoint_register(ep);
+	const int err = usb2_bus_endpoint_register(&bus->helper, ep);
 	if (err)
 		return err;
@@ -119,5 +124,5 @@
 	assert(ep);
 
-	usb2_bus_ops.endpoint_unregister(ep);
+	usb2_bus_endpoint_unregister(&bus->helper, ep);
 	hc_dequeue_endpoint(hc, ep);
 	/*
@@ -154,8 +159,8 @@
 
 static const bus_ops_t ehci_bus_ops = {
-	.parent = &usb2_bus_ops,
-
 	.interrupt = ehci_hc_interrupt,
 	.status = ehci_hc_status,
+
+	.device_enumerate = ehci_device_enumerate,
 
 	.endpoint_destroy = ehci_endpoint_destroy,
@@ -174,9 +179,9 @@
 	assert(bus);
 
-	usb2_bus_t *usb2_bus = (usb2_bus_t *) bus;
 	bus_t *bus_base = (bus_t *) bus;
+	bus_init(bus_base, sizeof(device_t));
+	bus_base->ops = &ehci_bus_ops;
 
-	usb2_bus_init(usb2_bus, &bandwidth_accounting_usb2);
-	bus_base->ops = &ehci_bus_ops;
+	usb2_bus_helper_init(&bus->helper, &bandwidth_accounting_usb2);
 
 	bus->hc = hc;
Index: uspace/drv/bus/usb/ehci/ehci_bus.h
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.h	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/ehci/ehci_bus.h	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -64,5 +64,6 @@
 
 typedef struct {
-	usb2_bus_t base;
+	bus_t base;
+	usb2_bus_helper_t helper;
 	hc_t *hc;
 } ehci_bus_t;
Index: uspace/drv/bus/usb/ohci/ohci_bus.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_bus.c	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/ohci/ohci_bus.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -57,4 +57,10 @@
 }
 
+static int ohci_device_enumerate(device_t *dev)
+{
+	ohci_bus_t *bus = (ohci_bus_t *) dev->bus;
+	return usb2_bus_device_enumerate(&bus->helper, dev);
+}
+
 /** Creates new hcd endpoint representation.
  */
@@ -109,5 +115,5 @@
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
 
-	const int err = usb2_bus_ops.endpoint_register(ep);
+	const int err = usb2_bus_endpoint_register(&bus->helper, ep);
 	if (err)
 		return err;
@@ -126,5 +132,5 @@
 	assert(ep);
 
-	usb2_bus_ops.endpoint_unregister(ep);
+	usb2_bus_endpoint_unregister(&bus->helper, ep);
 	hc_dequeue_endpoint(bus->hc, ep);
 
@@ -162,8 +168,8 @@
 
 static const bus_ops_t ohci_bus_ops = {
-	.parent = &usb2_bus_ops,
-
 	.interrupt = ohci_hc_interrupt,
 	.status = ohci_hc_status,
+
+	.device_enumerate = ohci_device_enumerate,
 
 	.endpoint_destroy = ohci_endpoint_destroy,
@@ -183,9 +189,9 @@
 	assert(bus);
 
-	usb2_bus_t *usb2_bus = (usb2_bus_t *) bus;
 	bus_t *bus_base = (bus_t *) bus;
-
-	usb2_bus_init(usb2_bus, &bandwidth_accounting_usb11);
+	bus_init(bus_base, sizeof(device_t));
 	bus_base->ops = &ohci_bus_ops;
+
+	usb2_bus_helper_init(&bus->helper, &bandwidth_accounting_usb11);
 
 	bus->hc = hc;
Index: uspace/drv/bus/usb/ohci/ohci_bus.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_bus.h	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/ohci/ohci_bus.h	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -60,5 +60,6 @@
 
 typedef struct {
-	usb2_bus_t base;
+	bus_t base;
+	usb2_bus_helper_t helper;
 	hc_t *hc;
 } ohci_bus_t;
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -329,5 +329,5 @@
 	hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
 
-	const int err = usb2_bus_ops.endpoint_register(ep);
+	const int err = usb2_bus_endpoint_register(&hc->bus_helper, ep);
 	if (err)
 		return err;
@@ -350,5 +350,5 @@
 {
 	hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
-	usb2_bus_ops.endpoint_unregister(ep);
+	usb2_bus_endpoint_unregister(&hc->bus_helper, ep);
 
 	// Check for the roothub, as it does not schedule into lists
@@ -406,12 +406,18 @@
 }
 
+static int device_enumerate(device_t *dev)
+{
+	hc_t * const hc = bus_to_hc(dev->bus);
+	return usb2_bus_device_enumerate(&hc->bus_helper, dev);
+}
+
 static int hc_status(bus_t *, uint32_t *);
 static int hc_schedule(usb_transfer_batch_t *);
 
 static const bus_ops_t uhci_bus_ops = {
-	.parent = &usb2_bus_ops,
-
 	.interrupt = hc_interrupt,
 	.status = hc_status,
+
+	.device_enumerate = device_enumerate,
 
 	.endpoint_create = endpoint_create,
@@ -438,10 +444,10 @@
 	assert(instance);
 
-	usb2_bus_init(&instance->bus, &bandwidth_accounting_usb11);
-
-	bus_t *bus = (bus_t *) &instance->bus;
-	bus->ops = &uhci_bus_ops;
-
-	hc_device_setup(&instance->base, bus);
+	usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
+
+	bus_init(&instance->bus, sizeof(device_t));
+	instance->bus.ops = &uhci_bus_ops;
+
+	hc_device_setup(&instance->base, &instance->bus);
 
 	/* Init USB frame list page */
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -104,5 +104,7 @@
 
 	uhci_rh_t rh;
-	usb2_bus_t bus;
+	bus_t bus;
+	usb2_bus_helper_t bus_helper;
+
 	/** Addresses of I/O registers */
 	uhci_regs_t *registers;
Index: uspace/drv/bus/usb/vhc/transfer.c
===================================================================
--- uspace/drv/bus/usb/vhc/transfer.c	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/vhc/transfer.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -163,9 +163,31 @@
 }
 
+static int device_enumerate(device_t *device)
+{
+	vhc_data_t *vhc = bus_to_vhc(device->bus);
+	return usb2_bus_device_enumerate(&vhc->bus_helper, device);
+}
+
+static int endpoint_register(endpoint_t *endpoint)
+{
+	vhc_data_t *vhc = bus_to_vhc(endpoint->device->bus);
+	return usb2_bus_endpoint_register(&vhc->bus_helper, endpoint);
+}
+
+static void endpoint_unregister(endpoint_t *endpoint)
+{
+	vhc_data_t *vhc = bus_to_vhc(endpoint->device->bus);
+	usb2_bus_endpoint_unregister(&vhc->bus_helper, endpoint);
+
+	// TODO: abort transfer?
+}
+
 static const bus_ops_t vhc_bus_ops = {
-	.parent = &usb2_bus_ops,
-
 	.batch_create = batch_create,
 	.batch_schedule = vhc_schedule,
+
+	.device_enumerate = device_enumerate,
+	.endpoint_register = endpoint_register,
+	.endpoint_unregister = endpoint_unregister,
 };
 
@@ -175,6 +197,7 @@
 	list_initialize(&instance->devices);
 	fibril_mutex_initialize(&instance->guard);
-	usb2_bus_init(&instance->bus, &bandwidth_accounting_usb11);
-	instance->bus.base.ops = &vhc_bus_ops;
+	bus_init(&instance->bus, sizeof(device_t));
+	usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
+	instance->bus.ops = &vhc_bus_ops;
 	return virthub_init(&instance->hub, "root hub");
 }
Index: uspace/drv/bus/usb/vhc/vhcd.h
===================================================================
--- uspace/drv/bus/usb/vhc/vhcd.h	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/drv/bus/usb/vhc/vhcd.h	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -60,5 +60,7 @@
 	hc_device_t base;
 
-	usb2_bus_t bus;
+	bus_t bus;
+	usb2_bus_helper_t bus_helper;
+
 	ddf_fun_t *virtual_fun;
 	list_t devices;
