Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision ddab093b60f3f1b5004feb68b9cefeac9b1de72c)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision 5994cc369bffdc443847380a09fcd418bfbacb78)
@@ -46,33 +46,5 @@
 #include "hc.h"
 
-typedef struct ohci {
-	ddf_fun_t *hc_fun;
-	ddf_fun_t *rh_fun;
-} ohci_t;
 
-static inline ohci_t *dev_to_ohci(ddf_dev_t *dev)
-{
-	return ddf_dev_data_get(dev);
-}
-
-static inline hcd_t *dev_to_hcd(ddf_dev_t *dev)
-{
-	ohci_t *ohci = dev_to_ohci(dev);
-	if (!ohci || !ohci->hc_fun) {
-		usb_log_error("Invalid OHCI device.\n");
-		return NULL;
-	}
-	return ddf_fun_data_get(ohci->hc_fun);
-}
-
-static inline hc_t * dev_to_hc(ddf_dev_t *dev)
-{
-	hcd_t *hcd = dev_to_hcd(dev);
-	if (!hcd) {
-		usb_log_error("Invalid OHCI HCD");
-		return NULL;
-	}
-	return hcd->private_data;
-}
 
 /** IRQ handling callback, identifies device
@@ -85,6 +57,6 @@
 {
 	assert(dev);
-	hc_t *hc = dev_to_hc(dev);
-	if (!hc) {
+	hcd_t *hcd = dev_to_hcd(dev);
+	if (!hcd || !hcd->private_data) {
 		usb_log_warning("Interrupt on device that is not ready.\n");
 		return;
@@ -92,59 +64,6 @@
 
 	const uint16_t status = IPC_GET_ARG1(*call);
-	hc_interrupt(hc, status);
+	hc_interrupt(hcd->private_data, status);
 }
-
-/** Get USB address assigned to root hub.
- *
- * @param[in] fun Root hub function.
- * @param[out] address Store the address here.
- * @return Error code.
- */
-static int rh_get_my_address(ddf_fun_t *fun, usb_address_t *address)
-{
-	assert(fun);
-
-	if (address != NULL) {
-		hc_t *hc = dev_to_hc(ddf_fun_get_dev(fun));
-		assert(hc);
-		*address = hc->rh.address;
-	}
-
-	return EOK;
-}
-
-/** Gets handle of the respective hc (this device, hc function).
- *
- * @param[in] root_hub_fun Root hub function seeking hc handle.
- * @param[out] handle Place to write the handle.
- * @return Error code.
- */
-static int rh_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
-{
-	assert(fun);
-
-	if (handle != NULL) {
-		ddf_fun_t *hc_fun = dev_to_ohci(ddf_fun_get_dev(fun))->hc_fun;
-		assert(hc_fun);
-		*handle = ddf_fun_get_handle(hc_fun);
-	}
-	return EOK;
-}
-
-/** Root hub USB interface */
-static usb_iface_t usb_iface = {
-	.get_hc_handle = rh_get_hc_handle,
-	.get_my_address = rh_get_my_address,
-};
-
-/** Standard USB HC options (HC interface) */
-static ddf_dev_ops_t hc_ops = {
-	.interfaces[USBHC_DEV_IFACE] = &hcd_iface,
-};
-
-/** Standard USB RH options (RH interface) */
-static ddf_dev_ops_t rh_ops = {
-	.interfaces[USB_DEV_IFACE] = &usb_iface,
-};
 
 /** Initialize hc and rh ddf structures and their respective drivers.
@@ -159,56 +78,4 @@
  *  - registers interrupt handler
  */
