Index: uspace/drv/ehci-hcd/Makefile
===================================================================
--- uspace/drv/ehci-hcd/Makefile	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/ehci-hcd/Makefile	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include -I.
+BINARY = ehci-hcd
+
+SOURCES = \
+	main.c \
+	pci.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/ehci-hcd/ehci-hcd.ma
===================================================================
--- uspace/drv/ehci-hcd/ehci-hcd.ma	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/ehci-hcd/ehci-hcd.ma	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,38 @@
+10 pci/ven=1002&dev=4345
+10 pci/ven=1002&dev=4386
+10 pci/ven=1002&dev=4396
+10 pci/ven=1022&dev=7463
+10 pci/ven=1022&dev=7808
+10 pci/ven=102f&dev=01b5
+10 pci/ven=10cf&dev=1415
+10 pci/ven=10de&dev=00e8
+10 pci/ven=10de&dev=055f
+10 pci/ven=10de&dev=056a
+10 pci/ven=10de&dev=077c
+10 pci/ven=10de&dev=077e
+10 pci/ven=10de&dev=0aa6
+10 pci/ven=10de&dev=0aa9
+10 pci/ven=10de&dev=0aaa
+10 pci/ven=10de&dev=0d9d
+10 pci/ven=1166&dev=0414
+10 pci/ven=1166&dev=0416
+10 pci/ven=1414&dev=5805
+10 pci/ven=1414&dev=5807
+10 pci/ven=15ad&dev=0770
+10 pci/ven=17a0&dev=8084
+10 pci/ven=8086&dev=24cd
+10 pci/ven=8086&dev=24dd
+10 pci/ven=8086&dev=265c
+10 pci/ven=8086&dev=268c
+10 pci/ven=8086&dev=27cc
+10 pci/ven=8086&dev=2836
+10 pci/ven=8086&dev=283a
+10 pci/ven=8086&dev=293a
+10 pci/ven=8086&dev=293c
+10 pci/ven=8086&dev=3a3a
+10 pci/ven=8086&dev=3a3c
+10 pci/ven=8086&dev=3a6a
+10 pci/ven=8086&dev=3a6c
+10 pci/ven=8086&dev=8117
+10 pci/ven=8086&dev=8807
+10 pci/ven=8086&dev=880f
Index: uspace/drv/ehci-hcd/main.c
===================================================================
--- uspace/drv/ehci-hcd/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/ehci-hcd/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbehci
+ * @{
+ */
+/** @file
+ * Main routines of EHCI driver.
+ */
+#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"
+
+#define NAME "ehci-hcd"
+
+static int ehci_add_device(ddf_dev_t *device);
+/*----------------------------------------------------------------------------*/
+static driver_ops_t ehci_driver_ops = {
+	.add_device = ehci_add_device,
+};
+/*----------------------------------------------------------------------------*/
+static driver_t ehci_driver = {
+	.name = NAME,
+	.driver_ops = &ehci_driver_ops
+};
+/*----------------------------------------------------------------------------*/
+/** Initializes a new ddf driver instance of EHCI hcd.
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int ehci_add_device(ddf_dev_t *device)
+{
+	assert(device);
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	usb_log_error(message); \
+	return ret; \
+}
+
+	usb_log_info("uhci_add_device() called\n");
+
+	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));
+
+	return EOK;
+#undef CHECK_RET_RETURN
+}
+/*----------------------------------------------------------------------------*/
+/** Initializes global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_ERROR, NAME);
+	return ddf_driver_main(&ehci_driver);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ehci-hcd/pci.c
===================================================================
--- uspace/drv/ehci-hcd/pci.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/ehci-hcd/pci.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,315 @@
+/*
+ * 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 drvusbehci
+ * @{
+ */
+/**
+ * @file
+ * PCI related functions needed by the EHCI driver.
+ */
+#include <errno.h>
+#include <assert.h>
+#include <as.h>
+#include <devman.h>
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <device/hw_res.h>
+
+#include <usb/debug.h>
+#include <pci_dev_iface.h>
+
+#include "pci.h"
+
+#define PAGE_SIZE_MASK 0xfffff000
+
+#define HCC_PARAMS_OFFSET 0x8
+#define HCC_PARAMS_EECP_MASK 0xff
+#define HCC_PARAMS_EECP_OFFSET 8
+
+#define CMD_OFFSET 0x0
+#define CONFIGFLAG_OFFSET 0x40
+
+#define USBCMD_RUN 1
+
+#define USBLEGSUP_OFFSET 0
+#define USBLEGSUP_BIOS_CONTROL (1 << 16)
+#define USBLEGSUP_OS_CONTROL (1 << 24)
+#define USBLEGCTLSTS_OFFSET 4
+
+#define DEFAULT_WAIT 10000
+#define WAIT_STEP 10
+
+/** Get address of registers and IRQ for given device.
+ *
+ * @param[in] dev Device asking for the addresses.
+ * @param[out] mem_reg_address Base address of the memory range.
+ * @param[out] mem_reg_size Size of the memory range.
+ * @param[out] irq_no IRQ assigned to the device.
+ * @return Error code.
+ */
+int pci_get_my_registers(ddf_dev_t *dev,
+    uintptr_t *mem_reg_address, size_t *mem_reg_size, int *irq_no)
+{
+	assert(dev != NULL);
+
+	int parent_phone = devman_parent_device_connect(dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (parent_phone < 0) {
+		return parent_phone;
+	}
+
+	int rc;
+
+	hw_resource_list_t hw_resources;
+	rc = hw_res_get_resource_list(parent_phone, &hw_resources);
+	if (rc != EOK) {
+		async_hangup(parent_phone);
+		return rc;
+	}
+
+	uintptr_t mem_address = 0;
+	size_t mem_size = 0;
+	bool mem_found = false;
+
+	int irq = 0;
+	bool irq_found = false;
+
+	size_t i;
+	for (i = 0; i < hw_resources.count; i++) {
+		hw_resource_t *res = &hw_resources.resources[i];
+		switch (res->type)
+		{
+		case INTERRUPT:
+			irq = res->res.interrupt.irq;
+			irq_found = true;
+			usb_log_debug2("Found interrupt: %d.\n", irq);
+			break;
+
+		case MEM_RANGE:
+			if (res->res.mem_range.address != 0
+			    && res->res.mem_range.size != 0 ) {
+				mem_address = res->res.mem_range.address;
+				mem_size = res->res.mem_range.size;
+				usb_log_debug2("Found mem: %llx %zu.\n",
+				    mem_address, mem_size);
+				mem_found = true;
+				}
+		default:
+			break;
+		}
+	}
+
+	if (mem_found && irq_found) {
+		*mem_reg_address = mem_address;
+		*mem_reg_size = mem_size;
+		*irq_no = irq;
+		rc = EOK;
+	} else {
+		rc = ENOENT;
+	}
+
+	async_hangup(parent_phone);
+	return rc;
+}
+/*----------------------------------------------------------------------------*/
+/** Calls the PCI driver with a request to enable interrupts
+ *
+ * @param[in] device Device asking for interrupts
+ * @return Error code.
+ */
+int pci_enable_interrupts(ddf_dev_t *device)
+{
+	int parent_phone =
+	    devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING);
+	if (parent_phone < 0) {
+		return parent_phone;
+	}
+	bool enabled = hw_res_enable_interrupt(parent_phone);
+	async_hangup(parent_phone);
+	return enabled ? EOK : EIO;
+}
+/*----------------------------------------------------------------------------*/
+/** Implements BIOS handoff routine as decribed in EHCI spec
+ *
+ * @param[in] device Device asking for interrupts
+ * @return Error code.
+ */
+int pci_disable_legacy(ddf_dev_t *device)
+{
+	assert(device);
+	int parent_phone = devman_parent_device_connect(device->handle,
+		IPC_FLAG_BLOCKING);
+	if (parent_phone < 0) {
+		return parent_phone;
+	}
+
+#define CHECK_RET_HANGUP_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		async_hangup(parent_phone); \
+		return ret; \
+	} else (void)0
+
+
+	/* read register space BASE BAR */
+	sysarg_t address = 0x10;
+	sysarg_t value;
+
+	int ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, address, &value);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read PCI config space.\n",
+	    ret);
+	usb_log_info("Register space BAR at %p:%x.\n", address, value);
+
+	/* clear lower byte, it's not part of the BASE address */
+	uintptr_t registers = (value & 0xffffff00);
+	usb_log_info("Memory registers BASE address:%p.\n", registers);
+
+	/* if nothing setup the hc, we don't need to turn it off */
+	if (registers == 0)
+		return ENOTSUP;
+
+	/* map EHCI registers */
+	void *regs = as_get_mappable_page(4096);
+	ret = physmem_map((void*)(registers & PAGE_SIZE_MASK), regs, 1,
+	    AS_AREA_READ | AS_AREA_WRITE);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to map registers %p:%p.\n",
+	    ret, regs, registers);
+
+	/* calculate value of BASE */
+	registers = (registers & 0xf00) | (uintptr_t)regs;
+
+	const uint32_t hcc_params =
+	    *(uint32_t*)(registers + HCC_PARAMS_OFFSET);
+	usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
+
+	/* Read value of EHCI Extended Capabilities Pointer
+	 * (points to PCI config space) */
+	uint32_t eecp =
+	    (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
+	usb_log_debug("Value of EECP: %x.\n", eecp);
+
+	/* Read the second EEC. i.e. Legacy Support and Control register */
+	/* TODO: Check capability type here */
+	ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret);
+	usb_log_debug("USBLEGCTLSTS: %x.\n", value);
+
+	/* Read the first EEC. i.e. Legacy Support register */
+	/* TODO: Check capability type here */
+	ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
+	usb_log_debug2("USBLEGSUP: %x.\n", value);
+
+	/* Request control from firmware/BIOS, by writing 1 to highest byte.
+	 * (OS Control semaphore)*/
+	ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	   IPC_M_CONFIG_SPACE_WRITE_8, eecp + USBLEGSUP_OFFSET + 3, 1);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to request OS EHCI control.\n",
+	    ret);
+
+	size_t wait = 0;
+	/* Wait for BIOS to release control. */
+	while ((wait < DEFAULT_WAIT) && (value & USBLEGSUP_BIOS_CONTROL)) {
+		async_usleep(WAIT_STEP);
+		ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+		    IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
+		wait += WAIT_STEP;
+	}
+
+
+	if ((value & USBLEGSUP_BIOS_CONTROL) == 0) {
+		usb_log_info("BIOS released control after %d usec.\n", wait);
+	} else {
+		/* BIOS failed to hand over control, this should not happen. */
+		usb_log_warning( "BIOS failed to release control after "
+		    "%d usecs, force it.\n", wait);
+		ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+		    IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGSUP_OFFSET,
+		    USBLEGSUP_OS_CONTROL);
+		CHECK_RET_HANGUP_RETURN(ret,
+		    "Failed(%d) to force OS EHCI control.\n", ret);
+	}
+
+	/* Zero SMI enables in legacy control register.
+	 * It would prevent pre-OS code from interfering. */
+	ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	   IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGCTLSTS_OFFSET, 0);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) zero USBLEGCTLSTS.\n", ret);
+	usb_log_debug("Zeroed USBLEGCTLSTS register.\n");
+
+	/* Read again Legacy Support and Control register */
+	ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret);
+	usb_log_debug2("USBLEGCTLSTS: %x.\n", value);
+
+	/* Read again Legacy Support register */
+	ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
+	CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
+	usb_log_debug2("USBLEGSUP: %x.\n", value);
+
+	/*
+	 * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT
+	 */
+
+	/* Get size of capability registers in memory space. */
+	uint8_t operation_offset = *(uint8_t*)registers;
+	usb_log_debug("USBCMD offset: %d.\n", operation_offset);
+
+	/* Zero USBCMD register. */
+	volatile uint32_t *usbcmd =
+	    (uint32_t*)((uint8_t*)registers + operation_offset + CMD_OFFSET);
+	volatile uint32_t *usbconfigured =
+	    (uint32_t*)((uint8_t*)registers + operation_offset
+	    + CONFIGFLAG_OFFSET);
+	usb_log_debug("USBCMD value: %x.\n", *usbcmd);
+	if (*usbcmd & USBCMD_RUN) {
+		*usbcmd = 0;
+		*usbconfigured = 0;
+		usb_log_info("EHCI turned off.\n");
+	} else {
+		usb_log_info("EHCI was not running.\n");
+	}
+
+	async_hangup(parent_phone);
+	return ret;
+#undef CHECK_RET_HANGUP_RETURN
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
Index: uspace/drv/ehci-hcd/pci.h
===================================================================
--- uspace/drv/ehci-hcd/pci.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/ehci-hcd/pci.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbehci
+ * @{
+ */
+/** @file
+ * PCI related functions needed by EHCI driver.
+ */
+#ifndef DRV_EHCI_PCI_H
+#define DRV_EHCI_PCI_H
+
+#include <ddf/driver.h>
+
+int pci_get_my_registers(ddf_dev_t *, uintptr_t *, size_t *, int *);
+int pci_enable_interrupts(ddf_dev_t *);
+int pci_disable_legacy(ddf_dev_t *);
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/pciintel/pci.c
===================================================================
--- uspace/drv/pciintel/pci.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/pciintel/pci.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -92,25 +92,27 @@
 	pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data;
 
-  sysarg_t apic;
-  sysarg_t i8259;
+	sysarg_t apic;
+	sysarg_t i8259;
 
 	int irc_phone = -1;
-	int irc_service = 0;
-
-  if ((sysinfo_get_value("apic", &apic) == EOK) && (apic)) {
-    irc_service = SERVICE_APIC;
+	int irc_service = -1;
+
+	if ((sysinfo_get_value("apic", &apic) == EOK) && (apic)) {
+		irc_service = SERVICE_APIC;
 	} else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)) {
-    irc_service = SERVICE_I8259;
-	}
-
-  if (irc_service == 0)
+		irc_service = SERVICE_I8259;
+	}
+
+	if (irc_service == -1) {
 		return false;
+	}
 
 	irc_phone = service_connect_blocking(irc_service, 0, 0);
-	if (irc_phone < 0)
+	if (irc_phone < 0) {
 		return false;
+	}
 
 	size_t i;
-  for (i = 0; i < dev_data->hw_resources.count; i++) {
+	for (i = 0; i < dev_data->hw_resources.count; i++) {
 		if (dev_data->hw_resources.resources[i].type == INTERRUPT) {
 			int irq = dev_data->hw_resources.resources[i].res.interrupt.irq;
@@ -127,5 +129,15 @@
 }
 
-static int pci_config_space_write_16(ddf_fun_t *fun, uint32_t address, uint16_t data)
+static int pci_config_space_write_32(
+    ddf_fun_t *fun, uint32_t address, uint32_t data)
+{
+	if (address > 252)
+		return EINVAL;
+	pci_conf_write_32(PCI_FUN(fun), address, data);
+	return EOK;
+}
+
+static int pci_config_space_write_16(
+    ddf_fun_t *fun, uint32_t address, uint16_t data)
 {
 	if (address > 254)
@@ -135,4 +147,39 @@
 }
 
+static int pci_config_space_write_8(
+    ddf_fun_t *fun, uint32_t address, uint8_t data)
+{
+	if (address > 255)
+		return EINVAL;
+	pci_conf_write_8(PCI_FUN(fun), address, data);
+	return EOK;
+}
+
+static int pci_config_space_read_32(
+    ddf_fun_t *fun, uint32_t address, uint32_t *data)
+{
+	if (address > 252)
+		return EINVAL;
+	*data = pci_conf_read_32(PCI_FUN(fun), address);
+	return EOK;
+}
+
+static int pci_config_space_read_16(
+    ddf_fun_t *fun, uint32_t address, uint16_t *data)
+{
+	if (address > 254)
+		return EINVAL;
+	*data = pci_conf_read_16(PCI_FUN(fun), address);
+	return EOK;
+}
+
+static int pci_config_space_read_8(
+    ddf_fun_t *fun, uint32_t address, uint8_t *data)
+{
+	if (address > 255)
+		return EINVAL;
+	*data = pci_conf_read_8(PCI_FUN(fun), address);
+	return EOK;
+}
 
 static hw_res_ops_t pciintel_hw_res_ops = {
@@ -142,10 +189,10 @@
 
 static pci_dev_iface_t pci_dev_ops = {
-	.config_space_read_8 = NULL,
-	.config_space_read_16 = NULL,
-	.config_space_read_32 = NULL,
-	.config_space_write_8 = NULL,
+	.config_space_read_8 = &pci_config_space_read_8,
+	.config_space_read_16 = &pci_config_space_read_16,
+	.config_space_read_32 = &pci_config_space_read_32,
+	.config_space_write_8 = &pci_config_space_write_8,
 	.config_space_write_16 = &pci_config_space_write_16,
-	.config_space_write_32 = NULL
+	.config_space_write_32 = &pci_config_space_write_32
 };
 
Index: uspace/drv/uhci-hcd/Makefile
===================================================================
--- uspace/drv/uhci-hcd/Makefile	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/Makefile	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -35,7 +35,8 @@
 	iface.c \
 	main.c \
-	root_hub.c \
 	transfer_list.c \
 	uhci.c \
+	uhci_hc.c \
+	uhci_rh.c \
 	uhci_struct/transfer_descriptor.c \
 	utils/device_keeper.c \
Index: uspace/drv/uhci-hcd/batch.c
===================================================================
--- uspace/drv/uhci-hcd/batch.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/batch.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,9 +26,9 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver USB transaction structure
  */
 #include <errno.h>
@@ -40,13 +40,12 @@
 #include "batch.h"
 #include "transfer_list.h"
-#include "uhci.h"
+#include "uhci_hc.h"
 #include "utils/malloc32.h"
 
 #define DEFAULT_ERROR_COUNT 3
 
-static int batch_schedule(batch_t *instance);
-
-static void batch_control(
-    batch_t *instance, int data_stage, int status_stage);
+static void batch_control(batch_t *instance,
+    usb_packet_id data_stage, usb_packet_id status_stage);
+static void batch_data(batch_t *instance, usb_packet_id pid);
 static void batch_call_in(batch_t *instance);
 static void batch_call_out(batch_t *instance);
@@ -55,4 +54,26 @@
 
 
+/** Allocate memory and initialize internal data structure.
+ *
+ * @param[in] fun DDF function to pass to callback.
+ * @param[in] target Device and endpoint target of the transaction.
+ * @param[in] transfer_type Interrupt, Control or Bulk.
+ * @param[in] max_packet_size maximum allowed size of data packets.
+ * @param[in] speed Speed of the transaction.
+ * @param[in] buffer Data source/destination.
+ * @param[in] size Size of the buffer.
+ * @param[in] setup_buffer Setup data source (if not NULL)
+ * @param[in] setup_size Size of setup_buffer (should be always 8)
+ * @param[in] func_in function to call on inbound transaction completion
+ * @param[in] func_out function to call on outbound transaction completion
+ * @param[in] arg additional parameter to func_in or func_out
+ * @param[in] manager Pointer to toggle management structure.
+ * @return Valid pointer if all substructures were successfully created,
+ * NULL otherwise.
+ *
+ * Determines the number of needed packets (TDs). Prepares a transport buffer
+ * (that is accessible by the hardware). Initializes parameters needed for the
+ * transaction and callback.
+ */
 batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
     usb_transfer_type_t transfer_type, size_t max_packet_size,
@@ -60,21 +81,29 @@
     char* setup_buffer, size_t setup_size,
     usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out, void *arg)
+    usbhc_iface_transfer_out_callback_t func_out, void *arg,
+    device_keeper_t *manager
+    )
 {
 	assert(func_in == NULL || func_out == NULL);
 	assert(func_in != NULL || func_out != NULL);
 
+#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
+	if (ptr == NULL) { \
+		usb_log_error(message); \
+		if (instance) { \
+			batch_dispose(instance); \
+		} \
+		return NULL; \
+	} else (void)0
+
 	batch_t *instance = malloc(sizeof(batch_t));
-	if (instance == NULL) {
-		usb_log_error("Failed to allocate batch instance.\n");
-		return NULL;
-	}
-
-	instance->qh = queue_head_get();
-	if (instance->qh == NULL) {
-		usb_log_error("Failed to allocate queue head.\n");
-		free(instance);
-		return NULL;
-	}
+	CHECK_NULL_DISPOSE_RETURN(instance,
+	    "Failed to allocate batch instance.\n");
+	bzero(instance, sizeof(batch_t));
+
+	instance->qh = malloc32(sizeof(qh_t));
+	CHECK_NULL_DISPOSE_RETURN(instance->qh,
+	    "Failed to allocate batch queue head.\n");
+	qh_init(instance->qh);
 
 	instance->packets = (size + max_packet_size - 1) / max_packet_size;
@@ -83,51 +112,28 @@
 	}
 
-	instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets);
-	if (instance->tds == NULL) {
-		usb_log_error("Failed to allocate transfer descriptors.\n");
-		queue_head_dispose(instance->qh);
-		free(instance);
-		return NULL;
-	}
-	bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets);
-
-	const size_t transport_size = max_packet_size * instance->packets;
-
-	instance->transport_buffer =
-	   (size > 0) ? malloc32(transport_size) : NULL;
-
-	if ((size > 0) && (instance->transport_buffer == NULL)) {
-		usb_log_error("Failed to allocate device accessible buffer.\n");
-		queue_head_dispose(instance->qh);
-		free32(instance->tds);
-		free(instance);
-		return NULL;
-	}
-
-	instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL;
-	if ((setup_size > 0) && (instance->setup_buffer == NULL)) {
-		usb_log_error("Failed to allocate device accessible setup buffer.\n");
-		queue_head_dispose(instance->qh);
-		free32(instance->tds);
-		free32(instance->transport_buffer);
-		free(instance);
-		return NULL;
-	}
-	if (instance->setup_buffer) {
+	instance->tds = malloc32(sizeof(td_t) * instance->packets);
+	CHECK_NULL_DISPOSE_RETURN(
+	    instance->tds, "Failed to allocate transfer descriptors.\n");
+	bzero(instance->tds, sizeof(td_t) * instance->packets);
+
+	if (size > 0) {
+		instance->transport_buffer = malloc32(size);
+		CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
+		    "Failed to allocate device accessible buffer.\n");
+	}
+
+	if (setup_size > 0) {
+		instance->setup_buffer = malloc32(setup_size);
+		CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
+		    "Failed to allocate device accessible setup buffer.\n");
 		memcpy(instance->setup_buffer, setup_buffer, setup_size);
 	}
 
+
+	link_initialize(&instance->link);
+
 	instance->max_packet_size = max_packet_size;
-
-	link_initialize(&instance->link);
-
 	instance->target = target;
 	instance->transfer_type = transfer_type;
-
-	if (func_out)
-		instance->callback_out = func_out;
-	if (func_in)
-		instance->callback_in = func_in;
-
 	instance->buffer = buffer;
 	instance->buffer_size = size;
@@ -136,6 +142,10 @@
 	instance->arg = arg;
 	instance->speed = speed;
-
-	queue_head_element_td(instance->qh, addr_to_phys(instance->tds));
+	instance->manager = manager;
+	instance->callback_out = func_out;
+	instance->callback_in = func_in;
+
+	qh_set_element_td(instance->qh, addr_to_phys(instance->tds));
+
 	usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
 	    instance, target.address, target.endpoint);
@@ -143,4 +153,13 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Check batch TDs for activity.
+ *
+ * @param[in] instance Batch structure to use.
+ * @return False, if there is an active TD, true otherwise.
+ *
+ * Walk all TDs. Stop with false if there is an active one (it is to be
+ * processed). Stop with true if an error is found. Return true if the last TS
+ * is reached.
+ */
 bool batch_is_complete(batch_t *instance)
 {
@@ -151,33 +170,53 @@
 	size_t i = 0;
 	for (;i < instance->packets; ++i) {
-		if (transfer_descriptor_is_active(&instance->tds[i])) {
+		if (td_is_active(&instance->tds[i])) {
 			return false;
 		}
-		instance->error = transfer_descriptor_status(&instance->tds[i]);
+
+		instance->error = td_status(&instance->tds[i]);
 		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
+			    instance, i, instance->tds[i].status);
+			td_print_status(&instance->tds[i]);
+
+			device_keeper_set_toggle(instance->manager,
+			    instance->target, td_toggle(&instance->tds[i]));
 			if (i > 0)
-				instance->transfered_size -= instance->setup_size;
-			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
-			  instance, i, instance->tds[i].status);
+				goto substract_ret;
 			return true;
 		}
-		instance->transfered_size +=
-		    transfer_descriptor_actual_size(&instance->tds[i]);
-	}
+
+		instance->transfered_size += td_act_size(&instance->tds[i]);
+		if (td_is_short(&instance->tds[i]))
+			goto substract_ret;
+	}
+substract_ret:
 	instance->transfered_size -= instance->setup_size;
 	return true;
 }
 /*----------------------------------------------------------------------------*/
+/** Prepares control write transaction.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses genercir control function with pids OUT and IN.
+ */
 void batch_control_write(batch_t *instance)
 {
 	assert(instance);
-	/* we are data out, we are supposed to provide data */
-	memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->transport_buffer, instance->buffer,
+	    instance->buffer_size);
 	batch_control(instance, USB_PID_OUT, USB_PID_IN);
 	instance->next_step = batch_call_out_and_dispose;
 	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
-	batch_schedule(instance);
-}
-/*----------------------------------------------------------------------------*/
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control read transaction.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control with pids IN and OUT.
+ */
 void batch_control_read(batch_t *instance)
 {
@@ -186,62 +225,126 @@
 	instance->next_step = batch_call_in_and_dispose;
 	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
-	batch_schedule(instance);
-}
-/*----------------------------------------------------------------------------*/
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt in transaction.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transaction with PID_IN.
+ */
 void batch_interrupt_in(batch_t *instance)
 {
 	assert(instance);
-
-	const bool low_speed = instance->speed == USB_SPEED_LOW;
-	int toggle = 1;
-	size_t i = 0;
-	for (;i < instance->packets; ++i) {
-		char *data =
-		    instance->transport_buffer + (i  * instance->max_packet_size);
-		transfer_descriptor_t *next = (i + 1) < instance->packets ?
-		    &instance->tds[i + 1] : NULL;
-		toggle = 1 - toggle;
-
-		transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
-		    instance->max_packet_size, toggle, false, low_speed,
-		    instance->target, USB_PID_IN, data, next);
-	}
-
-	instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
-
+	batch_data(instance, USB_PID_IN);
 	instance->next_step = batch_call_in_and_dispose;
 	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
