Index: uspace/drv/bus/usb/ohci/Makefile
===================================================================
--- uspace/drv/bus/usb/ohci/Makefile	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/Makefile	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -38,5 +38,5 @@
 	main.c \
 	ohci_batch.c \
-	ohci_endpoint.c \
+	ohci_bus.c \
 	ohci_rh.c \
 	hw_struct/endpoint_descriptor.c \
Index: uspace/drv/bus/usb/ohci/endpoint_list.h
===================================================================
--- uspace/drv/bus/usb/ohci/endpoint_list.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/endpoint_list.h	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -41,5 +41,5 @@
 #include <usb/host/utils/malloc32.h>
 
-#include "ohci_endpoint.h"
+#include "ohci_bus.h"
 #include "hw_struct/endpoint_descriptor.h"
 
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -47,5 +47,5 @@
 #include <usb/usb.h>
 
-#include "ohci_endpoint.h"
+#include "ohci_bus.h"
 #include "ohci_batch.h"
 
@@ -89,6 +89,4 @@
 };
 
-static void hc_gain_control(hc_t *instance);
-static void hc_start(hc_t *instance);
 static int hc_init_transfer_lists(hc_t *instance);
 static int hc_init_memory(hc_t *instance);
@@ -103,5 +101,5 @@
  * @return Error code.
  */
-int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
+int ohci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
 {
 	assert(code);
@@ -151,5 +149,5 @@
  * @return Error code
  */
-int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
+int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res)
 {
 	assert(instance);
@@ -172,5 +170,4 @@
 	list_initialize(&instance->pending_batches);
 	fibril_mutex_initialize(&instance->guard);
-	instance->hw_interrupts = interrupts;
 
 	ret = hc_init_memory(instance);
@@ -181,9 +178,4 @@
 		return ret;
 	}
-
-	hc_gain_control(instance);
-
-	ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
-	hc_start(instance);
 
 	return EOK;
@@ -295,5 +287,5 @@
 
 	/* Check for root hub communication */