-static int device_setup_hcd(ddf_dev_t *device)
-{
-	if (device == NULL)
-		return EBADMEM;
-
-	ohci_t *instance = ddf_dev_data_alloc(device, sizeof(ohci_t));
-	if (instance == NULL) {
-		usb_log_error("Failed to allocate OHCI driver.\n");
-		return ENOMEM;
-	}
-
-#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
-if (ret != EOK) { \
-	if (instance->hc_fun) { \
-		ddf_fun_destroy(instance->hc_fun); \
-	} \
-	usb_log_error(message); \
-	return ret; \
-} else (void)0
-
-	instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc");
-	int ret = instance->hc_fun ? EOK : ENOMEM;
-	CHECK_RET_DEST_FREE_RETURN(ret,
-	    "Failed to create OHCI HC function: %s.\n", str_error(ret));
-	ddf_fun_set_ops(instance->hc_fun, &hc_ops);
-	hcd_t *hcd = ddf_fun_data_alloc(instance->hc_fun, sizeof(hcd_t));
-	ret = hcd ? EOK : ENOMEM;
-	CHECK_RET_DEST_FREE_RETURN(ret,
-	    "Failed to allocate HCD structure: %s.\n", str_error(ret));
-
-	hcd_init(hcd, USB_SPEED_FULL, BANDWIDTH_AVAILABLE_USB11,
-	    bandwidth_count_usb11);
-
-	ret = ddf_fun_bind(instance->hc_fun);
-	CHECK_RET_DEST_FREE_RETURN(ret,
-	    "Failed to bind OHCI device function: %s.\n", str_error(ret));
-
-#define CHECK_RET_UNBIND_FREE_RETURN(ret, message...) \
-if (ret != EOK) { \
-	ddf_fun_unbind(instance->hc_fun); \
-	CHECK_RET_DEST_FREE_RETURN(ret, \
-	    "Failed to add OHCI to HC class: %s.\n", str_error(ret)); \
-} else (void)0
-	ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
-	CHECK_RET_UNBIND_FREE_RETURN(ret,
-	    "Failed to add hc to category: %s\n", str_error(ret));
-
-	/* HC should be ok at this point (except it can't do anything) */
-
-	return EOK;
-}
-
 int device_setup_ohci(ddf_dev_t *device)
 {
@@ -264,5 +131,5 @@
 	}
 
-	ret = device_setup_hcd(device);
+	ret = hcd_setup_device(device);
 	if (ret != EOK) {
 		unregister_interrupt_handler(device, irq);
@@ -285,23 +152,10 @@
 	CHECK_RET_CLEAN_RETURN(ret, "Failed to init hc: %s.\n", str_error(ret));
 
-	ohci_t *ohci = dev_to_ohci(device);
-
 	hcd_set_implementation(dev_to_hcd(device), hc_impl,
 	    hc_schedule, ohci_endpoint_init, ohci_endpoint_fini);
+	ret = hcd_setup_hub(dev_to_hcd(device), &hc_impl->rh.address, device);
+	CHECK_RET_CLEAN_RETURN(ret,
+	    "Failed to register OHCI root hub: %s.\n", str_error(ret));
 
-#define CHECK_RET_FINI_RETURN(ret, message...) \
-if (ret != EOK) { \
-	hc_fini(hc_impl); \
-	CHECK_RET_CLEAN_RETURN(ret, message); \
-} else (void)0
-	ohci->rh_fun = ddf_fun_create(device, fun_inner, "ohci_rh");
-	ret = ohci->rh_fun ? EOK : ENOMEM;
-	CHECK_RET_FINI_RETURN(ret,
-	    "Failed to create OHCI RH function: %s.\n", str_error(ret));
-	ddf_fun_set_ops(ohci->rh_fun, &rh_ops);
-
-	ret = hcd_register_hub(dev_to_hcd(device), &hc_impl->rh.address, ohci->rh_fun);
-	CHECK_RET_FINI_RETURN(ret,
-	    "Failed to register OHCI root hub: %s.\n", str_error(ret));
 	return ret;
 }
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision ddab093b60f3f1b5004feb68b9cefeac9b1de72c)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision 5994cc369bffdc443847380a09fcd418bfbacb78)
@@ -67,4 +67,5 @@
 };
 