-	batch_schedule(instance);
-}
-/*----------------------------------------------------------------------------*/
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt out transaction.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transaction with PID_OUT.
+ */
 void batch_interrupt_out(batch_t *instance)
 {
 	assert(instance);
+	/* We are data out, we are supposed to provide data */
 	memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
-
-	const bool low_speed = instance->speed == USB_SPEED_LOW;
-	int toggle = 1;
-	size_t i = 0;
-	for (;i < instance->packets; ++i) {
-		char *data =
-		    instance->transport_buffer + (i  * instance->max_packet_size);
-		transfer_descriptor_t *next = (i + 1) < instance->packets ?
-		    &instance->tds[i + 1] : NULL;
-		toggle = 1 - toggle;
-
-		transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
-		    instance->max_packet_size, toggle++, false, low_speed,
-		    instance->target, USB_PID_OUT, data, next);
-	}
-
-	instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
-
+	batch_data(instance, USB_PID_OUT);
 	instance->next_step = batch_call_out_and_dispose;
 	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
-	batch_schedule(instance);
-}
-/*----------------------------------------------------------------------------*/
-static void batch_control(
-    batch_t *instance, int data_stage, int status_stage)
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk in transaction.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transaction with PID_IN.
+ */
+void batch_bulk_in(batch_t *instance)
+{
+	assert(instance);
+	batch_data(instance, USB_PID_IN);
+	instance->next_step = batch_call_in_and_dispose;
+	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk out transaction.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transaction with PID_OUT.
+ */
+void batch_bulk_out(batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
+	batch_data(instance, USB_PID_OUT);
+	instance->next_step = batch_call_out_and_dispose;
+	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic data transaction
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] pid to use for data packets.
+ *
+ * Packets with alternating toggle bit and supplied pid value.
+ * The last packet is marked with IOC flag.
+ */
+void batch_data(batch_t *instance, usb_packet_id pid)
+{
+	assert(instance);
+	const bool low_speed = instance->speed == USB_SPEED_LOW;
+	int toggle =
+	    device_keeper_get_toggle(instance->manager, instance->target);
+	assert(toggle == 0 || toggle == 1);
+
+	size_t packet = 0;
+	size_t remain_size = instance->buffer_size;
+	while (remain_size > 0) {
+		char *data =
+		    instance->transport_buffer + instance->buffer_size
+		    - remain_size;
+
+		const size_t packet_size =
+		    (instance->max_packet_size > remain_size) ?
+		    remain_size : instance->max_packet_size;
+
+		td_t *next_packet = (packet + 1 < instance->packets)
+		    ? &instance->tds[packet + 1] : NULL;
+
+		assert(packet < instance->packets);
+		assert(packet_size <= remain_size);
+
+		td_init(
+		    &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, instance->target, pid, data,
+		    next_packet);
+
+
+		toggle = 1 - toggle;
+		remain_size -= packet_size;
+		++packet;
+	}
+	td_set_ioc(&instance->tds[packet - 1]);
+	device_keeper_set_toggle(instance->manager, instance->target, toggle);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic control transaction
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data_stage to use for data packets.
+ * @param[in] status_stage to use for data packets.
+ *
+ * Setup stage with toggle 0 and USB_PID_SETUP.
+ * Data stage with alternating toggle and pid supplied by parameter.
+ * Status stage with toggle 1 and pid supplied by parameter.
+ * The last packet is marked with IOC.
+ */
+void batch_control(batch_t *instance,
+   usb_packet_id data_stage, usb_packet_id status_stage)
 {
 	assert(instance);
@@ -250,5 +353,5 @@
 	int toggle = 0;
 	/* setup stage */
-	transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,
+	td_init(instance->tds, DEFAULT_ERROR_COUNT,
 	    instance->setup_size, toggle, false, low_speed, instance->target,
 	    USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
@@ -268,8 +371,8 @@
 		    remain_size : instance->max_packet_size;
 
-		transfer_descriptor_init(&instance->tds[packet],
-		    DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
-		    instance->target, data_stage, data,
-		    &instance->tds[packet + 1]);
+		td_init(
+		    &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, instance->target, data_stage,
+		    data, &instance->tds[packet + 1]);
 
 		++packet;
@@ -281,13 +384,18 @@
 	/* status stage */
 	assert(packet == instance->packets - 1);
-	transfer_descriptor_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
+	td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
 	    0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
 
-
-	instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
+	td_set_ioc(&instance->tds[packet]);
 	usb_log_debug2("Control last TD status: %x.\n",
 	    instance->tds[packet].status);
 }
 /*----------------------------------------------------------------------------*/
+/** Prepare data, get error status and call callback in.
+ *
+ * @param[in] instance Batch structure to use.
+ * Copies data from transport buffer, and calls callback with appropriate
+ * parameters.
+ */
 void batch_call_in(batch_t *instance)
 {
@@ -295,5 +403,7 @@
 	assert(instance->callback_in);
 
-	memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size);
+	/* We are data in, we need data */
+	memcpy(instance->buffer, instance->transport_buffer,
+	    instance->buffer_size);
 
 	int err = instance->error;
@@ -302,9 +412,12 @@
 	    instance->transfered_size);
 
-	instance->callback_in(instance->fun,
-	    err, instance->transfered_size,
-	    instance->arg);
-}
-/*----------------------------------------------------------------------------*/
+	instance->callback_in(
+	    instance->fun, err, instance->transfered_size, instance->arg);
+}
+/*----------------------------------------------------------------------------*/
+/** Get error status and call callback out.
+ *
+ * @param[in] instance Batch structure to use.
+ */
 void batch_call_out(batch_t *instance)
 {
@@ -319,9 +432,35 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Helper function calls callback and correctly disposes of batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
 void batch_call_in_and_dispose(batch_t *instance)
 {
 	assert(instance);
 	batch_call_in(instance);
+	batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function calls callback and correctly disposes of batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void batch_call_out_and_dispose(batch_t *instance)
+{
+	assert(instance);
+	batch_call_out(instance);
+	batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Correctly dispose all used data structures.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void batch_dispose(batch_t *instance)
+{
+	assert(instance);
 	usb_log_debug("Batch(%p) disposing.\n", instance);
+	/* free32 is NULL safe */
 	free32(instance->tds);
 	free32(instance->qh);
@@ -330,24 +469,4 @@
 	free(instance);
 }
-/*----------------------------------------------------------------------------*/
-void batch_call_out_and_dispose(batch_t *instance)
-{
-	assert(instance);
-	batch_call_out(instance);
-	usb_log_debug("Batch(%p) disposing.\n", instance);
-	free32(instance->tds);
-	free32(instance->qh);
-	free32(instance->setup_buffer);
-	free32(instance->transport_buffer);
-	free(instance);
-}
-/*----------------------------------------------------------------------------*/
-int batch_schedule(batch_t *instance)
-{
-	assert(instance);
-	uhci_t *hc = fun_to_uhci(instance->fun);
-	assert(hc);
-	return uhci_schedule(hc, instance);
-}
 /**
  * @}
Index: uspace/drv/uhci-hcd/batch.h
===================================================================
--- uspace/drv/uhci-hcd/batch.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/batch.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,9 +26,9 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver USB transaction structure
  */
 #ifndef DRV_UHCI_BATCH_H
@@ -42,4 +42,5 @@
 #include "uhci_struct/transfer_descriptor.h"
 #include "uhci_struct/queue_head.h"
+#include "utils/device_keeper.h"
 
 typedef struct batch
@@ -49,8 +50,6 @@
 	usb_target_t target;
 	usb_transfer_type_t transfer_type;
-	union {
-		usbhc_iface_transfer_in_callback_t callback_in;
-		usbhc_iface_transfer_out_callback_t callback_out;
-	};
+	usbhc_iface_transfer_in_callback_t callback_in;
+	usbhc_iface_transfer_out_callback_t callback_out;
 	void *arg;
 	char *transport_buffer;
@@ -64,7 +63,8 @@
 	int error;
 	ddf_fun_t *fun;
-	queue_head_t *qh;
-	transfer_descriptor_t *tds;
+	qh_t *qh;
+	td_t *tds;
 	void (*next_step)(struct batch*);
+	device_keeper_t *manager;
 } batch_t;
 
@@ -74,5 +74,9 @@
 		char *setup_buffer, size_t setup_size,
     usbhc_iface_transfer_in_callback_t func_in,
-    usbhc_iface_transfer_out_callback_t func_out, void *arg);
+    usbhc_iface_transfer_out_callback_t func_out, void *arg,
+		device_keeper_t *manager
+		);
+
+void batch_dispose(batch_t *instance);
 
 bool batch_is_complete(batch_t *instance);
@@ -86,14 +90,7 @@
 void batch_interrupt_out(batch_t *instance);
 
-/* DEPRECATED FUNCTIONS NEEDED BY THE OLD API */
-void batch_control_setup_old(batch_t *instance);
+void batch_bulk_in(batch_t *instance);
 
-void batch_control_write_data_old(batch_t *instance);
-
-void batch_control_read_data_old(batch_t *instance);
-
-void batch_control_write_status_old(batch_t *instance);
-
-void batch_control_read_status_old(batch_t *instance);
+void batch_bulk_out(batch_t *instance);
 #endif
 /**
Index: uspace/drv/uhci-hcd/iface.c
===================================================================
--- uspace/drv/uhci-hcd/iface.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/iface.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,9 +26,9 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver hc interface implementation
  */
 #include <ddf/driver.h>
@@ -40,12 +40,18 @@
 
 #include "iface.h"
-#include "uhci.h"
+#include "uhci_hc.h"
 #include "utils/device_keeper.h"
 
+/** Reserve default address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
+ * @return Error code.
+ */
 /*----------------------------------------------------------------------------*/
 static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	usb_log_debug("Default address request with speed %d.\n", speed);
@@ -54,8 +60,13 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Release default address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @return Error code.
+ */
 static int release_default_address(ddf_fun_t *fun)
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	usb_log_debug("Default address release.\n");
@@ -64,9 +75,16 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Request address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
+ * @param[out] address Place to write a new address.
+ * @return Error code.
+ */
 static int request_address(ddf_fun_t *fun, usb_speed_t speed,
     usb_address_t *address)
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	assert(address);
@@ -80,9 +98,16 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Bind address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address of the device
+ * @param[in] handle Devman handle of the device driver.
+ * @return Error code.
+ */
 static int bind_address(
   ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	usb_log_debug("Address bind %d-%d.\n", address, handle);
@@ -91,8 +116,14 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Release address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address USB address to be released.
+ * @return Error code.
+ */
 static int release_address(ddf_fun_t *fun, usb_address_t address)
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	usb_log_debug("Address release %d.\n", address);
@@ -101,4 +132,15 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Interrupt out transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[in] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
+ * @return Error code.
+ */
 static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
     size_t max_packet_size, void *data, size_t size,
@@ -106,5 +148,5 @@
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
@@ -114,11 +156,28 @@
 
 	batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT,
-	    max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg);
+	    max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg,
+	    &hc->device_manager);
 	if (!batch)
 		return ENOMEM;
 	batch_interrupt_out(batch);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
+	const int ret = uhci_hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+		return ret;
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Interrupt in transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[out] data Data destination.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
+ * @return Error code.
+ */
 static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
     size_t max_packet_size, void *data, size_t size,
@@ -126,5 +185,5 @@
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
 	assert(hc);
 	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
@@ -133,11 +192,103 @@
 
 	batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT,
-	    max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg);
+	    max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg,
+			&hc->device_manager);
 	if (!batch)
 		return ENOMEM;
 	batch_interrupt_in(batch);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
+	const int ret = uhci_hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+		return ret;
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Bulk out transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[in] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
+ * @return Error code.
+ */
+static int bulk_out(ddf_fun_t *fun, usb_target_t target,
+    size_t max_packet_size, void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	assert(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
+	assert(hc);
+	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
+
+	usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
+	    target.address, target.endpoint, size, max_packet_size);
+
+	batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK,
+	    max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg,
+	    &hc->device_manager);
+	if (!batch)
+		return ENOMEM;
+	batch_bulk_out(batch);
+	const int ret = uhci_hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+		return ret;
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Bulk in transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts
+ * @param[out] data Data destination.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion
+ * @param[in] arg Additional for callback function.
+ * @return Error code.
+ */
+static int bulk_in(ddf_fun_t *fun, usb_target_t target,
+    size_t max_packet_size, void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	assert(fun);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
+	assert(hc);
+	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
+	usb_log_debug("Bulk IN %d:%d %zu(%zu).\n",
+	    target.address, target.endpoint, size, max_packet_size);
+
+	batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK,
+	    max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg,
+	    &hc->device_manager);
+	if (!batch)
+		return ENOMEM;
+	batch_bulk_in(batch);
+	const int ret = uhci_hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+		return ret;
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Control write transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts.
+ * @param[in] setup_data Data to send with SETUP packet.
+ * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
+ * @param[in] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion.
+ * @param[in] arg Additional for callback function.
+ * @return Error code.
+ */
 static int control_write(ddf_fun_t *fun, usb_target_t target,
     size_t max_packet_size,
@@ -146,19 +297,41 @@
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
-	assert(hc);
-	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
-	usb_log_debug("Control WRITE %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
+	assert(hc);
+	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
+	usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n",
+	    speed, target.address, target.endpoint, size, max_packet_size);
+
+	if (setup_size != 8)
+		return EINVAL;
 
 	batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL,
 	    max_packet_size, speed, data, size, setup_data, setup_size,
-	    NULL, callback, arg);
-	if (!batch)
-		return ENOMEM;
+	    NULL, callback, arg, &hc->device_manager);
+	if (!batch)
+		return ENOMEM;
+	device_keeper_reset_if_need(&hc->device_manager, target, setup_data);
 	batch_control_write(batch);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
+	const int ret = uhci_hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+		return ret;
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Control read transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] max_packet_size maximum size of data packet the device accepts.
+ * @param[in] setup_data Data to send with SETUP packet.
+ * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
+ * @param[out] data Source of data.
+ * @param[in] size Size of data source.
+ * @param[in] callback Function to call on transaction completion.
+ * @param[in] arg Additional for callback function.
+ * @return Error code.
+ */
 static int control_read(ddf_fun_t *fun, usb_target_t target,
     size_t max_packet_size,
@@ -167,22 +340,25 @@
 {
 	assert(fun);
-	uhci_t *hc = fun_to_uhci(fun);
-	assert(hc);
-	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
-
-	usb_log_debug("Control READ %d:%d %zu(%zu).\n",
-	    target.address, target.endpoint, size, max_packet_size);
+	uhci_hc_t *hc = fun_to_uhci_hc(fun);
+	assert(hc);
+	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
+
+	usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n",
+	    speed, target.address, target.endpoint, size, max_packet_size);
 	batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL,
 	    max_packet_size, speed, data, size, setup_data, setup_size, callback,
-	    NULL, arg);
+	    NULL, arg, &hc->device_manager);
 	if (!batch)
 		return ENOMEM;
 	batch_control_read(batch);
