Index: uspace/drv/bus/usb/ehci/ehci_bus.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ehci/ehci_bus.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -79,7 +79,7 @@
 /** Creates new hcd endpoint representation.
  */
-static endpoint_t *ehci_endpoint_create(bus_t *bus)
+static endpoint_t *ehci_endpoint_create(device_t *dev, const usb_endpoint_desc_t *desc)
 {
-	assert(bus);
+	assert(dev);
 
 	ehci_endpoint_t *ehci_ep = malloc(sizeof(ehci_endpoint_t));
@@ -87,5 +87,7 @@
 		return NULL;
 
-	endpoint_init(&ehci_ep->base, bus);
+	endpoint_init(&ehci_ep->base, dev, desc);
+
+	// TODO: extract USB2 information from desc
 
 	ehci_ep->qh = malloc32(sizeof(qh_t));
@@ -114,12 +116,12 @@
 
 
-static int ehci_register_ep(bus_t *bus_base, device_t *dev, endpoint_t *ep, const usb_endpoint_desc_t *desc)
+static int ehci_register_ep(endpoint_t *ep)
 {
+	bus_t *bus_base = endpoint_get_bus(ep);
 	ehci_bus_t *bus = (ehci_bus_t *) bus_base;
 	ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);
+	assert(fibril_mutex_is_locked(&bus_base->guard));
 
-	// TODO utilize desc->usb2
-
-	const int err = bus->parent_ops.register_endpoint(bus_base, dev, ep, desc);
+	const int err = usb2_bus_ops.endpoint_register(ep);
 	if (err)
 		return err;
@@ -131,11 +133,12 @@
 }
 
-static int ehci_unregister_ep(bus_t *bus_base, endpoint_t *ep)
+static int ehci_unregister_ep(endpoint_t *ep)
 {
+	bus_t *bus_base = endpoint_get_bus(ep);
 	ehci_bus_t *bus = (ehci_bus_t *) bus_base;
 	assert(bus);
 	assert(ep);
 
-	const int err = bus->parent_ops.unregister_endpoint(bus_base, ep);
+	const int err = usb2_bus_ops.endpoint_unregister(ep);
 	if (err)
 		return err;
@@ -145,5 +148,5 @@
 }
 
-static usb_transfer_batch_t *ehci_bus_create_batch(bus_t *bus, endpoint_t *ep)
+static usb_transfer_batch_t *ehci_create_batch(endpoint_t *ep)
 {
 	ehci_transfer_batch_t *batch = ehci_transfer_batch_create(ep);
@@ -151,29 +154,33 @@
 }
 
-static void ehci_bus_destroy_batch(usb_transfer_batch_t *batch)
+static void ehci_destroy_batch(usb_transfer_batch_t *batch)
 {
 	ehci_transfer_batch_destroy(ehci_transfer_batch_get(batch));
 }
 
-int ehci_bus_init(ehci_bus_t *bus, hc_t *hc)
+static const bus_ops_t ehci_bus_ops = {
+	.parent = &usb2_bus_ops,
+
+	.endpoint_destroy = ehci_endpoint_destroy,
+	.endpoint_create = ehci_endpoint_create,
+	.endpoint_register = ehci_register_ep,
+	.endpoint_unregister = ehci_unregister_ep,
+	.endpoint_set_toggle = ehci_ep_toggle_set,
+	.endpoint_get_toggle = ehci_ep_toggle_get,
+	.endpoint_count_bw = bandwidth_count_usb11,
+	.batch_create = ehci_create_batch,
+	.batch_destroy = ehci_destroy_batch,
+};
+
+int ehci_bus_init(ehci_bus_t *bus, hcd_t *hcd, hc_t *hc)
 {
 	assert(hc);
 	assert(bus);
 
-	// FIXME: Implement the USB2 bw counting.
-	usb2_bus_init(&bus->base, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
+	usb2_bus_t *usb2_bus = (usb2_bus_t *) bus;
+	bus_t *bus_base = (bus_t *) bus;
 
-	bus_ops_t *ops = &bus->base.base.ops;
-	bus->parent_ops = *ops;
-	ops->create_endpoint = ehci_endpoint_create;
-	ops->destroy_endpoint = ehci_endpoint_destroy;
-	ops->endpoint_set_toggle = ehci_ep_toggle_set;
-	ops->endpoint_get_toggle = ehci_ep_toggle_get;
-
-	ops->register_endpoint = ehci_register_ep;
-	ops->unregister_endpoint = ehci_unregister_ep;
-
-	ops->create_batch = ehci_bus_create_batch;
-	ops->destroy_batch = ehci_bus_destroy_batch;
+	usb2_bus_init(usb2_bus, hcd, BANDWIDTH_AVAILABLE_USB11);
+	bus_base->ops = &ehci_bus_ops;
 
 	bus->hc = hc;
Index: uspace/drv/bus/usb/ehci/ehci_bus.h
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_bus.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ehci/ehci_bus.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -59,10 +59,9 @@
 	usb2_bus_t base;
 	hc_t *hc;
-
-	/* Stored original ops from base, they are called in our handlers */
-	bus_ops_t parent_ops;
 } ehci_bus_t;
 
-int ehci_bus_init(ehci_bus_t *, hc_t *);
+void ehci_bus_prepare_ops(void);
+
+int ehci_bus_init(ehci_bus_t *, hcd_t *, hc_t *);
 
 /** Get and convert assigned ehci_endpoint_t structure
Index: uspace/drv/bus/usb/ehci/hc.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ehci/hc.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -149,5 +149,5 @@
  * @return Error code
  */
-int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res)
+int hc_init(hc_t *instance, hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
 {
 	assert(instance);
@@ -190,5 +190,5 @@
 	    &instance->rh, instance->caps, instance->registers, "ehci rh");
 
-	ehci_bus_init(&instance->bus, instance);
+	ehci_bus_init(&instance->bus, hcd, instance);
 	return EOK;
 }
Index: uspace/drv/bus/usb/ehci/hc.h
===================================================================
--- uspace/drv/bus/usb/ehci/hc.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ehci/hc.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -85,5 +85,5 @@
 } hc_t;
 
-int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res);
+int hc_init(hc_t *instance, hcd_t *hcd, const hw_res_list_parsed_t *hw_res);
 int hc_start(hc_t *instance, bool interrupts);
 void hc_fini(hc_t *instance);
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -81,5 +81,5 @@
 		return ENOMEM;
 
-	const int ret = hc_init(instance, res);
+	const int ret = hc_init(instance, hcd, res);
 	if (ret == EOK) {
 		hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops, &instance->bus.base.base);
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ohci/main.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -83,5 +83,5 @@
 		goto err;
 
-	if ((err = ohci_bus_init(&instance->bus, instance)))
+	if ((err = ohci_bus_init(&instance->bus, hcd, instance)))
 		goto err;
 
Index: uspace/drv/bus/usb/ohci/ohci_bus.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_bus.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ohci/ohci_bus.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -72,7 +72,7 @@
 /** Creates new hcd endpoint representation.
  */
