Index: uspace/lib/usbhost/include/usb/host/bus.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/bus.h	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
+++ uspace/lib/usbhost/include/usb/host/bus.h	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -102,7 +102,4 @@
  */
 struct bus_ops {
-	/* Undefined operations will be delegated to parent ops */
-	const bus_ops_t *parent;
-
 	/* Global operations on the bus */
 	void (*interrupt)(bus_t *, uint32_t);
@@ -126,9 +123,4 @@
 	void (*batch_destroy)(usb_transfer_batch_t *);		/**< Optional */
 };
-
-/**
- * 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 */
Index: uspace/lib/usbhost/src/bus.c
===================================================================
--- uspace/lib/usbhost/src/bus.c	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
+++ uspace/lib/usbhost/src/bus.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -129,6 +129,5 @@
 	assert(dev);
 
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_enumerate);
-	if (!ops)
+	if (!dev->bus->ops->device_enumerate)
 		return ENOTSUP;
 
@@ -138,5 +137,5 @@
 	device_setup_tt(dev);
 
-	const int r = ops->device_enumerate(dev);
+	const int r = dev->bus->ops->device_enumerate(dev);
 	if (r)
 		return r;
@@ -208,6 +207,5 @@
 	assert(dev->fun != NULL);
 
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_gone);
-	const bus_ops_t *ep_ops = BUS_OPS_LOOKUP(dev->bus->ops, endpoint_unregister);
+	const bus_ops_t *ops = dev->bus->ops;
 
 	/* First, block new transfers and operations. */
@@ -241,11 +239,11 @@
 
 	/* Tell the HC to release its resources. */