-	return EOK;
-}
-
-
-/*----------------------------------------------------------------------------*/
-usbhc_iface_t uhci_iface = {
+	const int ret = uhci_hc_schedule(hc, batch);
+	if (ret != EOK) {
+		batch_dispose(batch);
+		return ret;
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+usbhc_iface_t uhci_hc_iface = {
 	.reserve_default_address = reserve_default_address,
 	.release_default_address = release_default_address,
@@ -194,4 +370,7 @@
 	.interrupt_in = interrupt_in,
 
+	.bulk_in = bulk_in,
+	.bulk_out = bulk_out,
+
 	.control_read = control_read,
 	.control_write = control_write,
Index: uspace/drv/uhci-hcd/iface.h
===================================================================
--- uspace/drv/uhci-hcd/iface.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/iface.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -27,9 +27,9 @@
  */
 
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver iface
  */
 #ifndef DRV_UHCI_IFACE_H
@@ -38,5 +38,5 @@
 #include <usbhc_iface.h>
 
-extern usbhc_iface_t uhci_iface;
+extern usbhc_iface_t uhci_hc_iface;
 
 #endif
Index: uspace/drv/uhci-hcd/main.c
===================================================================
--- uspace/drv/uhci-hcd/main.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,23 +26,18 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver initialization
  */
 #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 "iface.h"
-#include "pci.h"
-#include "root_hub.h"
 #include "uhci.h"
 
@@ -60,102 +55,39 @@
 };
 /*----------------------------------------------------------------------------*/
-static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
+/** Initialize a new ddf driver instance for uhci hc and hub.
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+int uhci_add_device(ddf_dev_t *device)
 {
-	assert(dev);
-	uhci_t *hc = dev_to_uhci(dev);
-	uint16_t status = IPC_GET_ARG1(*call);
-	assert(hc);
-	uhci_interrupt(hc, status);
+	usb_log_info("uhci_add_device() called\n");
+	assert(device);
+	uhci_t *uhci = malloc(sizeof(uhci_t));
+	if (uhci == NULL) {
+		usb_log_error("Failed to allocate UHCI driver.\n");
+		return ENOMEM;
+	}
+
+	int ret = uhci_init(uhci, device);
+	if (ret != EOK) {
+		usb_log_error("Failed to initialzie UHCI driver.\n");
+		return ret;
+	}
+	device->driver_data = uhci;
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
-static int uhci_add_device(ddf_dev_t *device)
-{
-	assert(device);
-	uhci_t *hcd = NULL;
-#define CHECK_RET_FREE_HC_RETURN(ret, message...) \
-if (ret != EOK) { \
-	usb_log_error(message); \
-	if (hcd != NULL) \
-		free(hcd); \
-	return ret; \
-}
-
-	usb_log_info("uhci_add_device() called\n");
-
-	uintptr_t io_reg_base = 0;
-	size_t io_reg_size = 0;
-	int irq = 0;
-
-	int ret =
-	    pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
-	CHECK_RET_FREE_HC_RETURN(ret,
-	    "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
-	usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
-	    io_reg_base, io_reg_size, irq);
-
-	ret = pci_disable_legacy(device);
-	CHECK_RET_FREE_HC_RETURN(ret,
-	    "Failed(%d) disable legacy USB: %s.\n", ret, str_error(ret));
-
-#if 0
-	ret = pci_enable_interrupts(device);
-	if (ret != EOK) {
-		usb_log_warning(
-		    "Failed(%d) to enable interrupts, fall back to polling.\n",
-		    ret);
-	}
-#endif
-
-	hcd = malloc(sizeof(uhci_t));
-	ret = (hcd != NULL) ? EOK : ENOMEM;
-	CHECK_RET_FREE_HC_RETURN(ret,
-	    "Failed(%d) to allocate memory for uhci hcd.\n", ret);
-
-	ret = uhci_init(hcd, device, (void*)io_reg_base, io_reg_size);
-	CHECK_RET_FREE_HC_RETURN(ret, "Failed(%d) to init uhci-hcd.\n",
-	    ret);
-#undef CHECK_RET_FREE_HC_RETURN
-
-	/*
-	 * We might free hcd, but that does not matter since no one
-	 * else would access driver_data anyway.
-	 */
-	device->driver_data = hcd;
-
-	ddf_fun_t *rh = NULL;
-#define CHECK_RET_FINI_FREE_RETURN(ret, message...) \
-if (ret != EOK) { \
-	usb_log_error(message); \
-	if (hcd != NULL) {\
-		uhci_fini(hcd); \
-		free(hcd); \
-	} \
-	if (rh != NULL) \
-		free(rh); \
-	return ret; \
-}
-
-	/* It does no harm if we register this on polling */
-	ret = register_interrupt_handler(device, irq, irq_handler,
-	    &hcd->interrupt_code);
-	CHECK_RET_FINI_FREE_RETURN(ret,
-	    "Failed(%d) to register interrupt handler.\n", ret);
-
-	ret = setup_root_hub(&rh, device);
-	CHECK_RET_FINI_FREE_RETURN(ret,
-	    "Failed(%d) to setup UHCI root hub.\n", ret);
-	rh->driver_data = hcd->ddf_instance;
-
-	ret = ddf_fun_bind(rh);
-	CHECK_RET_FINI_FREE_RETURN(ret,
-	    "Failed(%d) to register UHCI root hub.\n", ret);
-
-	return EOK;
-#undef CHECK_RET_FINI_FREE_RETURN
-}
-/*----------------------------------------------------------------------------*/
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
 int main(int argc, char *argv[])
 {
-	sleep(3);
+	sleep(3); /* TODO: remove in final version */
 	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
 
Index: uspace/drv/uhci-hcd/pci.c
===================================================================
--- uspace/drv/uhci-hcd/pci.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/pci.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -27,5 +27,5 @@
  */
 /**
- * @addtogroup drvusbuhci
+ * @addtogroup drvusbuhcihc
  * @{
  */
@@ -65,5 +65,4 @@
 
 	int rc;
-
 	hw_resource_list_t hw_resources;
 	rc = hw_res_get_resource_list(parent_phone, &hw_resources);
@@ -82,28 +81,25 @@
 	for (i = 0; i < hw_resources.count; i++) {
 		hw_resource_t *res = &hw_resources.resources[i];
-		switch (res->type) {
-			case INTERRUPT:
-				irq = res->res.interrupt.irq;
-				irq_found = true;
-				usb_log_debug2("Found interrupt: %d.\n", irq);
-				break;
-			case IO_RANGE:
-				io_address = res->res.io_range.address;
-				io_size = res->res.io_range.size;
-				usb_log_debug2("Found io: %llx %zu.\n",
-				    res->res.io_range.address, res->res.io_range.size);
-				io_found = true;
-				break;
-			default:
-				break;
+		switch (res->type)
+		{
+		case INTERRUPT:
+			irq = res->res.interrupt.irq;
+			irq_found = true;
+			usb_log_debug2("Found interrupt: %d.\n", irq);
+			break;
+
+		case IO_RANGE:
+			io_address = res->res.io_range.address;
+			io_size = res->res.io_range.size;
+			usb_log_debug2("Found io: %llx %zu.\n",
+			    res->res.io_range.address, res->res.io_range.size);
+			io_found = true;
+
+		default:
+			break;
 		}
 	}
 
-	if (!io_found) {
-		rc = ENOENT;
-		goto leave;
-	}
-
-	if (!irq_found) {
+	if (!io_found || !irq_found) {
 		rc = ENOENT;
 		goto leave;
@@ -121,4 +117,9 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Call the PCI driver with a request to enable interrupts
+ *
+ * @param[in] device Device asking for interrupts
+ * @return Error code.
+ */
 int pci_enable_interrupts(ddf_dev_t *device)
 {
@@ -130,9 +131,14 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Call the PCI driver with a request to clear legacy support register
+ *
+ * @param[in] device Device asking to disable interrupts
+ * @return Error code.
+ */
 int pci_disable_legacy(ddf_dev_t *device)
 {
 	assert(device);
-	int parent_phone = devman_parent_device_connect(device->handle,
-		IPC_FLAG_BLOCKING);
+	int parent_phone =
+	    devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING);
 	if (parent_phone < 0) {
 		return parent_phone;
@@ -144,9 +150,9 @@
 	sysarg_t value = 0x8f00;
 
-  int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
+	int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
 	    IPC_M_CONFIG_SPACE_WRITE_16, address, value);
 	async_hangup(parent_phone);
 
-  return rc;
+	return rc;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/uhci-hcd/pci.h
===================================================================
--- uspace/drv/uhci-hcd/pci.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/pci.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -27,9 +27,9 @@
  */
 
-/** @addtogroup drvusbuhci
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver PCI helper functions
  */
 #ifndef DRV_UHCI_PCI_H
Index: uspace/drv/uhci-hcd/root_hub.c
===================================================================
--- uspace/drv/uhci-hcd/root_hub.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ 	(revision )
@@ -1,153 +1,0 @@
-/*
- * 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 usb
- * @{
- */
-/** @file
- * @brief UHCI driver
- */
-#include <assert.h>
-#include <errno.h>
-#include <str_error.h>
-#include <stdio.h>
-#include <ops/hw_res.h>
-
-#include <usb_iface.h>
-#include <usb/debug.h>
-
-#include "root_hub.h"
-#include "uhci.h"
-
-/*----------------------------------------------------------------------------*/
-static int usb_iface_get_hc_handle_rh_impl(ddf_fun_t *root_hub_fun,
-    devman_handle_t *handle)
-{
-	ddf_fun_t *hc_fun = root_hub_fun->driver_data;
-	assert(hc_fun != NULL);
-
-	*handle = hc_fun->handle;
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-static int usb_iface_get_address_rh_impl(ddf_fun_t *fun, devman_handle_t handle,
-    usb_address_t *address)
-{
-	assert(fun);
-	ddf_fun_t *hc_fun = fun->driver_data;
-	assert(hc_fun);
-	uhci_t *hc = fun_to_uhci(hc_fun);
-	assert(hc);
-
-	usb_address_t addr = device_keeper_find(&hc->device_manager,
-	    handle);
-	if (addr < 0) {
-		return addr;
-	}
-
-	if (address != NULL) {
-		*address = addr;
-	}
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-usb_iface_t usb_iface_root_hub_fun_impl = {
-	.get_hc_handle = usb_iface_get_hc_handle_rh_impl,
-	.get_address = usb_iface_get_address_rh_impl
-};
-/*----------------------------------------------------------------------------*/
-static hw_resource_list_t *get_resource_list(ddf_fun_t *dev)
-{
-	assert(dev);
-	ddf_fun_t *hc_ddf_instance = dev->driver_data;
-	assert(hc_ddf_instance);
-	uhci_t *hc = hc_ddf_instance->driver_data;
-	assert(hc);
-
-	//TODO: fix memory leak
-	hw_resource_list_t *resource_list = malloc(sizeof(hw_resource_list_t));
-	assert(resource_list);
-	resource_list->count = 1;
-	resource_list->resources = malloc(sizeof(hw_resource_t));
-	assert(resource_list->resources);
-	resource_list->resources[0].type = IO_RANGE;
-	resource_list->resources[0].res.io_range.address =
-	    ((uintptr_t)hc->registers) + 0x10; // see UHCI design guide
-	resource_list->resources[0].res.io_range.size = 4;
-	resource_list->resources[0].res.io_range.endianness = LITTLE_ENDIAN;
-
-	return resource_list;
-}
-/*----------------------------------------------------------------------------*/
-static hw_res_ops_t hw_res_iface = {
-	.get_resource_list = get_resource_list,
-	.enable_interrupt = NULL
-};
-/*----------------------------------------------------------------------------*/
-static ddf_dev_ops_t root_hub_ops = {
-	.interfaces[USB_DEV_IFACE] = &usb_iface_root_hub_fun_impl,
-	.interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
-};
-/*----------------------------------------------------------------------------*/
-int setup_root_hub(ddf_fun_t **fun, ddf_dev_t *hc)
-{
-	assert(fun);
-	assert(hc);
-	int ret;
-
-	ddf_fun_t *hub = ddf_fun_create(hc, fun_inner, "root-hub");
-	if (!hub) {
-		usb_log_error("Failed to create root hub device structure.\n");
-		return ENOMEM;
-	}
-
-	char *match_str;
-	ret = asprintf(&match_str, "usb&uhci&root-hub");
-	if (ret < 0) {
-		usb_log_error("Failed to create root hub match string.\n");
-		ddf_fun_destroy(hub);
-		return ENOMEM;
-	}
-
-	ret = ddf_fun_add_match_id(hub, match_str, 100);
-	if (ret != EOK) {
-		usb_log_error("Failed(%d) to add root hub match id: %s\n",
-		    ret, str_error(ret));
-		ddf_fun_destroy(hub);
-		return ret;
-	}
-
-	hub->ops = &root_hub_ops;
-
-	*fun = hub;
-	return EOK;
-}
-/**
- * @}
- */
Index: uspace/drv/uhci-hcd/root_hub.h
===================================================================
--- uspace/drv/uhci-hcd/root_hub.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2010 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 drvusbuhci
- * @{
- */
-/** @file
- * @brief UHCI driver
- */
-#ifndef DRV_UHCI_ROOT_HUB_H
-#define DRV_UHCI_ROOT_HUB_H
-
-#include <ddf/driver.h>
-
-int setup_root_hub(ddf_fun_t **device, ddf_dev_t *hc);
-
-#endif
-/**
- * @}
- */
Index: uspace/drv/uhci-hcd/transfer_list.c
===================================================================
--- uspace/drv/uhci-hcd/transfer_list.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/transfer_list.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,29 +26,38 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver transfer list implementation
  */
 #include <errno.h>
-
 #include <usb/debug.h>
 
 #include "transfer_list.h"
 
+static void transfer_list_remove_batch(
+    transfer_list_t *instance, batch_t *batch);
+/*----------------------------------------------------------------------------*/
+/** Initialize transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ * @param[in] name Name of the new list.
+ * @return Error code
+ *
+ * Allocates memory for internal qh_t structure.
+ */
 int transfer_list_init(transfer_list_t *instance, const char *name)
 {
 	assert(instance);
-	instance->next = NULL;
 	instance->name = name;
-	instance->queue_head = queue_head_get();
+	instance->queue_head = malloc32(sizeof(qh_t));
 	if (!instance->queue_head) {
 		usb_log_error("Failed to allocate queue head.\n");
 		return ENOMEM;
 	}
-	instance->queue_head_pa = (uintptr_t)addr_to_phys(instance->queue_head);
-
-	queue_head_init(instance->queue_head);
+	instance->queue_head_pa = addr_to_phys(instance->queue_head);
+
+	qh_init(instance->queue_head);
 	list_initialize(&instance->batch_list);
 	fibril_mutex_initialize(&instance->guard);
@@ -56,4 +65,12 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Set the next list in transfer list chain.
+ *
+ * @param[in] instance List to lead.
+ * @param[in] next List to append.
+ * @return Error code
+ *
+ * Does not check whether this replaces an existing list .
+ */
 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)
 {
@@ -62,46 +79,63 @@
 	if (!instance->queue_head)
 		return;
-	queue_head_append_qh(instance->queue_head, next->queue_head_pa);
-	instance->queue_head->element = instance->queue_head->next_queue;
-}
-/*----------------------------------------------------------------------------*/
+	/* Set both next and element to point to the same QH */
+	qh_set_next_qh(instance->queue_head, next->queue_head_pa);
+	qh_set_element_qh(instance->queue_head, next->queue_head_pa);
+}
+/*----------------------------------------------------------------------------*/
+/** Submit transfer batch to the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] batch Transfer batch to submit.
+ * @return Error code
+ *
+ * The batch is added to the end of the list and queue.
+ */
 void transfer_list_add_batch(transfer_list_t *instance, batch_t *batch)
 {
 	assert(instance);
 	assert(batch);
-	usb_log_debug2("Adding batch(%p) to queue %s.\n", batch, instance->name);
-
-	uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);
+	usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
+
+	const uint32_t pa = addr_to_phys(batch->qh);
 	assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
-	pa |= LINK_POINTER_QUEUE_HEAD_FLAG;
-
-	batch->qh->next_queue = instance->queue_head->next_queue;
+
+	/* New batch will be added to the end of the current list
+	 * so set the link accordingly */
+	qh_set_next_qh(batch->qh, instance->queue_head->next);
 
 	fibril_mutex_lock(&instance->guard);
 
-	if (instance->queue_head->element == instance->queue_head->next_queue) {
-		/* there is nothing scheduled */
-		list_append(&batch->link, &instance->batch_list);
-		instance->queue_head->element = pa;
-		usb_log_debug("Batch(%p) added to queue %s first.\n",
-			batch, instance->name);
-		fibril_mutex_unlock(&instance->guard);
-		return;
-	}
-	/* now we can be sure that there is someting scheduled */
-	assert(!list_empty(&instance->batch_list));
+	/* Add to the hardware queue. */
+	if (list_empty(&instance->batch_list)) {
+		/* There is nothing scheduled */
+		qh_t *qh = instance->queue_head;
+		assert(qh->element == qh->next);
+		qh_set_element_qh(qh, pa);
+	} else {
+		/* There is something scheduled */
+		batch_t *last = list_get_instance(
+		    instance->batch_list.prev, batch_t, link);
+		qh_set_next_qh(last->qh, pa);
+	}
+	/* Add to the driver list */
+	list_append(&batch->link, &instance->batch_list);
+
 	batch_t *first = list_get_instance(
-	          instance->batch_list.next, batch_t, link);
-	batch_t *last = list_get_instance(
-	    instance->batch_list.prev, batch_t, link);
-	queue_head_append_qh(last->qh, pa);
-	list_append(&batch->link, &instance->batch_list);
-	usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n",
-		batch, instance->name, first );
+	    instance->batch_list.next, batch_t, link);
+	usb_log_debug("Batch(%p) added to queue %s, first is %p.\n",
+		batch, instance->name, first);
 	fibril_mutex_unlock(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
-static void transfer_list_remove_batch(
-    transfer_list_t *instance, batch_t *batch)
+/** Remove a transfer batch from the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] batch Transfer batch to remove.
+ * @return Error code
+ *
+ * Does not lock the transfer list, caller is responsible for that.
+ */
+void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch)
 {
 	assert(instance);
@@ -109,20 +143,34 @@
 	assert(instance->queue_head);
 	assert(batch->qh);
-	usb_log_debug2("Removing batch(%p) from queue %s.\n", batch, instance->name);
-
-	/* I'm the first one here */
+	usb_log_debug2(
+	    "Queue %s: removing batch(%p).\n", instance->name, batch);
+
+	const char * pos = NULL;
+	/* Remove from the hardware queue */
 	if (batch->link.prev == &instance->batch_list) {
-		usb_log_debug("Batch(%p) removed (FIRST) from queue %s, next element %x.\n",
-			batch, instance->name, batch->qh->next_queue);
-		instance->queue_head->element = batch->qh->next_queue;
+		/* I'm the first one here */
+		qh_set_element_qh(instance->queue_head, batch->qh->next);
+		pos = "FIRST";
 	} else {
-		usb_log_debug("Batch(%p) removed (NOT FIRST) from queue, next element %x.\n",
-			batch, instance->name, batch->qh->next_queue);
-		batch_t *prev = list_get_instance(batch->link.prev, batch_t, link);
-		prev->qh->next_queue = batch->qh->next_queue;
-	}
+		batch_t *prev =
+		    list_get_instance(batch->link.prev, batch_t, link);
+		qh_set_next_qh(prev->qh, batch->qh->next);
+		pos = "NOT FIRST";
+	}
+	/* Remove from the driver list */
 	list_remove(&batch->link);
-}
-/*----------------------------------------------------------------------------*/
+	usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n",
+	    batch, pos, instance->name, batch->qh->next);
+}
+/*----------------------------------------------------------------------------*/
+/** Check list for finished batches.
+ *
+ * @param[in] instance List to use.
+ * @return Error code
+ *
+ * Creates a local list of finished batches and calls next_step on each and
+ * every one. This is safer because next_step may theoretically access
+ * this transfer list leading to the deadlock if its done inline.
+ */
 void transfer_list_remove_finished(transfer_list_t *instance)
 {
@@ -138,4 +186,5 @@
 
 		if (batch_is_complete(batch)) {
+			/* Save for post-processing */
 			transfer_list_remove_batch(instance, batch);
 			list_append(current, &done);
Index: uspace/drv/uhci-hcd/transfer_list.h
===================================================================
--- uspace/drv/uhci-hcd/transfer_list.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/transfer_list.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,9 +26,9 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver transfer list structure
  */
 #ifndef DRV_UHCI_TRANSFER_LIST_H
@@ -44,10 +44,21 @@
 {
 	fibril_mutex_t guard;
-	queue_head_t *queue_head;
+	qh_t *queue_head;
 	uint32_t queue_head_pa;
-	struct transfer_list *next;
 	const char *name;
 	link_t batch_list;
 } transfer_list_t;
+
+/** Dispose transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ *
+ * Frees memory for internal qh_t structure.
+ */
+static inline void transfer_list_fini(transfer_list_t *instance)
+{
+	assert(instance);
+	free32(instance->queue_head);
+}
 
 int transfer_list_init(transfer_list_t *instance, const char *name);
@@ -55,9 +66,4 @@
 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);
 
-static inline void transfer_list_fini(transfer_list_t *instance)
-{
-	assert(instance);
-	queue_head_dispose(instance->queue_head);
-}
 void transfer_list_remove_finished(transfer_list_t *instance);
 
Index: uspace/drv/uhci-hcd/uhci.c
===================================================================
--- uspace/drv/uhci-hcd/uhci.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/uhci.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,5 +26,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+
+/** @addtogroup drvusbuhci
  * @{
  */
@@ -34,40 +35,42 @@
 #include <errno.h>
 #include <str_error.h>
-#include <adt/list.h>
-#include <libarch/ddi.h>
-
+#include <ddf/interrupt.h>
+#include <usb_iface.h>
+#include <usb/ddfiface.h>
 #include <usb/debug.h>
-#include <usb/usb.h>
-#include <usb/ddfiface.h>
-#include <usb_iface.h>
 
 #include "uhci.h"
 #include "iface.h"
-
-static irq_cmd_t uhci_cmds[] = {
-	{
-		.cmd = CMD_PIO_READ_16,
-		.addr = NULL, /* patched for every instance */
-		.dstarg = 1
-	},
-	{
-		.cmd = CMD_PIO_WRITE_16,
-		.addr = NULL, /* pathed for every instance */
-		.value = 0x1f
-	},
-	{
-		.cmd = CMD_ACCEPT
-	}
-};
-
-static int usb_iface_get_address(ddf_fun_t *fun, devman_handle_t handle,
-    usb_address_t *address)
+#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);
+	uhci_hc_t *hc = &((uhci_t*)dev->driver_data)->hc;
+	uint16_t status = IPC_GET_ARG1(*call);
+	assert(hc);
+	uhci_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);
-	uhci_t *hc = fun_to_uhci(fun);
-	assert(hc);
-
-	usb_address_t addr = device_keeper_find(&hc->device_manager,
-	    handle);
+	device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager;
+
+	usb_address_t addr = device_keeper_find(manager, handle);
 	if (addr < 0) {
 		return addr;
@@ -81,342 +84,156 @@
 }
 /*----------------------------------------------------------------------------*/
-static usb_iface_t hc_usb_iface = {
-	.get_hc_handle = usb_iface_get_hc_handle_hc_impl,
+/** Gets handle of the respective hc (this or parent device).
+ *
+ * @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 = ((uhci_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 uhci_ops = {
-	.interfaces[USB_DEV_IFACE] = &hc_usb_iface,
-	.interfaces[USBHC_DEV_IFACE] = &uhci_iface,
-};
-/*----------------------------------------------------------------------------*/
-static int uhci_init_transfer_lists(uhci_t *instance);
-static int uhci_init_mem_structures(uhci_t *instance);
-static void uhci_init_hw(uhci_t *instance);
-
-static int uhci_interrupt_emulator(void *arg);
-static int uhci_debug_checker(void *arg);
-
-static bool allowed_usb_packet(
-	bool low_speed, usb_transfer_type_t, size_t size);
-
-
-int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size)
-{
-	assert(reg_size >= sizeof(regs_t));
-	int ret;
-
+static ddf_dev_ops_t uhci_hc_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface,
+	.interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */
+};
+/*----------------------------------------------------------------------------*/
+/** Get root hub hw resources (I/O registers).
+ *
+ * @param[in] fun Root hub function.
+ * @return Pointer to the resource list used by the root hub.
+ */
+static hw_resource_list_t *get_resource_list(ddf_fun_t *fun)
+{
+	assert(fun);
+	return &((uhci_rh_t*)fun->driver_data)->resource_list;
+}
+/*----------------------------------------------------------------------------*/
+static hw_res_ops_t hw_res_iface = {
+	.get_resource_list = get_resource_list,
+	.enable_interrupt = NULL
+};
+/*----------------------------------------------------------------------------*/
+static ddf_dev_ops_t uhci_rh_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface,
+	.interfaces[HW_RES_DEV_IFACE] = &hw_res_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 uhci_init(uhci_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->ddf_instance) \
-			ddf_fun_destroy(instance->ddf_instance); \
-		return ret; \
-	} else (void) 0
-
-	/* Create UHCI function. */
-	instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci");
-	ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK;
-	CHECK_RET_DEST_FUN_RETURN(ret,
-	    "Failed to create UHCI device function.\n");
-
-	instance->ddf_instance->ops = &uhci_ops;
-	instance->ddf_instance->driver_data = instance;
-
-	ret = ddf_fun_bind(instance->ddf_instance);
+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 io_reg_base = 0;
+	size_t io_reg_size = 0;
+	int irq = 0;
+
+	int ret =
+	    pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
+	usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
+	    io_reg_base, io_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;
+	ret = pci_enable_interrupts(device);
+	if (ret != EOK) {
+		usb_log_warning(
+		    "Failed(%d) to enable interrupts, fall back to polling.\n",
+		    ret);
+	} else {
+		usb_log_debug("Hw interrupts enabled.\n");
+		interrupts = true;
+	}
+
+	instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc");
+	ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to create HC function.\n", ret);
+
+	ret = uhci_hc_init(&instance->hc, instance->hc_fun,
+	    (void*)io_reg_base, io_reg_size, interrupts);
+	CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret);
+	instance->hc_fun->ops = &uhci_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));
-
-	/* allow access to hc control registers */
-	regs_t *io;
-	ret = pio_enable(regs, reg_size, (void**)&io);
-	CHECK_RET_DEST_FUN_RETURN(ret,
-	    "Failed(%d) to gain access to registers at %p: %s.\n",
-	    ret, str_error(ret), io);
-	instance->registers = io;
-	usb_log_debug("Device registers at %p(%u) accessible.\n",
-	    io, reg_size);
-
-	ret = uhci_init_mem_structures(instance);
-	CHECK_RET_DEST_FUN_RETURN(ret,
-	    "Failed to initialize UHCI memory structures.\n");
-
-	uhci_init_hw(instance);
-	instance->cleaner =
-	    fibril_create(uhci_interrupt_emulator, instance);
-	fibril_add_ready(instance->cleaner);
-
-	instance->debug_checker = fibril_create(uhci_debug_checker, instance);
-	fibril_add_ready(instance->debug_checker);
-
-	usb_log_info("Started UHCI driver.\n");
+#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); \
+	uhci_hc_fini(&instance->hc); \
+	return ret; \
+}
+
+	/* It does no harm if we register this on polling */
+	ret = register_interrupt_handler(device, irq, irq_handler,
+	    &instance->hc.interrupt_code);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to register interrupt handler.\n", ret);
+
+	instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh");
+	ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to create root hub function.\n", ret);
+
+	ret = uhci_rh_init(&instance->rh, instance->rh_fun,
+	    (uintptr_t)instance->hc.registers + 0x10, 4);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to setup UHCI root hub.\n", ret);
+
+	instance->rh_fun->ops = &uhci_rh_ops;
+	instance->rh_fun->driver_data = &instance->rh;
+	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_DEST_FUN_RETURN
-}
-/*----------------------------------------------------------------------------*/
-void uhci_init_hw(uhci_t *instance)
-{
-	assert(instance);
-
-	/* reset everything, who knows what touched it before us */
-	pio_write_16(&instance->registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
-	async_usleep(10000); /* 10ms according to USB spec */
-	pio_write_16(&instance->registers->usbcmd, 0);
-
-	/* reset hc, all states and counters */
-	pio_write_16(&instance->registers->usbcmd, UHCI_CMD_HCRESET);
-	while ((pio_read_16(&instance->registers->usbcmd) & UHCI_CMD_HCRESET) != 0)
-		{ async_usleep(10); }
-
-	/* set framelist pointer */
-	const uint32_t pa = addr_to_phys(instance->frame_list);
-	pio_write_32(&instance->registers->flbaseadd, pa);
-
-	/* enable all interrupts, but resume interrupt */
-	pio_write_16(&instance->registers->usbintr,
-	    UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
-
-	/* Start the hc with large(64B) packet FSBR */
-	pio_write_16(&instance->registers->usbcmd,
-	    UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE);
-}
-/*----------------------------------------------------------------------------*/
-int uhci_init_mem_structures(uhci_t *instance)
-{
-	assert(instance);
-#define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
-	if (ret != EOK) { \
-		usb_log_error(message); \
-		if (instance->interrupt_code.cmds != NULL) \
-			free(instance->interrupt_code.cmds); \
-		return ret; \
-	} else (void) 0
-
-	/* init interrupt code */
-	instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds));
-	int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK;
-	CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to allocate interrupt cmds space.\n");
-
-	{
-		irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds;
-		memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds));
-		interrupt_commands[0].addr = (void*)&instance->registers->usbsts;
-		interrupt_commands[1].addr = (void*)&instance->registers->usbsts;
-		instance->interrupt_code.cmdcount =
-		    sizeof(uhci_cmds) / sizeof(irq_cmd_t);
-	}
-
-	/* init transfer lists */
-	ret = uhci_init_transfer_lists(instance);
-	CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to initialize transfer lists.\n");
-	usb_log_debug("Initialized transfer lists.\n");
-
-	/* frame list initialization */
-	instance->frame_list = get_page();
-	ret = instance ? EOK : ENOMEM;
-	CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
-	usb_log_debug("Initialized frame list.\n");
-
-	/* initialize all frames to point to the first queue head */
-	const uint32_t queue =
-	  instance->transfers_interrupt.queue_head_pa
-	  | LINK_POINTER_QUEUE_HEAD_FLAG;
-
-	unsigned i = 0;
-	for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
-		instance->frame_list[i] = queue;
-	}
-
-	/* init address keeper(libusb) */
-	device_keeper_init(&instance->device_manager);
-	usb_log_debug("Initialized device manager.\n");
-
-	return EOK;
-#undef CHECK_RET_DEST_CMDS_RETURN
-}
-/*----------------------------------------------------------------------------*/
-int uhci_init_transfer_lists(uhci_t *instance)
-{
-	assert(instance);
-#define CHECK_RET_CLEAR_RETURN(ret, message...) \
-	if (ret != EOK) { \
-		usb_log_error(message); \
-		transfer_list_fini(&instance->transfers_bulk_full); \
-		transfer_list_fini(&instance->transfers_control_full); \
-		transfer_list_fini(&instance->transfers_control_slow); \
-		transfer_list_fini(&instance->transfers_interrupt); \
-		return ret; \
-	} else (void) 0
-
-	/* initialize TODO: check errors */
-	int ret;
-	ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
-
-	ret = transfer_list_init(&instance->transfers_control_full, "CONTROL_FULL");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
-
-	ret = transfer_list_init(&instance->transfers_control_slow, "CONTROL_SLOW");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
-
-	ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
-	CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
-
-	transfer_list_set_next(&instance->transfers_control_full,
-		&instance->transfers_bulk_full);
-	transfer_list_set_next(&instance->transfers_control_slow,
-		&instance->transfers_control_full);
-	transfer_list_set_next(&instance->transfers_interrupt,
-		&instance->transfers_control_slow);
-
-	/*FSBR*/
-#ifdef FSBR
-	transfer_list_set_next(&instance->transfers_bulk_full,
-		&instance->transfers_control_full);
-#endif
-
-	instance->transfers[0][USB_TRANSFER_INTERRUPT] =
-	  &instance->transfers_interrupt;
-	instance->transfers[1][USB_TRANSFER_INTERRUPT] =
-	  &instance->transfers_interrupt;
-	instance->transfers[0][USB_TRANSFER_CONTROL] =
-	  &instance->transfers_control_full;
-	instance->transfers[1][USB_TRANSFER_CONTROL] =
-	  &instance->transfers_control_slow;
-	instance->transfers[0][USB_TRANSFER_BULK] =
-	  &instance->transfers_bulk_full;
-
-	return EOK;
-#undef CHECK_RET_CLEAR_RETURN
-}
-/*----------------------------------------------------------------------------*/
-int uhci_schedule(uhci_t *instance, batch_t *batch)
-{
-	assert(instance);
-	assert(batch);
-	const int low_speed = (batch->speed == USB_SPEED_LOW);
-	if (!allowed_usb_packet(
-	    low_speed, batch->transfer_type, batch->max_packet_size)) {
-		usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n",
-		    low_speed ? "LOW" : "FULL" , batch->transfer_type,
-		    batch->max_packet_size);
-		return ENOTSUP;
-	}
-	/* TODO: check available bandwith here */
-
-	transfer_list_t *list =
-	    instance->transfers[low_speed][batch->transfer_type];
-	assert(list);
-	transfer_list_add_batch(list, batch);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-void uhci_interrupt(uhci_t *instance, uint16_t status)
-{
-	assert(instance);
-	transfer_list_remove_finished(&instance->transfers_interrupt);
-	transfer_list_remove_finished(&instance->transfers_control_slow);
-	transfer_list_remove_finished(&instance->transfers_control_full);
-	transfer_list_remove_finished(&instance->transfers_bulk_full);
-}
-/*----------------------------------------------------------------------------*/
-int uhci_interrupt_emulator(void* arg)
-{
-	usb_log_debug("Started interrupt emulator.\n");
-	uhci_t *instance = (uhci_t*)arg;
-	assert(instance);
-
-	while (1) {
-		uint16_t status = pio_read_16(&instance->registers->usbsts);
-		if (status != 0)
-			usb_log_debug2("UHCI status: %x.\n", status);
-		status |= 1;
-		uhci_interrupt(instance, status);
-		pio_write_16(&instance->registers->usbsts, 0x1f);
-		async_usleep(UHCI_CLEANER_TIMEOUT * 5);
-	}
-	return EOK;
-}
-/*---------------------------------------------------------------------------*/
-int uhci_debug_checker(void *arg)
-{
-	uhci_t *instance = (uhci_t*)arg;
-	assert(instance);
-
-#define QH(queue) \
-	instance->transfers_##queue.queue_head
-
-	while (1) {
-		const uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
-		const uint16_t sts = pio_read_16(&instance->registers->usbsts);
-		const uint16_t intr =
-		    pio_read_16(&instance->registers->usbintr);
-
-		if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
-			usb_log_debug2("Command: %X Status: %X Intr: %x\n",
-			    cmd, sts, intr);
-		}
-
-		uintptr_t frame_list =
-		    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
-		if (frame_list != addr_to_phys(instance->frame_list)) {
-			usb_log_debug("Framelist address: %p vs. %p.\n",
-			    frame_list, addr_to_phys(instance->frame_list));
-		}
-
-		int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
-		usb_log_debug2("Framelist item: %d \n", frnum );
-
-		uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf);
-		uintptr_t real_pa = addr_to_phys(QH(interrupt));
-		if (expected_pa != real_pa) {
-			usb_log_debug("Interrupt QH: %p vs. %p.\n",
-			    expected_pa, real_pa);
-		}
-
-		expected_pa = QH(interrupt)->next_queue & (~0xf);
-		real_pa = addr_to_phys(QH(control_slow));
-		if (expected_pa != real_pa) {
-			usb_log_debug("Control Slow QH: %p vs. %p.\n",
-			    expected_pa, real_pa);
-		}
-
-		expected_pa = QH(control_slow)->next_queue & (~0xf);
-		real_pa = addr_to_phys(QH(control_full));
-		if (expected_pa != real_pa) {
-			usb_log_debug("Control Full QH: %p vs. %p.\n",
-			    expected_pa, real_pa);
-		}
-
-		expected_pa = QH(control_full)->next_queue & (~0xf);
-		real_pa = addr_to_phys(QH(bulk_full));
-		if (expected_pa != real_pa ) {
-			usb_log_debug("Bulk QH: %p vs. %p.\n",
-			    expected_pa, real_pa);
-		}
-		async_usleep(UHCI_DEBUGER_TIMEOUT);
-	}
-	return 0;
-#undef QH
-}
-/*----------------------------------------------------------------------------*/
-bool allowed_usb_packet(
-    bool low_speed, usb_transfer_type_t transfer, size_t size)
-{
-	/* see USB specification chapter 5.5-5.8 for magic numbers used here */
-	switch(transfer)
-	{
-	case USB_TRANSFER_ISOCHRONOUS:
-		return (!low_speed && size < 1024);
-	case USB_TRANSFER_INTERRUPT:
-		return size <= (low_speed ? 8 : 64);
-	case USB_TRANSFER_CONTROL: /* device specifies its own max size */
-		return (size <= (low_speed ? 8 : 64));
-	case USB_TRANSFER_BULK: /* device specifies its own max size */
-		return (!low_speed && size <= 64);
-	}
-	return false;
+#undef CHECK_RET_FINI_RETURN
 }
 /**
Index: uspace/drv/uhci-hcd/uhci.h
===================================================================
--- uspace/drv/uhci-hcd/uhci.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/uhci.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jan Vesely
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -31,91 +31,23 @@
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI driver main structure for both host controller and root-hub.
  */
 #ifndef DRV_UHCI_UHCI_H
 #define DRV_UHCI_UHCI_H
+#include <ddi.h>
+#include <ddf/driver.h>
 