-static endpoint_t *ohci_endpoint_create(bus_t *bus)
+static endpoint_t *ohci_endpoint_create(device_t *dev, const usb_endpoint_desc_t *desc)
 {
-	assert(bus);
+	assert(dev);
 
 	ohci_endpoint_t *ohci_ep = malloc(sizeof(ohci_endpoint_t));
@@ -80,5 +80,5 @@
 		return NULL;
 
-	endpoint_init(&ohci_ep->base, bus);
+	endpoint_init(&ohci_ep->base, dev, desc);
 
 	ohci_ep->ed = malloc32(sizeof(ed_t));
@@ -115,10 +115,11 @@
 
 
-static int ohci_register_ep(bus_t *bus_base, device_t *dev, endpoint_t *ep, const usb_endpoint_desc_t *desc)
+static int ohci_register_ep(endpoint_t *ep)
 {
+	bus_t *bus_base = endpoint_get_bus(ep);
 	ohci_bus_t *bus = (ohci_bus_t *) bus_base;
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
 
-	const int err = bus->parent_ops.register_endpoint(bus_base, dev, ep, desc);
+	const int err = usb2_bus_ops.endpoint_register(ep);
 	if (err)
 		return err;
@@ -130,11 +131,10 @@
 }
 
-static int ohci_unregister_ep(bus_t *bus_base, endpoint_t *ep)
+static int ohci_unregister_ep(endpoint_t *ep)
 {
-	ohci_bus_t *bus = (ohci_bus_t *) bus_base;
-	assert(bus);
+	ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(ep);
 	assert(ep);
 
-	const int err = bus->parent_ops.unregister_endpoint(bus_base, ep);
+	const int err = usb2_bus_ops.endpoint_unregister(ep);
 	if (err)
 		return err;
@@ -144,5 +144,5 @@
 }
 
-static usb_transfer_batch_t *ohci_bus_create_batch(bus_t *bus, endpoint_t *ep)
+static usb_transfer_batch_t *ohci_create_batch(endpoint_t *ep)
 {
 	ohci_transfer_batch_t *batch = ohci_transfer_batch_create(ep);
@@ -150,28 +150,35 @@
 }
 
-static void ohci_bus_destroy_batch(usb_transfer_batch_t *batch)
+static void ohci_destroy_batch(usb_transfer_batch_t *batch)
 {
 	ohci_transfer_batch_destroy(ohci_transfer_batch_get(batch));
 }
 
-int ohci_bus_init(ohci_bus_t *bus, hc_t *hc)
+static const bus_ops_t ohci_bus_ops = {
+	.parent = &usb2_bus_ops,
+
+	.endpoint_destroy = ohci_endpoint_destroy,
+	.endpoint_create = ohci_endpoint_create,
+	.endpoint_register = ohci_register_ep,
+	.endpoint_unregister = ohci_unregister_ep,
+	.endpoint_count_bw = bandwidth_count_usb11,
+	.endpoint_set_toggle = ohci_ep_toggle_set,
+	.endpoint_get_toggle = ohci_ep_toggle_get,
+	.batch_create = ohci_create_batch,
+	.batch_destroy = ohci_destroy_batch,
+};
+
+
+int ohci_bus_init(ohci_bus_t *bus, hcd_t *hcd, hc_t *hc)
 {
 	assert(hc);
 	assert(bus);
 
-	usb2_bus_init(&bus->base, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
 
-	bus_ops_t *ops = &bus->base.base.ops;
-	bus->parent_ops = *ops;
-	ops->create_endpoint = ohci_endpoint_create;
-	ops->destroy_endpoint = ohci_endpoint_destroy;
-	ops->endpoint_set_toggle = ohci_ep_toggle_set;
-	ops->endpoint_get_toggle = ohci_ep_toggle_get;
+	usb2_bus_t *usb2_bus = (usb2_bus_t *) bus;
+	bus_t *bus_base = (bus_t *) bus;
 
-	ops->register_endpoint = ohci_register_ep;
-	ops->unregister_endpoint = ohci_unregister_ep;
-
-	ops->create_batch = ohci_bus_create_batch;
-	ops->destroy_batch = ohci_bus_destroy_batch;
+	usb2_bus_init(usb2_bus, hcd, BANDWIDTH_AVAILABLE_USB11);
+	bus_base->ops = &ohci_bus_ops;
 
 	bus->hc = hc;
Index: uspace/drv/bus/usb/ohci/ohci_bus.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_bus.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/ohci/ohci_bus.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -60,10 +60,7 @@
 	usb2_bus_t base;
 	hc_t *hc;
-
-	/* Stored original ops from base, they are called in our handlers */
-	bus_ops_t parent_ops;
 } ohci_bus_t;
 
-int ohci_bus_init(ohci_bus_t *, hc_t *);
+int ohci_bus_init(ohci_bus_t *, hcd_t *, hc_t *);
 
 /** Get and convert assigned ohci_endpoint_t structure
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -95,5 +95,5 @@
 
 static void hc_init_hw(const hc_t *instance);
-static int hc_init_mem_structures(hc_t *instance);
+static int hc_init_mem_structures(hc_t *instance, hcd_t *);
 static int hc_init_transfer_lists(hc_t *instance);
 
@@ -215,5 +215,5 @@
  * interrupt fibrils.
  */
-int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res)
+int hc_init(hc_t *instance, hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
 {
 	assert(instance);
@@ -238,5 +238,5 @@
 	    hw_res->io_ranges.ranges[0].size);
 
-	ret = hc_init_mem_structures(instance);
+	ret = hc_init_mem_structures(instance, hcd);
 	if (ret != EOK) {
 		usb_log_error("Failed to init UHCI memory structures: %s.\n",
@@ -309,5 +309,5 @@
 }
 
-static usb_transfer_batch_t *create_transfer_batch(bus_t *bus, endpoint_t *ep)
+static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep)
 {
 	uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);
@@ -319,4 +319,12 @@
 	uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
 }
+
+static const bus_ops_t uhci_bus_ops = {
+	.parent = &usb2_bus_ops,
+
+	.endpoint_count_bw = bandwidth_count_usb11,
+	.batch_create = create_transfer_batch,
+	.batch_destroy = destroy_transfer_batch,
+};
 
 /** Initialize UHCI hc memory structures.
@@ -330,14 +338,14 @@
  *  - frame list page (needs to be one UHCI hw accessible 4K page)
  */
-int hc_init_mem_structures(hc_t *instance)
+int hc_init_mem_structures(hc_t *instance, hcd_t *hcd)
 {
 	int err;
 	assert(instance);
 
-	if ((err = usb2_bus_init(&instance->bus, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11)))
+	if ((err = usb2_bus_init(&instance->bus, hcd, BANDWIDTH_AVAILABLE_USB11)))
 		return err;
 
-	instance->bus.base.ops.create_batch = create_transfer_batch;
-	instance->bus.base.ops.destroy_batch = destroy_transfer_batch;
+	bus_t *bus = (bus_t *) &instance->bus;
+	bus->ops = &uhci_bus_ops;
 
 	/* Init USB frame list page */
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -126,5 +126,5 @@
 } hc_t;
 
-extern int hc_init(hc_t *, const hw_res_list_parsed_t *);
+extern int hc_init(hc_t *, hcd_t *, const hw_res_list_parsed_t *);
 extern void hc_start(hc_t *);
 extern void hc_fini(hc_t *);
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/uhci/main.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -80,5 +80,5 @@
 		return ENOMEM;
 
-	if ((err = hc_init(instance, res)) != EOK)
+	if ((err = hc_init(instance, hcd, res)) != EOK)
 		goto err;
 
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -69,5 +69,5 @@
 		return ret;
 	}
-	vhc_init(vhc);
+	vhc_init(vhc, dev_to_hcd(dev));
 	return EOK;
 }
Index: uspace/drv/bus/usb/vhc/transfer.c
===================================================================
--- uspace/drv/bus/usb/vhc/transfer.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/vhc/transfer.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -157,10 +157,16 @@
 }
 
-int vhc_init(vhc_data_t *instance)
+static const bus_ops_t vhc_bus_ops = {
+	.parent = &usb2_bus_ops,
+	.endpoint_count_bw = bandwidth_count_usb11,
+};
+
+int vhc_init(vhc_data_t *instance, hcd_t *hcd)
 {
 	assert(instance);
 	list_initialize(&instance->devices);
 	fibril_mutex_initialize(&instance->guard);
-	usb2_bus_init(&instance->bus, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
+	usb2_bus_init(&instance->bus, hcd, BANDWIDTH_AVAILABLE_USB11);
+	instance->bus.base.ops = &vhc_bus_ops;
 	instance->magic = 0xDEADBEEF;
 	return virthub_init(&instance->hub, "root hub");
Index: uspace/drv/bus/usb/vhc/vhcd.h
===================================================================
--- uspace/drv/bus/usb/vhc/vhcd.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/vhc/vhcd.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -77,5 +77,5 @@
 void vhc_virtdev_unplug(vhc_data_t *, uintptr_t);
 
-int vhc_init(vhc_data_t *instance);
+int vhc_init(vhc_data_t *instance, hcd_t *);
 int vhc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
 int vhc_transfer_queue_processor(void *arg);
Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -58,50 +58,17 @@
 };
 
-static int prepare_endpoint(xhci_endpoint_t *ep, const usb_endpoint_desc_t *desc)
-{
-	/* Extract information from endpoint_desc */
-	ep->base.endpoint = desc->endpoint_no;
-	ep->base.direction = desc->direction;
-	ep->base.transfer_type = desc->transfer_type;
-	ep->base.max_packet_size = desc->max_packet_size;
-	ep->base.packets = desc->packets;
-	ep->max_streams = desc->usb3.max_streams;
-	ep->max_burst = desc->usb3.max_burst;
-	ep->mult = desc->usb3.mult;
-
-	if (ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS) {
-		if (ep->base.device->speed <= USB_SPEED_HIGH) {
-			ep->isoch_max_size = desc->max_packet_size * (desc->packets + 1);
-		}
-		else if (ep->base.device->speed == USB_SPEED_SUPER) {
-			ep->isoch_max_size = desc->usb3.bytes_per_interval;
-		}
-		/* Technically there could be superspeed plus too. */
-
-		/* Allocate and setup isochronous-specific structures. */
-		ep->isoch_enqueue = 0;
-		ep->isoch_dequeue = XHCI_ISOCH_BUFFER_COUNT - 1;
-		ep->isoch_started = false;
-
-		fibril_mutex_initialize(&ep->isoch_guard);
-		fibril_condvar_initialize(&ep->isoch_avail);
-	}
-
-	return xhci_endpoint_alloc_transfer_ds(ep);
-}
-
-static endpoint_t *create_endpoint(bus_t *base);
-
-static int address_device(xhci_hc_t *hc, xhci_device_t *dev)
+static endpoint_t *endpoint_create(device_t *, const usb_endpoint_desc_t *);
+
+static int address_device(xhci_bus_t *bus, xhci_device_t *dev)
 {
 	int err;
 
 	/* Enable new slot. */
-	if ((err = hc_enable_slot(hc, &dev->slot_id)) != EOK)
+	if ((err = hc_enable_slot(bus->hc, &dev->slot_id)) != EOK)
 		return err;
 	usb_log_debug2("Obtained slot ID: %u.\n", dev->slot_id);
 
 	/* Create and configure control endpoint. */
-	endpoint_t *ep0_base = create_endpoint(&hc->bus.base);
+	endpoint_t *ep0_base = endpoint_create(&dev->base, &ep0_initial_desc);
 	if (!ep0_base)
 		goto err_slot;
@@ -112,5 +79,5 @@
 	xhci_endpoint_t *ep0 = xhci_endpoint_get(ep0_base);
 
-	if ((err = prepare_endpoint(ep0, &ep0_initial_desc)))
+	if ((err = xhci_endpoint_alloc_transfer_ds(ep0)))
 		goto err_ep;
 
@@ -120,5 +87,5 @@
 
 	/* Address device */
-	if ((err = hc_address_device(hc, dev, ep0)))
+	if ((err = hc_address_device(bus->hc, dev, ep0)))
 		goto err_added;
 
@@ -135,5 +102,5 @@
 	endpoint_del_ref(ep0_base);
 err_slot:
-	hc_disable_slot(hc, dev);
+	hc_disable_slot(bus->hc, dev);
 	return err;
 }
@@ -164,5 +131,5 @@
 }
 
