Index: uspace/drv/bus/usb/ehci/hc.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ehci/hc.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -89,5 +89,4 @@
 };
 
-static void hc_start(hc_t *instance);
 static int hc_init_memory(hc_t *instance);
 
@@ -98,8 +97,10 @@
  * @return Error code.
  */
-int ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
+int ehci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
 {
 	assert(code);
 	assert(hw_res);
+
+	hc_t *instance = hcd_get_driver_data(hcd);
 
 	if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1)
@@ -128,17 +129,7 @@
 
 	memcpy(code->cmds, ehci_irq_commands, sizeof(ehci_irq_commands));
-	ehci_caps_regs_t *caps = NULL;
-
-	int ret = pio_enable_range(&regs, (void**)&caps);
-	if (ret != EOK) {
-		free(code->ranges);
-		free(code->cmds);
-		return ret;
-	}
-
-	ehci_regs_t *registers =
-	    (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(caps->caplength));
-	code->cmds[0].addr = (void *) &registers->usbsts;
-	code->cmds[3].addr = (void *) &registers->usbsts;
+
+	code->cmds[0].addr = (void *) &instance->registers->usbsts;
+	code->cmds[3].addr = (void *) &instance->registers->usbsts;
 	EHCI_WR(code->cmds[1].value, EHCI_USED_INTERRUPTS);
 
@@ -156,5 +147,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,4 +163,5 @@
 		return ret;
 	}
+
 	usb_log_info("HC(%p): Device registers at %"PRIx64" (%zuB) accessible.",
 	    instance, hw_res->mem_ranges.ranges[0].address.absolute,
@@ -195,6 +187,4 @@
 	ehci_rh_init(
 	    &instance->rh, instance->caps, instance->registers, "ehci rh");
-	usb_log_debug("HC(%p): Starting HW.", instance);
-	hc_start(instance);
 
 	return EOK;
@@ -368,7 +358,9 @@
  * @param[in] instance EHCI hc driver structure.
  */
-void hc_start(hc_t *instance)
-{
-	assert(instance);
+int hc_start(hc_t *instance, bool interrupts)
+{
+	assert(instance);
+	usb_log_debug("HC(%p): Starting HW.", instance);
+
 	/* Turn off the HC if it's running, Reseting a running device is
 	 * undefined */
@@ -435,4 +427,6 @@
 	EHCI_WR(instance->registers->usbsts, EHCI_RD(instance->registers->usbsts));
 	EHCI_WR(instance->registers->usbintr, EHCI_USED_INTERRUPTS);
+
+	return EOK;
 }
 
Index: uspace/drv/bus/usb/ehci/hc.h
===================================================================
--- uspace/drv/bus/usb/ehci/hc.h	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ehci/hc.h	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -82,5 +82,6 @@
 } hc_t;
 
-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);
+int hc_start(hc_t *instance, bool interrupts);
 void hc_fini(hc_t *instance);
 
@@ -88,5 +89,5 @@
 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep);
 
-int ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res);
+int ehci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res);
 
 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status);
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ehci/main.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -52,14 +52,17 @@
 #define NAME "ehci"
 
-static int ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
+static int ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *);
+static int ehci_driver_claim(hcd_t *, ddf_dev_t *);
+static int ehci_driver_start(hcd_t *, bool);
 static void ehci_driver_fini(hcd_t *);
 
 static const ddf_hc_driver_t ehci_hc_driver = {
-	.claim = disable_legacy,
 	.hc_speed = USB_SPEED_HIGH,
+	.name = "EHCI-PCI",
+	.init = ehci_driver_init,
 	.irq_code_gen = ehci_hc_gen_irq_code,
-	.init = ehci_driver_init,
+	.claim = ehci_driver_claim,
+	.start = ehci_driver_start,
 	.fini = ehci_driver_fini,
-	.name = "EHCI-PCI",
 	.ops = {
 		.schedule       = ehci_hc_schedule,
@@ -72,6 +75,5 @@
 
 
-static int ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res,
-    bool irq)
+static int ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res)
 {
 	assert(hcd);
@@ -82,5 +84,5 @@
 		return ENOMEM;
 
-	const int ret = hc_init(instance, res, irq);
+	const int ret = hc_init(instance, res);
 	if (ret == EOK) {
 		hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops);
@@ -89,4 +91,19 @@
 	}
 	return ret;