+
 /** Initialize hcd_t structure.
  * Initializes device and endpoint managers. Sets data and hook pointer to NULL.
@@ -109,6 +110,8 @@
 }
 
-int hcd_register_hub(hcd_t *instance, usb_address_t *address, ddf_fun_t *hub_fun);
+int hcd_setup_device(ddf_dev_t *device);
+int hcd_setup_hub(hcd_t *instance, usb_address_t *address, ddf_dev_t *dev);
 
+hcd_t *dev_to_hcd(ddf_dev_t *dev);
 
 /** Data retrieve wrapper.
Index: uspace/lib/usbhost/src/hcd.c
===================================================================
--- uspace/lib/usbhost/src/hcd.c	(revision ddab093b60f3f1b5004feb68b9cefeac9b1de72c)
+++ uspace/lib/usbhost/src/hcd.c	(revision 5994cc369bffdc443847380a09fcd418bfbacb78)
@@ -36,7 +36,82 @@
 #include <errno.h>
 #include <str_error.h>
+#include <usb_iface.h>
 #include <usb/debug.h>
 
 #include <usb/host/hcd.h>
+
+typedef struct hc_dev {
+	ddf_fun_t *hc_fun;
+	ddf_fun_t *rh_fun;
+} hc_dev_t;
+
+static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev)
+{
+	return ddf_dev_data_get(dev);
+}
+
+hcd_t *dev_to_hcd(ddf_dev_t *dev)
+{
+	hc_dev_t *hc_dev = dev_to_hc_dev(dev);
+	if (!hc_dev || !hc_dev->hc_fun) {
+		usb_log_error("Invalid OHCI device.\n");
+		return NULL;
+	}
+	return ddf_fun_data_get(hc_dev->hc_fun);
+}
+
+typedef struct usb_dev {
+	usb_address_t address;
+	usb_speed_t speed;
+	devman_handle_t handle;
+} usb_dev_t;
+
+/** Get USB address assigned to root hub.
+ *
+ * @param[in] fun Root hub function.
+ * @param[out] address Store the address here.
+ * @return Error code.
+ */
+static int rh_get_my_address(ddf_fun_t *fun, usb_address_t *address)
+{
+	assert(fun);
+	if (address != NULL) {
+		usb_dev_t *usb_dev = ddf_fun_data_get(fun);
+		*address = usb_dev->address;
+	}
+	return EOK;
+}
+
+/** Gets handle of the respective hc (this device, hc function).
+ *
+ * @param[in] root_hub_fun Root hub function seeking hc handle.
+ * @param[out] handle Place to write the handle.
+ * @return Error code.
+ */
+static int rh_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
+{
+	assert(fun);
+
+	if (handle != NULL) {
+		usb_dev_t *usb_dev = ddf_fun_data_get(fun);
+		*handle = usb_dev->handle;
+	}
+	return EOK;
+}
+
+/** Root hub USB interface */
+static usb_iface_t usb_iface = {
+	.get_hc_handle = rh_get_hc_handle,
+	.get_my_address = rh_get_my_address,
+};
+/** Standard USB RH options (RH interface) */
+static ddf_dev_ops_t rh_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface,
+};
+
+/** Standard USB HC options (HC interface) */
+static ddf_dev_ops_t hc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &hcd_iface,
+};
 
 /** Announce root hub to the DDF
@@ -46,18 +121,35 @@
  * @return Error code
  */
-int hcd_register_hub(hcd_t *instance, usb_address_t *address, ddf_fun_t *hub_fun)
+int hcd_setup_hub(hcd_t *instance, usb_address_t *address, ddf_dev_t *device)
 {
 	assert(instance);
 	assert(address);
-	assert(hub_fun);
-
-	int ret = usb_device_manager_request_address(
-	    &instance->dev_manager, address, false,
-	    USB_SPEED_FULL);
+	assert(device);
+
+	hc_dev_t *hc_dev = ddf_dev_data_get(device);
+	hc_dev->rh_fun = ddf_fun_create(device, fun_inner, "rh");
+	if (!hc_dev->rh_fun)
+		return ENOMEM;
+	usb_dev_t *rh = ddf_fun_data_alloc(hc_dev->rh_fun, sizeof(usb_dev_t));
+	if (!rh) {
+		ddf_fun_destroy(hc_dev->rh_fun);
+		return ENOMEM;
+	}
+
+
+	int ret = usb_device_manager_request_address(&instance->dev_manager,
+	    address, false, USB_SPEED_FULL);
 	if (ret != EOK) {
 		usb_log_error("Failed to get root hub address: %s\n",
 		    str_error(ret));
+		ddf_fun_destroy(hc_dev->rh_fun);
 		return ret;
 	}
+
+	rh->address = *address;
+	rh->speed = USB_SPEED_FULL;
+	rh->handle = ddf_fun_get_handle(hc_dev->hc_fun);
+
+	ddf_fun_set_ops(hc_dev->rh_fun, &rh_ops);
 
 #define CHECK_RET_UNREG_RETURN(ret, message...) \
@@ -69,4 +161,5 @@
 	usb_device_manager_release_address( \
 	    &instance->dev_manager, *address); \
+	ddf_fun_destroy(hc_dev->rh_fun); \
 	return ret; \
 } else (void)0