-#include <fibril.h>
-#include <fibril_synch.h>
-#include <adt/list.h>
-#include <ddi.h>
-
-#include <usbhc_iface.h>
-
-#include "batch.h"
-#include "transfer_list.h"
-#include "utils/device_keeper.h"
-
-typedef struct uhci_regs {
-	uint16_t usbcmd;
-#define UHCI_CMD_MAX_PACKET (1 << 7)
-#define UHCI_CMD_CONFIGURE  (1 << 6)
-#define UHCI_CMD_DEBUG  (1 << 5)
-#define UHCI_CMD_FORCE_GLOBAL_RESUME  (1 << 4)
-#define UHCI_CMD_FORCE_GLOBAL_SUSPEND  (1 << 3)
-#define UHCI_CMD_GLOBAL_RESET  (1 << 2)
-#define UHCI_CMD_HCRESET  (1 << 1)
-#define UHCI_CMD_RUN_STOP  (1 << 0)
-
-	uint16_t usbsts;
-#define UHCI_STATUS_HALTED (1 << 5)
-#define UHCI_STATUS_PROCESS_ERROR (1 << 4)
-#define UHCI_STATUS_SYSTEM_ERROR (1 << 3)
-#define UHCI_STATUS_RESUME (1 << 2)
-#define UHCI_STATUS_ERROR_INTERRUPT (1 << 1)
-#define UHCI_STATUS_INTERRUPT (1 << 0)
-
-	uint16_t usbintr;
-#define UHCI_INTR_SHORT_PACKET (1 << 3)
-#define UHCI_INTR_COMPLETE (1 << 2)
-#define UHCI_INTR_RESUME (1 << 1)
-#define UHCI_INTR_CRC (1 << 0)
-
-	uint16_t frnum;
-	uint32_t flbaseadd;
-	uint8_t sofmod;
-} regs_t;
-
-#define UHCI_FRAME_LIST_COUNT 1024
-#define UHCI_CLEANER_TIMEOUT 10000
-#define UHCI_DEBUGER_TIMEOUT 5000000
+#include "uhci_hc.h"
+#include "uhci_rh.h"
 
 typedef struct uhci {
-	device_keeper_t device_manager;
+	ddf_fun_t *hc_fun;
+	ddf_fun_t *rh_fun;
 
-	volatile regs_t *registers;
-
-	link_pointer_t *frame_list;
-
-	transfer_list_t transfers_bulk_full;
-	transfer_list_t transfers_control_full;
-	transfer_list_t transfers_control_slow;
-	transfer_list_t transfers_interrupt;
-
-	transfer_list_t *transfers[2][4];
-
-	irq_code_t interrupt_code;
-
-	fid_t cleaner;
-	fid_t debug_checker;
-
-	ddf_fun_t *ddf_instance;
+	uhci_hc_t hc;
+	uhci_rh_t rh;
 } uhci_t;
 
-/* init uhci specifics in device.driver_data */
-int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size);
-
-static inline void uhci_fini(uhci_t *instance) {};
-
-int uhci_schedule(uhci_t *instance, batch_t *batch);
-
-void uhci_interrupt(uhci_t *instance, uint16_t status);
-
-static inline uhci_t * dev_to_uhci(ddf_dev_t *dev)
-	{ return (uhci_t*)dev->driver_data; }
-
-static inline uhci_t * fun_to_uhci(ddf_fun_t *fun)
-	{ return (uhci_t*)fun->driver_data; }
-
+int uhci_init(uhci_t *instance, ddf_dev_t *device);
 
 #endif
Index: uspace/drv/uhci-hcd/uhci_hc.c
===================================================================
--- uspace/drv/uhci-hcd/uhci_hc.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/uhci-hcd/uhci_hc.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,475 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI Host controller driver routines
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <adt/list.h>
+#include <libarch/ddi.h>
+
+#include <usb/debug.h>
+#include <usb/usb.h>
+#include <usb/ddfiface.h>
+#include <usb_iface.h>
+
+#include "uhci_hc.h"
+
+static irq_cmd_t uhci_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_16,
+		.addr = NULL, /* patched for every instance */
+		.dstarg = 1
+	},
+	{
+		.cmd = CMD_PIO_WRITE_16,
+		.addr = NULL, /* pathed for every instance */
+		.value = 0x1f
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+/*----------------------------------------------------------------------------*/
+static int uhci_hc_init_transfer_lists(uhci_hc_t *instance);
+static int uhci_hc_init_mem_structures(uhci_hc_t *instance);
+static void uhci_hc_init_hw(uhci_hc_t *instance);
+
+static int uhci_hc_interrupt_emulator(void *arg);
+static int uhci_hc_debug_checker(void *arg);
+
+static bool allowed_usb_packet(
+    bool low_speed, usb_transfer_type_t transfer, size_t size);
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI hcd driver structure
+ *
+ * @param[in] instance Memory place to initialize.
+ * @param[in] fun DDF function.
+ * @param[in] regs Address of I/O control registers.
+ * @param[in] size Size of I/O control registers.
+ * @return Error code.
+ * @note Should be called only once on any structure.
+ *
+ * Initializes memory structures, starts up hw, and launches debugger and
+ * interrupt fibrils.
+ */
+int uhci_hc_init(uhci_hc_t *instance, ddf_fun_t *fun,
+    void *regs, size_t reg_size, bool interrupts)
+{
+	assert(reg_size >= sizeof(regs_t));
+	int ret;
+
+#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		if (instance->ddf_instance) \
+			ddf_fun_destroy(instance->ddf_instance); \
+		return ret; \
+	} else (void) 0
+
+	instance->hw_interrupts = interrupts;
+	/* Setup UHCI function. */
+	instance->ddf_instance = fun;
+
+	/* allow access to hc control registers */
+	regs_t *io;
+	ret = pio_enable(regs, reg_size, (void**)&io);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed(%d) to gain access to registers at %p: %s.\n",
+	    ret, str_error(ret), io);
+	instance->registers = io;
+	usb_log_debug("Device registers at %p(%u) accessible.\n",
+	    io, reg_size);
+
+	ret = uhci_hc_init_mem_structures(instance);
+	CHECK_RET_DEST_FUN_RETURN(ret,
+	    "Failed to initialize UHCI memory structures.\n");
+
+	uhci_hc_init_hw(instance);
+	if (!interrupts) {
+		instance->cleaner =
+		    fibril_create(uhci_hc_interrupt_emulator, instance);
+		fibril_add_ready(instance->cleaner);
+	}
+
+	instance->debug_checker = fibril_create(uhci_hc_debug_checker, instance);
+	fibril_add_ready(instance->debug_checker);
+
+	usb_log_info("Started UHCI driver.\n");
+	return EOK;
+#undef CHECK_RET_DEST_FUN_RETURN
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI hc hw resources.
+ *
+ * @param[in] instance UHCI structure to use.
+ * For magic values see UHCI Design Guide
+ */
+void uhci_hc_init_hw(uhci_hc_t *instance)
+{
+	assert(instance);
+	regs_t *registers = instance->registers;
+
+	/* Reset everything, who knows what touched it before us */
+	pio_write_16(&registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
+	async_usleep(10000); /* 10ms according to USB spec */
+	pio_write_16(&registers->usbcmd, 0);
+
+	/* Reset hc, all states and counters */
+	pio_write_16(&registers->usbcmd, UHCI_CMD_HCRESET);
+	do { async_usleep(10); }
+	while ((pio_read_16(&registers->usbcmd) & UHCI_CMD_HCRESET) != 0);
+
+	/* Set framelist pointer */
+	const uint32_t pa = addr_to_phys(instance->frame_list);
+	pio_write_32(&registers->flbaseadd, pa);
+
+	if (instance->hw_interrupts) {
+		/* Enable all interrupts, but resume interrupt */
+		pio_write_16(&instance->registers->usbintr,
+		    UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
+	}
+
+	uint16_t status = pio_read_16(&registers->usbcmd);
+	if (status != 0)
+		usb_log_warning("Previous command value: %x.\n", status);
+
+	/* Start the hc with large(64B) packet FSBR */
+	pio_write_16(&registers->usbcmd,
+	    UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE);
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI hc memory structures.
+ *
+ * @param[in] instance UHCI structure to use.
+ * @return Error code
+ * @note Should be called only once on any structure.
+ *
+ * Structures:
+ *  - interrupt code (I/O addressses are customized per instance)
+ *  - transfer lists (queue heads need to be accessible by the hw)
+ *  - frame list page (needs to be one UHCI hw accessible 4K page)
+ */
+int uhci_hc_init_mem_structures(uhci_hc_t *instance)
+{
+	assert(instance);
+#define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		if (instance->interrupt_code.cmds != NULL) \
+			free(instance->interrupt_code.cmds); \
+		return ret; \
+	} else (void) 0
+
+	/* Init interrupt code */
+	instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds));
+	int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK;
+	CHECK_RET_DEST_CMDS_RETURN(ret,
+	    "Failed to allocate interrupt cmds space.\n");
+
+	{
+		irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds;
+		memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds));
+		interrupt_commands[0].addr =
+		    (void*)&instance->registers->usbsts;
+		interrupt_commands[1].addr =
+		    (void*)&instance->registers->usbsts;
+		instance->interrupt_code.cmdcount =
+		    sizeof(uhci_cmds) / sizeof(irq_cmd_t);
+	}
+
+	/* Init transfer lists */
+	ret = uhci_hc_init_transfer_lists(instance);
+	CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n");
+	usb_log_debug("Initialized transfer lists.\n");
+
+	/* Init USB frame list page*/
+	instance->frame_list = get_page();
+	ret = instance ? EOK : ENOMEM;
+	CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
+	usb_log_debug("Initialized frame list.\n");
+
+	/* Set all frames to point to the first queue head */
+	const uint32_t queue =
+	  instance->transfers_interrupt.queue_head_pa
+	  | LINK_POINTER_QUEUE_HEAD_FLAG;
+
+	unsigned i = 0;
+	for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
+		instance->frame_list[i] = queue;
+	}
+
+	/* Init device keeper*/
+	device_keeper_init(&instance->device_manager);
+	usb_log_debug("Initialized device manager.\n");
+
+	return EOK;
+#undef CHECK_RET_DEST_CMDS_RETURN
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI hc transfer lists.
+ *
+ * @param[in] instance UHCI structure to use.
+ * @return Error code
+ * @note Should be called only once on any structure.
+ *
+ * Initializes transfer lists and sets them in one chain to support proper
+ * USB scheduling. Sets pointer table for quick access.
+ */
+int uhci_hc_init_transfer_lists(uhci_hc_t *instance)
+{
+	assert(instance);
+#define CHECK_RET_CLEAR_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		transfer_list_fini(&instance->transfers_bulk_full); \
+		transfer_list_fini(&instance->transfers_control_full); \
+		transfer_list_fini(&instance->transfers_control_slow); \
+		transfer_list_fini(&instance->transfers_interrupt); \
+		return ret; \
+	} else (void) 0
+
+	/* initialize TODO: check errors */
+	int ret;
+	ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
+	CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
+
+	ret = transfer_list_init(
+	    &instance->transfers_control_full, "CONTROL_FULL");
+	CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
+
+	ret = transfer_list_init(
+	    &instance->transfers_control_slow, "CONTROL_SLOW");
+	CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
+
+	ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
+	CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
+
+	transfer_list_set_next(&instance->transfers_control_full,
+		&instance->transfers_bulk_full);
+	transfer_list_set_next(&instance->transfers_control_slow,
+		&instance->transfers_control_full);
+	transfer_list_set_next(&instance->transfers_interrupt,
+		&instance->transfers_control_slow);
+
+	/*FSBR*/
+#ifdef FSBR
+	transfer_list_set_next(&instance->transfers_bulk_full,
+		&instance->transfers_control_full);
+#endif
+
+	/* Assign pointers to be used during scheduling */
+	instance->transfers[USB_SPEED_FULL][USB_TRANSFER_INTERRUPT] =
+	  &instance->transfers_interrupt;
+	instance->transfers[USB_SPEED_LOW][USB_TRANSFER_INTERRUPT] =
+	  &instance->transfers_interrupt;
+	instance->transfers[USB_SPEED_FULL][USB_TRANSFER_CONTROL] =
+	  &instance->transfers_control_full;
+	instance->transfers[USB_SPEED_LOW][USB_TRANSFER_CONTROL] =
+	  &instance->transfers_control_slow;
+	instance->transfers[USB_SPEED_FULL][USB_TRANSFER_BULK] =
+	  &instance->transfers_bulk_full;
+
+	return EOK;
+#undef CHECK_RET_CLEAR_RETURN
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule batch for execution.
+ *
+ * @param[in] instance UHCI structure to use.
+ * @param[in] batch Transfer batch to schedule.
+ * @return Error code
+ *
+ * Checks for bandwidth availability and appends the batch to the proper queue.
+ */
+int uhci_hc_schedule(uhci_hc_t *instance, batch_t *batch)
+{
+	assert(instance);
+	assert(batch);
+	const int low_speed = (batch->speed == USB_SPEED_LOW);
+	if (!allowed_usb_packet(
+	    low_speed, batch->transfer_type, batch->max_packet_size)) {
+		usb_log_warning(
+		    "Invalid USB packet specified %s SPEED %d %zu.\n",
+		    low_speed ? "LOW" : "FULL" , batch->transfer_type,
+		    batch->max_packet_size);
+		return ENOTSUP;
+	}
+	/* TODO: check available bandwidth here */
+
+	transfer_list_t *list =
+	    instance->transfers[batch->speed][batch->transfer_type];
+	assert(list);
+	transfer_list_add_batch(list, batch);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Take action based on the interrupt cause.
+ *
+ * @param[in] instance UHCI structure to use.
+ * @param[in] status Value of the status register at the time of interrupt.
+ *
+ * Interrupt might indicate:
+ * - transaction completed, either by triggering IOC, SPD, or an error
+ * - some kind of device error
+ * - resume from suspend state (not implemented)
+ */
+void uhci_hc_interrupt(uhci_hc_t *instance, uint16_t status)
+{
+	assert(instance);
+	/* TODO: Check interrupt cause here */
+	/* Lower 2 bits are transaction error and transaction complete */
+	if (status & 0x3) {
+		transfer_list_remove_finished(&instance->transfers_interrupt);
+		transfer_list_remove_finished(&instance->transfers_control_slow);
+		transfer_list_remove_finished(&instance->transfers_control_full);
+		transfer_list_remove_finished(&instance->transfers_bulk_full);
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Polling function, emulates interrupts.
+ *
+ * @param[in] arg UHCI hc structure to use.
+ * @return EOK (should never return)
+ */
+int uhci_hc_interrupt_emulator(void* arg)
+{
+	usb_log_debug("Started interrupt emulator.\n");
+	uhci_hc_t *instance = (uhci_hc_t*)arg;
+	assert(instance);
+
+	while (1) {
+		/* read and ack interrupts */
+		uint16_t status = pio_read_16(&instance->registers->usbsts);
+		pio_write_16(&instance->registers->usbsts, 0x1f);
+		if (status != 0)
+			usb_log_debug2("UHCI status: %x.\n", status);
+		uhci_hc_interrupt(instance, status);
+		async_usleep(UHCI_CLEANER_TIMEOUT);
+	}
+	return EOK;
+}
+/*---------------------------------------------------------------------------*/
+/** Debug function, checks consistency of memory structures.
+ *
+ * @param[in] arg UHCI structure to use.
+ * @return EOK (should never return)
+ */
+int uhci_hc_debug_checker(void *arg)
+{
+	uhci_hc_t *instance = (uhci_hc_t*)arg;
+	assert(instance);
+
+#define QH(queue) \
+	instance->transfers_##queue.queue_head
+
+	while (1) {
+		const uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
+		const uint16_t sts = pio_read_16(&instance->registers->usbsts);
+		const uint16_t intr =
+		    pio_read_16(&instance->registers->usbintr);
+
+		if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
+			usb_log_debug2("Command: %X Status: %X Intr: %x\n",
+			    cmd, sts, intr);
+		}
+
+		uintptr_t frame_list =
+		    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
+		if (frame_list != addr_to_phys(instance->frame_list)) {
+			usb_log_debug("Framelist address: %p vs. %p.\n",
+			    frame_list, addr_to_phys(instance->frame_list));
+		}
+
+		int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
+
+		uintptr_t expected_pa = instance->frame_list[frnum]
+		    & LINK_POINTER_ADDRESS_MASK;
+		uintptr_t real_pa = addr_to_phys(QH(interrupt));
+		if (expected_pa != real_pa) {
+			usb_log_debug("Interrupt QH: %p(frame: %d) vs. %p.\n",
+			    expected_pa, frnum, real_pa);
+		}
+
+		expected_pa = QH(interrupt)->next & LINK_POINTER_ADDRESS_MASK;
+		real_pa = addr_to_phys(QH(control_slow));
+		if (expected_pa != real_pa) {
+			usb_log_debug("Control Slow QH: %p vs. %p.\n",
+			    expected_pa, real_pa);
+		}
+
+		expected_pa = QH(control_slow)->next & LINK_POINTER_ADDRESS_MASK;
+		real_pa = addr_to_phys(QH(control_full));
+		if (expected_pa != real_pa) {
+			usb_log_debug("Control Full QH: %p vs. %p.\n",
+			    expected_pa, real_pa);
+		}
+
+		expected_pa = QH(control_full)->next & LINK_POINTER_ADDRESS_MASK;
+		real_pa = addr_to_phys(QH(bulk_full));
+		if (expected_pa != real_pa ) {
+			usb_log_debug("Bulk QH: %p vs. %p.\n",
+			    expected_pa, real_pa);
+		}
+		async_usleep(UHCI_DEBUGER_TIMEOUT);
+	}
+	return EOK;
+#undef QH
+}
+/*----------------------------------------------------------------------------*/
+/** Check transfer packets, for USB validity
+ *
+ * @param[in] low_speed Transfer speed.
+ * @param[in] transfer Transer type
+ * @param[in] size Maximum size of used packets
+ * @return True if transaction is allowed by USB specs, false otherwise
+ */
+bool allowed_usb_packet(
+    bool low_speed, usb_transfer_type_t transfer, size_t size)
+{
+	/* see USB specification chapter 5.5-5.8 for magic numbers used here */
+	switch(transfer)
+	{
+	case USB_TRANSFER_ISOCHRONOUS:
+		return (!low_speed && size < 1024);
+	case USB_TRANSFER_INTERRUPT:
+		return size <= (low_speed ? 8 : 64);
+	case USB_TRANSFER_CONTROL: /* device specifies its own max size */
+		return (size <= (low_speed ? 8 : 64));
+	case USB_TRANSFER_BULK: /* device specifies its own max size */
+		return (!low_speed && size <= 64);
+	}
+	return false;
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci-hcd/uhci_hc.h
===================================================================
--- uspace/drv/uhci-hcd/uhci_hc.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/uhci-hcd/uhci_hc.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,129 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI host controller driver structure
+ */
+#ifndef DRV_UHCI_UHCI_HC_H
+#define DRV_UHCI_UHCI_HC_H
+
+#include <fibril.h>
+#include <fibril_synch.h>
+#include <adt/list.h>
+#include <ddi.h>
+
+#include <usbhc_iface.h>
+
+#include "batch.h"
+#include "transfer_list.h"
+#include "utils/device_keeper.h"
+
+typedef struct uhci_regs {
+	uint16_t usbcmd;
+#define UHCI_CMD_MAX_PACKET (1 << 7)
+#define UHCI_CMD_CONFIGURE  (1 << 6)
+#define UHCI_CMD_DEBUG  (1 << 5)
+#define UHCI_CMD_FORCE_GLOBAL_RESUME  (1 << 4)
+#define UHCI_CMD_FORCE_GLOBAL_SUSPEND  (1 << 3)
+#define UHCI_CMD_GLOBAL_RESET  (1 << 2)
+#define UHCI_CMD_HCRESET  (1 << 1)
+#define UHCI_CMD_RUN_STOP  (1 << 0)
+
+	uint16_t usbsts;
+#define UHCI_STATUS_HALTED (1 << 5)
+#define UHCI_STATUS_PROCESS_ERROR (1 << 4)
+#define UHCI_STATUS_SYSTEM_ERROR (1 << 3)
+#define UHCI_STATUS_RESUME (1 << 2)
+#define UHCI_STATUS_ERROR_INTERRUPT (1 << 1)
+#define UHCI_STATUS_INTERRUPT (1 << 0)
+
+	uint16_t usbintr;
+#define UHCI_INTR_SHORT_PACKET (1 << 3)
+#define UHCI_INTR_COMPLETE (1 << 2)
+#define UHCI_INTR_RESUME (1 << 1)
+#define UHCI_INTR_CRC (1 << 0)
+
+	uint16_t frnum;
+	uint32_t flbaseadd;
+	uint8_t sofmod;
+} regs_t;
+
+#define UHCI_FRAME_LIST_COUNT 1024
+#define UHCI_CLEANER_TIMEOUT 10000
+#define UHCI_DEBUGER_TIMEOUT 5000000
+
+typedef struct uhci_hc {
+	device_keeper_t device_manager;
+
+	regs_t *registers;
+
+	link_pointer_t *frame_list;
+
+	transfer_list_t transfers_bulk_full;
+	transfer_list_t transfers_control_full;
+	transfer_list_t transfers_control_slow;
+	transfer_list_t transfers_interrupt;
+
+	transfer_list_t *transfers[2][4];
+
+	irq_code_t interrupt_code;
+
+	fid_t cleaner;
+	fid_t debug_checker;
+	bool hw_interrupts;
+
+	ddf_fun_t *ddf_instance;
+} uhci_hc_t;
+
+int uhci_hc_init(uhci_hc_t *instance, ddf_fun_t *fun,
+    void *regs, size_t reg_size, bool interupts);
+
+int uhci_hc_schedule(uhci_hc_t *instance, batch_t *batch);
+
+void uhci_hc_interrupt(uhci_hc_t *instance, uint16_t status);
+
+/** Safely dispose host controller internal structures
+ *
+ * @param[in] instance Host controller structure to use.
+ */
+static inline void uhci_hc_fini(uhci_hc_t *instance) { /* TODO: implement*/ };
+
+/** Get and cast pointer to the driver data
+ *
+ * @param[in] fun DDF function pointer
+ * @return cast pointer to driver_data
+ */
+static inline uhci_hc_t * fun_to_uhci_hc(ddf_fun_t *fun)
+	{ return (uhci_hc_t*)fun->driver_data; }
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci-hcd/uhci_rh.c
===================================================================
--- uspace/drv/uhci-hcd/uhci_rh.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/uhci-hcd/uhci_rh.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,83 @@
+/*
+ * 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 drvusbuhci
+ * @{
+ */
+/** @file
+ * @brief UHCI driver
+ */
+#include <assert.h>
+#include <errno.h>
+#include <str_error.h>
+#include <stdio.h>
+
+#include <usb/debug.h>
+
+#include "uhci_rh.h"
+#include "uhci_hc.h"
+
+/** Root hub initialization
+ * @param[in] instance RH structure to initialize
+ * @param[in] fun DDF function representing UHCI root hub
+ * @param[in] reg_addr Address of root hub status and control registers.
+ * @param[in] reg_size Size of accessible address space.
+ * @return Error code.
+ */
+int uhci_rh_init(
+    uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size)
+{
+	assert(fun);
+
+	char *match_str = NULL;
+	int ret = asprintf(&match_str, "usb&uhci&root-hub");
+	if (ret < 0) {
+		usb_log_error("Failed to create root hub match string.\n");
+		return ENOMEM;
+	}
+
+	ret = ddf_fun_add_match_id(fun, match_str, 100);
+	if (ret != EOK) {
+		usb_log_error("Failed(%d) to add root hub match id: %s\n",
+		    ret, str_error(ret));
+		return ret;
+	}
+
+	hw_resource_list_t *resource_list = &instance->resource_list;
+	resource_list->count = 1;
+	resource_list->resources = &instance->io_regs;
+	assert(resource_list->resources);
+	instance->io_regs.type = IO_RANGE;
+	instance->io_regs.res.io_range.address = reg_addr;
+	instance->io_regs.res.io_range.size = reg_size;
+	instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN;
+
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci-hcd/uhci_rh.h
===================================================================
--- uspace/drv/uhci-hcd/uhci_rh.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/uhci-hcd/uhci_rh.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,52 @@
+/*
+ * 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 drvusbuhci
+ * @{
+ */
+/** @file
+ * @brief UHCI driver
+ */
+#ifndef DRV_UHCI_UHCI_RH_H
+#define DRV_UHCI_UHCI_RH_H
+
+#include <ddf/driver.h>
+#include <ops/hw_res.h>
+
+typedef struct uhci_rh {
+	hw_resource_list_t resource_list;
+	hw_resource_t io_regs;
+} uhci_rh_t;
+
+int uhci_rh_init(
+    uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci-hcd/uhci_struct/link_pointer.h
===================================================================
--- uspace/drv/uhci-hcd/uhci_struct/link_pointer.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/uhci_struct/link_pointer.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
@@ -46,4 +46,7 @@
 #define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */
 
+#define LINK_POINTER_QH(address) \
+	((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_QUEUE_HEAD_FLAG)
+
 #endif
 /**
Index: uspace/drv/uhci-hcd/uhci_struct/queue_head.h
===================================================================
--- uspace/drv/uhci-hcd/uhci_struct/queue_head.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/uhci_struct/queue_head.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -1,3 +1,2 @@
-
 /*
  * Copyright (c) 2010 Jan Vesely
@@ -27,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drv usbuhcihc
  * @{
  */
@@ -43,49 +42,76 @@
 
 typedef struct queue_head {
-	volatile link_pointer_t next_queue;
+	volatile link_pointer_t next;
 	volatile link_pointer_t element;
-} __attribute__((packed)) queue_head_t;
-
-static inline void queue_head_init(queue_head_t *instance)
+} __attribute__((packed)) qh_t;
+/*----------------------------------------------------------------------------*/
+/** Initialize queue head structure
+ *
+ * @param[in] instance qh_t structure to initialize.
+ *
+ * Sets both pointer to terminal NULL.
+ */
+static inline void qh_init(qh_t *instance)
 {
 	assert(instance);
 
 	instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
-	instance->next_queue = 0 | LINK_POINTER_TERMINATE_FLAG;
+	instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
 }
-
-static inline void queue_head_append_qh(queue_head_t *instance, uint32_t pa)
+/*----------------------------------------------------------------------------*/
+/** Set queue head next pointer
+ *
+ * @param[in] instance qh_t structure to use.
+ * @param[in] pa Physical address of the next queue head.
+ *
+ * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal
+ * NULL.
+ */
+static inline void qh_set_next_qh(qh_t *instance, uint32_t pa)
 {
-	if (pa) {
-		instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK)
+	/* Address is valid and not terminal */
+	if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
+		instance->next = (pa & LINK_POINTER_ADDRESS_MASK)
 		    | LINK_POINTER_QUEUE_HEAD_FLAG;
+	} else {
+		instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
 	}
 }
-
-static inline void queue_head_element_qh(queue_head_t *instance, uint32_t pa)
+/*----------------------------------------------------------------------------*/
+/** Set queue head element pointer
+ *
+ * @param[in] instance qh_t structure to initialize.
+ * @param[in] pa Physical address of the next queue head.
+ *
+ * Adds proper flag. If the pointer is NULL or terminal, sets element
+ * to terminal NULL.
+ */
+static inline void qh_set_element_qh(qh_t *instance, uint32_t pa)
 {
-	if (pa) {
-		instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK)
+	/* Address is valid and not terminal */
+	if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
+		instance->element = (pa & LINK_POINTER_ADDRESS_MASK)
 		    | LINK_POINTER_QUEUE_HEAD_FLAG;
+	} else {
+		instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
 	}
 }
-
-static inline void queue_head_element_td(queue_head_t *instance, uint32_t pa)
+/*----------------------------------------------------------------------------*/
+/** Set queue head element pointer
+ *
+ * @param[in] instance qh_t structure to initialize.
+ * @param[in] pa Physical address of the TD structure.
+ *
+ * Adds proper flag. If the pointer is NULL or terminal, sets element
+ * to terminal NULL.
+ */
+static inline void qh_set_element_td(qh_t *instance, uint32_t pa)
 {
-	if (pa) {
+	if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
 		instance->element = (pa & LINK_POINTER_ADDRESS_MASK);
+	} else {
+		instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
 	}
 }
-
-static inline queue_head_t * queue_head_get() {
-	queue_head_t *ret = malloc32(sizeof(queue_head_t));
-	if (ret)
-		queue_head_init(ret);
-	return ret;
-}
-
-static inline void queue_head_dispose(queue_head_t *head)
-	{ free32(head); }
-
 
 #endif
Index: uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
@@ -38,9 +38,34 @@
 #include "utils/malloc32.h"
 
-void transfer_descriptor_init(transfer_descriptor_t *instance,
-    int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,
-    usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next)
+/** Initialize Transfer Descriptor
+ *
+ * @param[in] instance Memory place to initialize.
+ * @param[in] err_count Number of retries hc should attempt.
+ * @param[in] size Size of data source.
+ * @param[in] toggle Value of toggle bit.
+ * @param[in] iso True if TD represents Isochronous transfer.
+ * @param[in] low_speed Target device's speed.
+ * @param[in] target Address and endpoint receiving the transfer.
+ * @param[in] pid Packet identification (SETUP, IN or OUT).
+ * @param[in] buffer Source of data.
+ * @param[in] next Net TD in transaction.
+ * @return Error code.
+ *
+ * Uses a mix of supplied and default values.
+ * Implicit values:
+ *  - all TDs have vertical flag set (makes transfers to endpoints atomic)
+ *  - in the error field only active it is set
+ *  - if the packet uses PID_IN and is not isochronous SPD is set
+ *
+ * Dumps 8 bytes of buffer if PID_SETUP is used.
+ */
+void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso,
+    bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer,
+    td_t *next)
 {
 	assert(instance);
+	assert(size < 1024);
+	assert((pid == USB_PID_SETUP) || (pid == USB_PID_IN)
+	    || (pid == USB_PID_OUT));
 
 	instance->next = 0
@@ -49,15 +74,19 @@
 
 	instance->status = 0
-	  | ((error_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
-		| (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
-	  | TD_STATUS_ERROR_ACTIVE;
+	    | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
+	    | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
+	    | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0)
+	    | TD_STATUS_ERROR_ACTIVE;
 
-	assert(size < 1024);
+	if (pid == USB_PID_IN && !iso) {
+		instance->status |= TD_STATUS_SPD_FLAG;
+	}
+
 	instance->device = 0
-		| (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
-		| (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
-		| ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
-		| ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
-		| ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
+	    | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
+	    | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
+	    | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
+	    | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
+	    | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
 
 	instance->buffer_ptr = 0;
@@ -67,10 +96,20 @@
 	}
 
-	usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n",
-		instance->next, instance->status, instance->device,
-	  instance->buffer_ptr, buffer);
+	usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n",
+	    instance, instance->next, instance->status, instance->device,
+	    instance->buffer_ptr, buffer);
+	td_print_status(instance);
+	if (pid == USB_PID_SETUP) {
+		usb_log_debug("SETUP BUFFER: %s\n",
+		    usb_debug_str_buffer(buffer, 8, 8));
+	}
 }
 /*----------------------------------------------------------------------------*/
-int transfer_descriptor_status(transfer_descriptor_t *instance)
+/** Convert TD status into standard error code
+ *
+ * @param[in] instance TD structure to use.
+ * @return Error code.
+ */
+int td_status(td_t *instance)
 {
 	assert(instance);
@@ -96,4 +135,31 @@
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
+/** Print values in status field (dw1) in a human readable way.
+ *
+ * @param[in] instance TD structure to use.
+ */
+void td_print_status(td_t *instance)
+{
+	assert(instance);
+	const uint32_t s = instance->status;
+	usb_log_debug2("TD(%p) status(%#x):%s %d,%s%s%s%s%s%s%s%s%s%s%s %d.\n",
+	    instance, instance->status,
+	    (s & TD_STATUS_SPD_FLAG) ? " SPD," : "",
+	    (s >> TD_STATUS_ERROR_COUNT_POS) & TD_STATUS_ERROR_COUNT_MASK,
+	    (s & TD_STATUS_LOW_SPEED_FLAG) ? " LOW SPEED," : "",
+	    (s & TD_STATUS_ISOCHRONOUS_FLAG) ? " ISOCHRONOUS," : "",
+	    (s & TD_STATUS_IOC_FLAG) ? " IOC," : "",
+	    (s & TD_STATUS_ERROR_ACTIVE) ? " ACTIVE," : "",
+	    (s & TD_STATUS_ERROR_STALLED) ? " STALLED," : "",
+	    (s & TD_STATUS_ERROR_BUFFER) ? " BUFFER," : "",
+	    (s & TD_STATUS_ERROR_BABBLE) ? " BABBLE," : "",
+	    (s & TD_STATUS_ERROR_NAK) ? " NAK," : "",
+	    (s & TD_STATUS_ERROR_CRC) ? " CRC/TIMEOUT," : "",
+	    (s & TD_STATUS_ERROR_BIT_STUFF) ? " BIT_STUFF," : "",
+	    (s & TD_STATUS_ERROR_RESERVED) ? " RESERVED," : "",
+	    (s >> TD_STATUS_ACTLEN_POS) & TD_STATUS_ACTLEN_MASK
+	);
+}
 /**
  * @}
Index: uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jan Vesely
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcihc
  * @{
  */
@@ -45,13 +45,11 @@
 
 	volatile uint32_t status;
-
 #define TD_STATUS_RESERVED_MASK 0xc000f800
 #define TD_STATUS_SPD_FLAG ( 1 << 29 )
 #define TD_STATUS_ERROR_COUNT_POS ( 27 )
 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 )
-#define TD_STATUS_ERROR_COUNT_DEFAULT 3
 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 )
 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 )
-#define TD_STATUS_COMPLETE_INTERRUPT_FLAG ( 1 << 24 )
+#define TD_STATUS_IOC_FLAG ( 1 << 24 )
 
 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23 )