+}
+
+static int ehci_driver_claim(hcd_t *hcd, ddf_dev_t *dev)
+{
+	hc_t *instance = hcd_get_driver_data(hcd);
+	assert(instance);
+
+	return disable_legacy(instance, dev);
+}
+
+static int ehci_driver_start(hcd_t *hcd, bool irq) {
+	hc_t *instance = hcd_get_driver_data(hcd);
+	assert(instance);
+
+	return hc_start(instance, irq);
 }
 
Index: uspace/drv/bus/usb/ehci/res.c
===================================================================
--- uspace/drv/bus/usb/ehci/res.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ehci/res.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -172,5 +172,5 @@
 }
 
-int disable_legacy(ddf_dev_t *device)
+int disable_legacy(hc_t *hc, ddf_dev_t *device)
 {
 	assert(device);
@@ -183,34 +183,6 @@
 	usb_log_debug("Disabling EHCI legacy support.\n");
 
-	hw_res_list_parsed_t res;
-	hw_res_list_parsed_init(&res);
-	int ret = hw_res_get_list_parsed(parent_sess, &res, 0);
-	if (ret != EOK) {
-		usb_log_error("Failed to get resource list: %s\n",
-		    str_error(ret));
-		goto clean;
-	}
-
-	if (res.mem_ranges.count < 1) {
-		usb_log_error("Incorrect mem range count: %zu",
-		    res.mem_ranges.count);
-		ret = EINVAL;
-		goto clean;
-	}
-
-	/* Map EHCI registers */
-	void *regs = NULL;
-	ret = pio_enable_range(&res.mem_ranges.ranges[0], &regs);
-	if (ret != EOK) {
-		usb_log_error("Failed to map registers %p: %s.\n",
-		    RNGABSPTR(res.mem_ranges.ranges[0]), str_error(ret));
-		goto clean;
-	}
-
-	usb_log_debug("Registers mapped at: %p.\n", regs);
-
-	ehci_caps_regs_t *ehci_caps = regs;
-
-	const uint32_t hcc_params = EHCI_RD(ehci_caps->hccparams);
+
+	const uint32_t hcc_params = EHCI_RD(hc->caps->hccparams);
 	usb_log_debug2("Value of hcc params register: %x.\n", hcc_params);
 
@@ -221,5 +193,5 @@
 	usb_log_debug2("Value of EECP: %x.\n", eecp);
 
-	ret = disable_extended_caps(parent_sess, eecp);
+	int ret = disable_extended_caps(parent_sess, eecp);
 	if (ret != EOK) {
 		usb_log_error("Failed to disable extended capabilities: %s.\n",
@@ -228,6 +200,4 @@
 	}
 clean:
-	//TODO unmap registers
-	hw_res_list_parsed_clean(&res);
 	async_hangup(parent_sess);
 	return ret;
Index: uspace/drv/bus/usb/ehci/res.h
===================================================================
--- uspace/drv/bus/usb/ehci/res.h	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ehci/res.h	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -39,5 +39,7 @@
 #include <device/hw_res_parsed.h>
 
-extern int disable_legacy(ddf_dev_t *);
+#include "hc.h"
+
+extern int disable_legacy(hc_t *, ddf_dev_t *);
 
 #endif
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -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;
@@ -443,4 +435,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 cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -80,5 +80,7 @@
 } 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 +88,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/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/ohci/main.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -47,5 +47,7 @@
 
 #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 *);
+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 *);
 
@@ -54,4 +56,6 @@
         .irq_code_gen = ohci_hc_gen_irq_code,
         .init = ohci_driver_init,
+        .claim = ohci_driver_claim,
+        .start = ohci_driver_start,
         .fini = ohci_driver_fini,
         .name = "OHCI",
