Index: uspace/drv/bus/usb/xhci/debug.c
===================================================================
--- uspace/drv/bus/usb/xhci/debug.c	(revision ce6e001ef0a10ca6ac198e109c24150d184e9954)
+++ uspace/drv/bus/usb/xhci/debug.c	(revision 62ba2cbee5c3230302472cecb3778a285cb40cd4)
@@ -38,18 +38,21 @@
 
 #include "debug.h"
+#include "hc.h"
+
+#define PX "\t%-21s = "
 
 #define DUMP_REG_FIELD(ptr, title, size, ...) \
-	usb_log_debug2(title "%" PRIu##size, XHCI_REG_RD_FIELD(ptr, size, ##__VA_ARGS__))
+	usb_log_debug2(PX "%" PRIu##size, title, XHCI_REG_RD_FIELD(ptr, size, ##__VA_ARGS__))
 
 #define DUMP_REG_RANGE(ptr, title, size, ...) \
-	usb_log_debug2(title "%" PRIu##size, XHCI_REG_RD_RANGE(ptr, size, ##__VA_ARGS__))
+	usb_log_debug2(PX "%" PRIu##size, title, XHCI_REG_RD_RANGE(ptr, size, ##__VA_ARGS__))
 
 #define DUMP_REG_FLAG(ptr, title, size, ...) \
-	usb_log_debug2(title "%s", XHCI_REG_RD_FLAG(ptr, size, ##__VA_ARGS__) ? "true" : "false")
+	usb_log_debug2(PX "%s", title, XHCI_REG_RD_FLAG(ptr, size, ##__VA_ARGS__) ? "true" : "false")
 
 #define DUMP_REG_INNER(set, title, field, size, type, ...) \
 	DUMP_REG_##type(&(set)->field, title, size, ##__VA_ARGS__)
 
-#define DUMP_REG(set, c) DUMP_REG_INNER(set, "\t" #c ": ", c)
+#define DUMP_REG(set, c) DUMP_REG_INNER(set, #c, c)
 
 /**
@@ -92,4 +95,69 @@
 }
 
+void xhci_dump_port(xhci_port_regs_t *port)
+{
+	DUMP_REG(port, XHCI_PORT_CCS);
+	DUMP_REG(port, XHCI_PORT_PED);
+	DUMP_REG(port, XHCI_PORT_OCA);
+	DUMP_REG(port, XHCI_PORT_PR);
+	DUMP_REG(port, XHCI_PORT_PLS);
+	DUMP_REG(port, XHCI_PORT_PP);
+	DUMP_REG(port, XHCI_PORT_PIC);
+	DUMP_REG(port, XHCI_PORT_LWS);
+	DUMP_REG(port, XHCI_PORT_CSC);
+	DUMP_REG(port, XHCI_PORT_PEC);
+	DUMP_REG(port, XHCI_PORT_WRC);
+	DUMP_REG(port, XHCI_PORT_OCC);
+	DUMP_REG(port, XHCI_PORT_PRC);
+	DUMP_REG(port, XHCI_PORT_PLC);
+	DUMP_REG(port, XHCI_PORT_CEC);
+	DUMP_REG(port, XHCI_PORT_CAS);
+	DUMP_REG(port, XHCI_PORT_WCE);
+	DUMP_REG(port, XHCI_PORT_WDE);
+	DUMP_REG(port, XHCI_PORT_WOE);
+	DUMP_REG(port, XHCI_PORT_DR);
+	DUMP_REG(port, XHCI_PORT_WPR);
+}
+
+void xhci_dump_state(xhci_hc_t *hc)
+{
+	usb_log_debug2("Operational registers:");
+
+	DUMP_REG(hc->op_regs, XHCI_OP_RS);
+	DUMP_REG(hc->op_regs, XHCI_OP_RS);
+	DUMP_REG(hc->op_regs, XHCI_OP_HCRST);
+	DUMP_REG(hc->op_regs, XHCI_OP_INTE);
+	DUMP_REG(hc->op_regs, XHCI_OP_HSEE);
+	DUMP_REG(hc->op_regs, XHCI_OP_LHCRST);
+	DUMP_REG(hc->op_regs, XHCI_OP_CSS);
+	DUMP_REG(hc->op_regs, XHCI_OP_CRS);
+	DUMP_REG(hc->op_regs, XHCI_OP_EWE);
+	DUMP_REG(hc->op_regs, XHCI_OP_EU3S);
+	DUMP_REG(hc->op_regs, XHCI_OP_CME);
+	DUMP_REG(hc->op_regs, XHCI_OP_HCH);
+	DUMP_REG(hc->op_regs, XHCI_OP_HSE);
+	DUMP_REG(hc->op_regs, XHCI_OP_EINT);
+	DUMP_REG(hc->op_regs, XHCI_OP_PCD);
+	DUMP_REG(hc->op_regs, XHCI_OP_SSS);
+	DUMP_REG(hc->op_regs, XHCI_OP_RSS);
+	DUMP_REG(hc->op_regs, XHCI_OP_SRE);
+	DUMP_REG(hc->op_regs, XHCI_OP_CNR);
+	DUMP_REG(hc->op_regs, XHCI_OP_HCE);
+	DUMP_REG(hc->op_regs, XHCI_OP_PAGESIZE);
+	DUMP_REG(hc->op_regs, XHCI_OP_NOTIFICATION);
+	DUMP_REG(hc->op_regs, XHCI_OP_RCS);
+	DUMP_REG(hc->op_regs, XHCI_OP_CS);
+	DUMP_REG(hc->op_regs, XHCI_OP_CA);
+	DUMP_REG(hc->op_regs, XHCI_OP_CRR);
+	DUMP_REG(hc->op_regs, XHCI_OP_CRCR_LO);
+	DUMP_REG(hc->op_regs, XHCI_OP_CRCR_HI);
+
+	const size_t num_ports = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_PORTS);
+	for (size_t i = 0; i < num_ports; i++) {
+		usb_log_debug2("Port %zu state:", i);
+
+		xhci_dump_port(&hc->op_regs->portrs[i]);
+	}
+}
 /**
  * @}
Index: uspace/drv/bus/usb/xhci/debug.h
===================================================================
--- uspace/drv/bus/usb/xhci/debug.h	(revision ce6e001ef0a10ca6ac198e109c24150d184e9954)
+++ uspace/drv/bus/usb/xhci/debug.h	(revision 62ba2cbee5c3230302472cecb3778a285cb40cd4)
@@ -40,5 +40,9 @@
 #include "hw_struct/regs.h"
 
+typedef struct xhci_hc xhci_hc_t;
+
 void xhci_dump_cap_regs(xhci_cap_regs_t *);
+void xhci_dump_port(xhci_port_regs_t *);
+void xhci_dump_state(xhci_hc_t *);
 
 #endif
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision ce6e001ef0a10ca6ac198e109c24150d184e9954)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 62ba2cbee5c3230302472cecb3778a285cb40cd4)
@@ -36,47 +36,69 @@
 #include <errno.h>
 #include <usb/debug.h>
+#include <usb/host/ddf_helpers.h>
 #include "debug.h"
 #include "hc.h"
 
-int xhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
+const ddf_hc_driver_t xhci_ddf_hc_driver = {
+	.hc_speed = USB_SPEED_SUPER,
+	.init = xhci_hc_init,
+	.fini = xhci_hc_fini,
+	.name = "XHCI-PCI",
+	.ops = {
+		.schedule       = xhci_hc_schedule,
+		.irq_hook       = xhci_hc_interrupt,
+		.status_hook    = xhci_hc_status,
+	}
+};
+
+int xhci_hc_init(hcd_t *hcd, const hw_res_list_parsed_t *hw_res, bool irq)
 {
-	assert(code);
-	assert(hw_res);
+	int err;
 
-	usb_log_debug("Gen IRQ code, got %zu IRQs, %zu DMA chs, %zu mem rngs, %zu IO rngs",
-	    hw_res->irqs.count,
-	    hw_res->dma_channels.count,
-	    hw_res->mem_ranges.count,
-	    hw_res->io_ranges.count);
-	
-	if (hw_res->irqs.count != 1
-		|| hw_res->dma_channels.count != 0
-		|| hw_res->mem_ranges.count != 1
-		|| hw_res->io_ranges.count != 0) {
-		usb_log_debug("Unexpected HW resources, bailing out.");
+	assert(hcd);
+	assert(hcd_get_driver_data(hcd) == NULL);
+
+	if (hw_res->mem_ranges.count != 1) {
+		usb_log_debug("Unexpected MMIO area, bailing out.");
 		return EINVAL;
 	}
 
+	xhci_hc_t *hc = malloc(sizeof(xhci_hc_t));
+	if (!hc)
+		return ENOMEM;
+
 	addr_range_t mmio_range = hw_res->mem_ranges.ranges[0];
 
-	usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
+	usb_log_debug("MMIO area at %p (size %zu), IRQ %d.\n",
 	    RNGABSPTR(mmio_range), RNGSZ(mmio_range), hw_res->irqs.irqs[0]);
 
-	xhci_cap_regs_t *cap_regs = NULL;
-	int ret = pio_enable_range(&mmio_range, (void **)&cap_regs);
-	if (ret != EOK)
-		return ret;
+	if ((err = pio_enable_range(&mmio_range, (void **)&hc->cap_regs)))
+		goto err_hc;
 
-	xhci_dump_cap_regs(cap_regs);
+	xhci_dump_cap_regs(hc->cap_regs);
 
-	/*
-	 * XHCI uses an Interrupter mechanism. Possibly, we want to set it up here.
-	 */
-	code->rangecount = 0;
-	code->ranges = NULL;
-	code->cmdcount = 0;
-	code->cmds = NULL;
+	uintptr_t base = (uintptr_t) hc->cap_regs;
+
+	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_debug("Initialized MMIO reg areas:");
+	usb_log_debug("\tCapability regs: %p", hc->cap_regs);
+	usb_log_debug("\tOperational regs: %p", hc->op_regs);
+	usb_log_debug("\tRuntime regs: %p", hc->rt_regs);
+	usb_log_debug("\tDoorbell array base: %p", hc->db_arry);
+
+	xhci_dump_state(hc);
+
+	hcd_set_implementation(hcd, hc, &xhci_ddf_hc_driver.ops);
+
+	// TODO: check if everything fits into the mmio_area
 
 	return EOK;
+
+err_hc:
+	free(hc);
+	return err;
 }
 
@@ -98,4 +120,14 @@
 }
 
+void xhci_hc_fini(hcd_t *hcd)
+{
+	assert(hcd);
+	usb_log_info("Finishing");
+
+	xhci_hc_t *hc = hcd_get_driver_data(hcd);
+	free(hc);
+	hcd_set_implementation(hcd, NULL, NULL);
+}
+
 
 /**
Index: uspace/drv/bus/usb/xhci/hc.h
===================================================================
--- uspace/drv/bus/usb/xhci/hc.h	(revision ce6e001ef0a10ca6ac198e109c24150d184e9954)
+++ uspace/drv/bus/usb/xhci/hc.h	(revision 62ba2cbee5c3230302472cecb3778a285cb40cd4)
@@ -40,10 +40,16 @@
 	xhci_cap_regs_t *cap_regs;
 	xhci_op_regs_t *op_regs;
+	xhci_rt_regs_t *rt_regs;
+	xhci_doorbell_t *db_arry;
 } xhci_hc_t;
 
+extern const ddf_hc_driver_t xhci_ddf_hc_driver;
+
+int xhci_hc_init(hcd_t *, const hw_res_list_parsed_t *, bool irq);
 int xhci_hc_gen_irq_code(irq_code_t *, const hw_res_list_parsed_t *);
 int xhci_hc_status(hcd_t *, uint32_t *);
 int xhci_hc_schedule(hcd_t *, usb_transfer_batch_t *);
 void xhci_hc_interrupt(hcd_t *, uint32_t);
+void xhci_hc_fini(hcd_t *);
 
 
Index: uspace/drv/bus/usb/xhci/hw_struct/regs.h
===================================================================
--- uspace/drv/bus/usb/xhci/hw_struct/regs.h	(revision ce6e001ef0a10ca6ac198e109c24150d184e9954)
+++ uspace/drv/bus/usb/xhci/hw_struct/regs.h	(revision 62ba2cbee5c3230302472cecb3778a285cb40cd4)
@@ -32,4 +32,6 @@
 /** @file
  * Memory-mapped register structures of the xHC.
+ *
+ * The main pr
  */
 
@@ -42,7 +44,4 @@
 
 /*
- * The macros XHCI_REG_* might seem a bit magic. It is the most compact way to
- * provide flexible interface abstracting from the real storage of given
- * register, but to avoid having to specify several constants per register.
  */
 
@@ -134,7 +133,7 @@
 
 	/*
-	 *  0:3  - IST
+	 *  3:0  - IST
 	 *  7:4  - ERST Max
-	 * 21:25 - Max Scratchpad Bufs Hi
+	 * 24:21 - Max Scratchpad Bufs Hi
 	 *    26 - SPR
 	 * 31:27 - Max Scratchpad Bufs Lo
@@ -188,5 +187,7 @@
 #define XHCI_CAP_IST          hcsparams2, 32, RANGE,  3,  0
 #define XHCI_CAP_ERST_MAX     hcsparams2, 32, RANGE,  7,  4
-#define XHCI_CAP_SPR          hcsparams2, 32, RANGE, 26, 26
+#define XHCI_CAP_MAX_SPBUF_LO hcsparams2, 32, RANGE, 25,  4
+#define XHCI_CAP_SPR          hcsparams2, 32,  FLAG, 26
+#define XHCI_CAP_MAX_SPBUF_HI hcsparams2, 32, RANGE, 31, 27
 #define XHCI_CAP_U1EL         hcsparams3, 32, RANGE,  7,  0
 #define XHCI_CAP_U2EL         hcsparams3, 32, RANGE, 31, 16
@@ -203,6 +204,6 @@
 #define XHCI_CAP_SEC          hccparams1, 32,  FLAG, 10
 #define XHCI_CAP_CFC          hccparams1, 32,  FLAG, 11
-#define XHCI_CAP_MAX_PSA_SIZE hccparams1, 32,  FLAG, 12
-#define XHCI_CAP_XECP         hccparams1, 32,  FLAG, 13
+#define XHCI_CAP_MAX_PSA_SIZE hccparams1, 32, RANGE, 15, 12
+#define XHCI_CAP_XECP         hccparams1, 32, RANGE, 31, 16
 #define XHCI_CAP_DBOFF             dboff, 32, FIELD
 #define XHCI_CAP_RTSOFF           rtsoff, 32, FIELD
@@ -450,4 +451,11 @@
 #define XHCI_RT_MFINDEX        mfindex, 32, FIELD
 
+/**
+ * XHCI Doorbel Registers: section 5.6
+ *
+ * These registers are write-only, thus convenience macros are useless.
+ */
+typedef ioport32_t xhci_doorbell_t;
+
 #endif
 /**
Index: uspace/drv/bus/usb/xhci/main.c
===================================================================
--- uspace/drv/bus/usb/xhci/main.c	(revision ce6e001ef0a10ca6ac198e109c24150d184e9954)
+++ uspace/drv/bus/usb/xhci/main.c	(revision 62ba2cbee5c3230302472cecb3778a285cb40cd4)
@@ -45,32 +45,4 @@
 #define NAME "xhci"
 
-static int xhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
-static void xhci_driver_fini(hcd_t *);
-
-static const ddf_hc_driver_t xhci_ddf_hc_driver = {
-	.hc_speed = USB_SPEED_SUPER,
-	.irq_code_gen = xhci_hc_gen_irq_code,
-	.init = xhci_driver_init,
-	.fini = xhci_driver_fini,
-	.name = "XHCI-PCI",
-	.ops = {
-		.schedule       = xhci_hc_schedule,
-		.irq_hook       = xhci_hc_interrupt,
-		.status_hook    = xhci_hc_status,
-	}
-};
-
-static int xhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)
-{
-	usb_log_info("Initializing");
-	return ENOTSUP;
-}
-
-static void xhci_driver_fini(hcd_t *hcd)
-{
-	usb_log_info("Finishing");
-	assert(hcd);
-}
-
 /** Initializes a new ddf driver instance of XHCI hcd.
  *
