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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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 d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -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;
Index: uspace/lib/usbhost/include/usb/host/usb2_bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -47,8 +47,6 @@
 typedef struct endpoint endpoint_t;
 
-/** Endpoint management structure */
-typedef struct usb2_bus {
-	bus_t base;			/**< Inheritance - keep this first */
-
+/** Endpoint and bandwidth management structure */
+typedef struct usb2_bus_helper {
 	/** Map of occupied addresses */
 	bool address_occupied [USB_ADDRESS_COUNT];
@@ -61,9 +59,11 @@
 	/* Configured bandwidth accounting */
 	const bandwidth_accounting_t *bw_accounting;
-} usb2_bus_t;
+} usb2_bus_helper_t;
 
-extern const bus_ops_t usb2_bus_ops;
+extern void usb2_bus_helper_init(usb2_bus_helper_t *, const bandwidth_accounting_t *);
 
-extern void usb2_bus_init(usb2_bus_t *, const bandwidth_accounting_t *);
+extern int usb2_bus_device_enumerate(usb2_bus_helper_t *, device_t *);
+extern int usb2_bus_endpoint_register(usb2_bus_helper_t *, endpoint_t *);
+extern void usb2_bus_endpoint_unregister(usb2_bus_helper_t *, endpoint_t *);
 
 #endif
Index: uspace/lib/usbhost/src/usb2_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb2_bus.c	(revision b3573772a2359da2498360d630ee4e92272fd61c)
+++ uspace/lib/usbhost/src/usb2_bus.c	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
@@ -54,13 +54,4 @@
 
 /**
- * Ops receive generic bus_t pointer.
- */
-static inline usb2_bus_t *bus_to_usb2_bus(bus_t *bus_base)
-{
-	assert(bus_base);
-	return (usb2_bus_t *) bus_base;
-}
-
-/**
  * Request a new address. A free address is found and marked as occupied.
  *
@@ -71,19 +62,19 @@
  * @param addr Pointer to requested address value, place to store new address
  */
-static int request_address(usb2_bus_t *bus, usb_address_t *addr)
+static int request_address(usb2_bus_helper_t *helper, usb_address_t *addr)
 {
 	// Find a free address
-	usb_address_t new_address = bus->last_address;
+	usb_address_t new_address = helper->last_address;
 	do {
 		new_address = (new_address + 1) % USB_ADDRESS_COUNT;
 		if (new_address == USB_ADDRESS_DEFAULT)
 			new_address = 1;
-		if (new_address == bus->last_address)
+		if (new_address == helper->last_address)
 			return ENOSPC;
-	} while (bus->address_occupied[new_address]);
-	bus->last_address = new_address;
+	} while (helper->address_occupied[new_address]);
+	helper->last_address = new_address;
 
 	*addr = new_address;
-	bus->address_occupied[*addr] = true;
+	helper->address_occupied[*addr] = true;
 
 	return EOK;
@@ -93,7 +84,7 @@
  * Mark address as free.
  */