@@ -70,5 +68,4 @@
 
 	volatile uint32_t device;
-
 #define TD_DEVICE_MAXLEN_POS 21
 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff )
@@ -85,30 +82,78 @@
 
 	/* there is 16 bytes of data available here, according to UHCI
-	 * Design guide, according to linux kernel the hardware does not care
-	 * we don't use it anyway
+	 * Design guide, according to linux kernel the hardware does not care,
+	 * it just needs to be aligned, we don't use it anyway
 	 */
-} __attribute__((packed)) transfer_descriptor_t;
+} __attribute__((packed)) td_t;
 
 
-void transfer_descriptor_init(transfer_descriptor_t *instance,
-    int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,
-    usb_target_t target, int pid, void *buffer, transfer_descriptor_t * next);
+void td_init(td_t *instance, int error_count, size_t size, bool toggle,
+    bool iso, bool low_speed, usb_target_t target, usb_packet_id pid,
+    void *buffer, td_t *next);
 
-int transfer_descriptor_status(transfer_descriptor_t *instance);
+int td_status(td_t *instance);
 
-static inline size_t transfer_descriptor_actual_size(
-    transfer_descriptor_t *instance)
+void td_print_status(td_t *instance);
+/*----------------------------------------------------------------------------*/
+/** Helper function for parsing actual size out of TD.
+ *
+ * @param[in] instance TD structure to use.
+ * @return Parsed actual size.
+ */
+static inline size_t td_act_size(td_t *instance)
 {
 	assert(instance);
+	const uint32_t s = instance->status;
+	return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
+}
+/*----------------------------------------------------------------------------*/
+/** Check whether less than max data were recieved and packet is marked as SPD.
+ *
+ * @param[in] instance TD structure to use.
+ * @return True if packet is short (less than max bytes and SPD set), false
+ *     otherwise.
+ */
+static inline bool td_is_short(td_t *instance)
+{
+	const size_t act_size = td_act_size(instance);
+	const size_t max_size =
+	    ((instance->device >> TD_DEVICE_MAXLEN_POS) + 1)
+	    & TD_DEVICE_MAXLEN_MASK;
 	return
-	    ((instance->status >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
+	    (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size;
 }
-
-static inline bool transfer_descriptor_is_active(
-    transfer_descriptor_t *instance)
+/*----------------------------------------------------------------------------*/
+/** Helper function for parsing value of toggle bit.
+ *
+ * @param[in] instance TD structure to use.
+ * @return Toggle bit value.
+ */
+static inline int td_toggle(td_t *instance)
+{
+	assert(instance);
+	return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0;
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function for parsing value of active bit
+ *
+ * @param[in] instance TD structure to use.
+ * @return Active bit value.
+ */
+static inline bool td_is_active(td_t *instance)
 {
 	assert(instance);
 	return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0;
 }
+/*----------------------------------------------------------------------------*/
+/** Helper function for setting IOC bit.
+ *
+ * @param[in] instance TD structure to use.
+ */
+static inline void td_set_ioc(td_t *instance)
+{
+	assert(instance);
+	instance->status |= TD_STATUS_IOC_FLAG;
+}
+/*----------------------------------------------------------------------------*/
 #endif
 /**
Index: uspace/drv/uhci-hcd/utils/device_keeper.c
===================================================================
--- uspace/drv/uhci-hcd/utils/device_keeper.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/utils/device_keeper.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup drvusbuhci
+/** @addtogroup drvusbuhcihc
  * @{
  */
@@ -35,8 +35,15 @@
 #include <assert.h>
 #include <errno.h>
+#include <usb/debug.h>
 
 #include "device_keeper.h"
 
 /*----------------------------------------------------------------------------*/
+/** Initialize device keeper structure.
+ *
+ * @param[in] instance Memory place to initialize.
+ *
+ * Set all values to false/0.
+ */
 void device_keeper_init(device_keeper_t *instance)
 {
@@ -49,9 +56,14 @@
 		instance->devices[i].occupied = false;
 		instance->devices[i].handle = 0;
-	}
-}
-/*----------------------------------------------------------------------------*/
-void device_keeper_reserve_default(
-    device_keeper_t *instance, usb_speed_t speed)
+		instance->devices[i].toggle_status = 0;
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Attempt to obtain address 0, blocks.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] speed Speed of the device requesting default address.
+ */
+void device_keeper_reserve_default(device_keeper_t *instance, usb_speed_t speed)
 {
 	assert(instance);
@@ -66,4 +78,9 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Attempt to obtain address 0, blocks.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] speed Speed of the device requesting default address.
+ */
 void device_keeper_release_default(device_keeper_t *instance)
 {
@@ -75,4 +92,107 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Check setup packet data for signs of toggle reset.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] target Device to receive setup packet.
+ * @param[in] data Setup packet data.
+ *
+ * Really ugly one.
+ */
+void device_keeper_reset_if_need(
+    device_keeper_t *instance, usb_target_t target, const unsigned char *data)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	if (target.endpoint > 15 || target.endpoint < 0
+	    || target.address >= USB_ADDRESS_COUNT || target.address < 0
+	    || !instance->devices[target.address].occupied) {
+		fibril_mutex_unlock(&instance->guard);
+		usb_log_error("Invalid data when checking for toggle reset.\n");
+		return;
+	}
+
+	switch (data[1])
+	{
+	case 0x01: /*clear feature*/
+		/* recipient is endpoint, value is zero (ENDPOINT_STALL) */
+		if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
+			/* endpoint number is < 16, thus first byte is enough */
+			instance->devices[target.address].toggle_status &=
+			    ~(1 << data[4]);
+		}
+	break;
+
+	case 0x9: /* set configuration */
+	case 0x11: /* set interface */
+		/* target must be device */
+		if ((data[0] & 0xf) == 0) {
+			instance->devices[target.address].toggle_status = 0;
+		}
+	break;
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Get current value of endpoint toggle.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] target Device and endpoint used.
+ * @return Error code
+ */
+int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target)
+{
+	assert(instance);
+	int ret;
+	fibril_mutex_lock(&instance->guard);
+	if (target.endpoint > 15 || target.endpoint < 0
+	    || target.address >= USB_ADDRESS_COUNT || target.address < 0
+	    || !instance->devices[target.address].occupied) {
+		usb_log_error("Invalid data when asking for toggle value.\n");
+		ret = EINVAL;
+	} else {
+		ret = (instance->devices[target.address].toggle_status
+		        >> target.endpoint) & 1;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Set current value of endpoint toggle.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] target Device and endpoint used.
+ * @param[in] toggle Toggle value.
+ * @return Error code.
+ */
+int device_keeper_set_toggle(
+    device_keeper_t *instance, usb_target_t target, bool toggle)
+{
+	assert(instance);
+	int ret;
+	fibril_mutex_lock(&instance->guard);
+	if (target.endpoint > 15 || target.endpoint < 0
+	    || target.address >= USB_ADDRESS_COUNT || target.address < 0
+	    || !instance->devices[target.address].occupied) {
+		usb_log_error("Invalid data when setting toggle value.\n");
+		ret = EINVAL;
+	} else {
+		if (toggle) {
+			instance->devices[target.address].toggle_status |= (1 << target.endpoint);
+		} else {
+			instance->devices[target.address].toggle_status &= ~(1 << target.endpoint);
+		}
+		ret = EOK;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Get a free USB address
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] speed Speed of the device requiring address.
+ * @return Free address, or error code.
+ */
 usb_address_t device_keeper_request(
     device_keeper_t *instance, usb_speed_t speed)
@@ -96,4 +216,5 @@
 	instance->devices[new_address].occupied = true;
 	instance->devices[new_address].speed = speed;
+	instance->devices[new_address].toggle_status = 0;
 	instance->last_address = new_address;
 	fibril_mutex_unlock(&instance->guard);
@@ -101,4 +222,10 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Bind USB address to devman handle.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] address Device address
+ * @param[in] handle Devman handle of the device.
+ */
 void device_keeper_bind(
     device_keeper_t *instance, usb_address_t address, devman_handle_t handle)
@@ -113,4 +240,9 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Release used USB address.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] address Device address
+ */
 void device_keeper_release(device_keeper_t *instance, usb_address_t address)
 {
@@ -125,4 +257,10 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Find USB address associated with the device
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] handle Devman handle of the device seeking its address.
+ * @return USB Address, or error code.
+ */
 usb_address_t device_keeper_find(
     device_keeper_t *instance, devman_handle_t handle)
@@ -142,4 +280,10 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Get speed associated with the address
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] address Address of the device.
+ * @return USB speed.
+ */
 usb_speed_t device_keeper_speed(
     device_keeper_t *instance, usb_address_t address)
Index: uspace/drv/uhci-hcd/utils/device_keeper.h
===================================================================
--- uspace/drv/uhci-hcd/utils/device_keeper.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/utils/device_keeper.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup drvusbuhci
+/** @addtogroup drvusbuhcihc
  * @{
  */
@@ -44,4 +44,5 @@
 	usb_speed_t speed;
 	bool occupied;
+	uint16_t toggle_status;
 	devman_handle_t handle;
 };
@@ -55,13 +56,26 @@
 
 void device_keeper_init(device_keeper_t *instance);
+
 void device_keeper_reserve_default(
     device_keeper_t *instance, usb_speed_t speed);
+
 void device_keeper_release_default(device_keeper_t *instance);
+
+void device_keeper_reset_if_need(
+    device_keeper_t *instance, usb_target_t target, const unsigned char *setup_data);
+
+int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target);
+
+int device_keeper_set_toggle(
+    device_keeper_t *instance, usb_target_t target, bool toggle);
 
 usb_address_t device_keeper_request(
     device_keeper_t *instance, usb_speed_t speed);
+
 void device_keeper_bind(
     device_keeper_t *instance, usb_address_t address, devman_handle_t handle);
+
 void device_keeper_release(device_keeper_t *instance, usb_address_t address);
+
 usb_address_t device_keeper_find(
     device_keeper_t *instance, devman_handle_t handle);
Index: uspace/drv/uhci-hcd/utils/malloc32.h
===================================================================
--- uspace/drv/uhci-hcd/utils/malloc32.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-hcd/utils/malloc32.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -35,6 +35,4 @@
 #define DRV_UHCI_TRANSLATOR_H
 
-#include <usb/usbmem.h>
-
 #include <assert.h>
 #include <malloc.h>
@@ -45,4 +43,9 @@
 #define UHCI_REQUIRED_PAGE_SIZE 4096
 
+/** Get physical address translation
+ *
+ * @param[in] addr Virtual address to translate
+ * @return Physical address if exists, NULL otherwise.
+ */
 static inline uintptr_t addr_to_phys(void *addr)
 {
@@ -50,27 +53,41 @@
 	int ret = as_get_physical_mapping(addr, &result);
 
-	assert(ret == 0);
+	if (ret != EOK)
+		return 0;
 	return (result | ((uintptr_t)addr & 0xfff));
 }
-
+/*----------------------------------------------------------------------------*/
+/** Physical mallocator simulator
+ *
+ * @param[in] size Size of the required memory space
+ * @return Address of the alligned and big enough memory place, NULL on failure.
+ */
 static inline void * malloc32(size_t size)
 	{ return memalign(UHCI_STRCUTURES_ALIGNMENT, size); }
-
-static inline void * get_page()
+/*----------------------------------------------------------------------------*/
+/** Physical mallocator simulator
+ *
+ * @param[in] addr Address of the place allocated by malloc32
+ */
+static inline void free32(void *addr)
+	{ if (addr) free(addr); }
+/*----------------------------------------------------------------------------*/
+/** Create 4KB page mapping
+ *
+ * @return Address of the mapped page, NULL on failure.
+ */
+static inline void * get_page(void)
 {
 	void * free_address = as_get_mappable_page(UHCI_REQUIRED_PAGE_SIZE);
 	assert(free_address);
 	if (free_address == 0)
-		return 0;
+		return NULL;
 	void* ret =
 	  as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE,
 		  AS_AREA_READ | AS_AREA_WRITE);
 	if (ret != free_address)
-		return 0;
+		return NULL;
 	return ret;
 }
-
-static inline void free32(void *addr)
-	{ if (addr) free(addr); }
 
 #endif
Index: uspace/drv/uhci-rhd/Makefile
===================================================================
--- uspace/drv/uhci-rhd/Makefile	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-rhd/Makefile	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -35,5 +35,4 @@
 	main.c \
 	port.c \
-	port_status.c \
 	root_hub.c
 
Index: uspace/drv/uhci-rhd/main.c
===================================================================
--- uspace/drv/uhci-rhd/main.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-rhd/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,18 +26,16 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcirh
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI root hub initialization routines
  */
 #include <ddf/driver.h>
 #include <devman.h>
 #include <device/hw_res.h>
+#include <errno.h>
 #include <usb_iface.h>
 #include <usb/ddfiface.h>
-
-#include <errno.h>
-
 #include <usb/debug.h>
 
@@ -47,5 +45,6 @@
 static int hc_get_my_registers(ddf_dev_t *dev,
     uintptr_t *io_reg_address, size_t *io_reg_size);
-
+#if 0
+/*----------------------------------------------------------------------------*/
 static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
 {
@@ -58,14 +57,20 @@
 	return EOK;
 }
-
+/*----------------------------------------------------------------------------*/
 static usb_iface_t uhci_rh_usb_iface = {
 	.get_hc_handle = usb_iface_get_hc_handle,
 	.get_address = usb_iface_get_address_hub_impl
 };
-
+/*----------------------------------------------------------------------------*/
 static ddf_dev_ops_t uhci_rh_ops = {
 	.interfaces[USB_DEV_IFACE] = &uhci_rh_usb_iface,
 };
-
+#endif
+/*----------------------------------------------------------------------------*/
+/** Initialize a new ddf driver instance of UHCI root hub.
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
 static int uhci_rh_add_device(ddf_dev_t *device)
 {
@@ -76,20 +81,20 @@
 
 	//device->ops = &uhci_rh_ops;
-	(void) uhci_rh_ops;
-
-	uhci_root_hub_t *rh = malloc(sizeof(uhci_root_hub_t));
-	if (!rh) {
-		usb_log_error("Failed to allocate memory for driver instance.\n");
-		return ENOMEM;
-	}
-
 	uintptr_t io_regs = 0;
 	size_t io_size = 0;
 
 	int ret = hc_get_my_registers(device, &io_regs, &io_size);
-	assert(ret == EOK);
+	if (ret != EOK) {
+		usb_log_error("Failed(%d) to get registers from parent hc.",
+		    ret);
+	}
+	usb_log_info("I/O regs at %#X (size %zu).\n", io_regs, io_size);
 
-	/* TODO: verify values from hc */
-	usb_log_info("I/O regs at 0x%X (size %zu).\n", io_regs, io_size);
+	uhci_root_hub_t *rh = malloc(sizeof(uhci_root_hub_t));
+	if (!rh) {
+		usb_log_error("Failed to allocate driver instance.\n");
+		return ENOMEM;
+	}
+
 	ret = uhci_root_hub_init(rh, (void*)io_regs, io_size, device);
 	if (ret != EOK) {
@@ -104,9 +109,9 @@
 	return EOK;
 }
-
+/*----------------------------------------------------------------------------*/
 static driver_ops_t uhci_rh_driver_ops = {
 	.add_device = uhci_rh_add_device,
 };
-
+/*----------------------------------------------------------------------------*/
 static driver_t uhci_rh_driver = {
 	.name = NAME,
@@ -114,4 +119,12 @@
 };
 /*----------------------------------------------------------------------------*/
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
 int main(int argc, char *argv[])
 {
@@ -120,6 +133,13 @@
 }
 /*----------------------------------------------------------------------------*/
-int hc_get_my_registers(ddf_dev_t *dev,
-    uintptr_t *io_reg_address, size_t *io_reg_size)
+/** Get address of I/O registers.
+ *
+ * @param[in] dev Device asking for the addresses.
+ * @param[out] io_reg_address Base address of the memory range.
+ * @param[out] io_reg_size Size of the memory range.
+ * @return Error code.
+ */
+int hc_get_my_registers(
+    ddf_dev_t *dev, uintptr_t *io_reg_address, size_t *io_reg_size)
 {
 	assert(dev != NULL);
@@ -146,13 +166,13 @@
 	for (i = 0; i < hw_resources.count; i++) {
 		hw_resource_t *res = &hw_resources.resources[i];
-		switch (res->type) {
-			case IO_RANGE:
-				io_address = (uintptr_t)
-				    res->res.io_range.address;
-				io_size = res->res.io_range.size;
-				io_found = true;
-				break;
-			default:
-				break;
+		switch (res->type)
+		{
+		case IO_RANGE:
+			io_address = (uintptr_t) res->res.io_range.address;
+			io_size = res->res.io_range.size;
+			io_found = true;
+
+		default:
+			break;
 		}
 	}
@@ -170,7 +190,7 @@
 	}
 	rc = EOK;
+
 leave:
 	async_hangup(parent_phone);
-
 	return rc;
 }
Index: uspace/drv/uhci-rhd/port.c
===================================================================
--- uspace/drv/uhci-rhd/port.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-rhd/port.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,10 +26,11 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcirh
  * @{
  */
 /** @file
- * @brief UHCI driver
- */
+ * @brief UHCI root hub port routines
+ */
+#include <libarch/ddi.h> /* pio_read and pio_write */
 #include <errno.h>
 #include <str_error.h>
@@ -37,24 +38,62 @@
 
 #include <usb/usb.h>    /* usb_address_t */
-#include <usb/usbdevice.h>
 #include <usb/hub.h>
-#include <usb/request.h>
 #include <usb/debug.h>
-#include <usb/recognise.h>
 
 #include "port.h"
-#include "port_status.h"
-
-static int uhci_port_new_device(uhci_port_t *port, uint16_t status);
+
+static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed);
 static int uhci_port_remove_device(uhci_port_t *port);
 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
 static int uhci_port_check(void *port);