@@ -80,20 +173,83 @@
 	    str_error(ret));
 
-	ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
+	ret = ddf_fun_add_match_id(hc_dev->rh_fun, "usb&class=hub", 100);
 	CHECK_RET_UNREG_RETURN(ret,
 	    "Failed to add root hub match-id: %s.\n", str_error(ret));
 
-	ret = ddf_fun_bind(hub_fun);
+	ret = ddf_fun_bind(hc_dev->rh_fun);
 	CHECK_RET_UNREG_RETURN(ret,
 	    "Failed to bind root hub function: %s.\n", str_error(ret));
 
 	ret = usb_device_manager_bind_address(&instance->dev_manager,
-	    *address, ddf_fun_get_handle(hub_fun));
+	    *address, ddf_fun_get_handle(hc_dev->rh_fun));
 	if (ret != EOK)
 		usb_log_warning("Failed to bind root hub address: %s.\n",
 		    str_error(ret));
 
+
 	return EOK;
 #undef CHECK_RET_UNREG_RETURN
+}
+
+/** Initialize hc structures.
+ *
+ * @param[in] device DDF instance of the device to use.
+ *
+ * This function does all the preparatory work for hc driver implementation.
+ *  - gets device hw resources
+ *  - disables OHCI legacy support
+ *  - asks for interrupt
+ *  - registers interrupt handler
+ */
+int hcd_setup_device(ddf_dev_t *device)
+{
+	if (device == NULL)
+		return EBADMEM;
+
+	hc_dev_t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));
+	if (instance == NULL) {
+		usb_log_error("Failed to allocate OHCI driver.\n");
+		return ENOMEM;
+	}
+
+#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
+if (ret != EOK) { \
+	if (instance->hc_fun) { \
+		ddf_fun_destroy(instance->hc_fun); \
+	} \
+	usb_log_error(message); \
+	return ret; \
+} else (void)0
+
+	instance->hc_fun = ddf_fun_create(device, fun_exposed, "hc");
+	int ret = instance->hc_fun ? EOK : ENOMEM;
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to create OHCI HC function: %s.\n", str_error(ret));
+	ddf_fun_set_ops(instance->hc_fun, &hc_ops);
+	hcd_t *hcd = ddf_fun_data_alloc(instance->hc_fun, sizeof(hcd_t));
+	ret = hcd ? EOK : ENOMEM;
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to allocate HCD structure: %s.\n", str_error(ret));
+
+	hcd_init(hcd, USB_SPEED_FULL, BANDWIDTH_AVAILABLE_USB11,
+	    bandwidth_count_usb11);
+
+	ret = ddf_fun_bind(instance->hc_fun);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to bind OHCI device function: %s.\n", str_error(ret));
+
+#define CHECK_RET_UNBIND_FREE_RETURN(ret, message...) \
+if (ret != EOK) { \
+	ddf_fun_unbind(instance->hc_fun); \
+	CHECK_RET_DEST_FREE_RETURN(ret, \
+	    "Failed to add OHCI to HC class: %s.\n", str_error(ret)); \
+} else (void)0
+	ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
+	CHECK_RET_UNBIND_FREE_RETURN(ret,
+	    "Failed to add hc to category: %s\n", str_error(ret));
+
+	/* HC should be ok at this point (except it can't do anything) */
+
+	return EOK;
 }
 
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision ddab093b60f3f1b5004feb68b9cefeac9b1de72c)
+++ uspace/lib/usbhost/src/iface.c	(revision 5994cc369bffdc443847380a09fcd418bfbacb78)
@@ -215,7 +215,7 @@
 	assert(hcd);
 	usb_log_debug("Address release %d.\n", address);
-	usb_device_manager_release_address(&hcd->dev_manager, address);
 	usb_endpoint_manager_remove_address(&hcd->ep_manager, address,
 	    unregister_helper_warn, hcd);
+	usb_device_manager_release_address(&hcd->dev_manager, address);
 	return EOK;
 }