-static void release_address(usb2_bus_t *bus, usb_address_t address)
-{
-	bus->address_occupied[address] = false;
+static void release_address(usb2_bus_helper_t *helper, usb_address_t address)
+{
+	helper->address_occupied[address] = false;
 }
 
@@ -109,9 +100,7 @@
  * Configure the device with the new address,
  */
-static int address_device(device_t *dev)
+static int address_device(usb2_bus_helper_t *helper, device_t *dev)
 {
 	int err;
-
-	usb2_bus_t *bus = (usb2_bus_t *) dev->bus;
 
 	/* The default address is currently reserved for this device */
@@ -120,5 +109,5 @@
 	/** Reserve address early, we want pretty log messages */
 	usb_address_t address = USB_ADDRESS_DEFAULT;
-	if ((err = request_address(bus, &address))) {
+	if ((err = request_address(helper, &address))) {
 		usb_log_error("Failed to reserve new address: %s.",
 		    str_error(err));
@@ -141,5 +130,5 @@
 	}
 
-	if ((err = hc_get_ep0_max_packet_size(&ep0_desc.endpoint.max_packet_size, &bus->base, dev)))
+	if ((err = hc_get_ep0_max_packet_size(&ep0_desc.endpoint.max_packet_size, dev->bus, dev)))
 		goto err_address;
 
@@ -178,5 +167,5 @@
 	bus_endpoint_remove(default_ep);
 err_address:
-	release_address(bus, address);
+	release_address(helper, address);
 	return err;
 }
@@ -186,13 +175,11 @@
  * to create a DDF function node with proper characteristics.
  */
-static int usb2_bus_device_enumerate(device_t *dev)
+int usb2_bus_device_enumerate(usb2_bus_helper_t *helper, device_t *dev)
 {
 	int err;
-	usb2_bus_t *bus = bus_to_usb2_bus(dev->bus);
-
 	usb_log_debug("Found new %s speed USB device.", usb_str_speed(dev->speed));
 
 	/* Assign an address to the device */
-	if ((err = address_device(dev))) {
+	if ((err = address_device(helper, dev))) {
 		usb_log_error("Failed to setup address of the new device: %s", str_error(err));
 		return err;
@@ -202,5 +189,5 @@
 	if ((err = hc_device_explore(dev))) {
 		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
-		release_address(bus, dev->address);
+		release_address(helper, dev->address);
 		return err;
 	}
@@ -210,70 +197,46 @@
 
 /**
- * Call the bus operation to count bandwidth.
- *
- * @param ep Endpoint on which the transfer will take place.
- * @param size The payload size.
- */
-static ssize_t endpoint_count_bw(endpoint_t *ep)
+ * Register an endpoint to the bus. Reserves bandwidth.
+ */
+int usb2_bus_endpoint_register(usb2_bus_helper_t *helper, endpoint_t *ep)
 {
 	assert(ep);
-
-	usb2_bus_t *bus = bus_to_usb2_bus(ep->device->bus);
-
-	return bus->bw_accounting->count_bw(ep);
-}
-
-/**
- * Register an endpoint to the bus. Reserves bandwidth.
- */
-static int usb2_bus_register_ep(endpoint_t *ep)
-{
-	usb2_bus_t *bus = bus_to_usb2_bus(ep->device->bus);
 	assert(fibril_mutex_is_locked(&ep->device->guard));
+
+	size_t bw = helper->bw_accounting->count_bw(ep);
+
+	/* Check for available bandwidth */
+	if (bw > helper->free_bw)
+		return ENOSPC;
+
+	helper->free_bw -= bw;
+
+	return EOK;
+}
+
+/**
+ * Release bandwidth reserved by the given endpoint.
+ */
+void usb2_bus_endpoint_unregister(usb2_bus_helper_t *helper, endpoint_t *ep)
+{
+	assert(helper);
 	assert(ep);
 
-	size_t bw = endpoint_count_bw(ep);
-
-	/* Check for available bandwidth */
-	if (bw > bus->free_bw)
-		return ENOSPC;
-
-	bus->free_bw -= bw;
-
-	return EOK;
-}
-
-/**
- * Release bandwidth reserved by the given endpoint.
- */
-static void usb2_bus_unregister_ep(endpoint_t *ep)
-{
-	usb2_bus_t *bus = bus_to_usb2_bus(ep->device->bus);
-	assert(ep);
-
-	bus->free_bw += endpoint_count_bw(ep);
-}
-
-const bus_ops_t usb2_bus_ops = {
-	.device_enumerate = usb2_bus_device_enumerate,
-	.endpoint_register = usb2_bus_register_ep,
-	.endpoint_unregister = usb2_bus_unregister_ep,
-};
-
-/** Initialize to default state.
- *
- * @param bus usb_bus structure, non-null.
- * @param available_bandwidth Size of the bandwidth pool.
- */
-void usb2_bus_init(usb2_bus_t *bus, const bandwidth_accounting_t *bw_accounting)
-{
-	assert(bus);
+	helper->free_bw += helper->bw_accounting->count_bw(ep);
+}
+
+/**
+ * Initialize to default state.
+ *
+ * @param helper usb_bus_helper structure, non-null.
+ * @param bw_accounting a structure defining bandwidth accounting
+ */
+void usb2_bus_helper_init(usb2_bus_helper_t *helper, const bandwidth_accounting_t *bw_accounting)
+{
+	assert(helper);
 	assert(bw_accounting);
 
-	bus_init(&bus->base, sizeof(device_t));
-	bus->base.ops = &usb2_bus_ops;
-
-	bus->bw_accounting = bw_accounting;
-	bus->free_bw = bw_accounting->available_bandwidth;
+	helper->bw_accounting = bw_accounting;
+	helper->free_bw = bw_accounting->available_bandwidth;
 
 	/*
@@ -282,5 +245,5 @@
 	 * address 1.
 	 */
-	bus->last_address = USB_ADDRESS_COUNT - 2;
+	helper->last_address = USB_ADDRESS_COUNT - 2;
 }
 
