Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision 8de2cca8110ed56b2ed8065d0aa05dfbafd5e24c)
+++ 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 8de2cca8110ed56b2ed8065d0aa05dfbafd5e24c)
+++ 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 8de2cca8110ed56b2ed8065d0aa05dfbafd5e24c)
+++ 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;
 }