@@ -66,5 +70,5 @@
 
 
-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)
 {
 	assert(hcd);
@@ -75,5 +79,5 @@
 		return ENOMEM;
 
-	const int ret = hc_init(instance, res, irq);
+	const int ret = hc_init(instance, res);
 	if (ret == EOK) {
 		hcd_set_implementation(hcd, instance, &ohci_hc_driver.ops);
@@ -82,4 +86,24 @@
 	}
 	return ret;
+}
+
+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;
 }
 
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -106,5 +106,5 @@
  * @return Error code.
  */
-int uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
+int uhci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
 {
 	assert(code);
@@ -214,5 +214,5 @@
  * interrupt fibrils.
  */
-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);
@@ -222,5 +222,4 @@
 	    return EINVAL;
 
-	instance->hw_interrupts = interrupts;
 	instance->hw_failures = 0;
 
@@ -246,10 +245,13 @@
 	}
 
+	return EOK;
+}
+
+void hc_start(hc_t *instance)
+{
 	hc_init_hw(instance);
 	(void)hc_debug_checker;
 
 	uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
-
-	return EOK;
 }
 
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -124,8 +124,9 @@
 } 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_start(hc_t *);
 extern void hc_fini(hc_t *);
 
-extern int uhci_hc_gen_irq_code(irq_code_t *, const hw_res_list_parsed_t *);
+extern int uhci_hc_gen_irq_code(irq_code_t *, hcd_t *,const hw_res_list_parsed_t *);
 
 extern void uhci_hc_interrupt(hcd_t *, uint32_t);
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/uhci/main.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -50,7 +50,8 @@
 #define NAME "uhci"
 
-static int uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
+static int uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *);
+static int uhci_driver_start(hcd_t *, bool);
 static void uhci_driver_fini(hcd_t *);
-static int disable_legacy(ddf_dev_t *);
+static int disable_legacy(hcd_t *, ddf_dev_t *);
 
 static const ddf_hc_driver_t uhci_hc_driver = {
@@ -59,4 +60,5 @@
         .irq_code_gen = uhci_hc_gen_irq_code,
         .init = uhci_driver_init,
+        .start = uhci_driver_start,
         .fini = uhci_driver_fini,
         .name = "UHCI",
@@ -68,5 +70,5 @@
 };
 
-static int uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)
+static int uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res)
 {
 	assert(hcd);
@@ -77,5 +79,5 @@
 		return ENOMEM;
 
-	const int ret = hc_init(instance, res, irq);
+	const int ret = hc_init(instance, res);
 	if (ret == EOK) {
 		hcd_set_implementation(hcd, instance, &uhci_hc_driver.ops);
@@ -84,4 +86,14 @@
 	}
 	return ret;
+}
+
+static int uhci_driver_start(hcd_t *hcd, bool interrupts)
+{
+	assert(hcd);
+	hc_t *hc = hcd_get_driver_data(hcd);
+
+	hc->hw_interrupts = interrupts;
+	hc_start(hc);
+	return EOK;
 }
 
@@ -102,5 +114,5 @@
  * @return Error code.
  */
-static int disable_legacy(ddf_dev_t *device)
+static int disable_legacy(hcd_t *hcd, ddf_dev_t *device)
 {
 	assert(device);
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -37,5 +37,4 @@
 #include <str_error.h>
 #include <usb/debug.h>
-#include <usb/host/ddf_helpers.h>
 #include <usb/host/utils/malloc32.h>
 #include "debug.h"
@@ -70,4 +69,71 @@
 };
 
