Index: uspace/drv/ohci/Makefile
===================================================================
--- uspace/drv/ohci/Makefile	(revision fa3de85013536f0386386c46bfaebceff2126a15)
+++ uspace/drv/ohci/Makefile	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -37,4 +37,5 @@
 	main.c \
 	hc.c \
+	ohci.c \
 	root_hub.c \
 	pci.c
Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision fa3de85013536f0386386c46bfaebceff2126a15)
+++ uspace/drv/ohci/hc.c	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -39,5 +39,4 @@
 #include <usb/debug.h>
 #include <usb/usb.h>
-#include <usb/hub.h>
 #include <usb/ddfiface.h>
 #include <usb/usbdevice.h>
@@ -45,6 +44,31 @@
 #include "hc.h"
 
-static int dummy_reset(int foo, void *arg);
 static int interrupt_emulator(hc_t *instance);
+/*----------------------------------------------------------------------------*/
+int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
+{
+	assert(instance);
+	assert(hub_fun);
+
+	usb_address_t hub_address =
+	    device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
+	instance->rh.address = hub_address;
+	usb_device_keeper_bind(
+	    &instance->manager, hub_address, hub_fun->handle);
+
+	char *match_str = NULL;
+	int ret = asprintf(&match_str, "usb&mid");
+	ret = (match_str == NULL) ? ret : EOK;
+	if (ret < 0) {
+		usb_log_error("Failed to create root hub match-id string.\n");
+		return ret;
+	}
+
+	ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
+	if (ret != EOK) {
+		usb_log_error("Failed add create root hub match-id.\n");
+	}
+	return ret;
+}
 /*----------------------------------------------------------------------------*/
 int hc_init(hc_t *instance, ddf_fun_t *fun, ddf_dev_t *dev,
@@ -68,44 +92,7 @@
 	}
 
+	rh_init(&instance->rh, dev, instance->registers);
 
-	rh_init(&instance->rh, dev, instance->registers);
 	/* TODO: implement */
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-int hc_register_hub(hc_t *instance)
-{
-	async_usleep(1000000);
-#define CHECK_RET_RETURN(ret, msg...) \
-	if (ret != EOK) { \
-		usb_log_error(msg); \
-		return ret; \
-	} else (void)0
-	assert(instance);
-	assert(instance->ddf_instance);
-	assert(instance->ddf_instance->handle);
-	ddf_dev_t *dev = instance->rh.device;
-	int ret = EOK;
-
-	usb_hc_connection_t conn;
-	ret =
-	    usb_hc_connection_initialize(&conn, instance->ddf_instance->handle);
-	CHECK_RET_RETURN(ret, "Failed to initialize hc connection.\n");
-
-	ret = usb_hc_connection_open(&conn);
-	CHECK_RET_RETURN(ret, "Failed to open hc connection.\n");
-
-	usb_address_t address;
-	devman_handle_t handle;
-	ret = usb_hc_new_device_wrapper(dev, &conn, USB_SPEED_FULL, dummy_reset,
-	    0, instance, &address, &handle, NULL, NULL, NULL);
-	if (ret != EOK) {
-		usb_log_error("Failed to add rh device.\n");
-		instance->rh.address = -1;
-		return ret;
-	}
-
-	ret = usb_hc_connection_close(&conn);
-	CHECK_RET_RETURN(ret, "Failed to close hc connection.\n");
 	return EOK;
 }
@@ -134,13 +121,5 @@
 }
 /*----------------------------------------------------------------------------*/
-static int dummy_reset(int foo, void *arg)
-{
-	hc_t *hc = (hc_t*)arg;
-	assert(hc);
-	hc->rh.address = 0;
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-static int interrupt_emulator(hc_t *instance)
+int interrupt_emulator(hc_t *instance)
 {
 	assert(instance);
Index: uspace/drv/ohci/hc.h
===================================================================
--- uspace/drv/ohci/hc.h	(revision fa3de85013536f0386386c46bfaebceff2126a15)
+++ uspace/drv/ohci/hc.h	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -57,8 +57,8 @@
 } hc_t;
 
+int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun);
+
 int hc_init(hc_t *instance, ddf_fun_t *fun, ddf_dev_t *dev,
      uintptr_t regs, size_t reg_size, bool interrupts);
-
-int hc_register_hub(hc_t *instance);
 
 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