-int xhci_bus_enumerate_device(xhci_bus_t *bus, xhci_hc_t *hc, device_t *dev)
+int xhci_bus_enumerate_device(xhci_bus_t *bus, device_t *dev)
 {
 	int err;
@@ -184,5 +151,5 @@
 
 	/* Assign an address to the device */
-	if ((err = address_device(hc, xhci_dev))) {
+	if ((err = address_device(bus, xhci_dev))) {
 		usb_log_error("Failed to setup address of the new device: %s", str_error(err));
 		return err;
@@ -195,5 +162,5 @@
 	fibril_mutex_unlock(&bus->base.guard);
 
-	if ((err = setup_ep0_packet_size(hc, xhci_dev))) {
+	if ((err = setup_ep0_packet_size(bus->hc, xhci_dev))) {
 		usb_log_error("Failed to setup control endpoint of the new device: %s", str_error(err));
 		goto err_address;
@@ -201,5 +168,5 @@
 
 	/* Read the device descriptor, derive the match ids */
-	if ((err = hcd_ddf_device_explore(hc->hcd, dev))) {
+	if ((err = hcd_ddf_device_explore(dev))) {
 		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
 		goto err_address;
@@ -213,7 +180,7 @@
 }
 
-static int unregister_endpoint(bus_t *, endpoint_t *);
-
-int xhci_bus_remove_device(xhci_bus_t *bus, xhci_hc_t *hc, device_t *dev)
+static int endpoint_unregister(endpoint_t *);
+
+int xhci_bus_remove_device(xhci_bus_t *bus, device_t *dev)
 {
 	int err;
@@ -246,5 +213,5 @@
 	/* Disable the slot, dropping all endpoints. */
 	const uint32_t slot_id = xhci_dev->slot_id;
-	if ((err = hc_disable_slot(hc, xhci_dev))) {
+	if ((err = hc_disable_slot(bus->hc, xhci_dev))) {
 		usb_log_warning("Failed to disable slot of device " XHCI_DEV_FMT ": %s",
 		    XHCI_DEV_ARGS(*xhci_dev), str_error(err));
@@ -258,5 +225,5 @@
 			continue;
 
-		if ((err = unregister_endpoint(&bus->base, &xhci_dev->endpoints[i]->base))) {
+		if ((err = endpoint_unregister(&xhci_dev->endpoints[i]->base))) {
 			usb_log_warning("Failed to unregister endpoint " XHCI_EP_FMT ": %s",
 			    XHCI_EP_ARGS(*xhci_dev->endpoints[i]), str_error(err));
@@ -278,34 +245,21 @@
 }
 
-static int enumerate_device(bus_t *bus_base, hcd_t *hcd, device_t *dev)
-{
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
-	assert(bus);
-
-	return xhci_bus_enumerate_device(bus, hc, dev);
-}
-
-static int remove_device(bus_t *bus_base, hcd_t *hcd, device_t *dev)
-{
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
-	assert(bus);
-
-	return xhci_bus_remove_device(bus, hc, dev);
-}
-
-static int online_device(bus_t *bus_base, hcd_t *hcd, device_t *dev_base)
-{
-	int err;
-
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
+static int device_enumerate(device_t *dev)
+{
+	xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
+	return xhci_bus_enumerate_device(bus, dev);
+}
+
+static int device_remove(device_t *dev)
+{
+	xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
+	return xhci_bus_remove_device(bus, dev);
+}
+
+static int device_online(device_t *dev_base)
+{
+	int err;
+
+	xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);
 	assert(bus);
 
@@ -314,5 +268,5 @@
 
 	/* Transition the device from the Addressed to the Configured state. */
-	if ((err = hc_configure_device(hc, dev->slot_id))) {
+	if ((err = hc_configure_device(bus->hc, dev->slot_id))) {
 		usb_log_warning("Failed to configure device " XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*dev));
 	}
@@ -331,12 +285,9 @@
 }
 
-static int offline_device(bus_t *bus_base, hcd_t *hcd, device_t *dev_base)
-{
-	int err;
-
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
+static int device_offline(device_t *dev_base)
+{
+	int err;
+
+	xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);
 	assert(bus);
 
@@ -370,5 +321,5 @@
 
 	/* Issue one HC command to simultaneously drop all endpoints except zero. */
-	if ((err = hc_deconfigure_device(hc, dev->slot_id))) {
+	if ((err = hc_deconfigure_device(bus->hc, dev->slot_id))) {
 		usb_log_warning("Failed to deconfigure device " XHCI_DEV_FMT ".",
 		    XHCI_DEV_ARGS(*dev));
@@ -388,13 +339,11 @@
 }
 
-static endpoint_t *create_endpoint(bus_t *base)
-{
-	xhci_bus_t *bus = bus_to_xhci_bus(base);
-
+static endpoint_t *endpoint_create(device_t *dev, const usb_endpoint_desc_t *desc)
+{
 	xhci_endpoint_t *ep = calloc(1, sizeof(xhci_endpoint_t));
 	if (!ep)
 		return NULL;
 
-	if (xhci_endpoint_init(ep, bus)) {
+	if (xhci_endpoint_init(ep, dev, desc)) {
 		free(ep);
 		return NULL;
@@ -404,5 +353,5 @@
 }
 
-static void destroy_endpoint(endpoint_t *ep)
+static void endpoint_destroy(endpoint_t *ep)
 {
 	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
@@ -412,13 +361,13 @@
 }
 
-static int register_endpoint(bus_t *bus_base, device_t *device, endpoint_t *ep_base, const usb_endpoint_desc_t *desc)
-{
-	int err;
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
+static int endpoint_register(endpoint_t *ep_base)
+{
+	int err;
+	xhci_bus_t *bus = bus_to_xhci_bus(endpoint_get_bus(ep_base));
 	xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
 
-	xhci_device_t *dev = xhci_device_get(device);
-
-	if ((err = prepare_endpoint(ep, desc)))
+	xhci_device_t *dev = xhci_device_get(ep_base->device);
+
+	if ((err = xhci_endpoint_alloc_transfer_ds(ep)))
 		return err;
 
@@ -443,8 +392,8 @@
 }
 
-static int unregister_endpoint(bus_t *bus_base, endpoint_t *ep_base)
-{
-	int err;
-	xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
+static int endpoint_unregister(endpoint_t *ep_base)
+{
+	int err;
+	xhci_bus_t *bus = bus_to_xhci_bus(endpoint_get_bus(ep_base));
 	xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
 	xhci_device_t *dev = xhci_device_get(ep_base->device);
@@ -470,5 +419,5 @@
 }
 
-static endpoint_t* find_endpoint(bus_t *bus_base, device_t *dev_base, usb_target_t target, usb_direction_t direction)
+static endpoint_t* device_find_endpoint(device_t *dev_base, usb_target_t target, usb_direction_t direction)
 {
 	xhci_device_t *dev = xhci_device_get(dev_base);
@@ -487,10 +436,4 @@
 }
 
-static size_t count_bw(endpoint_t *ep, size_t size)
-{
-	// TODO: Implement me!
-	return 0;
-}
-
 /* Endpoint ops, optional (have generic fallback) */
 static bool endpoint_get_toggle(endpoint_t *ep)
@@ -525,5 +468,5 @@
 }
 
-static usb_transfer_batch_t *create_batch(bus_t *bus, endpoint_t *ep)
+static usb_transfer_batch_t *batch_create(endpoint_t *ep)
 {
 	xhci_transfer_t *transfer = xhci_transfer_create(ep);
@@ -531,5 +474,5 @@
 }
 
-static void destroy_batch(usb_transfer_batch_t *batch)
+static void batch_destroy(usb_transfer_batch_t *batch)
 {
 	xhci_transfer_destroy(xhci_transfer_from_batch(batch));
@@ -538,28 +481,23 @@
 static const bus_ops_t xhci_bus_ops = {
 #define BIND_OP(op) .op = op,
-	BIND_OP(enumerate_device)
-	BIND_OP(remove_device)
-
-	BIND_OP(online_device)
-	BIND_OP(offline_device)
-
-	BIND_OP(create_endpoint)
-	BIND_OP(destroy_endpoint)
-
-	BIND_OP(register_endpoint)
-	BIND_OP(unregister_endpoint)
-	BIND_OP(find_endpoint)
-
 	BIND_OP(reserve_default_address)
 	BIND_OP(release_default_address)
-
 	BIND_OP(reset_toggle)
-	BIND_OP(count_bw)
-
+
+	BIND_OP(device_enumerate)
+	BIND_OP(device_remove)
+	BIND_OP(device_online)
+	BIND_OP(device_offline)
+	BIND_OP(device_find_endpoint)
+
+	BIND_OP(endpoint_create)
+	BIND_OP(endpoint_destroy)
+	BIND_OP(endpoint_register)
+	BIND_OP(endpoint_unregister)
 	BIND_OP(endpoint_get_toggle)
 	BIND_OP(endpoint_set_toggle)
 
-	BIND_OP(create_batch)
-	BIND_OP(destroy_batch)
+	BIND_OP(batch_create)
+	BIND_OP(batch_destroy)
 #undef BIND_OP
 };
@@ -569,5 +507,5 @@
 	assert(bus);
 
-	bus_init(&bus->base, sizeof(xhci_device_t));
+	bus_init(&bus->base, hc->hcd, sizeof(xhci_device_t));
 
 	bus->devices_by_slot = calloc(hc->max_slots, sizeof(xhci_device_t *));
@@ -576,5 +514,5 @@
 
 	bus->hc = hc;
-	bus->base.ops = xhci_bus_ops;
+	bus->base.ops = &xhci_bus_ops;
 	bus->default_address_speed = USB_SPEED_MAX;
 	return EOK;
Index: uspace/drv/bus/usb/xhci/bus.h
===================================================================
--- uspace/drv/bus/usb/xhci/bus.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/bus.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -58,6 +58,6 @@
 void xhci_bus_fini(xhci_bus_t *);
 
-int xhci_bus_enumerate_device(xhci_bus_t *, xhci_hc_t *, device_t *);
-int xhci_bus_remove_device(xhci_bus_t *, xhci_hc_t *, device_t *);
+int xhci_bus_enumerate_device(xhci_bus_t *, device_t *);
+int xhci_bus_remove_device(xhci_bus_t *, device_t *);
 
 #endif
Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -45,13 +45,30 @@
 #include "endpoint.h"
 
-int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, xhci_bus_t *xhci_bus)
+int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, device_t *dev, const usb_endpoint_desc_t *desc)
 {
 	assert(xhci_ep);
-	assert(xhci_bus);
-
-	bus_t *bus = &xhci_bus->base;
+
 	endpoint_t *ep = &xhci_ep->base;
 
-	endpoint_init(ep, bus);
+	endpoint_init(ep, dev, desc);
+
+	xhci_ep->max_streams = desc->usb3.max_streams;
+	xhci_ep->max_burst = desc->usb3.max_burst;
+	xhci_ep->mult = desc->usb3.mult;
+
+	if (xhci_ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS) {
+		xhci_ep->isoch_max_size = desc->usb3.bytes_per_interval
+			? desc->usb3.bytes_per_interval
+			: desc->max_packet_size * (desc->packets + 1);
+		/* Technically there could be superspeed plus too. */
+
+		/* Allocate and setup isochronous-specific structures. */
+		xhci_ep->isoch_enqueue = 0;
+		xhci_ep->isoch_dequeue = XHCI_ISOCH_BUFFER_COUNT - 1;
+		xhci_ep->isoch_started = false;
+
+		fibril_mutex_initialize(&xhci_ep->isoch_guard);
+		fibril_condvar_initialize(&xhci_ep->isoch_avail);
+	}
 
 	return EOK;
Index: uspace/drv/bus/usb/xhci/endpoint.h
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/endpoint.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -149,5 +149,5 @@
 #define XHCI_DEV_ARGS(dev)		 ddf_fun_get_name((dev).base.fun), (dev).slot_id
 
-int xhci_endpoint_init(xhci_endpoint_t *, xhci_bus_t *);
+int xhci_endpoint_init(xhci_endpoint_t *, device_t *, const usb_endpoint_desc_t *);
 void xhci_endpoint_fini(xhci_endpoint_t *);
 int xhci_endpoint_alloc_transfer_ds(xhci_endpoint_t *);
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -212,15 +212,14 @@
 		goto err_scratch;
 
+	if ((err = xhci_bus_init(&hc->bus, hc)))
+		goto err_cmd;
+
 	if ((err = xhci_rh_init(&hc->rh, hc, device)))
-		goto err_cmd;
-
-	if ((err = xhci_bus_init(&hc->bus, hc)))
-		goto err_rh;
-
-
-	return EOK;
-
-err_rh:
-	xhci_rh_fini(&hc->rh);
+		goto err_bus;
+
+	return EOK;
+
+err_bus:
+	xhci_bus_fini(&hc->bus);
 err_cmd:
 	xhci_fini_commands(hc);
Index: uspace/drv/bus/usb/xhci/main.c
===================================================================
--- uspace/drv/bus/usb/xhci/main.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/main.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -82,9 +82,10 @@
 		goto err;
 
+	hc->hcd = hcd;
+
 	if ((err = hc_init_memory(hc, device)))
 		goto err;
 
 	hcd_set_implementation(hcd, hc, &xhci_ddf_hc_driver.ops, &hc->bus.base);
-	hc->hcd = hcd;
 
 	return EOK;
Index: uspace/drv/bus/usb/xhci/rh.c
===================================================================
--- uspace/drv/bus/usb/xhci/rh.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/drv/bus/usb/xhci/rh.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -71,5 +71,5 @@
 	rh->hc_device = device;
 
-	const int err = device_init(&rh->device.base);
+	const int err = bus_device_init(&rh->device.base, &rh->hc->bus.base);
 	if (err)
 		return err;
@@ -94,5 +94,5 @@
 	xhci_bus_t *bus = &rh->hc->bus;
 
-	device_t *dev = hcd_ddf_device_create(rh->hc_device, bus->base.device_size);
+	device_t *dev = hcd_ddf_device_create(rh->hc_device, &bus->base);
 	if (!dev) {
 		usb_log_error("Failed to create USB device function.");
@@ -109,5 +109,5 @@
 	dev->speed = port_speed->usb_speed;
 
-	if ((err = xhci_bus_enumerate_device(bus, rh->hc, dev))) {
+	if ((err = xhci_bus_enumerate_device(bus, dev))) {
 		usb_log_error("Failed to enumerate USB device: %s", str_error(err));
 		return err;
@@ -115,5 +115,5 @@
 
 	if (!ddf_fun_get_name(dev->fun)) {
-		device_set_default_name(dev);
+		bus_device_set_default_name(dev);
 	}
 
@@ -196,5 +196,5 @@
 
 	/* Remove device from XHCI bus. */
-	if ((err = xhci_bus_remove_device(&rh->hc->bus, rh->hc, &dev->base))) {
+	if ((err = xhci_bus_remove_device(&rh->hc->bus, &dev->base))) {
 		usb_log_warning("Failed to remove device " XHCI_DEV_FMT " from XHCI bus: %s",
 		    XHCI_DEV_ARGS(*dev), str_error(err));
Index: uspace/lib/usbhost/include/usb/host/bandwidth.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/bandwidth.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/include/usb/host/bandwidth.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -51,7 +51,7 @@
 typedef struct endpoint endpoint_t;
 
-extern size_t bandwidth_count_usb11(endpoint_t *, size_t);
+extern ssize_t bandwidth_count_usb11(endpoint_t *, size_t);
 
-extern size_t bandwidth_count_usb20(endpoint_t *, size_t);
+extern ssize_t bandwidth_count_usb20(endpoint_t *, size_t);
 
 #endif
Index: uspace/lib/usbhost/include/usb/host/bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/bus.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/include/usb/host/bus.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -77,33 +77,50 @@
 	usb_address_t address;
 
+	/* Managing bus */
+	bus_t *bus;
+
 	/* This structure is meant to be extended by overriding. */
 } device_t;
 
-typedef struct {
-	int (*enumerate_device)(bus_t *, hcd_t *, device_t *);
-	int (*remove_device)(bus_t *, hcd_t *, device_t *);
+typedef struct bus_ops bus_ops_t;
 
-	int (*online_device)(bus_t *, hcd_t *, device_t *);			/**< Optional */
-	int (*offline_device)(bus_t *, hcd_t *, device_t *);			/**< Optional */
+/**
+ * Operations structure serving as an interface of hc driver for the library
+ * (and the rest of the system).
+ */
+struct bus_ops {
+	/* Undefined operations will be delegated to parent ops */
+	const bus_ops_t *parent;
 
-	/* The following operations are protected by a bus guard. */
-	endpoint_t *(*create_endpoint)(bus_t *);
-	int (*register_endpoint)(bus_t *, device_t *, endpoint_t *, const usb_endpoint_desc_t *);
-	int (*unregister_endpoint)(bus_t *, endpoint_t *);
-	endpoint_t *(*find_endpoint)(bus_t *, device_t*, usb_target_t, usb_direction_t);
-	void (*destroy_endpoint)(endpoint_t *);			/**< Optional */
+	/* Global operations on the bus */
+	int (*reserve_default_address)(bus_t *, usb_speed_t);
+	int (*release_default_address)(bus_t *);
+	int (*reset_toggle)(bus_t *, usb_target_t, toggle_reset_mode_t);
+
+	/* Operations on device */
+	int (*device_enumerate)(device_t *);
+	int (*device_remove)(device_t *);
+	int (*device_online)(device_t *);			/**< Optional */
+	int (*device_offline)(device_t *);			/**< Optional */
+	endpoint_t *(*device_find_endpoint)(device_t*, usb_target_t, usb_direction_t);
+	endpoint_t *(*endpoint_create)(device_t *, const usb_endpoint_desc_t *);
+
+	/* Operations on endpoint */
+	int (*endpoint_register)(endpoint_t *);
+	int (*endpoint_unregister)(endpoint_t *);
+	void (*endpoint_destroy)(endpoint_t *);			/**< Optional */
 	bool (*endpoint_get_toggle)(endpoint_t *);		/**< Optional */
 	void (*endpoint_set_toggle)(endpoint_t *, bool);	/**< Optional */
+	ssize_t (*endpoint_count_bw) (endpoint_t *, size_t);
+	usb_transfer_batch_t *(*batch_create)(endpoint_t *);	/**< Optional */
 
-	int (*reserve_default_address)(bus_t *, usb_speed_t);
-	int (*release_default_address)(bus_t *);
+	/* Operations on batch */
+	void (*batch_destroy)(usb_transfer_batch_t *);	/**< Optional */
+};
 
-	int (*reset_toggle)(bus_t *, usb_target_t, toggle_reset_mode_t);
-
-	size_t (*count_bw) (endpoint_t *, size_t);
-
-	usb_transfer_batch_t *(*create_batch)(bus_t *, endpoint_t *); /**< Optional */
-	void (*destroy_batch)(usb_transfer_batch_t *);	/**< Optional */
-} bus_ops_t;
+/**
+ * Use this macro to lookup virtual function.
+ */
+#define BUS_OPS_LOOKUP(start, fn) ({ bus_ops_t const * ops = (start); while (ops && ops->fn == NULL) ops = ops->parent; ops; })
 
 /** Endpoint management structure */
@@ -112,28 +129,29 @@
 	fibril_mutex_t guard;
 
+	/* TODO: get rid of this one. */
+	hcd_t *hcd;
+
 	size_t device_size;
 
 	/* Do not call directly, ops are synchronized. */
-	bus_ops_t ops;
+	const bus_ops_t *ops;
 
 	/* This structure is meant to be extended by overriding. */
 } bus_t;
 
-void bus_init(bus_t *, size_t);
-int device_init(device_t *);
+void bus_init(bus_t *, hcd_t *, size_t);
+int bus_device_init(device_t *, bus_t *);
 
-int device_set_default_name(device_t *);
+int bus_device_set_default_name(device_t *);
 
-int bus_enumerate_device(bus_t *, hcd_t *, device_t *);
-int bus_remove_device(bus_t *, hcd_t *, device_t *);
+int bus_device_enumerate(device_t *);
+int bus_device_remove(device_t *);
 
-int bus_online_device(bus_t *, hcd_t *, device_t *);
-int bus_offline_device(bus_t *, hcd_t *, device_t *);
+int bus_device_online(device_t *);
+int bus_device_offline(device_t *);
 
-int bus_add_endpoint(bus_t *, device_t *, const usb_endpoint_desc_t *, endpoint_t **);
-endpoint_t *bus_find_endpoint(bus_t *, device_t *, usb_target_t, usb_direction_t);
-int bus_remove_endpoint(bus_t *, endpoint_t *);
-
-size_t bus_count_bw(endpoint_t *, size_t);
+int bus_endpoint_add(device_t *, const usb_endpoint_desc_t *, endpoint_t **);
+endpoint_t *bus_find_endpoint(device_t *, usb_target_t, usb_direction_t);
+int bus_endpoint_remove(endpoint_t *);
 
 int bus_reserve_default_address(bus_t *, usb_speed_t);
Index: uspace/lib/usbhost/include/usb/host/ddf_helpers.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -81,7 +81,7 @@
 int hcd_setup_virtual_root_hub(hcd_t *, ddf_dev_t *);
 
-device_t *hcd_ddf_device_create(ddf_dev_t *, size_t);
+device_t *hcd_ddf_device_create(ddf_dev_t *, bus_t *);
 void hcd_ddf_device_destroy(device_t *);
-int hcd_ddf_device_explore(hcd_t *, device_t *);
+int hcd_ddf_device_explore(device_t *);
 int hcd_ddf_device_online(ddf_fun_t *);
 int hcd_ddf_device_offline(ddf_fun_t *);
Index: uspace/lib/usbhost/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -45,4 +45,5 @@
 #include <stdbool.h>
 #include <usb/usb.h>
+#include <usb/host/bus.h>
 
 typedef struct bus bus_t;
@@ -54,10 +55,8 @@
 	/** Part of linked list. */
 	link_t link;
-	/** Managing bus */
-	bus_t *bus;
+	/** USB device */
+	device_t *device;
 	/** Reference count. */
 	atomic_t refcnt;
-	/** USB device */
-	device_t *device;
 	/** Enpoint number */
 	usb_endpoint_t endpoint;
@@ -84,5 +83,5 @@
 } endpoint_t;
 
-extern void endpoint_init(endpoint_t *, bus_t *);
+extern void endpoint_init(endpoint_t *, device_t *, const usb_endpoint_desc_t *);
 
 extern void endpoint_add_ref(endpoint_t *);
@@ -103,6 +102,15 @@
 void endpoint_abort(endpoint_t *);
 
+/* Manage the toggle bit */
 extern int endpoint_toggle_get(endpoint_t *);
 extern void endpoint_toggle_set(endpoint_t *, bool);
+
+/* Calculate bandwidth */
+ssize_t endpoint_count_bw(endpoint_t *, size_t);
+
+static inline bus_t *endpoint_get_bus(endpoint_t *ep)
+{
+	return ep->device->bus;
+}
 
 /** list_get_instance wrapper.
Index: uspace/lib/usbhost/include/usb/host/usb2_bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/include/usb/host/usb2_bus.h	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -46,6 +46,4 @@
 typedef struct endpoint endpoint_t;
 
-typedef size_t (*count_bw_func_t)(endpoint_t *, size_t);
-
 /** Endpoint management structure */
 typedef struct usb2_bus {
@@ -66,5 +64,7 @@
 } usb2_bus_t;
 
-extern int usb2_bus_init(usb2_bus_t *, size_t, count_bw_func_t);
+extern const bus_ops_t usb2_bus_ops;
+
+extern int usb2_bus_init(usb2_bus_t *, hcd_t *, size_t);
 
 #endif
Index: uspace/lib/usbhost/src/bandwidth.c
===================================================================
--- uspace/lib/usbhost/src/bandwidth.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/bandwidth.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -48,5 +48,5 @@
  * @param max_packet_size Maximum bytes in one packet.
  */
-size_t bandwidth_count_usb11(endpoint_t *ep, size_t size)
+ssize_t bandwidth_count_usb11(endpoint_t *ep, size_t size)
 {
 	assert(ep);
@@ -102,5 +102,5 @@
  * @param max_packet_size Maximum bytes in one packet.
  */
-size_t bandwidth_count_usb20(endpoint_t *ep, size_t size)
+ssize_t bandwidth_count_usb20(endpoint_t *ep, size_t size)
 {
 	assert(ep);
Index: uspace/lib/usbhost/src/bus.c
===================================================================
--- uspace/lib/usbhost/src/bus.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/bus.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -46,17 +46,24 @@
  * Initializes the bus structure.
  */
-void bus_init(bus_t *bus, size_t device_size)
-{
-	assert(bus);
+void bus_init(bus_t *bus, hcd_t *hcd, size_t device_size)
+{
+	assert(bus);
+	assert(hcd);
 	assert(device_size >= sizeof(device_t));
 	memset(bus, 0, sizeof(bus_t));
 
 	fibril_mutex_initialize(&bus->guard);
+	bus->hcd = hcd;
 	bus->device_size = device_size;
 }
 
-int device_init(device_t *dev)
-{
+int bus_device_init(device_t *dev, bus_t *bus)
+{
+	assert(bus);
+	assert(bus->hcd);
+
 	memset(dev, 0, sizeof(*dev));
+
+	dev->bus = bus;
 
 	link_initialize(&dev->link);
@@ -67,5 +74,5 @@
 }
 
-int device_set_default_name(device_t *dev)
+int bus_device_set_default_name(device_t *dev)
 {
 	assert(dev);
@@ -79,55 +86,55 @@
 }
 
-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;
-
-	return bus->ops.enumerate_device(bus, hcd, dev);
-}
-
-int bus_remove_device(bus_t *bus, hcd_t *hcd, device_t *dev)
-{
-	assert(bus);
-	assert(dev);
-
-	if (!bus->ops.remove_device)
-		return ENOTSUP;
-
-	return bus->ops.remove_device(bus, hcd, dev);
-}
-
-int bus_online_device(bus_t *bus, hcd_t *hcd, device_t *dev)
-{
-	assert(bus);
-	assert(hcd);
-	assert(dev);
-
-	if (!bus->ops.online_device)
-		return ENOTSUP;
-
-	return bus->ops.online_device(bus, hcd, dev);
-}
-
-int bus_offline_device(bus_t *bus, hcd_t *hcd, device_t *dev)
-{
-	assert(bus);
-	assert(hcd);
-	assert(dev);
-
-	if (!bus->ops.offline_device)
-		return ENOTSUP;
-
-	return bus->ops.offline_device(bus, hcd, dev);
-}
-
-int bus_add_endpoint(bus_t *bus, device_t *device, const usb_endpoint_desc_t *desc, endpoint_t **out_ep)
-{
-	assert(bus);
+int bus_device_enumerate(device_t *dev)
+{
+	assert(dev);
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_enumerate);
+	if (!ops)
+		return ENOTSUP;
+
+	return ops->device_enumerate(dev);
+}
+
+int bus_device_remove(device_t *dev)
+{
+	assert(dev);
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_remove);
+
+	if (!ops)
+		return ENOTSUP;
+
+	return ops->device_remove(dev);
+}
+
+int bus_device_online(device_t *dev)
+{
+	assert(dev);
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_online);
+	if (!ops)
+		return ENOTSUP;
+
+	return ops->device_online(dev);
+}
+
+int bus_device_offline(device_t *dev)
+{
+	assert(dev);
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_offline);
+	if (!ops)
+		return ENOTSUP;
+
+	return ops->device_offline(dev);
+}
+
+int bus_endpoint_add(device_t *device, const usb_endpoint_desc_t *desc, endpoint_t **out_ep)
+{
+	int err;
 	assert(device);
+
+	bus_t *bus = device->bus;
 
 	if (desc->max_packet_size == 0 || desc->packets == 0) {
@@ -136,29 +143,28 @@
 	}
 
-	fibril_mutex_lock(&bus->guard);
-
-	int err = ENOMEM;
-	endpoint_t *ep = bus->ops.create_endpoint(bus);
+	const bus_ops_t *create_ops = BUS_OPS_LOOKUP(bus->ops, endpoint_create);
+	const bus_ops_t *register_ops = BUS_OPS_LOOKUP(bus->ops, endpoint_register);
+	if (!create_ops || !register_ops)
+		return ENOTSUP;
+
+	endpoint_t *ep = create_ops->endpoint_create(device, desc);
 	if (!ep)
-		goto err;
-
-	/* Bus reference */
+		return ENOMEM;
+
+	/* Temporary reference */
 	endpoint_add_ref(ep);
 
-	if ((err = bus->ops.register_endpoint(bus, device, ep, desc)))
-		goto err_ep;
+	fibril_mutex_lock(&bus->guard);
+	err = register_ops->endpoint_register(ep);
+	fibril_mutex_unlock(&bus->guard);
 
 	if (out_ep) {
+		/* Exporting reference */
 		endpoint_add_ref(ep);
 		*out_ep = ep;
 	}
 
-	fibril_mutex_unlock(&bus->guard);
-	return EOK;
-
-err_ep:
+	/* Temporary reference */
 	endpoint_del_ref(ep);
-err:
-	fibril_mutex_unlock(&bus->guard);
 	return err;
 }
@@ -166,10 +172,16 @@
 /** Searches for an endpoint. Returns a reference.
  */
-endpoint_t *bus_find_endpoint(bus_t *bus, device_t *device, usb_target_t endpoint, usb_direction_t dir)
-{
-	assert(bus);
-
-	fibril_mutex_lock(&bus->guard);
-	endpoint_t *ep = bus->ops.find_endpoint(bus, device, endpoint, dir);
+endpoint_t *bus_find_endpoint(device_t *device, usb_target_t endpoint, usb_direction_t dir)
+{
+	assert(device);
+
+	bus_t *bus = device->bus;
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, device_find_endpoint);
+	if (!ops)
+		return NULL;
+
+	fibril_mutex_lock(&bus->guard);
+	endpoint_t *ep = ops->device_find_endpoint(device, endpoint, dir);
 	if (ep) {
 		/* Exporting reference */
@@ -181,11 +193,16 @@
 }
 
-int bus_remove_endpoint(bus_t *bus, endpoint_t *ep)
-{
-	assert(bus);
+int bus_endpoint_remove(endpoint_t *ep)
+{
 	assert(ep);
 
-	fibril_mutex_lock(&bus->guard);
-	const int r = bus->ops.unregister_endpoint(bus, ep);
+	bus_t *bus = endpoint_get_bus(ep);
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(ep->device->bus->ops, endpoint_unregister);
+	if (!ops)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = ops->endpoint_unregister(ep);
 	fibril_mutex_unlock(&bus->guard);
 
@@ -203,9 +220,10 @@
 	assert(bus);
 
-	if (!bus->ops.reserve_default_address)
-		return ENOTSUP;
-
-	fibril_mutex_lock(&bus->guard);
-	const int r = bus->ops.reserve_default_address(bus, speed);
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, reserve_default_address);
+	if (!ops)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = ops->reserve_default_address(bus, speed);
 	fibril_mutex_unlock(&bus->guard);
 	return r;
@@ -216,10 +234,10 @@
 	assert(bus);
 
-	/* If this op is not set, allow everything */
-	if (!bus->ops.release_default_address)
-		return ENOTSUP;
-
-	fibril_mutex_lock(&bus->guard);
-	const int r = bus->ops.release_default_address(bus);
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, release_default_address);
+	if (!ops)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = ops->release_default_address(bus);
 	fibril_mutex_unlock(&bus->guard);
 	return r;
@@ -230,21 +248,12 @@
 	assert(bus);
 
-	if (!bus->ops.reset_toggle)
-		return ENOTSUP;
-
-	fibril_mutex_lock(&bus->guard);
-	const int r = bus->ops.reset_toggle(bus, target, all);
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, reset_toggle);
+	if (!ops)
+		return ENOTSUP;
+
+	fibril_mutex_lock(&bus->guard);
+	const int r = ops->reset_toggle(bus, target, all);
 	fibril_mutex_unlock(&bus->guard);
 	return r;
-}
-
-size_t bus_count_bw(endpoint_t *ep, size_t size)
-{
-	assert(ep);
-
-	fibril_mutex_lock(&ep->guard);
-	const size_t bw = ep->bus->ops.count_bw(ep, size);
-	fibril_mutex_unlock(&ep->guard);
-	return bw;
 }
 
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -101,5 +101,5 @@
 		endpoint_desc->max_packet_size, endpoint_desc->usb2.polling_interval);
 
-	return bus_add_endpoint(hcd->bus, dev, endpoint_desc, NULL);
+	return bus_endpoint_add(dev, endpoint_desc, NULL);
 }
 
@@ -128,9 +128,9 @@
 		usb_str_direction(endpoint_desc->direction));
 
-	endpoint_t *ep = bus_find_endpoint(hcd->bus, dev, target, endpoint_desc->direction);
+	endpoint_t *ep = bus_find_endpoint(dev, target, endpoint_desc->direction);
 	if (!ep)
 		return ENOENT;
 
-	return bus_remove_endpoint(hcd->bus, ep);
+	return bus_endpoint_remove(ep);
 }
 
@@ -362,5 +362,5 @@
 		const int ret = ddf_fun_unbind(victim->fun);
 		if (ret == EOK) {
-			bus_remove_device(hcd->bus, hcd, victim);
+			bus_device_remove(victim);
 			ddf_fun_destroy(victim->fun);
 		} else {
@@ -374,5 +374,5 @@
 }
 
-device_t *hcd_ddf_device_create(ddf_dev_t *hc, size_t device_size)
+device_t *hcd_ddf_device_create(ddf_dev_t *hc, bus_t *bus)
 {
 	/* Create DDF function for the new device */
@@ -384,5 +384,5 @@
 
 	/* Create USB device node for the new device */
-	device_t *dev = ddf_fun_data_alloc(fun, device_size);
+	device_t *dev = ddf_fun_data_alloc(fun, bus->device_size);
 	if (!dev) {
 		ddf_fun_destroy(fun);
@@ -390,5 +390,5 @@
 	}
 
-	device_init(dev);
+	bus_device_init(dev, bus);
 	dev->fun = fun;
 	return dev;
@@ -402,5 +402,5 @@
 }
 
-int hcd_ddf_device_explore(hcd_t *hcd, device_t *device)
+int hcd_ddf_device_explore(device_t *device)
 {
 	int err;
@@ -421,5 +421,5 @@
 	usb_log_debug("Device(%d): Requesting full device descriptor.",
 	    device->address);
-	ssize_t got = hcd_send_batch_sync(hcd, device, control_ep, USB_DIRECTION_IN,
+	ssize_t got = hcd_send_batch_sync(device->bus->hcd, device, control_ep, USB_DIRECTION_IN,
 	    (char *) &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
 	    "read device descriptor");
@@ -458,5 +458,5 @@
 	usb_log_info("Device(%d): Requested to be brought online.", dev->address);
 
-	return bus_online_device(hcd->bus, hcd, dev);
+	return bus_device_online(dev);
 }
 
@@ -472,5 +472,5 @@
 	usb_log_info("Device(%d): Requested to be taken offline.", dev->address);
 
-	return bus_offline_device(hcd->bus, hcd, dev);
+	return bus_device_offline(dev);
 }
 
@@ -483,5 +483,5 @@
 	assert(hc);
 
-	device_t *dev = hcd_ddf_device_create(hc, hcd->bus->device_size);
+	device_t *dev = hcd_ddf_device_create(hc, hcd->bus);
 	if (!dev) {
 		usb_log_error("Failed to create USB device function.");
@@ -492,5 +492,5 @@
 	dev->port = port;
 
-	if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) {
+	if ((err = bus_device_enumerate(dev))) {
 		usb_log_error("Failed to initialize USB dev memory structures.");
 		return err;
@@ -501,5 +501,5 @@
 	 */
 	if (!ddf_fun_get_name(dev->fun)) {
-		device_set_default_name(dev);
+		bus_device_set_default_name(dev);
 	}
 
@@ -538,5 +538,5 @@
 	}
 
-	device_t *dev = hcd_ddf_device_create(hc, hcd->bus->device_size);
+	device_t *dev = hcd_ddf_device_create(hc, hcd->bus);
 	if (!dev) {
 		usb_log_error("Failed to create function for the root hub.");
@@ -547,5 +547,5 @@
 
 	/* Assign an address to the device */
-	if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) {
+	if ((err = bus_device_enumerate(dev))) {
 		usb_log_error("Failed to enumerate roothub device: %s", str_error(err));
 		goto err_usb_dev;
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -47,13 +47,28 @@
 /** Initialize provided endpoint structure.
  */
-void endpoint_init(endpoint_t *ep, bus_t *bus)
+void endpoint_init(endpoint_t *ep, device_t *dev, const usb_endpoint_desc_t *desc)
 {
 	memset(ep, 0, sizeof(endpoint_t));
 
-	ep->bus = bus;
+	assert(dev);
+	ep->device = dev;
+
 	atomic_set(&ep->refcnt, 0);
 	link_initialize(&ep->link);
 	fibril_mutex_initialize(&ep->guard);
 	fibril_condvar_initialize(&ep->avail);
+
+	ep->endpoint = desc->endpoint_no;
+	ep->direction = desc->direction;
+	ep->transfer_type = desc->transfer_type;
+	ep->max_packet_size = desc->max_packet_size;
+	ep->packets = desc->packets;
+
+	ep->bandwidth = endpoint_count_bw(ep, desc->max_packet_size);
+}
+
+static inline const bus_ops_t *get_bus_ops(endpoint_t *ep)
+{
+	return ep->device->bus->ops;
 }
 
@@ -63,16 +78,21 @@
 }
 
+static inline void endpoint_destroy(endpoint_t *ep)
+{
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(get_bus_ops(ep), endpoint_destroy);
+	if (ops) {
+		ops->endpoint_destroy(ep);
+	} else {
+		assert(ep->active_batch == NULL);
+
+		/* Assume mostly the eps will be allocated by malloc. */
+		free(ep);
+	}
+}
+
 void endpoint_del_ref(endpoint_t *ep)
 {
 	if (atomic_predec(&ep->refcnt) == 0) {
-		if (ep->bus->ops.destroy_endpoint) {
-			ep->bus->ops.destroy_endpoint(ep);
-		}
-		else {
-			assert(ep->active_batch == NULL);
-
-			/* Assume mostly the eps will be allocated by malloc. */
-			free(ep);
-		}
+		endpoint_destroy(ep);
 	}
 }
@@ -133,6 +153,7 @@
 	assert(ep);
 
-	return ep->bus->ops.endpoint_get_toggle
-	    ? ep->bus->ops.endpoint_get_toggle(ep)
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(get_bus_ops(ep), endpoint_get_toggle);
+	return ops
+	    ? ops->endpoint_get_toggle(ep)
 	    : ep->toggle;
 }
@@ -146,6 +167,7 @@
 	assert(ep);
 
-	if (ep->bus->ops.endpoint_set_toggle) {
-		ep->bus->ops.endpoint_set_toggle(ep, toggle);
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(get_bus_ops(ep), endpoint_set_toggle);
+	if (ops) {
+		ops->endpoint_set_toggle(ep, toggle);
 	}
 	else {
@@ -154,4 +176,15 @@
 }
 
+ssize_t endpoint_count_bw(endpoint_t *ep, size_t packet_size)
+{
+	assert(ep);
+
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(get_bus_ops(ep), endpoint_count_bw);
+	if (!ops)
+		return 0;
+
+	return ops->endpoint_count_bw(ep, packet_size);
+}
+
 /**
  * @}
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/hcd.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -208,5 +208,5 @@
 	}
 
-	endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction);
+	endpoint_t *ep = bus_find_endpoint(device, target, direction);
 	if (ep == NULL) {
 		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
@@ -216,9 +216,10 @@
 
 	// TODO cut here aka provide helper to call with instance of endpoint_t in hand
+	assert(ep->device == device);
 
 	usb_log_debug2("%s %d:%d %zu(%zu).\n",
 	    name, target.address, target.endpoint, size, ep->max_packet_size);
 
-	const size_t bw = bus_count_bw(ep, size);
+	const size_t bw = endpoint_count_bw(ep, size);
 	/* Check if we have enough bandwidth reserved */
 	if (ep->bandwidth < bw) {
Index: uspace/lib/usbhost/src/usb2_bus.c
===================================================================
--- uspace/lib/usbhost/src/usb2_bus.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/usb2_bus.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -200,7 +200,10 @@
 }};
 
-static int address_device(usb2_bus_t *bus, hcd_t *hcd, device_t *dev)
+static int address_device(device_t *dev)
 {
 	int err;
+
+	usb2_bus_t *bus = (usb2_bus_t *) dev->bus;
+	hcd_t *hcd = (hcd_t *) bus->base.hcd;
 
 	/* The default address is currently reserved for this device */
@@ -220,5 +223,5 @@
 
 	endpoint_t *default_ep;
-	err = bus_add_endpoint(&bus->base, dev, &usb2_default_control_ep, &default_ep);
+	err = bus_endpoint_add(dev, &usb2_default_control_ep, &default_ep);
 	if (err != EOK) {
 		usb_log_error("Device(%d): Failed to add default target: %s.",
@@ -244,5 +247,5 @@
 
 	/* We need to remove ep before we change the address */
-	if ((err = bus_remove_endpoint(&bus->base, default_ep))) {
+	if ((err = bus_endpoint_remove(default_ep))) {
 		usb_log_error("Device(%d): Failed to unregister default target: %s", address, str_error(err));
 		goto err_address;
@@ -262,5 +265,5 @@
 	/* Register EP on the new address */
 	usb_log_debug("Device(%d): Registering control EP.", address);
-	err = bus_add_endpoint(&bus->base, dev, &control_ep, NULL);
+	err = bus_endpoint_add(dev, &control_ep, NULL);
 	if (err != EOK) {
 		usb_log_error("Device(%d): Failed to register EP0: %s",
@@ -272,5 +275,5 @@
 
 err_default_control_ep:
-	bus_remove_endpoint(&bus->base, default_ep);
+	bus_endpoint_remove(default_ep);
 	endpoint_del_ref(default_ep);
 err_address:
@@ -281,8 +284,8 @@
 /** Enumerate a new USB device
  */
-static int usb2_bus_enumerate_device(bus_t *bus_base, hcd_t *hcd, device_t *dev)
+static int usb2_bus_device_enumerate(device_t *dev)
 {
 	int err;
-	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+	usb2_bus_t *bus = bus_to_usb2_bus(dev->bus);
 
 	/* The speed of the new device was reported by the hub when reserving
@@ -306,5 +309,5 @@
 
 	/* Assign an address to the device */
-	if ((err = address_device(bus, hcd, dev))) {
+	if ((err = address_device(dev))) {
 		usb_log_error("Failed to setup address of the new device: %s", str_error(err));
 		return err;
@@ -312,5 +315,5 @@
 
 	/* Read the device descriptor, derive the match ids */
-	if ((err = hcd_ddf_device_explore(hcd, dev))) {
+	if ((err = hcd_ddf_device_explore(dev))) {
 		usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
 		release_address(bus, dev->address);
@@ -329,7 +332,7 @@
  * @note Assumes that the internal mutex is locked.
  */
-static endpoint_t *usb2_bus_find_ep(bus_t *bus_base, device_t *device, usb_target_t target, usb_direction_t direction)
-{
-	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+static endpoint_t *usb2_bus_find_ep(device_t *device, usb_target_t target, usb_direction_t direction)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(device->bus);
 
 	assert(device->address == target.address);
@@ -345,5 +348,5 @@
 }
 
-static endpoint_t *usb2_bus_create_ep(bus_t *bus)
+static endpoint_t *usb2_bus_create_ep(device_t *dev, const usb_endpoint_desc_t *desc)
 {
 	endpoint_t *ep = malloc(sizeof(endpoint_t));
@@ -351,5 +354,5 @@
 		return NULL;
 
-	endpoint_init(ep, bus);
+	endpoint_init(ep, dev, desc);
 	return ep;
 }
@@ -370,22 +373,12 @@
  * @param endpoint USB endpoint number.
  */
-static int usb2_bus_register_ep(bus_t *bus_base, device_t *device, endpoint_t *ep, const usb_endpoint_desc_t *desc)
-{
-	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+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(&bus->base.guard));
 	assert(ep);
 
-	ep->device = device;
-
-	/* Extract USB2-related information from endpoint_desc */
-	ep->endpoint = desc->endpoint_no;
-	ep->direction = desc->direction;
-	ep->transfer_type = desc->transfer_type;
-	ep->max_packet_size = desc->max_packet_size;
-	ep->packets = desc->packets;
-
-	ep->bandwidth = bus_base->ops.count_bw(ep, desc->max_packet_size);
-
 	/* Check for existence */
-	if (usb2_bus_find_ep(bus_base, ep->device, usb2_ep_to_target(ep), ep->direction))
+	if (usb2_bus_find_ep(ep->device, usb2_ep_to_target(ep), ep->direction))
 		return EEXIST;
 
@@ -394,4 +387,5 @@
 		return ENOSPC;
 
+	endpoint_add_ref(ep);
 	list_append(&ep->link, get_list(bus, ep->device->address));
 	bus->free_bw -= ep->bandwidth;
@@ -400,16 +394,15 @@
 }
 
-
 /** Release bandwidth reserved by the given endpoint.
  */
-static int usb2_bus_unregister_ep(bus_t *bus_base, endpoint_t *ep)
-{
-	usb2_bus_t *bus = bus_to_usb2_bus(bus_base);
+static int usb2_bus_unregister_ep(endpoint_t *ep)
+{
+	usb2_bus_t *bus = bus_to_usb2_bus(ep->device->bus);
 	assert(ep);
 
 	list_remove(&ep->link);
-	ep->device = NULL;
 
 	bus->free_bw += ep->bandwidth;
+	endpoint_del_ref(ep);
 
 	return EOK;
@@ -452,13 +445,13 @@
 }
 
-static const bus_ops_t usb2_bus_ops = {
+const bus_ops_t usb2_bus_ops = {
 	.reserve_default_address = usb2_bus_register_default_address,
 	.release_default_address = usb2_bus_release_default_address,
-	.enumerate_device = usb2_bus_enumerate_device,
-	.create_endpoint = usb2_bus_create_ep,
-	.find_endpoint = usb2_bus_find_ep,
-	.unregister_endpoint = usb2_bus_unregister_ep,
-	.register_endpoint = usb2_bus_register_ep,
 	.reset_toggle = usb2_bus_reset_toggle,
+	.device_enumerate = usb2_bus_device_enumerate,
+	.device_find_endpoint = usb2_bus_find_ep,
+	.endpoint_create= usb2_bus_create_ep,
+	.endpoint_register= usb2_bus_register_ep,
+	.endpoint_unregister= usb2_bus_unregister_ep,
 };
 
@@ -470,12 +463,10 @@
  * @return Error code.
  */
-int usb2_bus_init(usb2_bus_t *bus, size_t available_bandwidth, count_bw_func_t count_bw)
+int usb2_bus_init(usb2_bus_t *bus, hcd_t *hcd, size_t available_bandwidth)
 {
 	assert(bus);
 
-	bus_init(&bus->base, sizeof(device_t));
-
-	bus->base.ops = usb2_bus_ops;
-	bus->base.ops.count_bw = count_bw;
+	bus_init(&bus->base, hcd, sizeof(device_t));
+	bus->base.ops = &usb2_bus_ops;
 
 	bus->free_bw = available_bandwidth;
Index: uspace/lib/usbhost/src/usb_transfer_batch.c
===================================================================
--- uspace/lib/usbhost/src/usb_transfer_batch.c	(revision bd05140d932d234ee044e634a47ef576a2dce904)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision 6832245517c6257fe330523cebfec7b916fdb0bf)
@@ -49,13 +49,15 @@
 {
 	assert(ep);
-	assert(ep->bus);
 
-	usb_transfer_batch_t *batch;
-	if (ep->bus->ops.create_batch)
-		batch = ep->bus->ops.create_batch(ep->bus, ep);
-	else
-		batch = calloc(1, sizeof(usb_transfer_batch_t));
+	bus_t *bus = endpoint_get_bus(ep);
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, batch_create);
 
-	return batch;
+	if (!ops) {
+		usb_transfer_batch_t *batch = calloc(1, sizeof(usb_transfer_batch_t));
+		usb_transfer_batch_init(batch, ep);
+		return batch;
+	}
+
+	return ops->batch_create(ep);
 }
 
@@ -64,4 +66,6 @@
 void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep)
 {
+	assert(ep);
+	endpoint_add_ref(ep);
 	batch->ep = ep;
 }
@@ -82,5 +86,5 @@
 	    batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle");
 
-	return bus_reset_toggle(batch->ep->bus, batch->target, batch->toggle_reset_mode);
+	return bus_reset_toggle(endpoint_get_bus(batch->ep), batch->target, batch->toggle_reset_mode);
 }
 
@@ -93,11 +97,14 @@
 	assert(batch);
 	assert(batch->ep);
-	assert(batch->ep->bus);
 
-	bus_t *bus = batch->ep->bus;
-	if (bus->ops.destroy_batch) {
+	bus_t *bus = endpoint_get_bus(batch->ep);
+	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, batch_destroy);
+
+	endpoint_del_ref(batch->ep);
+
+	if (ops) {
 		usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.\n",
 		    batch, USB_TRANSFER_BATCH_ARGS(*batch));
-		bus->ops.destroy_batch(batch);
+		ops->batch_destroy(batch);
 	}
 	else {