+int hc_init_mmio(xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
+{
+	int err;
+
+	if (hw_res->mem_ranges.count != 1) {
+		usb_log_error("Unexpected MMIO area, bailing out.");
+		return EINVAL;
+	}
+
+	hc->mmio_range = hw_res->mem_ranges.ranges[0];
+
+	usb_log_debug("MMIO area at %p (size %zu), IRQ %d.\n",
+	    RNGABSPTR(hc->mmio_range), RNGSZ(hc->mmio_range), hw_res->irqs.irqs[0]);
+
+	if (RNGSZ(hc->mmio_range) < sizeof(xhci_cap_regs_t))
+		return EOVERFLOW;
+
+	void *base;
+	if ((err = pio_enable_range(&hc->mmio_range, &base)))
+		return err;
+
+	hc->cap_regs = (xhci_cap_regs_t *)  base;
+	hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
+	hc->rt_regs  = (xhci_rt_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
+	hc->db_arry  = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
+
+	usb_log_debug2("Initialized MMIO reg areas:");
+	usb_log_debug2("\tCapability regs: %p", hc->cap_regs);
+	usb_log_debug2("\tOperational regs: %p", hc->op_regs);
+	usb_log_debug2("\tRuntime regs: %p", hc->rt_regs);
+	usb_log_debug2("\tDoorbell array base: %p", hc->db_arry);
+
+	xhci_dump_cap_regs(hc->cap_regs);
+
+	hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
+	hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
+
+	return EOK;
+}
+
+int hc_init_memory(xhci_hc_t *hc)
+{
+	int err;
+
+	hc->dcbaa = malloc32((1 + hc->max_slots) * sizeof(xhci_device_ctx_t));
+	if (!hc->dcbaa)
+		return ENOMEM;
+
+	if ((err = xhci_trb_ring_init(&hc->command_ring, hc)))
+		goto err_dcbaa;
+
+	if ((err = xhci_event_ring_init(&hc->event_ring, hc)))
+		goto err_cmd_ring;
+
+	// TODO: Allocate scratchpad buffers
+
+	return EOK;
+
+	xhci_event_ring_fini(&hc->event_ring);
+err_cmd_ring:
+	xhci_trb_ring_fini(&hc->command_ring);
+err_dcbaa:
+	free32(hc->dcbaa);
+	return err;
+}
+
+
 /**
  * Generates code to accept interrupts. The xHCI is designed primarily for
@@ -75,12 +141,10 @@
  * (except 0) are disabled.
  */
-static int hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
-{
-	int err;
-
+int hc_irq_code_gen(irq_code_t *code, xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
+{
 	assert(code);
 	assert(hw_res);
 
-	if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1) {
+	if (hw_res->irqs.count != 1) {
 		usb_log_info("Unexpected HW resources to enable interrupts.");
 		return EINVAL;
@@ -88,12 +152,4 @@
 
 	addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
-
-	if (RNGSZ(mmio_range) < sizeof(xhci_cap_regs_t))
-		return EOVERFLOW;
-
-
-	xhci_cap_regs_t *cap_regs = NULL;
-	if ((err = pio_enable_range(&mmio_range, (void **)&cap_regs)))
-		return EIO;
 
 	code->ranges = malloc(sizeof(irq_pio_range_t));
@@ -116,5 +172,5 @@
 	memcpy(code->cmds, irq_commands, sizeof(irq_commands));
 
-	void *intr0_iman = RNGABSPTR(mmio_range) + XHCI_REG_RD(cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
+	void *intr0_iman = RNGABSPTR(mmio_range) + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF) + offsetof(xhci_rt_regs_t, ir[0]);
 	code->cmds[0].addr = intr0_iman;
 	code->cmds[3].addr = intr0_iman;
@@ -124,7 +180,7 @@
 }
 
-static int hc_claim(ddf_dev_t *dev)
-{
-	// TODO: implement handoff: section 4.22.1
+int hc_claim(xhci_hc_t *hc, ddf_dev_t *dev)
+{
+	// TODO: impl
 	return EOK;
 }
@@ -152,5 +208,5 @@
  * Initialize the HC: section 4.2
  */
-static int hc_start(xhci_hc_t *hc, bool irq)
+int hc_start(xhci_hc_t *hc, bool irq)
 {
 	int err;
@@ -191,92 +247,9 @@
 }
 
-static int hc_init(hcd_t *hcd, const hw_res_list_parsed_t *hw_res, bool irq)
-{
-	int err;
-
-	assert(hcd);
-	assert(hw_res);
-	assert(hcd_get_driver_data(hcd) == NULL);
-
-	/* Initialize the MMIO ranges */
-	if (hw_res->mem_ranges.count != 1) {
-		usb_log_error("Unexpected MMIO area, bailing out.");
-		return EINVAL;
-	}
-
-	addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
-
-	usb_log_debug("MMIO area at %p (size %zu), IRQ %d.\n",
-	    RNGABSPTR(mmio_range), RNGSZ(mmio_range), hw_res->irqs.irqs[0]);
-
-	if (RNGSZ(mmio_range) < sizeof(xhci_cap_regs_t))
-		return EOVERFLOW;
-
-	void *base;
-	if ((err = pio_enable_range(&mmio_range, &base)))
-		return err;
-
-	xhci_hc_t *hc = malloc(sizeof(xhci_hc_t));
-	if (!hc)
-		return ENOMEM;
-
-	hc->cap_regs = (xhci_cap_regs_t *)  base;
-	hc->op_regs  = (xhci_op_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_LENGTH));
-	hc->rt_regs  = (xhci_rt_regs_t *)  (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_RTSOFF));
-	hc->db_arry  = (xhci_doorbell_t *) (base + XHCI_REG_RD(hc->cap_regs, XHCI_CAP_DBOFF));
-
-	usb_log_debug2("Initialized MMIO reg areas:");
-	usb_log_debug2("\tCapability regs: %p", hc->cap_regs);
-	usb_log_debug2("\tOperational regs: %p", hc->op_regs);
-	usb_log_debug2("\tRuntime regs: %p", hc->rt_regs);
-	usb_log_debug2("\tDoorbell array base: %p", hc->db_arry);
-
-	xhci_dump_cap_regs(hc->cap_regs);
-
-	hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64);
-	hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS);
-
-	hc->dcbaa = malloc32((1 + hc->max_slots) * sizeof(xhci_device_ctx_t));
-	if (!hc->dcbaa)
-		goto err_hc;
-
-	if ((err = xhci_trb_ring_init(&hc->command_ring, hc)))
-		goto err_dcbaa;
-
-	if ((err = xhci_event_ring_init(&hc->event_ring, hc)))
-		goto err_cmd_ring;
-
-	// TODO: Allocate scratchpad buffers
-
-	hcd_set_implementation(hcd, hc, &xhci_ddf_hc_driver.ops);
-
-	if ((err = hc_start(hc, irq)))
-		goto err_event_ring;
-
-	return EOK;
-
-err_event_ring:
-	xhci_event_ring_fini(&hc->event_ring);
-err_cmd_ring:
-	xhci_trb_ring_fini(&hc->command_ring);
-err_dcbaa:
-	free32(hc->dcbaa);
-err_hc:
-	free(hc);
-	hcd_set_implementation(hcd, NULL, NULL);
-	return err;
-}
-
-static int hc_status(hcd_t *hcd, uint32_t *status)
-{
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-	assert(status);
-
-	*status = 0;
-	if (hc->op_regs) {
-		*status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
-		XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
-	}
+int hc_status(xhci_hc_t *hc, uint32_t *status)
+{
+	*status = XHCI_REG_RD(hc->op_regs, XHCI_OP_STATUS);
+	XHCI_REG_WR(hc->op_regs, XHCI_OP_STATUS, *status & XHCI_STATUS_ACK_MASK);
+
 	usb_log_debug2("HC(%p): Read status: %x", hc, *status);
 	return EOK;
@@ -305,9 +278,6 @@
 }
 
-static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
-{
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
+int hc_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch)
+{
 	xhci_dump_state(hc);
 	send_no_op_command(hc);
@@ -346,9 +316,6 @@
 }
 
-static void hc_interrupt(hcd_t *hcd, uint32_t status)
-{
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
+void hc_interrupt(xhci_hc_t *hc, uint32_t status)
+{
 	if (status & XHCI_REG_MASK(XHCI_OP_HSE)) {
 		usb_log_error("Host controller error occured. Bad things gonna happen...");
@@ -375,31 +342,10 @@
 }
 
-static void hc_fini(hcd_t *hcd)
-{
-	xhci_hc_t *hc = hcd_get_driver_data(hcd);
-	assert(hc);
-
-	usb_log_info("Finishing");
-
+void hc_fini(xhci_hc_t *hc)
+{
 	xhci_trb_ring_fini(&hc->command_ring);
 	xhci_event_ring_fini(&hc->event_ring);
-
-	free(hc);
-	hcd_set_implementation(hcd, NULL, NULL);
-}
-
-const ddf_hc_driver_t xhci_ddf_hc_driver = {
-	.hc_speed = USB_SPEED_SUPER,
-	.irq_code_gen = hc_gen_irq_code,
-	.claim = hc_claim,
-	.init = hc_init,
-	.fini = hc_fini,
-	.name = "XHCI-PCI",
-	.ops = {
-		.schedule       = hc_schedule,
-		.irq_hook       = hc_interrupt,
-		.status_hook    = hc_status,
-	}
-};
+	usb_log_info("HC(%p): Finalized.", hc);
+}
 
 
Index: uspace/drv/bus/usb/xhci/hc.h
===================================================================
--- uspace/drv/bus/usb/xhci/hc.h	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/xhci/hc.h	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -34,5 +34,5 @@
  */
 
-#include <usb/host/ddf_helpers.h>
+#include <usb/host/usb_transfer_batch.h>
 #include "hw_struct/regs.h"
 #include "hw_struct/context.h"
@@ -44,4 +44,6 @@
 	xhci_rt_regs_t *rt_regs;
 	xhci_doorbell_t *db_arry;
+
+	addr_range_t mmio_range;
 
 	xhci_trb_ring_t command_ring;
@@ -55,6 +57,13 @@
 } xhci_hc_t;
 
-extern const ddf_hc_driver_t xhci_ddf_hc_driver;
-
+int hc_init_mmio(xhci_hc_t *, const hw_res_list_parsed_t *);
+int hc_init_memory(xhci_hc_t *);
+int hc_claim(xhci_hc_t *, ddf_dev_t *);
+int hc_irq_code_gen(irq_code_t *, xhci_hc_t *, const hw_res_list_parsed_t *);
+int hc_start(xhci_hc_t *, bool);
+int hc_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch);
+int hc_status(xhci_hc_t *, uint32_t *);
+void hc_interrupt(xhci_hc_t *, uint32_t);
+void hc_fini(xhci_hc_t *);
 
 /**
Index: uspace/drv/bus/usb/xhci/main.c
===================================================================
--- uspace/drv/bus/usb/xhci/main.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/drv/bus/usb/xhci/main.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -45,4 +45,108 @@
 #define NAME "xhci"
 
+static int hc_driver_init(hcd_t *, const hw_res_list_parsed_t *);
+static int hcd_irq_code_gen(irq_code_t *, hcd_t *, const hw_res_list_parsed_t *);
+static int hcd_claim(hcd_t *, ddf_dev_t *);
+static int hcd_start(hcd_t *, bool);
+static int hcd_status(hcd_t *, uint32_t *);
+static void hcd_interrupt(hcd_t *, uint32_t);
+static int hcd_schedule(hcd_t *, usb_transfer_batch_t *);
+static void hc_driver_fini(hcd_t *);
+
+static const ddf_hc_driver_t xhci_ddf_hc_driver = {
+	.hc_speed = USB_SPEED_SUPER,
+	.name = "XHCI-PCI",
+	.init = hc_driver_init,
+	.irq_code_gen = hcd_irq_code_gen,
+	.claim = hcd_claim,
+	.start = hcd_start,
+	.fini = hc_driver_fini,
+	.ops = {
+		.schedule       = hcd_schedule,
+		.irq_hook       = hcd_interrupt,
+		.status_hook    = hcd_status,
+	}
+};
+
+static int hc_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
+{
+	int err;
+
+	xhci_hc_t *hc = malloc(sizeof(xhci_hc_t));
+	if (!hc)
+		return ENOMEM;
+
+	if ((err = hc_init_mmio(hc, hw_res)))
+		goto err;
+
+	if ((err = hc_init_memory(hc)))
+		goto err;
+
+	hcd_set_implementation(hcd, hc, &xhci_ddf_hc_driver.ops);
+
+	return EOK;
+err:
+	free(hc);
+	return err;
+}
+
+static int hcd_irq_code_gen(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	return hc_irq_code_gen(code, hc, hw_res);
+}
+
+static int hcd_claim(hcd_t *hcd, ddf_dev_t *dev)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	return hc_claim(hc, dev);
+}
+
+static int hcd_start(hcd_t *hcd, bool irq)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	return hc_start(hc, irq);
+}
+
+static int hcd_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	return hc_schedule(hc, batch);
+}
+
+static int hcd_status(hcd_t *hcd, uint32_t *status)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+	assert(status);
+
+	return hc_status(hc, status);
+}
+
+static void hcd_interrupt(hcd_t *hcd, uint32_t status)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	hc_interrupt(hc, status);
+}
+
+static void hc_driver_fini(hcd_t *hcd)
+{
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	assert(hc);
+
+	hc_fini(hc);
+	free(hc);
+}
+
 /** Initializes a new ddf driver instance of XHCI hcd.
  *
Index: uspace/lib/usbhost/include/usb/host/ddf_helpers.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/lib/usbhost/include/usb/host/ddf_helpers.h	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -45,18 +45,31 @@
 #include <device/hw_res_parsed.h>
 
-typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, bool);
+typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *);
+typedef int (*irq_code_gen_t)(irq_code_t *, hcd_t *, const hw_res_list_parsed_t *);
+typedef int (*claim_t)(hcd_t *, ddf_dev_t *);
+typedef int (*driver_start_t)(hcd_t *, bool irq);
+
+typedef void (*driver_stop_t)(hcd_t *);
 typedef void (*driver_fini_t)(hcd_t *);
-typedef int (*claim_t)(ddf_dev_t *);
-typedef int (*irq_code_gen_t)(irq_code_t *, const hw_res_list_parsed_t *);
 
+/**
+ * All callbacks are optional.
+ */
 typedef struct {
 	hcd_ops_t ops;
-	claim_t claim;
 	usb_speed_t hc_speed;
-	driver_init_t init;
-	driver_fini_t fini;
-	interrupt_handler_t *irq_handler;
-	irq_code_gen_t irq_code_gen;
 	const char *name;
+
+	interrupt_handler_t *irq_handler;  /**< Handler of IRQ. Do have generic implementation. */
+
+	/* Initialization sequence: */
+	driver_init_t init;                /**< Initialize internal structures, memory */
+	claim_t claim;                     /**< Claim device from BIOS */
+	irq_code_gen_t irq_code_gen;       /**< Generate IRQ handling code */
+	driver_start_t start;              /**< Start the HC */
+
+	/* Destruction sequence: */
+	driver_stop_t stop;                /**< Stop the HC (counterpart of start) */
+	driver_fini_t fini;                /**< Destroy internal structures (counterpart of init) */
 } ddf_hc_driver_t;
 
@@ -75,5 +88,5 @@
     const hw_res_list_parsed_t *hw_res,
     interrupt_handler_t handler,
-    int (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *));
+    irq_code_gen_t gen_irq_code);
 void ddf_hcd_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev);
 