Index: uspace/drv/ohci/iface.h
===================================================================
--- uspace/drv/ohci/iface.h	(revision fa3de85013536f0386386c46bfaebceff2126a15)
+++ uspace/drv/ohci/iface.h	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -33,10 +33,8 @@
  * Common OHCI definitions.
  */
-#ifndef DRV_OHCI_OHCI_H
-#define DRV_OHCI_OHCI_H
+#ifndef DRV_OHCI_IFACE_H
+#define DRV_OHCI_IFACE_H
 
 #include <usbhc_iface.h>
-
-#define NAME "ohci"
 
 extern usbhc_iface_t hc_iface;
Index: uspace/drv/ohci/main.c
===================================================================
--- uspace/drv/ohci/main.c	(revision fa3de85013536f0386386c46bfaebceff2126a15)
+++ uspace/drv/ohci/main.c	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -34,57 +34,14 @@
  */
 #include <ddf/driver.h>
-#include <ddf/interrupt.h>
-#include <device/hw_res.h>
 #include <errno.h>
 #include <str_error.h>
 
-#include <usb_iface.h>
-#include <usb/ddfiface.h>
 #include <usb/debug.h>
 
-#include "pci.h"
-#include "iface.h"
-#include "hc.h"
+#include "ohci.h"
+
+#define NAME "ohci"
 
 static int ohci_add_device(ddf_dev_t *device);