-static int new_device_enable_port(int portno, void *arg);
-
-int uhci_port_init(
-  uhci_port_t *port, port_status_t *address, unsigned number,
-  unsigned usec, ddf_dev_t *rh)
-{
-	assert(port);
+static int uhci_port_reset_enable(int portno, void *arg);
+static void uhci_port_print_status(
+    uhci_port_t *port, const port_status_t value);
+
+/** Register reading helper function.
+ *
+ * @param[in] port Structure to use.
+ * @return Error code. (Always EOK)
+ */
+static inline port_status_t uhci_port_read_status(uhci_port_t *port)
+{
+	assert(port);
+	return pio_read_16(port->address);
+}
+/*----------------------------------------------------------------------------*/
+/** Register writing helper function.
+ *
+ * @param[in] port Structure to use.
+ * @param[in] value New register value.
+ * @return Error code. (Always EOK)
+ */
+static inline void uhci_port_write_status(
+    uhci_port_t *port, port_status_t value)
+{
+	assert(port);
+	pio_write_16(port->address, value);
+}
+
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI root hub port instance.
+ *
+ * @param[in] port Memory structure to use.
+ * @param[in] addr Address of I/O register.
+ * @param[in] number Port number.
+ * @param[in] usec Polling interval.
+ * @param[in] rh Pointer to ddf instance fo the root hub driver.
+ * @return Error code.
+ *
+ * Creates and starts the polling fibril.
+ */
+int uhci_port_init(uhci_port_t *port,
+    port_status_t *address, unsigned number, unsigned usec, ddf_dev_t *rh)
+{
+	assert(port);
+	asprintf(&port->id_string, "Port (%p - %d)", port, number);
+	if (port->id_string == NULL) {
+		return ENOMEM;
+	}
+
 	port->address = address;
 	port->number = number;
@@ -62,4 +101,5 @@
 	port->attached_device = 0;
 	port->rh = rh;
+
 	int rc = usb_hc_connection_initialize_from_device(
 	    &port->hc_connection, rh);
@@ -71,86 +111,92 @@
 	port->checker = fibril_create(uhci_port_check, port);
 	if (port->checker == 0) {
-		usb_log_error("Port(%p - %d): failed to launch root hub fibril.",
-		    port->address, port->number);
+		usb_log_error("%s: failed to create polling fibril.",
+		    port->id_string);
 		return ENOMEM;
 	}
+
 	fibril_add_ready(port->checker);
-	usb_log_debug("Port(%p - %d): Added fibril. %x\n",
-	    port->address, port->number, port->checker);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
+	usb_log_debug("%s: Started polling fibril(%x).\n",
+	    port->id_string, port->checker);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Cleanup UHCI root hub port instance.
+ *
+ * @param[in] port Memory structure to use.
+ *
+ * Stops the polling fibril.
+ */
 void uhci_port_fini(uhci_port_t *port)
 {
-// TODO: destroy fibril
-// TODO: hangup phone
-//	fibril_teardown(port->checker);
+	assert(port);
+	free(port->id_string);
+	/* TODO: Kill fibril here */
 	return;
 }
 /*----------------------------------------------------------------------------*/
+/** Periodically checks port status and reports new devices.
+ *
+ * @param[in] port Port structure to use.
+ * @return Error code.
+ */
 int uhci_port_check(void *port)
 {
-	uhci_port_t *port_instance = port;
-	assert(port_instance);
-//	port_status_write(port_instance->address, 0);
-
-	unsigned count = 0;
+	uhci_port_t *instance = port;
+	assert(instance);
 
 	while (1) {
-		async_usleep(port_instance->wait_period_usec);
-
-		/* read register value */
-		port_status_t port_status =
-			port_status_read(port_instance->address);
-
-		/* debug print */
-		static fibril_mutex_t dbg_mtx = FIBRIL_MUTEX_INITIALIZER(dbg_mtx);
-		fibril_mutex_lock(&dbg_mtx);
-		usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n",
-		  port_instance->address, port_instance->number, port_status, count++);
-//		print_port_status(port_status);
-		fibril_mutex_unlock(&dbg_mtx);
-
-		if ((port_status & STATUS_CONNECTED_CHANGED) != 0) {
-			usb_log_debug("Port(%p - %d): Connected change detected: %x.\n",
-			    port_instance->address, port_instance->number, port_status);
-
-
-			int rc = usb_hc_connection_open(
-			    &port_instance->hc_connection);
-			if (rc != EOK) {
-				usb_log_error("Port(%p - %d): Failed to connect to HC.",
-				    port_instance->address, port_instance->number);
-				continue;
-			}
-
-			/* remove any old device */
-			if (port_instance->attached_device) {
-				usb_log_debug("Port(%p - %d): Removing device.\n",
-				    port_instance->address, port_instance->number);
-				uhci_port_remove_device(port_instance);
-			}
-
-			if ((port_status & STATUS_CONNECTED) != 0) {
-				/* new device */
-				uhci_port_new_device(port_instance, port_status);
-			} else {
-				/* ack changes by writing one to WC bits */
-				port_status_write(port_instance->address, port_status);
-				usb_log_debug("Port(%p - %d): Change status ACK.\n",
-						port_instance->address, port_instance->number);
-			}
-
-			rc = usb_hc_connection_close(
-			    &port_instance->hc_connection);
-			if (rc != EOK) {
-				usb_log_error("Port(%p - %d): Failed to disconnect from HC.",
-				    port_instance->address, port_instance->number);
-			}
+		async_usleep(instance->wait_period_usec);
+
+		/* Read register value */
+		port_status_t port_status = uhci_port_read_status(instance);
+
+		/* Print the value if it's interesting */
+		if (port_status & ~STATUS_ALWAYS_ONE)
+			uhci_port_print_status(instance, port_status);
+
+		if ((port_status & STATUS_CONNECTED_CHANGED) == 0)
+			continue;
+
+		usb_log_debug("%s: Connected change detected: %x.\n",
+		    instance->id_string, port_status);
+
+		int rc =
+		    usb_hc_connection_open(&instance->hc_connection);
+		if (rc != EOK) {
+			usb_log_error("%s: Failed to connect to HC.",
+			    instance->id_string);
+			continue;
 		}
-	}
-	return EOK;
-}
-
+
+		/* Remove any old device */
+		if (instance->attached_device) {
+			usb_log_debug2("%s: Removing device.\n",
+			    instance->id_string);
+			uhci_port_remove_device(instance);
+		}
+
+		if ((port_status & STATUS_CONNECTED) != 0) {
+			/* New device */
+			const usb_speed_t speed =
+			    ((port_status & STATUS_LOW_SPEED) != 0) ?
+			    USB_SPEED_LOW : USB_SPEED_FULL;
+			uhci_port_new_device(instance, speed);
+		} else {
+			/* Write one to WC bits, to ack changes */
+			uhci_port_write_status(instance, port_status);
+			usb_log_debug("%s: status change ACK.\n",
+			    instance->id_string);
+		}
+
+		rc = usb_hc_connection_close(&instance->hc_connection);
+		if (rc != EOK) {
+			usb_log_error("%s: Failed to disconnect.",
+			    instance->id_string);
+		}
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 /** Callback for enabling port during adding a new device.
  *
@@ -158,11 +204,12 @@
  * @param arg Pointer to uhci_port_t of port with the new device.
  * @return Error code.
- */
-static int new_device_enable_port(int portno, void *arg)
+ *
+ * Resets and enables the ub port.
+ */
+int uhci_port_reset_enable(int portno, void *arg)
 {
 	uhci_port_t *port = (uhci_port_t *) arg;
 
-	usb_log_debug2("Port(%p - %d): new_device_enable_port.\n",
-	    port->address, port->number);
+	usb_log_debug2("%s: new_device_enable_port.\n", port->id_string);
 
 	/*
@@ -172,23 +219,21 @@
 	async_usleep(100000);
 
-
-	/* The hub maintains the reset signal to that port for 10 ms
-	 * (See Section 11.5.1.5)
+	/*
+	 * Resets from root ports should be nominally 50ms
 	 */
 	{
-		usb_log_debug("Port(%p - %d): Reset Signal start.\n",
-		    port->address, port->number);
-		port_status_t port_status =
-			port_status_read(port->address);
+		usb_log_debug("%s: Reset Signal start.\n", port->id_string);
+		port_status_t port_status = uhci_port_read_status(port);
 		port_status |= STATUS_IN_RESET;
-		port_status_write(port->address, port_status);
-		async_usleep(10000);
-		port_status =
-			port_status_read(port->address);
+		uhci_port_write_status(port, port_status);
+		async_usleep(50000);
+		port_status = uhci_port_read_status(port);
 		port_status &= ~STATUS_IN_RESET;
-		port_status_write(port->address, port_status);
-		usb_log_debug("Port(%p - %d): Reset Signal stop.\n",
-		    port->address, port->number);
-	}
+		uhci_port_write_status(port, port_status);
+		usb_log_debug("%s: Reset Signal stop.\n", port->id_string);
+	}
+
+	/* the reset recovery time 10ms */
+	async_usleep(10000);
 
 	/* Enable the port. */
@@ -197,51 +242,68 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-static int uhci_port_new_device(uhci_port_t *port, uint16_t status)
+/*----------------------------------------------------------------------------*/
+/** Initialize and report connected device.
+ *
+ * @param[in] port Port structure to use.
+ * @param[in] speed Detected speed.
+ * @return Error code.
+ *
+ * Uses libUSB function to do the actual work.
+ */
+int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed)
 {
 	assert(port);
 	assert(usb_hc_connection_is_opened(&port->hc_connection));
 
-	usb_log_info("Port(%p-%d): Detected new device.\n",
-	    port->address, port->number);
+	usb_log_info("%s: Detected new device.\n", port->id_string);
 
 	usb_address_t dev_addr;
 	int rc = usb_hc_new_device_wrapper(port->rh, &port->hc_connection,
-	    ((status & STATUS_LOW_SPEED) != 0) ? USB_SPEED_LOW : USB_SPEED_FULL,
-	    new_device_enable_port, port->number, port,
+	    speed, uhci_port_reset_enable, port->number, port,
 	    &dev_addr, &port->attached_device, NULL, NULL, NULL);
 
 	if (rc != EOK) {
-		usb_log_error("Port(%p-%d): Failed(%d) adding new device: %s.\n",
-		    port->address, port->number, rc, str_error(rc));
+		usb_log_error("%s: Failed(%d) to add device: %s.\n",
+		    port->id_string, rc, str_error(rc));
 		uhci_port_set_enabled(port, false);
 		return rc;
 	}
 
-	usb_log_info("Port(%p-%d): New device has address %d (handle %zu).\n",
-	    port->address, port->number, dev_addr, port->attached_device);
-
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-static int uhci_port_remove_device(uhci_port_t *port)
-{
-	usb_log_error("Port(%p-%d): Don't know how to remove device %#x.\n",
-		port->address, port->number, (unsigned int)port->attached_device);
-//	uhci_port_set_enabled(port, false);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
-{
-	assert(port);
-
-	/* read register value */
-	port_status_t port_status
-		= port_status_read(port->address);
-
-	/* enable port: register write */
+	usb_log_info("%s: New device has address %d (handle %zu).\n",
+	    port->id_string, dev_addr, port->attached_device);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Remove device.
+ *
+ * @param[in] port Memory structure to use.
+ * @return Error code.
+ *
+ * Does not work, DDF does not support device removal.
+ * Does not even free used USB address (it would be dangerous if tis driver
+ * is still running).
+ */
+int uhci_port_remove_device(uhci_port_t *port)
+{
+	usb_log_error("%s: Don't know how to remove device %d.\n",
+	    port->id_string, (unsigned int)port->attached_device);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Enable or disable root hub port.
+ *
+ * @param[in] port Port structure to use.
+ * @param[in] enabled Port status to set.
+ * @return Error code. (Always EOK)
+ */
+int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
+{
+	assert(port);
+
+	/* Read register value */
+	port_status_t port_status = uhci_port_read_status(port);
+
+	/* Set enabled bit */
 	if (enabled) {
 		port_status |= STATUS_ENABLED;
@@ -249,11 +311,37 @@
 		port_status &= ~STATUS_ENABLED;
 	}
-	port_status_write(port->address, port_status);
-
-	usb_log_info("Port(%p-%d): %sabled port.\n",
-		port->address, port->number, enabled ? "En" : "Dis");
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
+
+	/* Write new value. */
+	uhci_port_write_status(port, port_status);
+
+	usb_log_info("%s: %sabled port.\n",
+		port->id_string, enabled ? "En" : "Dis");
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Print the port status value in a human friendly way
+ *
+ * @param[in] port Port structure to use.
+ * @param[in] value Port register value to print.
+ * @return Error code. (Always EOK)
+ */
+void uhci_port_print_status(uhci_port_t *port, const port_status_t value)
+{
+	assert(port);
+	usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n",
+	    port->id_string, value,
+	    (value & STATUS_SUSPEND) ? " SUSPENDED," : "",
+	    (value & STATUS_RESUME) ? " IN RESUME," : "",
+	    (value & STATUS_IN_RESET) ? " IN RESET," : "",
+	    (value & STATUS_LINE_D_MINUS) ? " VD-," : "",
+	    (value & STATUS_LINE_D_PLUS) ? " VD+," : "",
+	    (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "",
+	    (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "",
+	    (value & STATUS_ENABLED) ? " ENABLED," : "",
+	    (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "",
+	    (value & STATUS_CONNECTED) ? " CONNECTED," : "",
+	    (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE"
+	);
+}
 /**
  * @}
Index: uspace/drv/uhci-rhd/port.h
===================================================================
--- uspace/drv/uhci-rhd/port.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-rhd/port.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jan Vesely
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,22 +26,35 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcirh
  * @{
  */
 /** @file
- * @brief UHCI port driver
+ * @brief UHCI root hub port routines
  */
 #ifndef DRV_UHCI_PORT_H
 #define DRV_UHCI_PORT_H
 
-#include <assert.h>
+#include <stdint.h>
+#include <fibril.h>
 #include <ddf/driver.h>
-#include <stdint.h>
-#include <usb/usbdevice.h>
+#include <usb/usbdevice.h> /* usb_hc_connection_t */
 
-#include "port_status.h"
+typedef uint16_t port_status_t;
+#define STATUS_CONNECTED         (1 << 0)
+#define STATUS_CONNECTED_CHANGED (1 << 1)
+#define STATUS_ENABLED           (1 << 2)
+#define STATUS_ENABLED_CHANGED   (1 << 3)
+#define STATUS_LINE_D_PLUS       (1 << 4)
+#define STATUS_LINE_D_MINUS      (1 << 5)
+#define STATUS_RESUME            (1 << 6)
+#define STATUS_ALWAYS_ONE        (1 << 7)
+
+#define STATUS_LOW_SPEED (1 <<  8)
+#define STATUS_IN_RESET  (1 <<  9)
+#define STATUS_SUSPEND   (1 << 12)
 
 typedef struct uhci_port
 {
+	char *id_string;
 	port_status_t *address;
 	unsigned number;
@@ -58,4 +71,5 @@
 
 void uhci_port_fini(uhci_port_t *port);
+
 #endif
 /**
Index: uspace/drv/uhci-rhd/port_status.c
===================================================================
--- uspace/drv/uhci-rhd/port_status.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ 	(revision )
@@ -1,72 +1,0 @@
-/*
- * 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 usb
- * @{
- */
-/** @file
- * @brief UHCI driver
- */
-#include <assert.h>
-#include <stdio.h>
-
-#include <usb/debug.h>
-
-#include "port_status.h"
-
-struct flag_name
-{
-	uint16_t flag;
-	const char *name;
-};
-
-static const struct flag_name flags[] =
-{
-	{ STATUS_SUSPEND, "suspended" },
-	{ STATUS_IN_RESET, "in reset" },
-	{ STATUS_LOW_SPEED, "low speed device" },
-	{ STATUS_ALWAYS_ONE, "always 1 bit" },
-	{ STATUS_RESUME, "resume" },
-	{ STATUS_LINE_D_MINUS, "line D- value" },
-	{ STATUS_LINE_D_PLUS, "line D+ value" },
-	{ STATUS_ENABLED_CHANGED, "enabled changed" },
-	{ STATUS_ENABLED, "enabled" },
-	{ STATUS_CONNECTED_CHANGED, "connected changed" },
-	{ STATUS_CONNECTED, "connected" }
-};
-
-void print_port_status(port_status_t value)
-{
-	unsigned i = 0;
-	for (;i < sizeof(flags)/sizeof(struct flag_name); ++i) {
-		usb_log_debug2("\t%s status: %s.\n", flags[i].name,
-		  ((value & flags[i].flag) != 0) ? "YES" : "NO");
-	}
-}
-/**
- * @}
- */
Index: uspace/drv/uhci-rhd/port_status.h
===================================================================
--- uspace/drv/uhci-rhd/port_status.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ 	(revision )
@@ -1,67 +1,0 @@
-/*
- * Copyright (c) 2010 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 usb
- * @{
- */
-/** @file
- * @brief UHCI driver
- */
-#ifndef DRV_UHCI_TD_PORT_STATUS_H
-#define DRV_UHCI_TD_PORT_STATUS_H
-
-#include <libarch/ddi.h> /* pio_read and pio_write */
-
-#include <stdint.h>
-
-typedef uint16_t port_status_t;
-
-#define STATUS_CONNECTED         (1 << 0)
-#define STATUS_CONNECTED_CHANGED (1 << 1)
-#define STATUS_ENABLED           (1 << 2)
-#define STATUS_ENABLED_CHANGED   (1 << 3)
-#define STATUS_LINE_D_PLUS       (1 << 4)
-#define STATUS_LINE_D_MINUS      (1 << 5)
-#define STATUS_RESUME            (1 << 6)
-#define STATUS_ALWAYS_ONE        (1 << 7)
-
-#define STATUS_LOW_SPEED (1 <<  8)
-#define STATUS_IN_RESET  (1 <<  9)
-#define STATUS_SUSPEND   (1 << 12)
-
-static inline port_status_t port_status_read(port_status_t * address)
-	{ return pio_read_16(address); }
-
-static inline void port_status_write(
-  port_status_t *address, port_status_t value)
-	{ pio_write_16(address, value); }
-
-void print_port_status(const port_status_t status);
-#endif
-/**
- * @}
- */
Index: uspace/drv/uhci-rhd/root_hub.c
===================================================================
--- uspace/drv/uhci-rhd/root_hub.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-rhd/root_hub.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -26,18 +26,24 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcirh
  * @{
  */
 /** @file
- * @brief UHCI driver
+ * @brief UHCI root hub driver
  */
 #include <errno.h>
-#include <stdint.h>
 #include <ddi.h>
-#include <devman.h>
 #include <usb/debug.h>
 
 #include "root_hub.h"
 
+/** Initialize UHCI root hub instance.
+ *
+ * @param[in] instance Driver memory structure to use.
+ * @param[in] addr Address of I/O registers.
+ * @param[in] size Size of available I/O space.
+ * @param[in] rh Pointer to ddf instance of the root hub driver.
+ * @return Error code.
+ */
 int uhci_root_hub_init(
   uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh)
@@ -47,20 +53,21 @@
 	int ret;
 
-	/* allow access to root hub registers */
-	assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT == size);
+	/* Allow access to root hub port registers */
+	assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT <= size);
 	port_status_t *regs;
 	ret = pio_enable(addr, size, (void**)&regs);
-
 	if (ret < 0) {
-		usb_log_error("Failed to gain access to port registers at %p\n", regs);
+		usb_log_error(
+		    "Failed(%d) to gain access to port registers at %p\n",
+		    ret, regs);
 		return ret;
 	}
 
-	/* add fibrils for periodic port checks */
+	/* Initialize root hub ports */
 	unsigned i = 0;
 	for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
-		/* mind pointer arithmetics */
+		/* NOTE: mind pointer arithmetics here */
 		ret = uhci_port_init(
-		  &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);
+		    &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);
 		if (ret != EOK) {
 			unsigned j = 0;
@@ -74,10 +81,16 @@
 }
 /*----------------------------------------------------------------------------*/
-int uhci_root_hub_fini( uhci_root_hub_t* instance )
+/** Cleanup UHCI root hub instance.
+ *
+ * @param[in] instance Root hub structure to use.
+ * @return Error code.
+ */
+int uhci_root_hub_fini(uhci_root_hub_t* instance)
 {
-	assert( instance );
-	// TODO:
-	//destroy fibril here
-	//disable access to registers
+	assert(instance);
+	unsigned i = 0;
+	for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
+		uhci_port_fini(&instance->ports[i]);
+	}
 	return EOK;
 }
Index: uspace/drv/uhci-rhd/root_hub.h
===================================================================
--- uspace/drv/uhci-rhd/root_hub.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/uhci-rhd/root_hub.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jan Vesely
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup usb
+/** @addtogroup drvusbuhcirh
  * @{
  */
@@ -35,5 +35,4 @@
 #define DRV_UHCI_ROOT_HUB_H
 
-#include <fibril.h>
 #include <ddf/driver.h>
 
Index: uspace/drv/usbhid/Makefile
===================================================================
--- uspace/drv/usbhid/Makefile	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/Makefile	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -42,4 +42,5 @@
 	hidreq.c \
 	kbddev.c \
+	kbdrepeat.c \
 	hiddev.c \
 	$(STOLEN_LAYOUT_SOURCES)
Index: uspace/drv/usbhid/conv.c
===================================================================
--- uspace/drv/usbhid/conv.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/conv.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -40,4 +40,8 @@
 #include "conv.h"
 
+/**
+ * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
+ * HelenOS key codes.
+ */
 static int scanmap_simple[255] = {
 
@@ -163,4 +167,12 @@
 };
 
+/**
+ * Translate USB HID key codes (from HID Usage Tables) to generic key codes
+ * recognized by HelenOS.
+ *
+ * @param scancode USB HID key code (from HID Usage Tables).
+ * 
+ * @retval HelenOS key code corresponding to the given USB HID key code.
+ */
 unsigned int usbhid_parse_scancode(int scancode)
 {
Index: uspace/drv/usbhid/descdump.c
===================================================================
--- uspace/drv/usbhid/descdump.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/descdump.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -44,4 +44,11 @@
 #define BYTES_PER_LINE 12
 
+/**
+ * Dumps the given buffer in hexadecimal format to standard output.
+ *
+ * @param msg Message to print before the buffer.
+ * @param buffer Buffer to print.
+ * @param length Size of the buffer in bytes.
+ */
 static void dump_buffer(const char *msg, const uint8_t *buffer, size_t length)
 {
@@ -62,4 +69,10 @@
 #define INDENT "  "
 
+/**
+ * Print standard configuration descriptor to standard output.
+ *
+ * @param index Index of the descriptor.
+ * @param d Standard configuration descriptor to print.
+ */
 void dump_standard_configuration_descriptor(
     int index, const usb_standard_configuration_descriptor_t *d)
@@ -84,4 +97,9 @@
 }
 
+/**
+ * Print standard interface descriptor to standard output.
+ *
+ * @param d Standard interface descriptor to print.
+ */
 void dump_standard_interface_descriptor(
     const usb_standard_interface_descriptor_t *d)
@@ -99,4 +117,9 @@
 }
 
+/**
+ * Print standard endpoint descriptor to standard output.
+ *
+ * @param d Standard endpoint descriptor to print.
+ */
 void dump_standard_endpoint_descriptor(
     const usb_standard_endpoint_descriptor_t *d)
@@ -126,4 +149,9 @@
 }
 
+/**
+ * Print standard HID descriptor to standard output.
+ *
+ * @param d Standard HID descriptor to print.
+ */
 void dump_standard_hid_descriptor_header(
     const usb_standard_hid_descriptor_t *d)
@@ -139,4 +167,10 @@
 }
 
+/**
+ * Print HID class-specific descriptor header (type and length) to standard 
+ * output.
+ * 
+ * @param d HID class-specific descriptor header to print.
+ */
 void dump_standard_hid_class_descriptor_info(
     const usb_standard_hid_class_descriptor_info_t *d)
@@ -146,4 +180,12 @@
 }
 
+/**
+ * Print HID class-specific descriptor (without the header) to standard output.
+ *
+ * @param index Index of the descriptor.
+ * @param type Type of the HID class-specific descriptor (Report or Physical).
+ * @param d HID class descriptor to print.
+ * @param size Size of the descriptor in bytes.
+ */
 void dump_hid_class_descriptor(int index, uint8_t type, 
     const uint8_t *d, size_t size )
Index: uspace/drv/usbhid/hiddev.c
===================================================================
--- uspace/drv/usbhid/hiddev.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/hiddev.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -53,5 +53,28 @@
 /* Non-API functions                                                          */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Retreives HID Report descriptor from the device.
+ *
+ * This function first parses the HID descriptor from the Interface descriptor
+ * to get the size of the Report descriptor and then requests the Report 
+ * descriptor from the device.
+ *
+ * @param hid_dev HID device structure.
+ * @param config_desc Full configuration descriptor (including all nested
+ *                    descriptors).
+ * @param config_desc_size Size of the full configuration descriptor (in bytes).
+ * @param iface_desc Pointer to the interface descriptor inside the full
+ *                   configuration descriptor (@a config_desc) for the interface
+ *                   assigned with this device (@a hid_dev).
+ *
+ * @retval EOK if successful.
+ * @retval ENOENT if no HID descriptor could be found.
+ * @retval EINVAL if the HID descriptor  or HID report descriptor have different
+ *                size than expected.
+ * @retval ENOMEM if some allocation failed.
+ * @return Other value inherited from function usb_request_get_descriptor().
+ *
+ * @sa usb_request_get_descriptor()
+ */
 static int usbhid_dev_get_report_descriptor(usbhid_dev_t *hid_dev, 
     uint8_t *config_desc, size_t config_desc_size, uint8_t *iface_desc)
@@ -141,5 +164,25 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Retreives descriptors from the device, initializes pipes and stores 
+ * important information from descriptors.
+ *
+ * Initializes the polling pipe described by the given endpoint description
+ * (@a poll_ep_desc).
+ * 
+ * Information retreived from descriptors and stored in the HID device structure:
+ *    - Assigned interface number (the interface controlled by this instance of
+ *                                 the driver)
+ *    - Polling interval (from the interface descriptor)
+ *    - Report descriptor
+ *
+ * @param hid_dev HID device structure to be initialized.
+ * @param poll_ep_desc Description of the polling (Interrupt In) endpoint
+ *                     that has to be present in the device in order to
+ *                     successfuly initialize the structure.
+ *
+ * @sa usb_endpoint_pipe_initialize_from_configuration(), 
+ *     usbhid_dev_get_report_descriptor()
+ */
 static int usbhid_dev_process_descriptors(usbhid_dev_t *hid_dev, 
     usb_endpoint_description_t *poll_ep_desc) 
@@ -230,5 +273,9 @@
 /* API functions                                                              */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Creates new uninitialized HID device structure.
+ *
+ * @return Pointer to the new HID device structure, or NULL if an error occured.
+ */
 usbhid_dev_t *usbhid_dev_new(void)
 {
@@ -249,5 +296,12 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Properly destroys the HID device structure.
+ *
+ * @note Currently does not clean-up the used pipes, as there are no functions
+ *       offering such functionality.
+ * 
+ * @param hid_dev Pointer to the structure to be destroyed.
+ */
 void usbhid_dev_free(usbhid_dev_t **hid_dev)
 {
@@ -272,5 +326,23 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Initializes HID device structure.
+ *
+ * @param hid_dev HID device structure to be initialized.
+ * @param dev DDF device representing the HID device.
+ * @param poll_ep_desc Description of the polling (Interrupt In) endpoint
+ *                     that has to be present in the device in order to
+ *                     successfuly initialize the structure.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if some argument is missing.
+ * @return Other value inherited from one of functions 
+ *         usb_device_connection_initialize_from_device(),
+ *         usb_endpoint_pipe_initialize_default_control(),
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usbhid_dev_process_descriptors().
+ *
+ * @sa usbhid_dev_process_descriptors()
+ */
 int usbhid_dev_init(usbhid_dev_t *hid_dev, ddf_dev_t *dev, 
     usb_endpoint_description_t *poll_ep_desc)
@@ -319,14 +391,24 @@
 		return rc;
 	}
+	rc = usb_endpoint_pipe_probe_default_control(&hid_dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_error("Probing default control pipe failed: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
 
 	/*
 	 * Get descriptors, parse descriptors and save endpoints.
 	 */
-	usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
+	rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_error("Failed to start session on the control pipe: %s"
+		    ".\n", str_error(rc));
+		return rc;
+	}
 	
 	rc = usbhid_dev_process_descriptors(hid_dev, poll_ep_desc);
-	
-	usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
-	if (rc != EOK) {
+	if (rc != EOK) {
+		/* TODO: end session?? */
 		usb_log_error("Failed to process descriptors: %s.\n",
 		    str_error(rc));
@@ -334,4 +416,11 @@
 	}
 	
+	rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_warning("Failed to start session on the control pipe: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+	
 	hid_dev->initialized = 1;
 	usb_log_info("HID device structure initialized.\n");
Index: uspace/drv/usbhid/hiddev.h
===================================================================
--- uspace/drv/usbhid/hiddev.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/hiddev.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -48,20 +48,35 @@
 
 /**
- * @brief USB/HID device type.
+ * USB/HID device type.
+ *
+ * Holds a reference to DDF device structure, and HID-specific data, such 
+ * as information about used pipes (one Control pipe and one Interrupt In pipe),
+ * polling interval, assigned interface number, Report descriptor and a
+ * reference to the Report parser used to parse incoming reports and composing
+ * outgoing reports.
  */
 typedef struct {
+	/** DDF device representing the controlled HID device. */
 	ddf_dev_t *device;
 
+	/** Physical connection to the device. */
 	usb_device_connection_t wire;
+	/** USB pipe corresponding to the default Control endpoint. */
 	usb_endpoint_pipe_t ctrl_pipe;
+	/** USB pipe corresponding to the Interrupt In (polling) pipe. */
 	usb_endpoint_pipe_t poll_pipe;
 	
+	/** Polling interval retreived from the Interface descriptor. */
 	short poll_interval;
 	
+	/** Interface number assigned to this device. */
 	uint16_t iface;
 	
+	/** Report descriptor. */
 	uint8_t *report_desc;
+	/** HID Report parser. */
 	usb_hid_report_parser_t *parser;
 	
+	/** State of the structure (for checking before use). */
 	int initialized;
 } usbhid_dev_t;
Index: uspace/drv/usbhid/hidreq.c
===================================================================
--- uspace/drv/usbhid/hidreq.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/hidreq.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -46,5 +46,18 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Send Set Report request to the HID device.
+ *
+ * @param hid_dev HID device to send the request to.
+ * @param type Type of the report.
+ * @param buffer Report data.
+ * @param buf_size Report data size (in bytes).
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if no HID device is given.
+ * @return Other value inherited from one of functions 
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usb_control_request_set().
+ */
 int usbhid_req_set_report(usbhid_dev_t *hid_dev,
     usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size)
@@ -69,4 +82,7 @@
 		return sess_rc;
 	}
+	
+	uint16_t value = 0;
+	value |= (type << 8);
 
 	usb_log_debug("Sending Set_Report request to the device.\n");
@@ -74,25 +90,36 @@
 	rc = usb_control_request_set(&hid_dev->ctrl_pipe, 
 	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
-	    USB_HIDREQ_SET_REPORT, type, hid_dev->iface, buffer, buf_size);
-
-	sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
-
-	if (rc != EOK) {
-		usb_log_warning("Error sending output report to the keyboard: "
-		    "%s.\n", str_error(rc));
-		return rc;
-	}
-
-	if (sess_rc != EOK) {
-		usb_log_warning("Error closing session: %s.\n",
-		    str_error(sess_rc));
-		return sess_rc;
-	}
-	
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
+	    USB_HIDREQ_SET_REPORT, value, hid_dev->iface, buffer, buf_size);
+
+	sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+
+	if (sess_rc != EOK) {
+		usb_log_warning("Error closing session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Send Set Protocol request to the HID device.
+ *
+ * @param hid_dev HID device to send the request to.
+ * @param protocol Protocol to set.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if no HID device is given.
+ * @return Other value inherited from one of functions 
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usb_control_request_set().
+ */
 int usbhid_req_set_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t protocol)
 {
@@ -142,4 +169,276 @@
 
 /*----------------------------------------------------------------------------*/
+/**
+ * Send Set Idle request to the HID device.
+ *
+ * @param hid_dev HID device to send the request to.
+ * @param duration Duration value (is multiplicated by 4 by the device to
+ *                 get real duration in miliseconds).
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if no HID device is given.
+ * @return Other value inherited from one of functions 
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usb_control_request_set().
+ */
+int usbhid_req_set_idle(usbhid_dev_t *hid_dev, uint8_t duration)
+{
+	if (hid_dev == NULL) {
+		usb_log_error("usbhid_req_set_idle(): no HID device "
+		    "structure given.\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc, sess_rc;
+	
+	sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
+	if (sess_rc != EOK) {
+		usb_log_warning("Failed to start a session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+
+	usb_log_debug("Sending Set_Idle request to the device ("
+	    "duration: %u, iface: %d).\n", duration, hid_dev->iface);
+	
+	uint16_t value = duration << 8;
+	
+	rc = usb_control_request_set(&hid_dev->ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_SET_IDLE, value, hid_dev->iface, NULL, 0);
+
+	sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+
+	if (sess_rc != EOK) {
+		usb_log_warning("Error closing session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Send Get Report request to the HID device.
+ *
+ * @param[in] hid_dev HID device to send the request to.
+ * @param[in] type Type of the report.
+ * @param[in][out] buffer Buffer for the report data.
+ * @param[in] buf_size Size of the buffer (in bytes).
+ * @param[out] actual_size Actual size of report received from the device 
+ *                         (in bytes).
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if no HID device is given.
+ * @return Other value inherited from one of functions 
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usb_control_request_set().
+ */
+int usbhid_req_get_report(usbhid_dev_t *hid_dev, usb_hid_report_type_t type, 
+    uint8_t *buffer, size_t buf_size, size_t *actual_size)
+{
+	if (hid_dev == NULL) {
+		usb_log_error("usbhid_req_set_report(): no HID device structure"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc, sess_rc;
+	
+	sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
+	if (sess_rc != EOK) {
+		usb_log_warning("Failed to start a session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+
+	uint16_t value = 0;
+	value |= (type << 8);
+	
+	usb_log_debug("Sending Get_Report request to the device.\n");
+	
+	rc = usb_control_request_get(&hid_dev->ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_GET_REPORT, value, hid_dev->iface, buffer, buf_size,
+	    actual_size);
+
+	sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+
+	if (sess_rc != EOK) {
+		usb_log_warning("Error closing session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Send Get Protocol request to the HID device.
+ *
+ * @param[in] hid_dev HID device to send the request to.
+ * @param[out] protocol Current protocol of the device.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if no HID device is given.
+ * @return Other value inherited from one of functions 
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usb_control_request_set().
+ */
+int usbhid_req_get_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t *protocol)
+{
+	if (hid_dev == NULL) {
+		usb_log_error("usbhid_req_set_protocol(): no HID device "
+		    "structure given.\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc, sess_rc;
+	
+	sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
+	if (sess_rc != EOK) {
+		usb_log_warning("Failed to start a session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+
+	usb_log_debug("Sending Get_Protocol request to the device ("
+	    "iface: %d).\n", hid_dev->iface);
+	
+	uint8_t buffer[1];
+	size_t actual_size = 0;
+	
+	rc = usb_control_request_get(&hid_dev->ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_GET_PROTOCOL, 0, hid_dev->iface, buffer, 1, &actual_size);
+
+	sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+
+	if (sess_rc != EOK) {
+		usb_log_warning("Error closing session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+	
+	if (actual_size != 1) {
+		usb_log_warning("Wrong data size: %zu, expected: 1.\n",
+			actual_size);
+		return ELIMIT;
+	}
+	
+	*protocol = buffer[0];
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Send Get Idle request to the HID device.
+ *
+ * @param[in] hid_dev HID device to send the request to.
+ * @param[out] duration Duration value (multiplicate by 4 to get real duration
+ *                      in miliseconds).
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if no HID device is given.
+ * @return Other value inherited from one of functions 
+ *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
+ *         usb_control_request_set().
+ */
+int usbhid_req_get_idle(usbhid_dev_t *hid_dev, uint8_t *duration)
+{
+	if (hid_dev == NULL) {
+		usb_log_error("usbhid_req_set_idle(): no HID device "
+		    "structure given.\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc, sess_rc;
+	
+	sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
+	if (sess_rc != EOK) {
+		usb_log_warning("Failed to start a session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+
+	usb_log_debug("Sending Get_Idle request to the device ("
+	    "iface: %d).\n", hid_dev->iface);
+	
+	uint16_t value = 0;
+	uint8_t buffer[1];
+	size_t actual_size = 0;
+	
+	rc = usb_control_request_get(&hid_dev->ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_GET_IDLE, value, hid_dev->iface, buffer, 1, 
+	    &actual_size);
+
+	sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+
+	if (sess_rc != EOK) {
+		usb_log_warning("Error closing session: %s.\n",
+		    str_error(sess_rc));
+		return sess_rc;
+	}
+	
+	if (actual_size != 1) {
+		usb_log_warning("Wrong data size: %zu, expected: 1.\n",
+			actual_size);
+		return ELIMIT;
+	}
+	
+	*duration = buffer[0];
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
 
 /**
Index: uspace/drv/usbhid/hidreq.h
===================================================================
--- uspace/drv/usbhid/hidreq.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/hidreq.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -50,4 +50,13 @@
 int usbhid_req_set_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t protocol);
 
+int usbhid_req_set_idle(usbhid_dev_t *hid_dev, uint8_t duration);
+
+int usbhid_req_get_report(usbhid_dev_t *hid_dev, usb_hid_report_type_t type, 
+    uint8_t *buffer, size_t buf_size, size_t *actual_size);
+
+int usbhid_req_get_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t *protocol);
+
+int usbhid_req_get_idle(usbhid_dev_t *hid_dev, uint8_t *duration);
+
 /*----------------------------------------------------------------------------*/
 
Index: uspace/drv/usbhid/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbddev.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/kbddev.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -37,9 +37,11 @@
 #include <errno.h>
 #include <str_error.h>
-#include <fibril.h>
+#include <stdio.h>
 
 #include <io/keycode.h>
 #include <ipc/kbd.h>
 #include <async.h>
+#include <fibril.h>
+#include <fibril_synch.h>
 
 #include <usb/usb.h>
@@ -55,11 +57,30 @@
 #include "layout.h"
 #include "conv.h"
-
-/*----------------------------------------------------------------------------*/
-
+#include "kbdrepeat.h"
+
+/*----------------------------------------------------------------------------*/
+/** Default modifiers when the keyboard is initialized. */
 static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
+
+/** Boot protocol report size (key part). */
 static const size_t BOOTP_REPORT_SIZE = 6;
+
+/** Boot protocol total report size. */
 static const size_t BOOTP_BUFFER_SIZE = 8;
+
+/** Boot protocol output report size. */
 static const size_t BOOTP_BUFFER_OUT_SIZE = 1;
+
+/** Boot protocol error key code. */
+static const uint8_t BOOTP_ERROR_ROLLOVER = 1;
+
+/** Default idle rate for keyboards. */
+static const uint8_t IDLE_RATE = 0;
+
+/** Delay before a pressed key starts auto-repeating. */
+static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
+
+/** Delay between two repeats of a pressed key when auto-repeating. */
+static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
 
 /** Keyboard polling endpoint description for boot protocol class. */
@@ -79,4 +100,5 @@
 #define NUM_LAYOUTS 3
 
+/** Keyboard layout map. */
 static layout_op_t *layout[NUM_LAYOUTS] = {
 	&us_qwerty_op,
@@ -90,5 +112,5 @@
 /* Modifier constants                                                         */
 /*----------------------------------------------------------------------------*/
-
+/** Mapping of USB modifier key codes to generic modifier key codes. */
 static const keycode_t usbhid_modifiers_keycodes[USB_HID_MOD_COUNT] = {
 	KC_LCTRL,         /* USB_HID_MOD_LCTRL */
@@ -111,7 +133,12 @@
 };
 
-/** Default handler for IPC methods not handled by DDF.
- *
- * @param dev Device handling the call.
+/** 
+ * Default handler for IPC methods not handled by DDF.
+ *
+ * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
+ * assumes the caller is the console and thus it stores IPC phone to it for 
+ * later use by the driver to notify about key events.
+ *
+ * @param fun Device function handling the call.
  * @param icallid Call id.
  * @param icall Call data.
@@ -144,10 +171,20 @@
 /* Key processing functions                                                   */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Handles turning of LED lights on and off.
+ *
+ * In case of USB keyboards, the LEDs are handled in the driver, not in the 
+ * device. When there should be a change (lock key was pressed), the driver
+ * uses a Set_Report request sent to the device to set the state of the LEDs.
+ *
+ * This functions sets the LED lights according to current settings of modifiers
+ * kept in the keyboard device structure.
+ *
+ * @param kbd_dev Keyboard device structure.
+ */
 static void usbhid_kbd_set_led(usbhid_kbd_t *kbd_dev) 
 {
 	uint8_t buffer[BOOTP_BUFFER_OUT_SIZE];
 	int rc= 0;
-	unsigned i;
 	
 	memset(buffer, 0, BOOTP_BUFFER_OUT_SIZE);
@@ -177,30 +214,41 @@
 	}
 	
-	// TODO: REFACTOR!!!
-	
-	usb_log_debug("Output report buffer: ");
-	for (i = 0; i < BOOTP_BUFFER_OUT_SIZE; ++i) {
-		usb_log_debug("0x%x ", buffer[i]);
-	}
-	usb_log_debug("\n");
-	
-	uint16_t value = 0;
-	value |= (USB_HID_REPORT_TYPE_OUTPUT << 8);
-
+	usb_log_debug("Output report buffer: %s\n", 
+	    usb_debug_str_buffer(buffer, BOOTP_BUFFER_OUT_SIZE, 0));
+	
 	assert(kbd_dev->hid_dev != NULL);
 	assert(kbd_dev->hid_dev->initialized);
-	usbhid_req_set_report(kbd_dev->hid_dev, value, buffer, 
-	    BOOTP_BUFFER_OUT_SIZE);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, 
-    unsigned int key)
+	usbhid_req_set_report(kbd_dev->hid_dev, USB_HID_REPORT_TYPE_OUTPUT, 
+	    buffer, BOOTP_BUFFER_OUT_SIZE);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Processes key events.
+ *
+ * @note This function was copied from AT keyboard driver and modified to suit
+ *       USB keyboard.
+ *
+ * @note Lock keys are not sent to the console, as they are completely handled
+ *       in the driver. It may, however, be required later that the driver
+ *       sends also these keys to application (otherwise it cannot use those
+ *       keys at all).
+ * 
+ * @param kbd_dev Keyboard device structure.
+ * @param type Type of the event (press / release). Recognized values: 
+ *             KEY_PRESS, KEY_RELEASE
+ * @param key Key code of the key according to HID Usage Tables.
+ */
+void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, unsigned int key)
 {
 	console_event_t ev;
 	unsigned mod_mask;
 
-	// TODO: replace by our own parsing?? or are the key codes identical??
+	/*
+	 * These parts are copy-pasted from the AT keyboard driver.
+	 *
+	 * They definitely require some refactoring, but will keep it for later
+	 * when the console and keyboard system is changed in HelenOS.
+	 */
 	switch (key) {
 	case KC_LCTRL: mod_mask = KM_LCTRL; break;
@@ -228,11 +276,5 @@
 
 	if (mod_mask != 0) {
-		usb_log_debug2("\n\nChanging mods and lock keys\n");
-		usb_log_debug2("\nmods before: 0x%x\n", kbd_dev->mods);
-		usb_log_debug2("\nLock keys before:0x%x\n\n", 
-		    kbd_dev->lock_keys);
-		
 		if (type == KEY_PRESS) {
-			usb_log_debug2("\nKey pressed.\n");
 			/*
 			 * Only change lock state on transition from released
@@ -240,4 +282,6 @@
 			 * up the lock state.
 			 */
+			unsigned int locks_old = kbd_dev->lock_keys;
+			
 			kbd_dev->mods = 
 			    kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
@@ -245,14 +289,12 @@
 
 			/* Update keyboard lock indicator lights. */
- 			usbhid_kbd_set_led(kbd_dev);
+			if (kbd_dev->lock_keys != locks_old) {
+				usbhid_kbd_set_led(kbd_dev);
+			}
 		} else {
-			usb_log_debug2("\nKey released.\n");
 			kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
 		}
 	}
 
-	usb_log_debug2("\n\nmods after: 0x%x\n", kbd_dev->mods);
-	usb_log_debug2("\nLock keys after: 0x%x\n\n", kbd_dev->lock_keys);
-	
 	if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
 		// do not send anything to the console, this is our business
@@ -281,8 +323,4 @@
 	ev.key = key;
 	ev.mods = kbd_dev->mods;
-	
-	if (ev.mods & KM_NUM_LOCK) {
-		usb_log_debug("\n\nNum Lock turned on.\n\n");
-	}
 
 	ev.c = layout[active_layout]->parse_ev(&ev);
@@ -300,5 +338,12 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Checks if modifiers were pressed or released and generates key events.
+ *
+ * @param kbd_dev Keyboard device structure.
+ * @param modifiers Bitmap of modifiers.
+ *
+ * @sa usbhid_kbd_push_ev()
+ */
 static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev,
     uint8_t modifiers)
@@ -336,31 +381,60 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Checks if some keys were pressed or released and generates key events.
+ *
+ * An event is created only when key is pressed or released. Besides handling
+ * the events (usbhid_kbd_push_ev()), the auto-repeat fibril is notified about
+ * key presses and releases (see usbhid_kbd_repeat_start() and 
+ * usbhid_kbd_repeat_stop()).
+ *
+ * @param kbd_dev Keyboard device structure.
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ *
+ * @sa usbhid_kbd_push_ev(), usbhid_kbd_repeat_start(), usbhid_kbd_repeat_stop()
+ */
 static void usbhid_kbd_check_key_changes(usbhid_kbd_t *kbd_dev, 
-    const uint8_t *key_codes)
-{
-	// TODO: phantom state!!
-	
+    const uint8_t *key_codes, size_t count)
+{
 	unsigned int key;
 	unsigned int i, j;
 	
-	// TODO: quite dummy right now, think of better implementation
+	/*
+	 * First of all, check if the kbd have reported phantom state.
+	 */
+	i = 0;
+	// all fields should report Error Rollover
+	while (i < count &&
+	    key_codes[i] == BOOTP_ERROR_ROLLOVER) {
+		++i;
+	}
+	if (i == count) {
+		usb_log_debug("Phantom state occured.\n");
+		// phantom state, do nothing
+		return;
+	}
+	
+	/* TODO: quite dummy right now, think of better implementation */
+	assert(count == kbd_dev->key_count);
 	
 	/*
 	 * 1) Key releases
 	 */
-	for (j = 0; j < kbd_dev->keycode_count; ++j) {
+	for (j = 0; j < count; ++j) {
 		// try to find the old key in the new key list
 		i = 0;
-		while (i < kbd_dev->keycode_count
-		    && key_codes[i] != kbd_dev->keycodes[j]) {
+		while (i < kbd_dev->key_count
+		    && key_codes[i] != kbd_dev->keys[j]) {
 			++i;
 		}
 		
-		if (i == kbd_dev->keycode_count) {
+		if (i == count) {
 			// not found, i.e. the key was released
-			key = usbhid_parse_scancode(kbd_dev->keycodes[j]);
+			key = usbhid_parse_scancode(kbd_dev->keys[j]);
+			usbhid_kbd_repeat_stop(kbd_dev, key);
 			usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
-			usb_log_debug2("\nKey released: %d\n", key);
+			usb_log_debug2("Key released: %d\n", key);
 		} else {
 			// found, nothing happens
@@ -371,18 +445,18 @@
 	 * 1) Key presses
 	 */
-	for (i = 0; i < kbd_dev->keycode_count; ++i) {
+	for (i = 0; i < kbd_dev->key_count; ++i) {
 		// try to find the new key in the old key list
 		j = 0;
-		while (j < kbd_dev->keycode_count 
-		    && kbd_dev->keycodes[j] != key_codes[i]) { 
+		while (j < count && kbd_dev->keys[j] != key_codes[i]) { 
 			++j;
 		}
 		
-		if (j == kbd_dev->keycode_count) {
+		if (j == count) {
 			// not found, i.e. new key pressed
 			key = usbhid_parse_scancode(key_codes[i]);
-			usb_log_debug2("\nKey pressed: %d (keycode: %d)\n", key,
+			usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
 			    key_codes[i]);
 			usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, key);
+			usbhid_kbd_repeat_start(kbd_dev, key);
 		} else {
 			// found, nothing happens
@@ -390,10 +464,8 @@
 	}
 	
-	memcpy(kbd_dev->keycodes, key_codes, kbd_dev->keycode_count);
-	
-	usb_log_debug2("\nNew stored keycodes: ");
-	for (i = 0; i < kbd_dev->keycode_count; ++i) {
-		usb_log_debug2("%d ", kbd_dev->keycodes[i]);
-	}
+	memcpy(kbd_dev->keys, key_codes, count);
+
+	usb_log_debug("New stored keycodes: %s\n", 
+	    usb_debug_str_buffer(kbd_dev->keys, kbd_dev->key_count, 0));
 }
 
@@ -401,5 +473,20 @@
 /* Callbacks for parser                                                       */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Callback function for the HID report parser.
+ *
+ * This function is called by the HID report parser with the parsed report.
+ * The parsed report is used to check if any events occured (key was pressed or
+ * released, modifier was pressed or released).
+ *
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ * @param modifiers Bitmap of modifiers (Ctrl, Alt, Shift, GUI).
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @sa usbhid_kbd_check_key_changes(), usbhid_kbd_check_modifier_changes()
+ */
 static void usbhid_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
     uint8_t modifiers, void *arg)
@@ -410,23 +497,19 @@
 		return;
 	}
-
-	usb_log_debug2("Got keys from parser: ");
-	unsigned i;
-	for (i = 0; i < count; ++i) {
-		usb_log_debug2("%d ", key_codes[i]);
-	}
-	usb_log_debug2("\n");
 	
 	usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg;
 	assert(kbd_dev != NULL);
-	
-	if (count != kbd_dev->keycode_count) {
+
+	usb_log_debug("Got keys from parser: %s\n", 
+	    usb_debug_str_buffer(key_codes, kbd_dev->key_count, 0));
+	
+	if (count != kbd_dev->key_count) {
 		usb_log_warning("Number of received keycodes (%d) differs from"
-		    " expected number (%d).\n", count, kbd_dev->keycode_count);
+		    " expected number (%d).\n", count, kbd_dev->key_count);
 		return;
 	}
 	
 	usbhid_kbd_check_modifier_changes(kbd_dev, modifiers);
-	usbhid_kbd_check_key_changes(kbd_dev, key_codes);
+	usbhid_kbd_check_key_changes(kbd_dev, key_codes, count);
 }
 
@@ -434,5 +517,19 @@
 /* General kbd functions                                                      */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Processes data received from the device in form of report.
+ *
+ * This function uses the HID report parser to translate the data received from
+ * the device into generic USB HID key codes and into generic modifiers bitmap.
+ * The parser then calls the given callback (usbhid_kbd_process_keycodes()).
+ *
+ * @note Currently, only the boot protocol is supported.
+ *
+ * @param kbd_dev Keyboard device structure (must be initialized).
+ * @param buffer Data from the keyboard (i.e. the report).
+ * @param actual_size Size of the data from keyboard (report size) in bytes.
+ *
+ * @sa usbhid_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report().
+ */
 static void usbhid_kbd_process_data(usbhid_kbd_t *kbd_dev,
                                     uint8_t *buffer, size_t actual_size)
@@ -444,9 +541,6 @@
 	callbacks->keyboard = usbhid_kbd_process_keycodes;
 
-	//usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks, 
-	//    NULL);
-	/*usb_log_debug2("Calling usb_hid_boot_keyboard_input_report() with size"
-	    " %zu\n", actual_size);*/
-	//dump_buffer("bufffer: ", buffer, actual_size);
+	usb_log_debug("Calling usb_hid_boot_keyboard_input_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
 	
 	int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
@@ -462,5 +556,13 @@
 /* HID/KBD structure manipulation                                             */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Creates a new USB/HID keyboard structure.
+ *
+ * The structure returned by this function is not initialized. Use 
+ * usbhid_kbd_init() to initialize it prior to polling.
+ *
+ * @return New uninitialized structure for representing a USB/HID keyboard or
+ *         NULL if not successful (memory error).
+ */
 static usbhid_kbd_t *usbhid_kbd_new(void)
 {
@@ -488,5 +590,9 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Properly destroys the USB/HID keyboard structure.
+ *
+ * @param kbd_dev Pointer to the structure to be destroyed.
+ */
 static void usbhid_kbd_free(usbhid_kbd_t **kbd_dev)
 {
@@ -503,4 +609,10 @@
 	}
 	
+	if ((*kbd_dev)->repeat_mtx != NULL) {
+		/* TODO: replace by some check and wait */
+		assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
+		free((*kbd_dev)->repeat_mtx);
+	}
+	
 	free(*kbd_dev);
 	*kbd_dev = NULL;
@@ -508,5 +620,24 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Initialization of the USB/HID keyboard structure.
+ *
+ * This functions initializes required structures from the device's descriptors.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ *
+ * @param kbd_dev Keyboard device structure to be initialized.
+ * @param dev DDF device structure of the keyboard.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if some parameter is not given.
+ * @return Other value inherited from function usbhid_dev_init().
+ */
 static int usbhid_kbd_init(usbhid_kbd_t *kbd_dev, ddf_dev_t *dev)
 {
@@ -543,11 +674,11 @@
 	
 	// save the size of the report (boot protocol report by default)
-	kbd_dev->keycode_count = BOOTP_REPORT_SIZE;
-	kbd_dev->keycodes = (uint8_t *)calloc(
-	    kbd_dev->keycode_count, sizeof(uint8_t));
-	
-	if (kbd_dev->keycodes == NULL) {
+	kbd_dev->key_count = BOOTP_REPORT_SIZE;
+	kbd_dev->keys = (uint8_t *)calloc(
+	    kbd_dev->key_count, sizeof(uint8_t));
+	
+	if (kbd_dev->keys == NULL) {
 		usb_log_fatal("No memory!\n");
-		return rc;
+		return ENOMEM;
 	}
 	
@@ -556,7 +687,23 @@
 	kbd_dev->lock_keys = 0;
 	
+	kbd_dev->repeat.key_new = 0;
+	kbd_dev->repeat.key_repeated = 0;
+	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
+	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
+	
+	kbd_dev->repeat_mtx = (fibril_mutex_t *)(
+	    malloc(sizeof(fibril_mutex_t)));
+	if (kbd_dev->repeat_mtx == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev->keys);
+		return ENOMEM;
+	}
+	
+	fibril_mutex_initialize(kbd_dev->repeat_mtx);
+	
 	/*
 	 * Set boot protocol.
 	 * Set LEDs according to initial setup.
+	 * Set Idle rate
 	 */
 	assert(kbd_dev->hid_dev != NULL);
@@ -566,4 +713,6 @@
 	usbhid_kbd_set_led(kbd_dev);
 	
+	usbhid_req_set_idle(kbd_dev->hid_dev, IDLE_RATE);
+	
 	kbd_dev->initialized = 1;
 	usb_log_info("HID/KBD device structure initialized.\n");
@@ -575,5 +724,17 @@
 /* HID/KBD polling                                                            */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Main keyboard polling function.
+ *
+ * This function uses the Interrupt In pipe of the keyboard to poll for events.
+ * The keyboard is initialized in a way that it reports only when a key is 
+ * pressed or released, so there is no actual need for any sleeping between
+ * polls (see usbhid_kbd_try_add_device() or usbhid_kbd_init()).
+ *
+ * @param kbd_dev Initialized keyboard structure representing the device to 
+ *                poll.
+ *
+ * @sa usbhid_kbd_process_data()
+ */
 static void usbhid_kbd_poll(usbhid_kbd_t *kbd_dev)
 {
@@ -598,5 +759,5 @@
 			usb_log_warning("Failed to start a session: %s.\n",
 			    str_error(sess_rc));
-			continue;
+			break;
 		}
 
@@ -610,5 +771,5 @@
 			usb_log_warning("Error polling the keyboard: %s.\n",
 			    str_error(rc));
-			continue;
+			break;
 		}
 
@@ -616,5 +777,5 @@
 			usb_log_warning("Error closing session: %s.\n",
 			    str_error(sess_rc));
-			continue;
+			break;
 		}
 
@@ -634,13 +795,27 @@
 		usbhid_kbd_process_data(kbd_dev, buffer, actual_size);
 		
-		async_usleep(kbd_dev->hid_dev->poll_interval);
-	}
-
-	// not reached
-	assert(0);
-}
-
-/*----------------------------------------------------------------------------*/
-
+		// disabled for now, no reason to sleep
+		//async_usleep(kbd_dev->hid_dev->poll_interval);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Function executed by the main driver fibril.
+ *
+ * Just starts polling the keyboard for events.
+ * 
+ * @param arg Initialized keyboard device structure (of type usbhid_kbd_t) 
+ *            representing the device.
+ *
+ * @retval EOK if the fibril finished polling the device.
+ * @retval EINVAL if no device was given in the argument.
+ *
+ * @sa usbhid_kbd_poll()
+ *
+ * @todo Change return value - only case when the fibril finishes is in case
+ *       of some error, so the error should probably be propagated from function
+ *       usbhid_kbd_poll() to here and up.
+ */
 static int usbhid_kbd_fibril(void *arg)
 {
@@ -664,5 +839,29 @@
 /* API functions                                                              */
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Function for adding a new device of type USB/HID/keyboard.
+ *
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ * @note Currently supports only boot-protocol keyboards.
+ *
+ * @param dev Device to add.
+ *
+ * @retval EOK if successful.
+ * @retval ENOMEM if there
+ * @return Other error code inherited from one of functions usbhid_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ *
+ * @sa usbhid_kbd_fibril(), usbhid_kbd_repeat_fibril()
+ */
 int usbhid_kbd_try_add_device(ddf_dev_t *dev)
 {
@@ -686,5 +885,5 @@
 		    "structure.\n");
 		ddf_fun_destroy(kbd_fun);
-		return EINVAL;  // TODO: some other code??
+		return ENOMEM;  // TODO: some other code??
 	}
 	
@@ -735,4 +934,14 @@
 	}
 	fibril_add_ready(fid);
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid = fibril_create(usbhid_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
 
 	(void)keyboard_ops;
Index: uspace/drv/usbhid/kbddev.h
===================================================================
--- uspace/drv/usbhid/kbddev.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/kbddev.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -39,4 +39,6 @@
 #include <stdint.h>
 
+#include <fibril_synch.h>
+
 #include <usb/classes/hid.h>
 #include <ddf/driver.h>
@@ -46,20 +48,57 @@
 
 /*----------------------------------------------------------------------------*/
+/**
+ * Structure for keeping information needed for auto-repeat of keys.
+ */
+typedef struct {
+	/** Last pressed key. */
+	unsigned int key_new;
+	/** Key to be repeated. */
+	unsigned int key_repeated;
+	/** Delay before first repeat in microseconds. */
+	unsigned int delay_before;
+	/** Delay between repeats in microseconds. */
+	unsigned int delay_between;
+} usbhid_kbd_repeat_t;
 
 /**
- * @brief USB/HID keyboard device type.
+ * USB/HID keyboard device type.
+ *
+ * Holds a reference to generic USB/HID device structure and keyboard-specific
+ * data, such as currently pressed keys, modifiers and lock keys.
+ *
+ * Also holds a IPC phone to the console (since there is now no other way to 
+ * communicate with it).
+ *
+ * @note Storing active lock keys in this structure results in their setting
+ *       being device-specific.
  */
 typedef struct {
+	/** Structure holding generic USB/HID device information. */
 	usbhid_dev_t *hid_dev;
 	
-	uint8_t *keycodes;
-	size_t keycode_count;
+	/** Currently pressed keys (not translated to key codes). */
+	uint8_t *keys;
+	/** Count of stored keys (i.e. number of keys in the report). */
+	size_t key_count;
+	/** Currently pressed modifiers (bitmap). */
 	uint8_t modifiers;
 	
+	/** Currently active modifiers including locks. Sent to the console. */
 	unsigned mods;
+	
+	/** Currently active lock keys. */
 	unsigned lock_keys;
 	
+	/** IPC phone to the console device (for sending key events). */
 	int console_phone;
 	
+	/** Information for auto-repeat of keys. */
+	usbhid_kbd_repeat_t repeat;
+	
+	/** Mutex for accessing the information about auto-repeat. */
+	fibril_mutex_t *repeat_mtx;
+	
+	/** State of the structure (for checking before use). */
 	int initialized;
 } usbhid_kbd_t;
@@ -69,4 +108,6 @@
 int usbhid_kbd_try_add_device(ddf_dev_t *dev);
 
+void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, unsigned int key);
+
 #endif /* USBHID_KBDDEV_H_ */
 
Index: uspace/drv/usbhid/kbdrepeat.c
===================================================================
--- uspace/drv/usbhid/kbdrepeat.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/usbhid/kbdrepeat.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#include <fibril_synch.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+
+#include "kbdrepeat.h"
+#include "kbddev.h"
+
+
+/** Delay between auto-repeat state checks when no key is being repeated. */
+static unsigned int CHECK_DELAY = 10000;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Main loop handling the auto-repeat of keys.
+ *
+ * This functions periodically checks if there is some key to be auto-repeated.
+ *
+ * If a new key is to be repeated, it uses the delay before first repeat stored
+ * in the keyboard structure to wait until the key has to start repeating.
+ *
+ * If the same key is still pressed, it uses the delay between repeats stored
+ * in the keyboard structure to wait until the key should be repeated.
+ * 
+ * If the currently repeated key is not pressed any more (
+ * usbhid_kbd_repeat_stop() was called), it stops repeating it and starts 
+ * checking again.
+ *
+ * @note For accessing the keyboard device auto-repeat information a fibril
+ *       mutex (repeat_mtx) from the @a kbd structure is used.
+ * 
+ * @param kbd Keyboard device structure.
+ */
+static void usbhid_kbd_repeat_loop(usbhid_kbd_t *kbd)
+{
+	unsigned int delay = 0;
+	
+	usb_log_debug("Starting autorepeat loop.\n");
+
+	while (true) {
+		fibril_mutex_lock(kbd->repeat_mtx);
+
+		if (kbd->repeat.key_new > 0) {
+			if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
+				usb_log_debug2("Repeating key: %u.\n", 
+				    kbd->repeat.key_repeated);
+				usbhid_kbd_push_ev(kbd, KEY_PRESS, 
+				    kbd->repeat.key_repeated);
+				delay = kbd->repeat.delay_between;
+			} else {
+				usb_log_debug("New key to repeat: %u.\n", 
+				    kbd->repeat.key_new);
+				kbd->repeat.key_repeated = kbd->repeat.key_new;
+				delay = kbd->repeat.delay_before;
+			}
+		} else {
+			if (kbd->repeat.key_repeated > 0) {
+				usb_log_debug("Stopping to repeat key: %u.\n", 
+				    kbd->repeat.key_repeated);
+				kbd->repeat.key_repeated = 0;
+			}
+			delay = CHECK_DELAY;
+		}
+		fibril_mutex_unlock(kbd->repeat_mtx);
+		
+		async_usleep(delay);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Main routine to be executed by a fibril for handling auto-repeat.
+ *
+ * Starts the loop for checking changes in auto-repeat.
+ * 
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @retval EOK if the routine has finished.
+ * @retval EINVAL if no argument is supplied.
+ */
+int usbhid_kbd_repeat_fibril(void *arg)
+{
+	usb_log_debug("Autorepeat fibril spawned.\n");
+	
+	if (arg == NULL) {
+		usb_log_error("No device!\n");
+		return EINVAL;
+	}
+	
+	usbhid_kbd_t *kbd = (usbhid_kbd_t *)arg;
+	
+	usbhid_kbd_repeat_loop(kbd);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Start repeating particular key.
+ *
+ * @note Only one key is repeated at any time, so calling this function 
+ *       effectively cancels auto-repeat of the current repeated key (if any)
+ *       and 'schedules' another key for auto-repeat.
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to start repeating.
+ */
+void usbhid_kbd_repeat_start(usbhid_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(kbd->repeat_mtx);
+	kbd->repeat.key_new = key;
+	fibril_mutex_unlock(kbd->repeat_mtx);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Stop repeating particular key.
+ *
+ * @note Only one key is repeated at any time, but this function may be called
+ *       even with key that is not currently repeated (in that case nothing 
+ *       happens).
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to stop repeating.
+ */
+void usbhid_kbd_repeat_stop(usbhid_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(kbd->repeat_mtx);
+	if (key == kbd->repeat.key_new) {
+		kbd->repeat.key_new = 0;
+	}
+	fibril_mutex_unlock(kbd->repeat_mtx);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbdrepeat.h
===================================================================
--- uspace/drv/usbhid/kbdrepeat.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
+++ uspace/drv/usbhid/kbdrepeat.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#ifndef USBHID_KBDREPEAT_H_
+#define USBHID_KBDREPEAT_H_
+
+#include "kbddev.h"
+
+/*----------------------------------------------------------------------------*/
+
+int usbhid_kbd_repeat_fibril(void *arg);
+
+void usbhid_kbd_repeat_start(usbhid_kbd_t *kbd, unsigned int key);
+
+void usbhid_kbd_repeat_stop(usbhid_kbd_t *kbd, unsigned int key);
+
+#endif /* USBHID_KBDREPEAT_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhid/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -47,5 +47,14 @@
 
 /*----------------------------------------------------------------------------*/
-
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ *
+ * @retval EOK if successful. 
+ * @retval EREFUSED if the device is not supported.
+ */
 static int usbhid_add_device(ddf_dev_t *dev)
 {
@@ -80,5 +89,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_INFO, NAME);
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
 	return ddf_driver_main(&kbd_driver);
 }
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbhub/usbhub.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -118,6 +118,14 @@
 		dprintf(USB_LOG_LEVEL_ERROR,
 				"could not initialize connection to device endpoint, errno %d",opResult);
-	}
-	return opResult;
+		return opResult;
+	}
+
+	opResult = usb_endpoint_pipe_probe_default_control(&hub->endpoints.control);
+	if (opResult != EOK) {
+		dprintf(USB_LOG_LEVEL_ERROR, "failed probing endpoint 0, %d", opResult);
+		return opResult;
+	}
+
+	return EOK;
 }
 
@@ -233,4 +241,7 @@
 	dprintf(USB_LOG_LEVEL_DEBUG, "starting control transaction");
 	usb_endpoint_pipe_start_session(&result->endpoints.control);
+	opResult = usb_request_set_configuration(&result->endpoints.control, 1);
+	assert(opResult == EOK);
+
 	opResult = usb_request_get_descriptor(&result->endpoints.control,
 			USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
@@ -427,4 +438,5 @@
 			&new_device_pipe,
 			&new_device_connection);
+	usb_endpoint_pipe_probe_default_control(&new_device_pipe);
 	/// \TODO get highspeed info
 	usb_speed_t speed = isLowSpeed?USB_SPEED_LOW:USB_SPEED_FULL;
Index: uspace/drv/usbmid/main.c
===================================================================
--- uspace/drv/usbmid/main.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmid/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -44,4 +44,9 @@
 #include "usbmid.h"
 
+/** Callback when new MID device is attached to the host.
+ *
+ * @param gen_dev Generic DDF device representing the new device.
+ * @return Error code.
+ */
 static int usbmid_add_device(ddf_dev_t *gen_dev)
 {
@@ -86,8 +91,10 @@
 }
 
+/** USB MID driver ops. */
 static driver_ops_t mid_driver_ops = {
 	.add_device = usbmid_add_device,
 };
 
+/** USB MID driver. */
 static driver_t mid_driver = {
 	.name = NAME,
Index: uspace/drv/usbmid/usbmid.c
===================================================================
--- uspace/drv/usbmid/usbmid.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmid/usbmid.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -67,4 +67,5 @@
 }
 
+/** DDF interface of the child - interface function. */
 static usb_iface_t child_usb_iface = {
 	.get_hc_handle = usb_iface_get_hc_handle_hub_child_impl,
@@ -73,9 +74,10 @@
 };
 
-
+/** Operations for children - interface functions. */
 static ddf_dev_ops_t child_device_ops = {
 	.interfaces[USB_DEV_IFACE] = &child_usb_iface
 };
 
+/** Operations of the device itself. */
 static ddf_dev_ops_t mid_device_ops = {
 	.interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
@@ -114,4 +116,11 @@
 		return NULL;
 	}
+	rc = usb_endpoint_pipe_probe_default_control(&mid->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_error("Probing default control pipe failed: %s.\n",
+		    str_error(rc));
+		free(mid);
+		return NULL;
+	}
 
 	mid->dev = dev;
@@ -123,5 +132,5 @@
 /** Create new interface for USB MID device.
  *
- * @param dev Backing generic DDF child device (representing interface).
+ * @param fun Backing generic DDF device function (representing interface).
  * @param iface_no Interface number.
  * @return New interface.
Index: uspace/drv/usbmid/usbmid.h
===================================================================
--- uspace/drv/usbmid/usbmid.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmid/usbmid.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -44,4 +44,5 @@
 #define NAME "usbmid"
 
+/** USB MID device container. */
 typedef struct {
 	/** Device container. */
@@ -54,4 +55,6 @@
 } usbmid_device_t;
 
+
+/** Container for single interface in a MID device. */
 typedef struct {
 	/** Function container. */
Index: uspace/drv/usbmouse/init.c
===================================================================
--- uspace/drv/usbmouse/init.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmouse/init.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -42,5 +42,5 @@
 
 /** Mouse polling endpoint description for boot protocol subclass. */
-static usb_endpoint_description_t poll_endpoint_description = {
+usb_endpoint_description_t poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
@@ -51,54 +51,6 @@
 };
 
-/** Initialize poll pipe.
- *
- * Expects that session is already started on control pipe zero.
- *
- * @param mouse Mouse device.
- * @param my_interface Interface number.
- * @return Error code.
- */
-static int intialize_poll_pipe(usb_mouse_t *mouse, int my_interface)
-{
-	assert(usb_endpoint_pipe_is_session_started(&mouse->ctrl_pipe));
-
-	int rc;
-
-	void *config_descriptor;
-	size_t config_descriptor_size;
-
-	rc = usb_request_get_full_configuration_descriptor_alloc(
-	    &mouse->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	usb_endpoint_mapping_t endpoint_mapping[1] = {
-		{
-			.pipe = &mouse->poll_pipe,
-			.description = &poll_endpoint_description,
-			.interface_no = my_interface
-		}
-	};
-
-	rc = usb_endpoint_pipe_initialize_from_configuration(endpoint_mapping,
-	    1, config_descriptor, config_descriptor_size, &mouse->wire);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (!endpoint_mapping[0].present) {
-		return ENOENT;
-	}
-
-	mouse->poll_interval_us = 1000 * endpoint_mapping[0].descriptor->poll_interval;
-
-	usb_log_debug("prepared polling endpoint %d (interval %zu).\n",
-	    mouse->poll_pipe.endpoint_no, mouse->poll_interval_us);
-
-	return EOK;
-}
-
 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+/** Device ops for USB mouse. */
 static ddf_dev_ops_t mouse_ops = {
 	.default_handler = default_connection_handler
@@ -107,5 +59,5 @@
 /** Default handler for IPC methods not handled by DDF.
  *
- * @param dev Device handling the call.
+ * @param fun Device function handling the call.
  * @param icallid Call id.
  * @param icall Call data.
@@ -135,6 +87,12 @@
 }
 
-
-int usb_mouse_create(ddf_dev_t *dev)
+/** Create USB mouse device.
+ *
+ * The mouse device is stored into <code>dev-&gt;driver_data</code>.
+ *
+ * @param dev Generic device.
+ * @return Error code.
+ */
+int usb_mouse_create(usb_device_t *dev)
 {
 	usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t));
@@ -142,38 +100,11 @@
 		return ENOMEM;
 	}
-	mouse->device = dev;
+	mouse->dev = dev;
 	mouse->console_phone = -1;
 
 	int rc;
 
-	/* Initialize the backing connection. */
-	rc = usb_device_connection_initialize_from_device(&mouse->wire, dev);
-	if (rc != EOK) {
-		goto leave;
-	}
-
-	/* Initialize the default control pipe. */
-	rc = usb_endpoint_pipe_initialize_default_control(&mouse->ctrl_pipe,
-	    &mouse->wire);
-	if (rc != EOK) {
-		goto leave;
-	}
-
-	rc = usb_endpoint_pipe_start_session(&mouse->ctrl_pipe);
-	if (rc != EOK) {
-		goto leave;
-	}
-
-	rc = intialize_poll_pipe(mouse, usb_device_get_assigned_interface(dev));
-
-	/* We can ignore error here. */
-	usb_endpoint_pipe_end_session(&mouse->ctrl_pipe);
-
-	if (rc != EOK) {
-		goto leave;
-	}
-
 	/* Create DDF function. */
-	mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse");
+	mouse->mouse_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "mouse");
 	if (mouse->mouse_fun == NULL) {
 		rc = ENOMEM;
Index: uspace/drv/usbmouse/main.c
===================================================================
--- uspace/drv/usbmouse/main.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmouse/main.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -39,5 +39,10 @@
 #include <str_error.h>
 
-static int usbmouse_add_device(ddf_dev_t *dev)
+/** Callback when new mouse device is attached and recognised by DDF.
+ *
+ * @param dev Representation of a generic DDF device.
+ * @return Error code.
+ */
+static int usbmouse_add_device(usb_device_t *dev)
 {
 	int rc = usb_mouse_create(dev);
@@ -48,26 +53,37 @@
 	}
 
-	fid_t poll_fibril = fibril_create(usb_mouse_polling_fibril, dev);
-	if (poll_fibril == 0) {
-		usb_log_error("Failed to initialize polling fibril.\n");
-		/* FIXME: free allocated resources. */
-		return ENOMEM;
+	usb_log_debug("Polling pipe at endpoint %d.\n", dev->pipes[0].pipe->endpoint_no);
+
+	rc = usb_device_auto_poll(dev, 0,
+	    usb_mouse_polling_callback, dev->pipes[0].pipe->max_packet_size,
+	    usb_mouse_polling_ended_callback, dev->driver_data);
+
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril: %s.\n",
+		    str_error(rc));
+		return rc;
 	}
 
-	fibril_add_ready(poll_fibril);
-
 	usb_log_info("controlling new mouse (handle %llu).\n",
-	    dev->handle);
+	    dev->ddf_dev->handle);
 
 	return EOK;
 }
 
-static driver_ops_t mouse_driver_ops = {
+/** USB mouse driver ops. */
+static usb_driver_ops_t mouse_driver_ops = {
 	.add_device = usbmouse_add_device,
 };
 
-static driver_t mouse_driver = {
+static usb_endpoint_description_t *endpoints[] = {
+	&poll_endpoint_description,
+	NULL
+};
+
+/** USB mouse driver. */
+static usb_driver_t mouse_driver = {
 	.name = NAME,
-	.driver_ops = &mouse_driver_ops
+	.ops = &mouse_driver_ops,
+	.endpoints = endpoints
 };
 
@@ -76,5 +92,5 @@
 	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
 
-	return ddf_driver_main(&mouse_driver);
+	return usb_driver_main(&mouse_driver);
 }
 
Index: uspace/drv/usbmouse/mouse.c
===================================================================
--- uspace/drv/usbmouse/mouse.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmouse/mouse.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -37,85 +37,85 @@
 #include <usb/debug.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ipc/mouse.h>
 
-int usb_mouse_polling_fibril(void *arg)
+/** Mouse polling callback.
+ *
+ * @param dev Device that is being polled.
+ * @param buffer Data buffer.
+ * @param buffer_size Buffer size in bytes.
+ * @param arg Custom argument - points to usb_mouse_t.
+ * @return Always true.
+ */
+bool usb_mouse_polling_callback(usb_device_t *dev,
+    uint8_t *buffer, size_t buffer_size, void *arg)
 {
-	assert(arg != NULL);
-	ddf_dev_t *dev = (ddf_dev_t *) arg;
-	usb_mouse_t *mouse = (usb_mouse_t *) dev->driver_data;
+	usb_mouse_t *mouse = (usb_mouse_t *) arg;
 
-	assert(mouse);
+	usb_log_debug2("got buffer: %s.\n",
+	    usb_debug_str_buffer(buffer, buffer_size, 0));
 
-	size_t buffer_size = mouse->poll_pipe.max_packet_size;
+	uint8_t butt = buffer[0];
+	char str_buttons[4] = {
+		butt & 1 ? '#' : '.',
+		butt & 2 ? '#' : '.',
+		butt & 4 ? '#' : '.',
+		0
+	};
 
-	if (buffer_size < 4) {
-		usb_log_error("Weird mouse, results will be skewed.\n");
-		buffer_size = 4;
+	int shift_x = ((int) buffer[1]) - 127;
+	int shift_y = ((int) buffer[2]) - 127;
+	int wheel = ((int) buffer[3]) - 127;
+
+	if (buffer[1] == 0) {
+		shift_x = 0;
+	}
+	if (buffer[2] == 0) {
+		shift_y = 0;
+	}
+	if (buffer[3] == 0) {
+		wheel = 0;
 	}
 
-	uint8_t *buffer = malloc(buffer_size);
-	if (buffer == NULL) {
-		usb_log_error("Out of memory, poll fibril aborted.\n");
-		return ENOMEM;
+	if (mouse->console_phone >= 0) {
+		if ((shift_x != 0) || (shift_y != 0)) {
+			/* FIXME: guessed for QEMU */
+			async_req_2_0(mouse->console_phone,
+			    MEVENT_MOVE,
+			    - shift_x / 10,  - shift_y / 10);
+		}
+		if (butt) {
+			/* FIXME: proper button clicking. */
+			async_req_2_0(mouse->console_phone,
+			    MEVENT_BUTTON, 1, 1);
+			async_req_2_0(mouse->console_phone,
+			    MEVENT_BUTTON, 1, 0);
+		}
 	}
 
-	while (true) {
-		async_usleep(mouse->poll_interval_us);
+	usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
+	    str_buttons, shift_x, shift_y, wheel);
 
-		size_t actual_size;
+	/* Guess. */
+	async_usleep(1000);
 
-		/* FIXME: check for errors. */
-		usb_endpoint_pipe_start_session(&mouse->poll_pipe);
-
-		usb_endpoint_pipe_read(&mouse->poll_pipe,
-		    buffer, buffer_size, &actual_size);
-
-		usb_endpoint_pipe_end_session(&mouse->poll_pipe);
-
-		uint8_t butt = buffer[0];
-		char str_buttons[4] = {
-			butt & 1 ? '#' : '.',
-			butt & 2 ? '#' : '.',
-			butt & 4 ? '#' : '.',
-			0
-		};
-
-		int shift_x = ((int) buffer[1]) - 127;
-		int shift_y = ((int) buffer[2]) - 127;
-		int wheel = ((int) buffer[3]) - 127;
-
-		if (buffer[1] == 0) {
-			shift_x = 0;
-		}
-		if (buffer[2] == 0) {
-			shift_y = 0;
-		}
-		if (buffer[3] == 0) {
-			wheel = 0;
-		}
-
-		if (mouse->console_phone >= 0) {
-			if ((shift_x != 0) || (shift_y != 0)) {
-				/* FIXME: guessed for QEMU */
-				async_req_2_0(mouse->console_phone,
-				    MEVENT_MOVE,
-				    - shift_x / 10,  - shift_y / 10);
-			}
-			if (butt) {
-				/* FIXME: proper button clicking. */
-				async_req_2_0(mouse->console_phone,
-				    MEVENT_BUTTON, 1, 1);
-				async_req_2_0(mouse->console_phone,
-				    MEVENT_BUTTON, 1, 0);
-			}
-		}
-
-		usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
-		   str_buttons, shift_x, shift_y, wheel);
-	}
-
-	return EOK;
+	return true;
 }
 
+/** Callback when polling is terminated.
+ *
+ * @param dev Device where the polling terminated.
+ * @param recurring_errors Whether the polling was terminated due to
+ *	recurring errors.
+ * @param arg Custom argument - points to usb_mouse_t.
+ */
+void usb_mouse_polling_ended_callback(usb_device_t *dev,
+    bool recurring_errors, void *arg)
+{
+	usb_mouse_t *mouse = (usb_mouse_t *) arg;
+
+	async_hangup(mouse->console_phone);
+	mouse->console_phone = -1;
+}
 
 /**
Index: uspace/drv/usbmouse/mouse.h
===================================================================
--- uspace/drv/usbmouse/mouse.h	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/usbmouse/mouse.h	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -37,5 +37,5 @@
 #define USBMOUSE_MOUSE_H_
 
-#include <ddf/driver.h>
+#include <usb/devdrv.h>
 #include <usb/pipes.h>
 #include <time.h>
@@ -43,17 +43,24 @@
 #define NAME "usbmouse"
 
+/** Container for USB mouse device. */
 typedef struct {
-	ddf_dev_t *device;
+	/** Generic device container. */
+	usb_device_t *dev;
+	/** Function representing the device. */
 	ddf_fun_t *mouse_fun;
-	usb_device_connection_t wire;
-	usb_endpoint_pipe_t ctrl_pipe;
-	usb_endpoint_pipe_t poll_pipe;
+	/** Polling interval in microseconds. */
 	suseconds_t poll_interval_us;
+	/** IPC phone to console (consumer). */
 	int console_phone;
 } usb_mouse_t;
 
-int usb_mouse_create(ddf_dev_t *);
+#define POLL_PIPE(dev) ((dev)->pipes[0].pipe)
 
-int usb_mouse_polling_fibril(void *);
+extern usb_endpoint_description_t poll_endpoint_description;
+
+int usb_mouse_create(usb_device_t *);
+
+bool usb_mouse_polling_callback(usb_device_t *, uint8_t *, size_t, void *);
+void usb_mouse_polling_ended_callback(usb_device_t *, bool, void *);
 
 #endif
Index: uspace/drv/vhc/conndev.c
===================================================================
--- uspace/drv/vhc/conndev.c	(revision 3e7b7cd1a4fa51ff3ddd914472d15d1e5b670a7b)
+++ uspace/drv/vhc/conndev.c	(revision 72af8da9b8a1c4b2070e322bb32a8d379d171455)
@@ -110,5 +110,5 @@
 /** Callback for DDF when client disconnects.
  *
- * @param d Device the client was connected to.
+ * @param fun Device function the client was connected to.
  */
 void on_client_close(ddf_fun_t *fun)