Index: uspace/lib/usbhost/src/ddf_helpers.c
===================================================================
--- uspace/lib/usbhost/src/ddf_helpers.c	(revision cb89430129f9d8d3b93b48217d53165f33b1774f)
+++ uspace/lib/usbhost/src/ddf_helpers.c	(revision e4d7363ab09538c786991a26952f1695de85df2c)
@@ -753,8 +753,10 @@
     const hw_res_list_parsed_t *hw_res,
     interrupt_handler_t handler,
-    int (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *hw_res))
-{
-
+    irq_code_gen_t gen_irq_code)
+{
 	assert(device);
+
+	hcd_t *hcd = dev_to_hcd(device);
+
 	if (!handler || !gen_irq_code)
 		return ENOTSUP;
@@ -762,5 +764,5 @@
 	irq_code_t irq_code = {0};
 
-	const int irq = gen_irq_code(&irq_code, hw_res);
+	const int irq = gen_irq_code(&irq_code, hcd, hw_res);
 	if (irq < 0) {
 		usb_log_error("Failed to generate IRQ code: %s.\n",
@@ -878,32 +880,39 @@
 	if (ret != EOK) {
 		usb_log_error("Failed to setup generic HCD.\n");
-		hw_res_list_parsed_clean(&hw_res);
-		return ret;
-	}
-
+		goto err_hw_res;
+	}
+
+	hcd_t *hcd = dev_to_hcd(device);
+
+	if (driver->init)
+		ret = driver->init(hcd, &hw_res);
+	if (ret != EOK) {
+		usb_log_error("Failed to init HCD.\n");
+		goto err_hcd;
+	}
+
+	/* Setup interrupts  */
 	interrupt_handler_t *irq_handler =
 	    driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;
-	const int irq = hcd_ddf_setup_interrupts(device, &hw_res, irq_handler,
-	    driver->irq_code_gen);
+	const int irq = hcd_ddf_setup_interrupts(device, &hw_res, irq_handler, driver->irq_code_gen);
 	if (!(irq < 0)) {
 		usb_log_debug("Hw interrupts enabled.\n");
 	}
 
+	/* Claim the device from BIOS */
 	if (driver->claim)
-		ret = driver->claim(device);
-	if (ret != EOK) {
-		usb_log_error("Failed to claim `%s' for driver `%s'",
-		    ddf_dev_get_name(device), driver->name);
-		return ret;
-	}
-
-
-	/* Init hw driver */
-	hcd_t *hcd = dev_to_hcd(device);
-	ret = driver->init(hcd, &hw_res, !(irq < 0));
-	hw_res_list_parsed_clean(&hw_res);
-	if (ret != EOK) {
-		usb_log_error("Failed to init HCD: %s.\n", str_error(ret));
-		goto irq_unregister;
+		ret = driver->claim(hcd, device);
+	if (ret != EOK) {
+		usb_log_error("Failed to claim `%s' for driver `%s': %s",
+		    ddf_dev_get_name(device), driver->name, str_error(ret));
+		goto err_irq;
+	}
+
+	/* Start hw driver */
+	if (driver->start)
+		ret = driver->start(hcd, !(irq < 0));
+	if (ret != EOK) {
+		usb_log_error("Failed to start HCD: %s.\n", str_error(ret));
+		goto err_irq;
 	}
 
@@ -914,5 +923,5 @@
 			usb_log_error("Failed to create polling fibril\n");
 			ret = ENOMEM;
-			goto irq_unregister;
+			goto err_started;
 		}
 		fibril_add_ready(hcd->polling_fibril);
@@ -929,10 +938,5 @@
 		usb_log_error("Failed to setup HC root hub: %s.\n",
 		    str_error(ret));
-		driver->fini(dev_to_hcd(device));
-irq_unregister:
-		/* Unregistering non-existent should be ok */
-		unregister_interrupt_handler(device, irq);
-		hcd_ddf_clean_hc(device);
-		return ret;
+		goto err_polling;
 	}
 
@@ -940,4 +944,20 @@
 	    driver->name, ddf_dev_get_name(device));
 	return EOK;
+	
+err_polling:
+	// TODO: Stop the polling fibril (refactor the interrupt_polling func)
+	//
+err_started:
+	if (driver->stop)
+		driver->stop(hcd);
+err_irq:
+	unregister_interrupt_handler(device, irq);
+	if (driver->fini)
+		driver->fini(hcd);
+err_hcd:
+	hcd_ddf_clean_hc(device);
+err_hw_res:
+	hw_res_list_parsed_clean(&hw_res);
+	return ret;
 }
 /**