-static int get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
-{
-	assert(handle);
-  assert(fun != NULL);
-
-  *handle = fun->handle;
-  return EOK;
-}
-/*----------------------------------------------------------------------------*/
-static int get_address(
-    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
-{
-	assert(fun);
-	usb_device_keeper_t *manager = &fun_to_hc(fun)->manager;
-  usb_address_t addr = usb_device_keeper_find(manager, handle);
-  if (addr < 0) {
-    return addr;
-  }
-
-  if (address != NULL) {
-    *address = addr;
-  }
-
-  return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** IRQ handling callback, identifies device
- *
- * @param[in] dev DDF instance of the device to use.
- * @param[in] iid (Unused).
- * @param[in] call Pointer to the call that represents interrupt.
- */
-static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
-{
-	assert(dev);
-	hc_t *hc = (hc_t*)dev->driver_data;
-	assert(hc);
-	hc_interrupt(hc, 0);
-}
 /*----------------------------------------------------------------------------*/
 static driver_ops_t ohci_driver_ops = {
@@ -97,14 +54,4 @@
 };
 /*----------------------------------------------------------------------------*/
-static usb_iface_t hc_usb_iface = {
-	.get_address = get_address,
-	.get_hc_handle = get_hc_handle,
-};
-/*----------------------------------------------------------------------------*/
-static ddf_dev_ops_t hc_ops = {
-	.interfaces[USB_DEV_IFACE] = &hc_usb_iface,
-	.interfaces[USBHC_DEV_IFACE] = &hc_iface,
-};
-/*----------------------------------------------------------------------------*/
 /** Initializes a new ddf driver instance of OHCI hcd.
  *
@@ -112,86 +59,25 @@
  * @return Error code.
  */
-static int ohci_add_device(ddf_dev_t *device)
+int ohci_add_device(ddf_dev_t *device)
 {
+	usb_log_debug("ohci_add_device() called\n");
 	assert(device);
-#define CHECK_RET_RETURN(ret, message...) \
-if (ret != EOK) { \
-	usb_log_error(message); \
-	return ret; \
-}
-
-	uintptr_t mem_reg_base = 0;
-	size_t mem_reg_size = 0;
-	int irq = 0;
-
-	int ret =
-	    pci_get_my_registers(device, &mem_reg_base, &mem_reg_size, &irq);
-	CHECK_RET_RETURN(ret,
-	    "Failed(%d) to get memory addresses:.\n", ret, device->handle);
-	usb_log_info("Memory mapped regs at 0x%X (size %zu), IRQ %d.\n",
-	    mem_reg_base, mem_reg_size, irq);
-
-	ret = pci_disable_legacy(device);
-	CHECK_RET_RETURN(ret,
-	    "Failed(%d) disable legacy USB: %s.\n", ret, str_error(ret));
-
-	hc_t *hcd = malloc(sizeof(hc_t));
-	if (hcd == NULL) {
+	ohci_t *ohci = malloc(sizeof(ohci_t));
+	if (ohci == NULL) {
 		usb_log_error("Failed to allocate OHCI driver.\n");
 		return ENOMEM;
 	}
 
-	ddf_fun_t *hc_fun = ddf_fun_create(device, fun_exposed, "ohci-hc");
-	if (hc_fun == NULL) {
-		usb_log_error("Failed to create OHCI function.\n");
-		free(hcd);
-		return ENOMEM;
-	}
-
-
-	bool interrupts = false;
-#ifdef CONFIG_USBHC_NO_INTERRUPTS
-	usb_log_warning("Interrupts disabled in OS config, " \
-	    "falling back to polling.\n");
-#else
-	ret = pci_enable_interrupts(device);
+	int ret = ohci_init(ohci, device);
 	if (ret != EOK) {
-		usb_log_warning("Failed to enable interrupts: %s.\n",
+		usb_log_error("Failed to initialize OHCI driver: %s.\n",
 		    str_error(ret));
-		usb_log_info("HW interrupts not available, " \
-		    "falling back to polling.\n");
-	} else {
-		usb_log_debug("Hw interrupts enabled.\n");
-		interrupts = true;
-	}
-#endif
-
-	ret = hc_init(hcd, hc_fun, device, mem_reg_base, mem_reg_size, interrupts);
-	if (ret != EOK) {
-		usb_log_error("Failed to initialize OHCI driver.\n");
-		free(hcd);
 		return ret;
 	}
+	device->driver_data = ohci;
 
-	ret = register_interrupt_handler(device, irq, irq_handler, NULL);
-
-	hc_fun->ops = &hc_ops;
-	ret = ddf_fun_bind(hc_fun);
-	if (ret != EOK) {
-		usb_log_error("Failed to bind OHCI function.\n");
-		ddf_fun_destroy(hc_fun);
-		free(hcd);
-		return ret;
-	}
-	hc_fun->driver_data = hcd;
-
-	fid_t later = fibril_create((int(*)(void*))hc_register_hub, hcd);
-	fibril_add_ready(later);
-
-	usb_log_info("Controlling new OHCI device `%s' (handle %llu).\n",
-	    device->name, device->handle);
+	usb_log_info("Controlling new OHCI device `%s'.\n", device->name);
 
 	return EOK;
-#undef CHECK_RET_RETURN
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/ohci/ohci.c
===================================================================
--- uspace/drv/ohci/ohci.c	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
+++ uspace/drv/ohci/ohci.c	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -0,0 +1,225 @@
+/*
+ * 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 UHCI driver
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/interrupt.h>
+#include <usb_iface.h>
+#include <usb/usb.h>
+#include <usb/ddfiface.h>
+#include <usb/debug.h>
+
+#include "ohci.h"
+#include "iface.h"
+#include "pci.h"
+
+/** IRQ handling callback, identifies device
+ *
+ * @param[in] dev DDF instance of the device to use.
+ * @param[in] iid (Unused).
+ * @param[in] call Pointer to the call that represents interrupt.
+ */
+static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
+{
+	assert(dev);
+	hc_t *hc = &((ohci_t*)dev->driver_data)->hc;
+	uint16_t status = IPC_GET_ARG1(*call);
+	assert(hc);
+	hc_interrupt(hc, status);
+}
+/*----------------------------------------------------------------------------*/
+/** Get address of the device identified by handle.
+ *
+ * @param[in] dev DDF instance of the device to use.
+ * @param[in] iid (Unused).
+ * @param[in] call Pointer to the call that represents interrupt.
+ */
+static int usb_iface_get_address(
+    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
+{
+	assert(fun);
+	usb_device_keeper_t *manager = &((ohci_t*)fun->dev->driver_data)->hc.manager;
+
+	usb_address_t addr = usb_device_keeper_find(manager, handle);
+	if (addr < 0) {
+		return addr;
+	}
+
+	if (address != NULL) {
+		*address = addr;
+	}
+
+	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 usb_iface_get_hc_handle(
+    ddf_fun_t *fun, devman_handle_t *handle)
+{
+	assert(handle);
+	ddf_fun_t *hc_fun = ((ohci_t*)fun->dev->driver_data)->hc_fun;
+	assert(hc_fun != NULL);
+
+	*handle = hc_fun->handle;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** This iface is generic for both RH and HC. */
+static usb_iface_t usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle,
+	.get_address = usb_iface_get_address
+};
+/*----------------------------------------------------------------------------*/
+static ddf_dev_ops_t hc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */
+};
+/*----------------------------------------------------------------------------*/
+static ddf_dev_ops_t rh_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface,
+};
+/*----------------------------------------------------------------------------*/
+/** Initialize hc and rh ddf structures and their respective drivers.
+ *
+ * @param[in] instance UHCI structure to use.
+ * @param[in] device DDF instance of the device to use.
+ *
+ * This function does all the preparatory work for hc and rh drivers:
+ *  - gets device hw resources
+ *  - disables UHCI legacy support
+ *  - asks for interrupt
+ *  - registers interrupt handler
+ */
+int ohci_init(ohci_t *instance, ddf_dev_t *device)
+{
+	assert(instance);
+	instance->hc_fun = NULL;
+	instance->rh_fun = NULL;
+#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
+if (ret != EOK) { \
+	usb_log_error(message); \
+	if (instance->hc_fun) \
+		ddf_fun_destroy(instance->hc_fun); \
+	if (instance->rh_fun) \
+		ddf_fun_destroy(instance->rh_fun); \
+	return ret; \
+}
+
+	uintptr_t mem_reg_base = 0;
+	size_t mem_reg_size = 0;
+	int irq = 0;
+
+	int ret =
+	    pci_get_my_registers(device, &mem_reg_base, &mem_reg_size, &irq);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to get memory addresses:.\n", ret, device->handle);
+	usb_log_debug("Memory mapped regs at 0x%X (size %zu), IRQ %d.\n",
+	    mem_reg_base, mem_reg_size, irq);
+
+	ret = pci_disable_legacy(device);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
+
+	bool interrupts = false;
+#ifdef CONFIG_USBHC_NO_INTERRUPTS
+	usb_log_warning("Interrupts disabled in OS config, " \
+	    "falling back to polling.\n");
+#else
+	ret = pci_enable_interrupts(device);
+	if (ret != EOK) {
+		usb_log_warning("Failed to enable interrupts: %s.\n",
+		    str_error(ret));
+		usb_log_info("HW interrupts not available, " \
+		    "falling back to polling.\n");
+	} else {
+		usb_log_debug("Hw interrupts enabled.\n");
+		interrupts = true;
+	}
+#endif
+
+	instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci-hc");
+	ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to create HC function.\n", ret);
+
+	ret = hc_init(&instance->hc, instance->hc_fun, device,
+	    mem_reg_base, mem_reg_size, interrupts);
+	CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init ohci-hcd.\n", ret);
+	instance->hc_fun->ops = &hc_ops;
+	instance->hc_fun->driver_data = &instance->hc;
+	ret = ddf_fun_bind(instance->hc_fun);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to bind UHCI device function: %s.\n",
+	    ret, str_error(ret));
+#undef CHECK_RET_HC_RETURN
+
+#define CHECK_RET_FINI_RETURN(ret, message...) \
+if (ret != EOK) { \
+	usb_log_error(message); \
+	if (instance->hc_fun) \
+		ddf_fun_destroy(instance->hc_fun); \
+	if (instance->rh_fun) \
+		ddf_fun_destroy(instance->rh_fun); \
+	hc_fini(&instance->hc); \
+	return ret; \
+}
+
+	/* It does no harm if we register this on polling */
+	ret = register_interrupt_handler(device, irq, irq_handler, NULL);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to register interrupt handler.\n", ret);
+
+	instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci-rh");
+	ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to create root hub function.\n", ret);
+
+	hc_register_hub(&instance->hc, instance->rh_fun);
+
+	instance->rh_fun->ops = &rh_ops;
+	instance->rh_fun->driver_data = NULL;
+	ret = ddf_fun_bind(instance->rh_fun);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to register UHCI root hub.\n", ret);
+
+	return EOK;
+#undef CHECK_RET_FINI_RETURN
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/ohci.h
===================================================================
--- uspace/drv/ohci/ohci.h	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
+++ uspace/drv/ohci/ohci.h	(revision 53f1c875f5885a2c30ff0c8f56d9e97f03564f5e)
@@ -0,0 +1,56 @@
+/*
+ * 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 main structure for both host controller and root-hub.
+ */
+#ifndef DRV_OHCI_OHCI_H
+#define DRV_OHCI_OHCI_H
+#include <ddi.h>
+#include <ddf/driver.h>
+
+#include "hc.h"
+#include "root_hub.h"
+
+typedef struct ohci {
+	ddf_fun_t *hc_fun;
+	ddf_fun_t *rh_fun;
+
+	hc_t hc;
+	rh_t rh;
+} ohci_t;
+
+int ohci_init(ohci_t *instance, ddf_dev_t *device);
+
+#endif
+/**
+ * @}
+ */