-	if (batch->ep->address == ohci_rh_get_address(&instance->rh)) {
+	if (batch->target.address == ohci_rh_get_address(&instance->rh)) {
 		usb_log_debug("OHCI root hub request.\n");
 		return ohci_rh_schedule(&instance->rh, batch);
@@ -302,4 +294,8 @@
 	if (!ohci_batch)
 		return ENOMEM;
+
+	const int err = ohci_transfer_batch_prepare(ohci_batch);
+	if (err)
+		return err;
 
 	fibril_mutex_lock(&instance->guard);
@@ -354,7 +350,7 @@
 			    ohci_transfer_batch_from_link(current);
 
-			if (ohci_transfer_batch_is_complete(batch)) {
+			if (ohci_transfer_batch_check_completed(batch)) {
 				list_remove(current);
-				ohci_transfer_batch_finish_dispose(batch);
+				usb_transfer_batch_finish(&batch->base);
 			}
 
@@ -443,4 +439,6 @@
 void hc_start(hc_t *instance)
 {
+	ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
+
 	/* OHCI guide page 42 */
 	assert(instance);
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -52,4 +52,5 @@
 #include "ohci_regs.h"
 #include "ohci_rh.h"
+#include "ohci_bus.h"
 #include "endpoint_list.h"
 #include "hw_struct/hcca.h"
@@ -59,4 +60,5 @@
 	/** Memory mapped I/O registers area */
 	ohci_regs_t *registers;
+	
 	/** Host controller communication area structure */
 	hcca_t *hcca;
@@ -64,4 +66,5 @@
 	/** Transfer schedules */
 	endpoint_list_t lists[4];
+
 	/** List of active transfers */
 	list_t pending_batches;
@@ -78,7 +81,12 @@
 	/** USB hub emulation structure */
 	ohci_rh_t rh;
+
+	/** USB bookkeeping */
+	ohci_bus_t bus;
 } hc_t;
 
-extern int hc_init(hc_t *, const hw_res_list_parsed_t *, bool);
+extern int hc_init(hc_t *, const hw_res_list_parsed_t *);
+extern void hc_gain_control(hc_t *instance);
+extern void hc_start(hc_t *instance);
 extern void hc_fini(hc_t *);
 
@@ -86,5 +94,5 @@
 extern void hc_dequeue_endpoint(hc_t *, const endpoint_t *);
 
-int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res);
+int ohci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res);
 
 extern void ohci_hc_interrupt(hcd_t *, uint32_t);
Index: uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -40,4 +40,6 @@
 #include <usb/usb.h>
 #include <usb/host/utils/malloc32.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/bus.h>
 
 #include "mem_access.h"
@@ -79,5 +81,5 @@
 	/* Status: address, endpoint nr, direction mask and max packet size. */
 	OHCI_MEM32_WR(instance->status,
-	    ((ep->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
+	    ((ep->device->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
 	    | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)
 	    | ((dir[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/main.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -45,19 +45,22 @@
 
 #include "hc.h"
+#include "ohci_bus.h"
 
 #define NAME "ohci"
-static int ohci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
+static int ohci_driver_init(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *);
+static int ohci_driver_start(hcd_t *, bool);
+static int ohci_driver_claim(hcd_t *, ddf_dev_t *);
 static void ohci_driver_fini(hcd_t *);
 
 static const ddf_hc_driver_t ohci_hc_driver = {
-        .hc_speed = USB_SPEED_FULL,
         .irq_code_gen = ohci_hc_gen_irq_code,
         .init = ohci_driver_init,
+        .claim = ohci_driver_claim,
+        .start = ohci_driver_start,
+	.setup_root_hub = hcd_setup_virtual_root_hub,
         .fini = ohci_driver_fini,
         .name = "OHCI",
 	.ops = {
                 .schedule       = ohci_hc_schedule,
-                .ep_add_hook    = ohci_endpoint_init,
-                .ep_remove_hook = ohci_endpoint_fini,
                 .irq_hook       = ohci_hc_interrupt,
                 .status_hook    = ohci_hc_status,
@@ -66,6 +69,8 @@
 
 
-static int ohci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)
+static int ohci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, ddf_dev_t *device)
 {
+	int err;
+
 	assert(hcd);
 	assert(hcd_get_driver_data(hcd) == NULL);
@@ -75,11 +80,37 @@
 		return ENOMEM;
 
-	const int ret = hc_init(instance, res, irq);
-	if (ret == EOK) {
-		hcd_set_implementation(hcd, instance, &ohci_hc_driver.ops);
-	} else {
-		free(instance);
-	}
-	return ret;
+	if ((err = hc_init(instance, res)) != EOK)
+		goto err;
+
+	if ((err = ohci_bus_init(&instance->bus, instance)))
+		goto err;
+
+	hcd_set_implementation(hcd, instance, &ohci_hc_driver.ops, &instance->bus.base.base);
+
+	return EOK;
+
+err:
+	free(instance);
+	return err;
+}
+
+static int ohci_driver_claim(hcd_t *hcd, ddf_dev_t *dev)
+{
+	hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	hc_gain_control(hc);
+
+	return EOK;
+}
+
+static int ohci_driver_start(hcd_t *hcd, bool interrupts)
+{
+	hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	hc->hw_interrupts = interrupts;
+	hc_start(hc);
+	return EOK;
 }
 
@@ -91,5 +122,5 @@
 		hc_fini(hc);
 
-	hcd_set_implementation(hcd, NULL, NULL);
+	hcd_set_implementation(hcd, NULL, NULL, NULL);
 	free(hc);
 }
@@ -107,6 +138,19 @@
 }
 
+static int ohci_fun_online(ddf_fun_t *fun)
+{
+	return hcd_ddf_device_online(fun);
+}
+
+static int ohci_fun_offline(ddf_fun_t *fun)
+{
+	return hcd_ddf_device_offline(fun);
+}
+
+
 static const driver_ops_t ohci_driver_ops = {
 	.dev_add = ohci_dev_add,
+	.fun_online = ohci_fun_online,
+	.fun_offline = ohci_fun_offline
 };
 
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -45,7 +45,7 @@
 
 #include "ohci_batch.h"
-#include "ohci_endpoint.h"
-
-static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t);
+#include "ohci_bus.h"
+
+static void (*const batch_setup[])(ohci_transfer_batch_t*);
 
 /** Safely destructs ohci_transfer_batch_t structure
@@ -53,8 +53,7 @@
  * @param[in] ohci_batch Instance to destroy.
  */
-static void ohci_transfer_batch_dispose(ohci_transfer_batch_t *ohci_batch)
-{
-	if (!ohci_batch)
-		return;
+void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
 	if (ohci_batch->tds) {
 		const ohci_endpoint_t *ohci_ep =
@@ -67,20 +66,6 @@
 		free(ohci_batch->tds);
 	}
-	usb_transfer_batch_destroy(ohci_batch->usb_batch);
 	free32(ohci_batch->device_buffer);
 	free(ohci_batch);
-}
-
-/** Finishes usb_transfer_batch and destroys the structure.
- *
- * @param[in] uhci_batch Instance to finish and destroy.
- */
-void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)
-{
-	assert(ohci_batch);
-	assert(ohci_batch->usb_batch);
-	usb_transfer_batch_finish(ohci_batch->usb_batch,
-	    ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size);
-	ohci_transfer_batch_dispose(ohci_batch);
 }
 
@@ -90,12 +75,8 @@
  * @return Valid pointer if all structures were successfully created,
  * NULL otherwise.
- *
- * Determines the number of needed transfer descriptors (TDs).
- * Prepares a transport buffer (that is accessible by the hardware).
- * Initializes parameters needed for the transfer and callback.
- */
-ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
-{
-	assert(usb_batch);
+ */
+ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *ep)
+{
+	assert(ep);
 
 	ohci_transfer_batch_t *ohci_batch =
@@ -103,9 +84,30 @@
 	if (!ohci_batch) {
 		usb_log_error("Failed to allocate OHCI batch data.");
-		goto dispose;
-	}
+		return NULL;
+	}
+
+	usb_transfer_batch_init(&ohci_batch->base, ep);
 	link_initialize(&ohci_batch->link);
-	ohci_batch->td_count =
-	    (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
+
+	return ohci_batch;
+}
+
+/** Prepares a batch to be sent.
+ *
+ * Determines the number of needed transfer descriptors (TDs).
+ * Prepares a transport buffer (that is accessible by the hardware).
+ * Initializes parameters needed for the transfer and callback.
+ */
+int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
+
+	const size_t setup_size = (ohci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
+		? USB_SETUP_PACKET_SIZE
+		: 0;
+
+	usb_transfer_batch_t *usb_batch = &ohci_batch->base;
+
+	ohci_batch->td_count = (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
 	    / OHCI_TD_MAX_TRANSFER;
 	/* Control transfer need Setup and Status stage */
@@ -118,5 +120,5 @@
 	if (!ohci_batch->tds) {
 		usb_log_error("Failed to allocate OHCI transfer descriptors.");
-		goto dispose;
+		return ENOMEM;
 	}
 
@@ -129,8 +131,7 @@
 		if (!ohci_batch->tds[i]) {
 			usb_log_error("Failed to allocate TD %d.", i);
-			goto dispose;
+			return ENOMEM;
 		}
 	}
-
 
 	/* NOTE: OHCI is capable of handling buffer that crosses page boundaries
@@ -138,31 +139,25 @@
 	 * than two pages (the first page is computed using start pointer, the
 	 * other using the end pointer) */
-        if (usb_batch->setup_size + usb_batch->buffer_size > 0) {
+        if (setup_size + usb_batch->buffer_size > 0) {
 		/* Use one buffer for setup and data stage */
 		ohci_batch->device_buffer =
-		    malloc32(usb_batch->setup_size + usb_batch->buffer_size);
+		    malloc32(setup_size + usb_batch->buffer_size);
 		if (!ohci_batch->device_buffer) {
 			usb_log_error("Failed to allocate device buffer");
-			goto dispose;
+			return ENOMEM;
 		}
 		/* Copy setup data */
-                memcpy(ohci_batch->device_buffer, usb_batch->setup_buffer,
-		    usb_batch->setup_size);
+                memcpy(ohci_batch->device_buffer, usb_batch->setup.buffer, setup_size);
 		/* Copy generic data */
 		if (usb_batch->ep->direction != USB_DIRECTION_IN)
 			memcpy(
-			    ohci_batch->device_buffer + usb_batch->setup_size,
+			    ohci_batch->device_buffer + setup_size,
 			    usb_batch->buffer, usb_batch->buffer_size);
         }
-	ohci_batch->usb_batch = usb_batch;
-
-	const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
+
 	assert(batch_setup[usb_batch->ep->transfer_type]);
-	batch_setup[usb_batch->ep->transfer_type](ohci_batch, dir);
-
-	return ohci_batch;
-dispose:
-	ohci_transfer_batch_dispose(ohci_batch);
-	return NULL;
+	batch_setup[usb_batch->ep->transfer_type](ohci_batch);
+
+	return EOK;
 }
 
@@ -176,8 +171,7 @@
  * completes with the last TD.
  */
-bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *ohci_batch)
-{
-	assert(ohci_batch);
-	assert(ohci_batch->usb_batch);
+bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
 
 	usb_log_debug("Batch %p checking %zu td(s) for completion.\n",
@@ -194,6 +188,5 @@
 
 	/* Assume all data got through */
-	ohci_batch->usb_batch->transfered_size =
-	    ohci_batch->usb_batch->buffer_size;
+	ohci_batch->base.transfered_size = ohci_batch->base.buffer_size;
 
 	/* Assume we will leave the last(unused) TD behind */
@@ -207,6 +200,6 @@
 		    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
 
-		ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
-		if (ohci_batch->usb_batch->error == EOK) {
+		ohci_batch->base.error = td_error(ohci_batch->tds[i]);
+		if (ohci_batch->base.error == EOK) {
 			/* If the TD got all its data through, it will report
 			 * 0 bytes remain, the sole exception is INPUT with
@@ -221,5 +214,5 @@
 			 * we leave the very last(unused) TD behind.
 			 */
-			ohci_batch->usb_batch->transfered_size
+			ohci_batch->base.transfered_size
 			    -= td_remain_size(ohci_batch->tds[i]);
 		} else {
@@ -252,9 +245,12 @@
 		}
 	}
-	assert(ohci_batch->usb_batch->transfered_size <=
-	    ohci_batch->usb_batch->buffer_size);
+	assert(ohci_batch->base.transfered_size <=
+	    ohci_batch->base.buffer_size);
+
+	if (ohci_batch->base.dir == USB_DIRECTION_IN)
+		memcpy(ohci_batch->base.buffer, ohci_batch->device_buffer, ohci_batch->base.transfered_size);
 
 	/* Store the remaining TD */
-	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
+	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep);
 	assert(ohci_ep);
 	ohci_ep->td = ohci_batch->tds[leave_td];
@@ -286,9 +282,11 @@
  * Status stage with toggle 1 and direction supplied by parameter.
  */
-static void batch_control(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
-{
-	assert(ohci_batch);
-	assert(ohci_batch->usb_batch);
+static void batch_control(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
+
+	usb_direction_t dir = ohci_batch->base.dir;
 	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
+
 	usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
 	    ohci_batch->ed->status, ohci_batch->ed->td_tail,
@@ -307,9 +305,9 @@
 	td_init(
 	    ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
-	    buffer, ohci_batch->usb_batch->setup_size, toggle);
+	    buffer, USB_SETUP_PACKET_SIZE, toggle);
 	usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
 	    ohci_batch->tds[0]->next, ohci_batch->tds[0]->be);
-	buffer += ohci_batch->usb_batch->setup_size;
+	buffer += USB_SETUP_PACKET_SIZE;
 
 	/* Data stage */
@@ -361,8 +359,9 @@
  * OHCI hw in ED.
  */
-static void batch_data(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
-{
-	assert(ohci_batch);
-	assert(ohci_batch->usb_batch);
+static void batch_data(ohci_transfer_batch_t *ohci_batch)
+{
+	assert(ohci_batch);
+
+	usb_direction_t dir = ohci_batch->base.dir;
 	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
 	usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
@@ -401,5 +400,5 @@
 
 /** Transfer setup table. */
-static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t) =
+static void (*const batch_setup[])(ohci_transfer_batch_t*) =
 {
 	[USB_TRANSFER_CONTROL] = batch_control,
Index: uspace/drv/bus/usb/ohci/ohci_batch.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/ohci_batch.h	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -45,4 +45,6 @@
 /** OHCI specific data required for USB transfer */
 typedef struct ohci_transfer_batch {
+	usb_transfer_batch_t base;
+
 	/** Link */
 	link_t link;
@@ -59,8 +61,9 @@
 } ohci_transfer_batch_t;
 
-ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *batch);
-bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *batch);
+ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *batch);
+int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch);
 void ohci_transfer_batch_commit(const ohci_transfer_batch_t *batch);
-void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch);
+bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *batch);
+void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch);
 
 static inline ohci_transfer_batch_t *ohci_transfer_batch_from_link(link_t *l)
@@ -69,4 +72,12 @@
 	return list_get_instance(l, ohci_transfer_batch_t, link);
 }
+
+static inline ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
+{
+	assert(usb_batch);
+
+	return (ohci_transfer_batch_t *) usb_batch;
+}
+
 #endif
 /**
Index: uspace/drv/bus/usb/ohci/ohci_bus.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_bus.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
+++ uspace/drv/bus/usb/ohci/ohci_bus.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <usb/host/utils/malloc32.h>
+#include <usb/host/bandwidth.h>
+
+#include "ohci_bus.h"
+#include "ohci_batch.h"
+#include "hc.h"
+
+/** Callback to set toggle on ED.
+ *
+ * @param[in] hcd_ep hcd endpoint structure
+ * @param[in] toggle new value of toggle bit
+ */
+static void ohci_ep_toggle_set(endpoint_t *ep, bool toggle)
+{
+	ohci_endpoint_t *instance = ohci_endpoint_get(ep);
+	assert(instance);
+	assert(instance->ed);
+	ep->toggle = toggle;
+	ed_toggle_set(instance->ed, toggle);
+}
+
+/** Callback to get value of toggle bit.
+ *
+ * @param[in] hcd_ep hcd endpoint structure
+ * @return Current value of toggle bit.
+ */
+static bool ohci_ep_toggle_get(endpoint_t *ep)
+{
+	ohci_endpoint_t *instance = ohci_endpoint_get(ep);
+	assert(instance);
+	assert(instance->ed);
+	return ed_toggle_get(instance->ed);
+}
+
+/** Creates new hcd endpoint representation.
+ */
+static endpoint_t *ohci_endpoint_create(bus_t *bus)
+{
+	assert(bus);
+
+	ohci_endpoint_t *ohci_ep = malloc(sizeof(ohci_endpoint_t));
+	if (ohci_ep == NULL)
+		return NULL;
+
+	endpoint_init(&ohci_ep->base, bus);
+
+	ohci_ep->ed = malloc32(sizeof(ed_t));
+	if (ohci_ep->ed == NULL) {
+		free(ohci_ep);
+		return NULL;
+	}
+
+	ohci_ep->td = malloc32(sizeof(td_t));
+	if (ohci_ep->td == NULL) {
+		free32(ohci_ep->ed);
+		free(ohci_ep);
+		return NULL;
+	}
+
+	link_initialize(&ohci_ep->link);
+	return &ohci_ep->base;
+}
+
+/** Disposes hcd endpoint structure
+ *
+ * @param[in] hcd driver using this instance.
+ * @param[in] ep endpoint structure.
+ */
+static void ohci_endpoint_destroy(endpoint_t *ep)
+{
+	assert(ep);
+	ohci_endpoint_t *instance = ohci_endpoint_get(ep);
+
+	free32(instance->ed);
+	free32(instance->td);
+	free(instance);
+}
+
+
+static int ohci_register_ep(bus_t *bus_base, device_t *dev, endpoint_t *ep, const usb_endpoint_desc_t *desc)
+{
+	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);
+	if (err)
+		return err;
+
+	ed_init(ohci_ep->ed, ep, ohci_ep->td);
+	hc_enqueue_endpoint(bus->hc, ep);
+
+	return EOK;
+}
+
+static int ohci_unregister_ep(bus_t *bus_base, endpoint_t *ep)
+{
+	ohci_bus_t *bus = (ohci_bus_t *) bus_base;
+	assert(bus);
+	assert(ep);
+
+	const int err = bus->parent_ops.unregister_endpoint(bus_base, ep);
+	if (err)
+		return err;
+
+	hc_dequeue_endpoint(bus->hc, ep);
+	return EOK;
+}
+
+static usb_transfer_batch_t *ohci_bus_create_batch(bus_t *bus, endpoint_t *ep)
+{
+	ohci_transfer_batch_t *batch = ohci_transfer_batch_create(ep);
+	return &batch->base;
+}
+
+static void ohci_bus_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)
+{
+	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;
+
+	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;
+
+	bus->hc = hc;
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/ohci_bus.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_bus.h	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
+++ uspace/drv/bus/usb/ohci/ohci_bus.h	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HCD_BUS_H
+#define DRV_OHCI_HCD_BUS_H
+
+#include <assert.h>
+#include <adt/list.h>
+#include <usb/host/usb2_bus.h>
+
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+/** Connector structure linking ED to to prepared TD. */
+typedef struct ohci_endpoint {
+	endpoint_t base;
+
+	/** OHCI endpoint descriptor */
+	ed_t *ed;
+	/** Currently enqueued transfer descriptor */
+	td_t *td;
+	/** Linked list used by driver software */
+	link_t link;
+} ohci_endpoint_t;
+
+typedef struct hc hc_t;
+
+typedef struct {
+	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 *);
+
+/** Get and convert assigned ohci_endpoint_t structure
+ * @param[in] ep USBD endpoint structure.
+ * @return Pointer to assigned hcd endpoint structure
+ */
+static inline ohci_endpoint_t * ohci_endpoint_get(const endpoint_t *ep)
+{
+	assert(ep);
+	return (ohci_endpoint_t *) ep;
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ 	(revision )
@@ -1,123 +1,0 @@
-/*
- * Copyright (c) 2011 Jan Vesely
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbohci
- * @{
- */
-/** @file
- * @brief OHCI driver
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <usb/host/utils/malloc32.h>
-
-#include "ohci_endpoint.h"
-#include "hc.h"
-
-/** Callback to set toggle on ED.
- *
- * @param[in] hcd_ep hcd endpoint structure
- * @param[in] toggle new value of toggle bit
- */
-static void ohci_ep_toggle_set(void *ohci_ep, int toggle)
-{
-	ohci_endpoint_t *instance = ohci_ep;
-	assert(instance);
-	assert(instance->ed);
-	ed_toggle_set(instance->ed, toggle);
-}
-
-/** Callback to get value of toggle bit.
- *
- * @param[in] hcd_ep hcd endpoint structure
- * @return Current value of toggle bit.
- */
-static int ohci_ep_toggle_get(void *ohci_ep)
-{
-	ohci_endpoint_t *instance = ohci_ep;
-	assert(instance);
-	assert(instance->ed);
-	return ed_toggle_get(instance->ed);
-}
-
-/** Creates new hcd endpoint representation.
- *
- * @param[in] ep USBD endpoint structure
- * @return Error code.
- */
-int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep)
-{
-	assert(ep);
-	ohci_endpoint_t *ohci_ep = malloc(sizeof(ohci_endpoint_t));
-	if (ohci_ep == NULL)
-		return ENOMEM;
-
-	ohci_ep->ed = malloc32(sizeof(ed_t));
-	if (ohci_ep->ed == NULL) {
-		free(ohci_ep);
-		return ENOMEM;
-	}
-
-	ohci_ep->td = malloc32(sizeof(td_t));
-	if (ohci_ep->td == NULL) {
-		free32(ohci_ep->ed);
-		free(ohci_ep);
-		return ENOMEM;
-	}
-
-	link_initialize(&ohci_ep->link);
-	ed_init(ohci_ep->ed, ep, ohci_ep->td);
-	endpoint_set_hc_data(
-	    ep, ohci_ep, ohci_ep_toggle_get, ohci_ep_toggle_set);
-	hc_enqueue_endpoint(hcd_get_driver_data(hcd), ep);
-	return EOK;
-}
-
-/** Disposes hcd endpoint structure
- *
- * @param[in] hcd driver using this instance.
- * @param[in] ep endpoint structure.
- */
-void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep)
-{
-	assert(hcd);
-	assert(ep);
-	ohci_endpoint_t *instance = ohci_endpoint_get(ep);
-	hc_dequeue_endpoint(hcd_get_driver_data(hcd), ep);
-	endpoint_clear_hc_data(ep);
-	if (instance) {
-		free32(instance->ed);
-		free32(instance->td);
-		free(instance);
-	}
-}
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.h	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ 	(revision )
@@ -1,71 +1,0 @@
-/*
- * Copyright (c) 2011 Jan Vesely
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/** @addtogroup drvusbohci
- * @{
- */
-/** @file
- * @brief OHCI driver
- */
-#ifndef DRV_OHCI_HCD_ENDPOINT_H
-#define DRV_OHCI_HCD_ENDPOINT_H
-
-#include <assert.h>
-#include <adt/list.h>
-#include <usb/host/endpoint.h>
-#include <usb/host/hcd.h>
-
-#include "hw_struct/endpoint_descriptor.h"
-#include "hw_struct/transfer_descriptor.h"
-
-/** Connector structure linking ED to to prepared TD. */
-typedef struct ohci_endpoint {
-	/** OHCI endpoint descriptor */
-	ed_t *ed;
-	/** Currently enqueued transfer descriptor */
-	td_t *td;
-	/** Linked list used by driver software */
-	link_t link;
-} ohci_endpoint_t;
-
-int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep);
-void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep);
-
-/** Get and convert assigned ohci_endpoint_t structure
- * @param[in] ep USBD endpoint structure.
- * @return Pointer to assigned hcd endpoint structure
- */
-static inline ohci_endpoint_t * ohci_endpoint_get(const endpoint_t *ep)
-{
-	assert(ep);
-	return ep->hc_data.data;
-}
-
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ohci/ohci_rh.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_rh.c	(revision cecba66ea48d60cfa59865e98aeda663808e42c7)
+++ uspace/drv/bus/usb/ohci/ohci_rh.c	(revision f9d0a86c86defda4d9f30fbb4f7217a75048bf8b)
@@ -178,10 +178,6 @@
 	assert(instance);
 	assert(batch);