-	if (ops)
+	if (ops->device_gone)
 		ops->device_gone(dev);
 
 	/* Check whether the driver didn't forgot EP0 */
 	if (dev->endpoints[0]) {
-		if (ep_ops)
-			ep_ops->endpoint_unregister(dev->endpoints[0]);
+		if (ops->endpoint_unregister)
+			ops->endpoint_unregister(dev->endpoints[0]);
 		/* Release the EP0 bus reference */
 		endpoint_del_ref(dev->endpoints[0]);
@@ -271,6 +269,6 @@
 
 	/* First, tell the HC driver. */
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_online);
-	if (ops && (rc = ops->device_online(dev))) {
+	const bus_ops_t *ops = dev->bus->ops;
+	if (ops->device_online && (rc = ops->device_online(dev))) {
 		usb_log_warning("Host controller failed to make device '%s' online: %s",
 		    ddf_fun_get_name(dev->fun), str_error(rc));
@@ -329,6 +327,6 @@
 
 	/* Tell also the HC driver. */
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(dev->bus->ops, device_offline);
-	if (ops)
+	const bus_ops_t *ops = dev->bus->ops;
+	if (ops->device_offline)
 		ops->device_offline(dev);
 
@@ -365,12 +363,10 @@
 	bus_t *bus = device->bus;
 
-	const bus_ops_t *register_ops = BUS_OPS_LOOKUP(bus->ops, endpoint_register);
-	if (!register_ops)
+	if (!bus->ops->endpoint_register)
 		return ENOTSUP;
 
-	const bus_ops_t *create_ops = BUS_OPS_LOOKUP(bus->ops, endpoint_create);
 	endpoint_t *ep;
-	if (create_ops) {
-		ep = create_ops->endpoint_create(device, desc);
+	if (bus->ops->endpoint_create) {
+		ep = bus->ops->endpoint_create(device, desc);
 		if (!ep)
 			return ENOMEM;
@@ -410,5 +406,5 @@
 		err = EEXIST;
 	} else {
-		err = register_ops->endpoint_register(ep);
+		err = bus->ops->endpoint_register(ep);
 		if (!err)
 			device->endpoints[idx] = ep;
@@ -480,6 +476,5 @@
 	bus_t *bus = device->bus;
 
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, endpoint_unregister);
-	if (!ops)
+	if (!bus->ops->endpoint_unregister)
 		return ENOTSUP;
 
@@ -496,5 +491,5 @@
 
 	fibril_mutex_lock(&device->guard);
-	ops->endpoint_unregister(ep);
+	bus->ops->endpoint_unregister(ep);
 	device->endpoints[idx] = NULL;
 	fibril_mutex_unlock(&device->guard);
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -97,6 +97,6 @@
 static inline void endpoint_destroy(endpoint_t *ep)
 {
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(get_bus_ops(ep), endpoint_destroy);
-	if (ops) {
+	const bus_ops_t *ops = get_bus_ops(ep);
+	if (ops->endpoint_destroy) {
 		ops->endpoint_destroy(ep);
 	} else {
@@ -237,6 +237,6 @@
 	}
 
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(device->bus->ops, batch_schedule);
-	if (!ops) {
+	const bus_ops_t *ops = device->bus->ops;
+	if (!ops->batch_schedule) {
 		usb_log_error("HCD does not implement scheduler.");
 		return ENOTSUP;
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
+++ uspace/lib/usbhost/src/hcd.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -100,9 +100,6 @@
 	hc_device_t *hcd = dev_to_hcd(dev);
 
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(hcd->bus->ops, interrupt);
-	assert(ops);
-
 	const uint32_t status = IPC_GET_ARG1(*call);
-	ops->interrupt(hcd->bus, status);
+	hcd->bus->ops->interrupt(hcd->bus, status);
 }
 
@@ -115,12 +112,10 @@
 	assert(bus);
 
-	const bus_ops_t *interrupt_ops = BUS_OPS_LOOKUP(bus->ops, interrupt);
-	const bus_ops_t *status_ops = BUS_OPS_LOOKUP(bus->ops, status);
-	if (!interrupt_ops || !status_ops)
+	if (!bus->ops->interrupt || !bus->ops->status)
 		return ENOTSUP;
 
 	uint32_t status = 0;
-	while (status_ops->status(bus, &status) == EOK) {
-		interrupt_ops->interrupt(bus, status);
+	while (bus->ops->status(bus, &status) == EOK) {
+		bus->ops->interrupt(bus, status);
 		status = 0;
 		/* We should wait 1 frame - 1ms here, but this polling is a
@@ -265,8 +260,8 @@
 	}
 
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(hcd->bus->ops, status);
+	const bus_ops_t *ops = hcd->bus->ops;
 
 	/* Need working irq replacement to setup root hub */
-	if (hcd->irq_cap < 0 && ops) {
+	if (hcd->irq_cap < 0 && ops->status) {
 		hcd->polling_fibril = fibril_create(interrupt_polling, hcd->bus);
 		if (!hcd->polling_fibril) {
Index: uspace/lib/usbhost/src/usb_transfer_batch.c
===================================================================
--- uspace/lib/usbhost/src/usb_transfer_batch.c	(revision d369b3b064d5f65c029ccc881a911bb4836375a0)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision 296d22fc7ac2cf337cdd964b70173f002f670d06)
@@ -54,7 +54,6 @@
 
 	bus_t *bus = endpoint_get_bus(ep);
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, batch_create);
 
-	if (!ops) {
+	if (!bus->ops->batch_create) {
 		usb_transfer_batch_t *batch = calloc(1, sizeof(usb_transfer_batch_t));
 		if (!batch)
@@ -64,5 +63,5 @@
 	}
 
-	return ops->batch_create(ep);
+	return bus->ops->batch_create(ep);
 }
 
@@ -87,13 +86,10 @@
 
 	bus_t *bus = endpoint_get_bus(batch->ep);
-	const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, batch_destroy);
+	endpoint_t *ep = batch->ep;
 
-	/* Batch reference */
-	endpoint_del_ref(batch->ep);
-
-	if (ops) {
+	if (bus->ops) {
 		usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.",
 		    batch, USB_TRANSFER_BATCH_ARGS(*batch));
-		ops->batch_destroy(batch);
+		bus->ops->batch_destroy(batch);
 	}
 	else {
@@ -102,4 +98,7 @@
 		free(batch);
 	}
+
+	/* Batch reference */
+	endpoint_del_ref(ep);
 }
 