-	const usb_target_t target = {{
-		.address = batch->ep->address,
-		.endpoint = batch->ep->endpoint,
-	}};
-	batch->error = virthub_base_request(&instance->base, target,
-	    usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
+	batch->error = virthub_base_request(&instance->base, batch->target,
+	    batch->dir, &batch->setup.packet,
 	    batch->buffer, batch->buffer_size, &batch->transfered_size);
 	if (batch->error == ENAK) {
@@ -192,6 +188,5 @@
 		instance->unfinished_interrupt_transfer = batch;
 	} else {
-		usb_transfer_batch_finish(batch, NULL);
-		usb_transfer_batch_destroy(batch);
+		usb_transfer_batch_finish(batch);
 	}
 	return EOK;
@@ -211,14 +206,8 @@
 	instance->unfinished_interrupt_transfer = NULL;
 	if (batch) {
-		const usb_target_t target = {{
-			.address = batch->ep->address,
-			.endpoint = batch->ep->endpoint,
-		}};
-		batch->error = virthub_base_request(&instance->base, target,
-		    usb_transfer_batch_direction(batch),
-		    (void*)batch->setup_buffer,
+		batch->error = virthub_base_request(&instance->base, batch->target,
+		    batch->dir, &batch->setup.packet,
 		    batch->buffer, batch->buffer_size, &batch->transfered_size);
-		usb_transfer_batch_finish(batch, NULL);
-		usb_transfer_batch_destroy(batch);
+		usb_transfer_batch_finish(batch);
 	}
 	return EOK;
