Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ HelenOS.config	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -537,7 +537,4 @@
 ! [CONFIG_BUILD_SHARED_LIBS=n] CONFIG_USE_SHARED_LIBS (n)
 
-% Run devman on startup
-! CONFIG_START_DEVMAN (y/n)
-
 % Launch (devman) test drivers
 ! [CONFIG_START_DEVMAN=y&CONFIG_DEBUG=y] CONFIG_TEST_DRIVERS (y/n)
@@ -563,2 +560,14 @@
 % Line debugging information
 ! [CONFIG_STRIP_BINARIES!=y] CONFIG_LINE_DEBUG (n/y)
+
+# USB settings 
+
+% USB release build (less logging)
+! CONFIG_USB_RELEASE_BUILD (y/n)
+
+% Start virtual USB host controller
+! CONFIG_RUN_VIRTUAL_USB_HC (n/y)
+
+% Polling UHCI & OHCI (no interrupts)
+! [PLATFORM=ia32|PLATFORM=amd64] CONFIG_USBHC_NO_INTERRUPTS (n/y)
+
Index: Makefile
===================================================================
--- Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -106,2 +106,4 @@
 	$(MAKE) -C uspace clean
 	$(MAKE) -C boot clean
+
+-include Makefile.local
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ boot/Makefile.common	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -97,4 +97,5 @@
 	$(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
 	$(USPACE_PATH)/srv/fs/fat/fat \
+	$(USPACE_PATH)/srv/fs/ext2fs/ext2fs \
 	$(USPACE_PATH)/srv/taskmon/taskmon \
 	$(USPACE_PATH)/srv/hw/netif/ne2000/ne2000 \
@@ -114,5 +115,6 @@
 	rootvirt \
 	test1 \
-	test2
+	test2 \
+	test3
 
 RD_DRV_CFG = 
@@ -134,15 +136,20 @@
 
 RD_APPS_NON_ESSENTIAL = \
+	$(USPACE_PATH)/app/blkdump/blkdump \
+	$(USPACE_PATH)/app/bnchmark/bnchmark \
 	$(USPACE_PATH)/app/dltest/dltest \
 	$(USPACE_PATH)/app/dltest2/dltest2 \
 	$(USPACE_PATH)/app/dload/dload \
 	$(USPACE_PATH)/app/edit/edit \
+	$(USPACE_PATH)/app/ext2info/ext2info \
 	$(USPACE_PATH)/app/kill/kill \
 	$(USPACE_PATH)/app/killall/killall \
 	$(USPACE_PATH)/app/mkfat/mkfat \
+	$(USPACE_PATH)/app/lsusb/lsusb \
 	$(USPACE_PATH)/app/sbi/sbi \
 	$(USPACE_PATH)/app/redir/redir \
 	$(USPACE_PATH)/app/taskdump/taskdump \
 	$(USPACE_PATH)/app/tester/tester \
+	$(USPACE_PATH)/app/testread/testread \
 	$(USPACE_PATH)/app/tetris/tetris \
 	$(USPACE_PATH)/app/trace/trace \
@@ -152,6 +159,9 @@
 	$(USPACE_PATH)/app/ping/ping \
 	$(USPACE_PATH)/app/stats/stats \
+	$(USPACE_PATH)/app/sysinfo/sysinfo \
 	$(USPACE_PATH)/app/top/top \
-	$(USPACE_PATH)/app/sysinfo/sysinfo \
+	$(USPACE_PATH)/app/usbinfo/usbinfo \
+	$(USPACE_PATH)/app/vuhid/vuh \
+	$(USPACE_PATH)/app/mkbd/mkbd \
 	$(USPACE_PATH)/app/websrv/websrv
 
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ boot/arch/amd64/Makefile.inc	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,5 +42,16 @@
 	pciintel \
 	isa \
-	ns8250
+	ns8250 \
+	ehci_hcd \
+	ohci \
+	uhci_hcd \
+	uhci_rhd \
+	usbflbk \
+	usbhub \
+	usbhid \
+	usbmast \
+	usbmid \
+	usbmouse \
+	vhc
 
 RD_DRV_CFG += \
Index: boot/generic/src/version.c
===================================================================
--- boot/generic/src/version.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ boot/generic/src/version.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -32,5 +32,5 @@
 
 static const char *project = "HelenOS bootloader";
-static const char *copyright = "Copyright (c) 2001-2010 HelenOS project";
+static const char *copyright = "Copyright (c) 2001-2011 HelenOS project";
 static const char *release = STRING(RELEASE);
 static const char *name = STRING(NAME);
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -329,43 +329,4 @@
 	endif
 	
-	ifeq ($(CONFIG_FPU),y)
-		ifeq ($(KARCH),ia32)
-			TEST_FPU1 = y
-			TEST_SSE1 = y
-			GENERIC_SOURCES += test/fpu/fpu1_x86.c
-		endif
-		
-		ifeq ($(KARCH),amd64)
-			TEST_FPU1 = y
-			TEST_SSE1 = y
-			GENERIC_SOURCES += test/fpu/fpu1_x86.c
-		endif
-		
-		ifeq ($(KARCH),ia64)
-			TEST_FPU1 = y
-			GENERIC_SOURCES += test/fpu/fpu1_ia64.c
-		endif
-		
-		ifeq ($(KARCH),mips32)
-			TEST_MIPS2 = y
-		endif
-	endif
-	
-	ifneq ($(TEST_FPU1),y)
-		GENERIC_SOURCES += test/fpu/fpu1_skip.c
-	endif
-	
-	ifeq ($(TEST_SSE1),y)
-		GENERIC_SOURCES += test/fpu/sse1.c
-	else
-		GENERIC_SOURCES += test/fpu/sse1_skip.c
-	endif
-	
-	ifeq ($(TEST_MIPS2),y)
-		GENERIC_SOURCES += test/fpu/mips2.c
-	else
-		GENERIC_SOURCES += test/fpu/mips2_skip.c
-	endif
-	
 endif
 
@@ -440,19 +401,4 @@
 endif
 
-#
-# The FPU tests are the only objects for which we allow the compiler to generate
-# FPU instructions.
-#
-
-test/fpu/%.o: test/fpu/%.c $(DEPEND)
-	$(CC) $(DEFS) $(CFLAGS) $(EXTRA_FLAGS) -c -o $@ $<
-ifeq ($(PRECHECK),y)
-	$(JOBFILE) $(JOB) $< $@ cc test $(DEFS) $(CFLAGS) $(EXTRA_FLAGS)
-endif
-
-#
-# Ordinary objects.
-#
-
 %.o: %.c $(DEPEND)
 	$(CC) $(DEFS) $(CFLAGS) $(EXTRA_FLAGS) $(FPU_NO_CFLAGS) $(if $(findstring $<,$(INSTRUMENTED_SOURCES)),$(INSTRUMENTATION)) -c -o $@ $<
Index: kernel/arch/ia64/include/register.h
===================================================================
--- kernel/arch/ia64/include/register.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/arch/ia64/include/register.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -60,4 +60,7 @@
 #define PSR_CPL_SHIFT         32
 #define PSR_CPL_MASK_SHIFTED  3
+
+#define PSR_RI_SHIFT	41
+#define PSR_RI_LEN	2
 
 #define PFM_MASK  (~0x3fffffffff)
Index: kernel/arch/ia64/src/ivt.S
===================================================================
--- kernel/arch/ia64/src/ivt.S	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/arch/ia64/src/ivt.S	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -50,4 +50,39 @@
 #define R_KSTACK_BSP	r22	/* keep in sync with before_thread_runs_arch() */
 #define R_KSTACK	r23	/* keep in sync with before_thread_runs_arch() */
+
+/* Speculation vector handler */
+.macro SPECULATION_VECTOR_HANDLER offs
+    .org ivt + \offs
+
+    /* 1. Save predicates, IIM, IIP, IPSR and ISR CR's in bank 0 registers. */
+	mov r16 = pr
+	mov r17 = cr.iim
+	mov r18 = cr.iip
+	mov r19 = cr.ipsr
+	mov r20 = cr.isr ;;
+	
+    /* 2. Move IIP to IIPA. */
+	mov cr.iipa = r18
+	
+    /* 3. Sign extend IIM[20:0], shift left by 4 and add to IIP. */
+	shl r17 = r17, 43 ;;	/* shift bit 20 to bit 63 */
+	shr r17 = r17, 39 ;;	/* signed shift right to bit 24 */
+	add r18 = r18, r17 ;;
+	mov cr.iip = r18
+	
+    /* 4. Set IPSR.ri to 0. */
+	dep r19 = 0, r19, PSR_RI_SHIFT, PSR_RI_LEN ;;
+	mov cr.ipsr = r19
+	
+    /* 5. Check whether IPSR.tb or IPSR.ss is set. */
+
+	/* TODO:
+	 * Implement this when Taken Branch and Single Step traps can occur.
+	 */
+    
+    /* 6. Restore predicates and return from interruption. */
+	mov pr = r16 ;;
+	rfi
+.endm
 
 /** Heavyweight interrupt handler
@@ -541,5 +576,5 @@
 	HEAVYWEIGHT_HANDLER 0x5500 disabled_fp_register
 	HEAVYWEIGHT_HANDLER 0x5600
-	HEAVYWEIGHT_HANDLER 0x5700
+	SPECULATION_VECTOR_HANDLER 0x5700
 	HEAVYWEIGHT_HANDLER 0x5800
 	HEAVYWEIGHT_HANDLER 0x5900
Index: kernel/arch/sparc64/Makefile.inc
===================================================================
--- kernel/arch/sparc64/Makefile.inc	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/arch/sparc64/Makefile.inc	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -31,5 +31,5 @@
 BFD = binary
 
-GCC_CFLAGS += -m64 -mcpu=ultrasparc -mcmodel=medlow
+GCC_CFLAGS += -m64 -mcpu=ultrasparc -mcmodel=medlow -mno-fpu
 SUNCC_CFLAGS += -m64 -xarch=sparc -xregs=appl,no%float
 
Index: kernel/generic/include/ddi/irq.h
===================================================================
--- kernel/generic/include/ddi/irq.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/include/ddi/irq.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -77,5 +77,26 @@
 	 */
 	CMD_PIO_WRITE_A_32,
-	
+
+	/** Read 1 byte from the memory space. */
+	CMD_MEM_READ_8,
+	/** Read 2 bytes from the memory space. */
+	CMD_MEM_READ_16,
+	/** Read 4 bytes from the memory space. */
+	CMD_MEM_READ_32,
+
+	/** Write 1 byte to the memory space. */
+	CMD_MEM_WRITE_8,
+	/** Write 2 bytes to the memory space. */
+	CMD_MEM_WRITE_16,
+	/** Write 4 bytes to the memory space. */
+	CMD_MEM_WRITE_32,
+
+	/** Write 1 byte from the source argument to the memory space. */
+	CMD_MEM_WRITE_A_8,
+	/** Write 2 bytes from the source argument to the memory space. */
+	CMD_MEM_WRITE_A_16,
+	/** Write 4 bytes from the source argument to the memory space. */
+	CMD_MEM_WRITE_A_32,
+
 	/**
 	 * Perform a bit masking on the source argument
@@ -203,4 +224,6 @@
 	/** Notification configuration structure. */
 	ipc_notif_cfg_t notif_cfg; 
+
+	as_t *driver_as;
 } irq_t;
 
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/include/ipc/ipc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -100,7 +100,4 @@
 #define IPC_GET_ARG5(data)  ((data).args[5])
 
-/* Well known phone descriptors */
-#define PHONE_NS  0
-
 /* Forwarding flags. */
 #define IPC_FF_NONE  0
@@ -117,150 +114,10 @@
 
 /* Data transfer flags. */
-#define IPC_XF_NONE		0
+#define IPC_XF_NONE  0
 
 /** Restrict the transfer size if necessary. */
-#define IPC_XF_RESTRICT		(1 << 0)
-
-/** Kernel IPC interfaces
- *
- */
-#define IPC_IF_KERNEL  0
-
-/** System-specific methods - only through special syscalls
- *
- * These methods have special behaviour. These methods also
- * have the implicit kernel interface 0.
- *
- */
-
-/** Clone connection.
- *
- * The calling task clones one of its phones for the callee.
- *
- * - ARG1 - The caller sets ARG1 to the phone of the cloned connection.
- *        - The callee gets the new phone from ARG1.
- *
- * - on answer, the callee acknowledges the new connection by sending EOK back
- *   or the kernel closes it
- *
- */
-#define IPC_M_CONNECTION_CLONE  1
-
-/** Protocol for CONNECT - ME
- *
- * Through this call, the recipient learns about the new cloned connection. 
- *
- * - ARG5 - the kernel sets ARG5 to contain the hash of the used phone
- * - on asnwer, the callee acknowledges the new connection by sending EOK back
- *   or the kernel closes it
- *
- */
-#define IPC_M_CONNECT_ME  2
-
-/** Protocol for CONNECT - TO - ME
- *
- * Calling process asks the callee to create a callback connection,
- * so that it can start initiating new messages.
- *
- * The protocol for negotiating is:
- * - sys_connect_to_me - sends a message IPC_M_CONNECT_TO_ME
- * - recipient         - upon receipt tries to allocate new phone
- *                       - if it fails, responds with ELIMIT
- *                     - passes call to userspace. If userspace
- *                       responds with error, phone is deallocated and
- *                       error is sent back to caller. Otherwise 
- *                       the call is accepted and the response is sent back.
- *                     - the hash of the client task is passed to userspace
- *                       (on the receiving side) as ARG4 of the call.
- *                     - the hash of the allocated phone is passed to userspace
- *                       (on the receiving side) as ARG5 of the call.
- *
- */
-#define IPC_M_CONNECT_TO_ME  3
-
-/** Protocol for CONNECT - ME - TO
- *
- * Calling process asks the callee to create for him a new connection.
- * E.g. the caller wants a name server to connect him to print server.
- *
- * The protocol for negotiating is:
- * - sys_connect_me_to - send a synchronous message to name server
- *                       indicating that it wants to be connected to some
- *                       service
- *                     - arg1/2/3 are user specified, arg5 contains
- *                       address of the phone that should be connected
- *                       (TODO: it leaks to userspace)
- *  - recipient        -  if ipc_answer == 0, then accept connection
- *                     -  otherwise connection refused
- *                     -  recepient may forward message.
- *
- */
-#define IPC_M_CONNECT_ME_TO  4
-
-/** This message is sent to answerbox when the phone is hung up
- *
- */
-#define IPC_M_PHONE_HUNGUP  5
-
-/** Send as_area over IPC.
- * - ARG1 - source as_area base address
- * - ARG2 - size of source as_area (filled automatically by kernel)
- * - ARG3 - flags of the as_area being sent
- *
- * on answer, the recipient must set:
- * - ARG1 - dst as_area base adress
- *
- */
-#define IPC_M_SHARE_OUT  6
-
-/** Receive as_area over IPC.
- * - ARG1 - destination as_area base address
- * - ARG2 - destination as_area size
- * - ARG3 - user defined argument
- *
- * on answer, the recipient must set:
- *
- * - ARG1 - source as_area base address
- * - ARG2 - flags that will be used for sharing
- *
- */
-#define IPC_M_SHARE_IN  7
-
-/** Send data to another address space over IPC.
- * - ARG1 - source address space virtual address
- * - ARG2 - size of data to be copied, may be overriden by the recipient
- *
- * on answer, the recipient must set:
- *
- * - ARG1 - final destination address space virtual address
- * - ARG2 - final size of data to be copied
- *
- */
-#define IPC_M_DATA_WRITE  8
-
-/** Receive data from another address space over IPC.
- * - ARG1 - destination virtual address in the source address space
- * - ARG2 - size of data to be received, may be cropped by the recipient 
- *
- * on answer, the recipient must set:
- *
- * - ARG1 - source virtual address in the destination address space
- * - ARG2 - final size of data to be copied
- *
- */
-#define IPC_M_DATA_READ  9
-
-/** Debug the recipient.
- * - ARG1 - specifies the debug method (from udebug_method_t)
- * - other arguments are specific to the debug method
- *
- */
-#define IPC_M_DEBUG_ALL  10
-
-/* Well-known methods */
-#define IPC_M_LAST_SYSTEM  511
-#define IPC_M_PING         512
-
-/* User methods */
+#define IPC_XF_RESTRICT  (1 << 0)
+
+/** User-defined IPC methods */
 #define IPC_FIRST_USER_METHOD  1024
 
Index: kernel/generic/include/ipc/ipc_methods.h
===================================================================
--- kernel/generic/include/ipc/ipc_methods.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ kernel/generic/include/ipc/ipc_methods.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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 genericipc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_IPC_METHODS_H_
+#define KERN_IPC_METHODS_H_
+
+/* Well known phone descriptors */
+#define PHONE_NS  0
+
+/** Kernel IPC interfaces
+ *
+ */
+#define IPC_IF_KERNEL  0
+
+/** System-specific IPC methods
+ *
+ * These methods have special behaviour. These methods also
+ * have the implicit kernel interface zero (0).
+ *
+ */
+
+/** This message is sent to answerbox when the phone is hung up
+ *
+ * The numerical value zero (0) of this method is important,
+ * so as the value can be easily tested in conditions.
+ *
+ */
+#define IPC_M_PHONE_HUNGUP  0
+
+/** Clone connection.
+ *
+ * The calling task clones one of its phones for the callee.
+ *
+ * - ARG1 - The caller sets ARG1 to the phone of the cloned connection.
+ *        - The callee gets the new phone from ARG1.
+ *
+ * - on answer, the callee acknowledges the new connection by sending EOK back
+ *   or the kernel closes it
+ *
+ */
+#define IPC_M_CONNECTION_CLONE  1
+
+/** Protocol for CONNECT - ME
+ *
+ * Through this call, the recipient learns about the new cloned connection.
+ *
+ * - ARG5 - the kernel sets ARG5 to contain the hash of the used phone
+ * - on answer, the callee acknowledges the new connection by sending EOK back
+ *   or the kernel closes it
+ *
+ */
+#define IPC_M_CONNECT_ME  2
+
+/** Protocol for CONNECT - TO - ME
+ *
+ * Calling process asks the callee to create a callback connection,
+ * so that it can start initiating new messages.
+ *
+ * The protocol for negotiating is:
+ * - sys_connect_to_me - sends a message IPC_M_CONNECT_TO_ME
+ * - recipient         - upon receipt tries to allocate new phone
+ *                       - if it fails, responds with ELIMIT
+ *                     - passes call to userspace. If userspace
+ *                       responds with error, phone is deallocated and
+ *                       error is sent back to caller. Otherwise 
+ *                       the call is accepted and the response is sent back.
+ *                     - the hash of the client task is passed to userspace
+ *                       (on the receiving side) as ARG4 of the call.
+ *                     - the hash of the allocated phone is passed to userspace
+ *                       (on the receiving side) as ARG5 of the call.
+ *
+ */
+#define IPC_M_CONNECT_TO_ME  3
+
+/** Protocol for CONNECT - ME - TO
+ *
+ * Calling process asks the callee to create for him a new connection.
+ * E.g. the caller wants a name server to connect him to print server.
+ *
+ * The protocol for negotiating is:
+ * - sys_connect_me_to - send a synchronous message to name server
+ *                       indicating that it wants to be connected to some
+ *                       service
+ *                     - arg1/2/3 are user specified, arg5 contains
+ *                       address of the phone that should be connected
+ *                       (TODO: it leaks to userspace)
+ *  - recipient        -  if ipc_answer == 0, then accept connection
+ *                     -  otherwise connection refused
+ *                     -  recepient may forward message.
+ *
+ */
+#define IPC_M_CONNECT_ME_TO  4
+
+/** Send as_area over IPC.
+ * - ARG1 - source as_area base address
+ * - ARG2 - size of source as_area (filled automatically by kernel)
+ * - ARG3 - flags of the as_area being sent
+ *
+ * on answer, the recipient must set:
+ * - ARG1 - dst as_area base adress
+ *
+ */
+#define IPC_M_SHARE_OUT  5
+
+/** Receive as_area over IPC.
+ * - ARG1 - destination as_area base address
+ * - ARG2 - destination as_area size
+ * - ARG3 - user defined argument
+ *
+ * on answer, the recipient must set:
+ *
+ * - ARG1 - source as_area base address
+ * - ARG2 - flags that will be used for sharing
+ *
+ */
+#define IPC_M_SHARE_IN  6
+
+/** Send data to another address space over IPC.
+ * - ARG1 - source address space virtual address
+ * - ARG2 - size of data to be copied, may be overriden by the recipient
+ *
+ * on answer, the recipient must set:
+ *
+ * - ARG1 - final destination address space virtual address
+ * - ARG2 - final size of data to be copied
+ *
+ */
+#define IPC_M_DATA_WRITE  7
+
+/** Receive data from another address space over IPC.
+ * - ARG1 - destination virtual address in the source address space
+ * - ARG2 - size of data to be received, may be cropped by the recipient 
+ *
+ * on answer, the recipient must set:
+ *
+ * - ARG1 - source virtual address in the destination address space
+ * - ARG2 - final size of data to be copied
+ *
+ */
+#define IPC_M_DATA_READ  8
+
+/** Debug the recipient.
+ * - ARG1 - specifies the debug method (from udebug_method_t)
+ * - other arguments are specific to the debug method
+ *
+ */
+#define IPC_M_DEBUG  9
+
+/** Last system IPC method */
+#define IPC_M_LAST_SYSTEM  511
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/mm/page.h
===================================================================
--- kernel/generic/include/mm/page.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/include/mm/page.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 
 #include <typedefs.h>
+#include <proc/task.h>
 #include <mm/as.h>
 #include <arch/mm/page.h>
@@ -65,4 +66,6 @@
 extern uintptr_t hw_map(uintptr_t, size_t);
 
+extern sysarg_t sys_page_find_mapping(uintptr_t, uintptr_t *);
+
 #endif
 
Index: kernel/generic/include/proc/thread.h
===================================================================
--- kernel/generic/include/proc/thread.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/include/proc/thread.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -258,4 +258,5 @@
 extern sysarg_t sys_thread_get_id(thread_id_t *);
 extern sysarg_t sys_thread_usleep(uint32_t);
+extern sysarg_t sys_thread_udelay(uint32_t);
 
 #endif
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/include/syscall/syscall.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,4 +44,5 @@
 	SYS_THREAD_GET_ID,
 	SYS_THREAD_USLEEP,
+	SYS_THREAD_UDELAY,
 	
 	SYS_TASK_GET_ID,
@@ -60,4 +61,6 @@
 	SYS_AS_AREA_DESTROY,
 	SYS_AS_GET_UNMAPPED_AREA,
+	
+	SYS_PAGE_FIND_MAPPING,
 	
 	SYS_IPC_CALL_SYNC_FAST,
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/interrupt/interrupt.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -177,4 +177,5 @@
 	    (void *) istate_get_pc(istate));
 	
+	istate_decode(istate);
 	stack_trace_istate(istate);
 	
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/ipc/ipc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,4 +44,5 @@
 #include <synch/synch.h>
 #include <ipc/ipc.h>
+#include <ipc/ipc_methods.h>
 #include <ipc/kbox.h>
 #include <ipc/event.h>
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/ipc/irq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -174,4 +174,5 @@
 	irq->notif_cfg.code = code;
 	irq->notif_cfg.counter = 0;
+	irq->driver_as = AS;
 	
 	/*
@@ -364,4 +365,23 @@
 		return IRQ_DECLINE;
 	
+#define CMD_MEM_READ(target) \
+do { \
+	void *va = code->cmds[i].addr; \
+	if (AS != irq->driver_as) \
+		as_switch(AS, irq->driver_as); \
+	memcpy_from_uspace(&target, va, (sizeof(target))); \
+	if (dstarg) \
+		scratch[dstarg] = target; \
+} while(0)
+
+#define CMD_MEM_WRITE(val) \
+do { \
+	void *va = code->cmds[i].addr; \
+	if (AS != irq->driver_as) \
+		as_switch(AS, irq->driver_as); \
+	memcpy_to_uspace(va, &val, sizeof(val)); \
+} while (0)
+
+	as_t *current_as = AS;
 	size_t i;
 	for (i = 0; i < code->cmdcount; i++) {
@@ -422,4 +442,52 @@
 			}
 			break;
+		case CMD_MEM_READ_8: {
+			uint8_t val;
+			CMD_MEM_READ(val);
+			break;
+			}
+		case CMD_MEM_READ_16: {
+			uint16_t val;
+			CMD_MEM_READ(val);
+			break;
+			}
+		case CMD_MEM_READ_32: {
+			uint32_t val;
+			CMD_MEM_READ(val);
+			break;
+			}
+		case CMD_MEM_WRITE_8: {
+			uint8_t val = code->cmds[i].value;
+			CMD_MEM_WRITE(val);
+			break;
+			}
+		case CMD_MEM_WRITE_16: {
+			uint16_t val = code->cmds[i].value;
+			CMD_MEM_WRITE(val);
+			break;
+			}
+		case CMD_MEM_WRITE_32: {
+			uint32_t val = code->cmds[i].value;
+			CMD_MEM_WRITE(val);
+			break;
+			}
+		case CMD_MEM_WRITE_A_8:
+			if (srcarg) {
+				uint8_t val = scratch[srcarg];
+				CMD_MEM_WRITE(val);
+			}
+			break;
+		case CMD_MEM_WRITE_A_16:
+			if (srcarg) {
+				uint16_t val = scratch[srcarg];
+				CMD_MEM_WRITE(val);
+			}
+			break;
+		case CMD_MEM_WRITE_A_32:
+			if (srcarg) {
+				uint32_t val = scratch[srcarg];
+				CMD_MEM_WRITE(val);
+			}
+			break;
 		case CMD_BTEST:
 			if ((srcarg) && (dstarg)) {
@@ -435,10 +503,16 @@
 			break;
 		case CMD_ACCEPT:
+			if (AS != current_as)
+				as_switch(AS, current_as);
 			return IRQ_ACCEPT;
 		case CMD_DECLINE:
 		default:
+			if (AS != current_as)
+				as_switch(AS, current_as);
 			return IRQ_DECLINE;
 		}
 	}
+	if (AS != current_as)
+		as_switch(AS, current_as);
 	
 	return IRQ_DECLINE;
Index: kernel/generic/src/ipc/kbox.c
===================================================================
--- kernel/generic/src/ipc/kbox.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/ipc/kbox.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 #include <synch/mutex.h>
 #include <ipc/ipc.h>
+#include <ipc/ipc_methods.h>
 #include <ipc/ipcrsc.h>
 #include <arch.h>
@@ -169,5 +170,5 @@
 		switch (IPC_GET_IMETHOD(call->data)) {
 		
-		case IPC_M_DEBUG_ALL:
+		case IPC_M_DEBUG:
 			/* Handle debug call. */
 			udebug_call_receive(call);
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/ipc/sysipc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,4 +40,5 @@
 #include <debug.h>
 #include <ipc/ipc.h>
+#include <ipc/ipc_methods.h>
 #include <ipc/sysipc.h>
 #include <ipc/irq.h>
@@ -460,5 +461,5 @@
 	}
 #ifdef CONFIG_UDEBUG
-	case IPC_M_DEBUG_ALL:
+	case IPC_M_DEBUG:
 		return udebug_request_preprocess(call, phone);
 #endif
@@ -495,5 +496,5 @@
 		/*
 		 * This must be an affirmative answer to IPC_M_DATA_READ
-		 * or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ...
+		 * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
 		 *
 		 */
@@ -531,5 +532,5 @@
 	
 	switch (IPC_GET_IMETHOD(call->data)) {
-	case IPC_M_DEBUG_ALL:
+	case IPC_M_DEBUG:
 		return -1;
 	default:
Index: kernel/generic/src/lib/memfnc.c
===================================================================
--- kernel/generic/src/lib/memfnc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/lib/memfnc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -56,9 +56,8 @@
 void *memset(void *dst, int val, size_t cnt)
 {
-	size_t i;
-	uint8_t *ptr = (uint8_t *) dst;
+	uint8_t *dp = (uint8_t *) dst;
 	
-	for (i = 0; i < cnt; i++)
-		ptr[i] = val;
+	while (cnt-- != 0)
+		*dp++ = val;
 	
 	return dst;
@@ -83,5 +82,5 @@
 	
 	while (cnt-- != 0)
-			*dp++ = *sp++;
+		*dp++ = *sp++;
 	
 	return dst;
Index: kernel/generic/src/main/version.c
===================================================================
--- kernel/generic/src/main/version.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/main/version.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 
 static const char *project = "SPARTAN kernel";
-static const char *copyright = "Copyright (c) 2001-2010 HelenOS project";
+static const char *copyright = "Copyright (c) 2001-2011 HelenOS project";
 static const char *release = STRING(RELEASE);
 static const char *name = STRING(NAME);
Index: kernel/generic/src/mm/page.c
===================================================================
--- kernel/generic/src/mm/page.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/mm/page.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -60,4 +60,6 @@
 
 #include <mm/page.h>
+#include <genarch/mm/page_ht.h>
+#include <genarch/mm/page_pt.h>
 #include <arch/mm/page.h>
 #include <arch/mm/asid.h>
@@ -70,4 +72,6 @@
 #include <debug.h>
 #include <arch.h>
+#include <syscall/copy.h>
+#include <errno.h>
 
 /** Virtual operations for page subsystem. */
@@ -172,4 +176,35 @@
 }
 
+/** Syscall wrapper for getting mapping of a virtual page.
+ * 
+ * @retval EOK Everything went find, @p uspace_frame and @p uspace_node
+ *             contains correct values.
+ * @retval ENOENT Virtual address has no mapping.
+ */
+sysarg_t sys_page_find_mapping(uintptr_t virt_address,
+    uintptr_t *uspace_frame)
+{
+	mutex_lock(&AS->lock);
+	
+	pte_t *pte = page_mapping_find(AS, virt_address, false);
+	if (!PTE_VALID(pte) || !PTE_PRESENT(pte)) {
+		mutex_unlock(&AS->lock);
+		
+		return (sysarg_t) ENOENT;
+	}
+	
+	uintptr_t phys_address = PTE_GET_FRAME(pte);
+	
+	mutex_unlock(&AS->lock);
+	
+	int rc = copy_to_uspace(uspace_frame,
+	    &phys_address, sizeof(phys_address));
+	if (rc != EOK) {
+		return (sysarg_t) rc;
+	}
+	
+	return EOK;
+}
+
 /** @}
  */
Index: kernel/generic/src/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/proc/thread.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -55,4 +55,5 @@
 #include <time/clock.h>
 #include <time/timeout.h>
+#include <time/delay.h>
 #include <config.h>
 #include <arch/interrupt.h>
@@ -912,4 +913,10 @@
 }
 
+sysarg_t sys_thread_udelay(uint32_t usec)
+{
+	delay(usec);
+	return 0;
+}
+
 /** @}
  */
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/generic/src/syscall/syscall.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,4 +41,5 @@
 #include <proc/program.h>
 #include <mm/as.h>
+#include <mm/page.h>
 #include <print.h>
 #include <arch.h>
@@ -118,4 +119,5 @@
 
 syshandler_t syscall_table[SYSCALL_END] = {
+	/* System management syscalls. */
 	(syshandler_t) sys_klog,
 	(syshandler_t) sys_tls_set,
@@ -126,4 +128,5 @@
 	(syshandler_t) sys_thread_get_id,
 	(syshandler_t) sys_thread_usleep,
+	(syshandler_t) sys_thread_udelay,
 	
 	(syshandler_t) sys_task_get_id,
@@ -144,4 +147,7 @@
 	(syshandler_t) sys_as_area_destroy,
 	(syshandler_t) sys_as_get_unmapped_area,
+	
+	/* Page mapping related syscalls. */
+	(syshandler_t) sys_page_find_mapping,
 	
 	/* IPC related syscalls. */
@@ -174,5 +180,5 @@
 	(syshandler_t) sys_unregister_irq,
 	
-	/* Sysinfo syscalls */
+	/* Sysinfo syscalls. */
 	(syshandler_t) sys_sysinfo_get_tag,
 	(syshandler_t) sys_sysinfo_get_value,
Index: rnel/test/fpu/fpu1.def
===================================================================
--- kernel/test/fpu/fpu1.def	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"fpu1",
-	"Intel FPU test",
-	&test_fpu1,
-	true
-},
Index: rnel/test/fpu/fpu1_ia64.c
===================================================================
--- kernel/test/fpu/fpu1_ia64.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,172 +1,0 @@
-/*
- * Copyright (c) 2005 Jakub Vana
- * Copyright (c) 2005 Jakub Jermar
- * 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.
- */
-
-#include <print.h>
-#include <debug.h>
-
-#include <test.h>
-#include <atomic.h>
-#include <proc/thread.h>
-
-#include <arch.h>
-#include <arch/arch.h>
-
-
-#define THREADS   150
-#define ATTEMPTS  100
-
-#define E_10e8   271828182
-#define PI_10e8  3141592
-
-static inline long double sqrt(long double a)
-{
-	long double x =	1;
-	long double lx = 0;
-	
-	if (a < 0.00000000000000001)
-		return 0;
-		
-	while (x != lx) {
-		lx = x;
-		x = (x + (a / x)) / 2;
-	}
-	
-	return x;
-}
-
-static atomic_t threads_ok;
-static atomic_t threads_fault;
-static waitq_t can_start;
-
-static void e(void *data)
-{
-	int i;
-	double e, d, le, f;
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i<ATTEMPTS; i++) {
-		le = -1;
-		e = 0;
-		f = 1;
-		
-		for (d = 1; e != le; d *= f, f += 1) {
-			le = e;
-			e = e + 1 / d;
-		}
-		
-		if ((int) (100000000 * e) != E_10e8) {
-			TPRINTF("tid%" PRIu64 ": e*10e8=%zd should be %" PRIun "\n", THREAD->tid, (sysarg_t) (100000000 * e), (sysarg_t) E_10e8);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-static void pi(void *data)
-{
-	int i;
-	double lpi, pi;
-	double n, ab, ad;
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i < ATTEMPTS; i++) {
-		lpi = -1;
-		pi = 0;
-		
-		for (n = 2, ab = sqrt(2); lpi != pi; n *= 2, ab = ad) {
-			double sc, cd;
-			
-			sc = sqrt(1 - (ab * ab / 4));
-			cd = 1 - sc;
-			ad = sqrt(ab * ab / 4 + cd * cd);
-			lpi = pi;
-			pi = 2 * n * ad;
-		}
-		
-		if ((int) (1000000 * pi) != PI_10e8) {
-			TPRINTF("tid%" PRIu64 ": pi*10e8=%zd should be %" PRIun "\n", THREAD->tid, (sysarg_t) (1000000 * pi), (sysarg_t) (PI_10e8 / 100));
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-const char *test_fpu1(void)
-{
-	unsigned int i;
-	atomic_count_t total = 0;
-	
-	waitq_initialize(&can_start);
-	atomic_set(&threads_ok, 0);
-	atomic_set(&threads_fault, 0);
-	
-	TPRINTF("Creating %u threads... ", 2 * THREADS);
-	
-	for (i = 0; i < THREADS; i++) {
-		thread_t *t;
-		
-		if (!(t = thread_create(e, NULL, TASK, 0, "e", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i);
-			break;
-		}
-		thread_ready(t);
-		total++;
-		
-		if (!(t = thread_create(pi, NULL, TASK, 0, "pi", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i + 1);
-			break;
-		}
-		thread_ready(t);
-		total++;
-	}
-	
-	TPRINTF("ok\n");
-	
-	thread_sleep(1);
-	waitq_wakeup(&can_start, WAKEUP_ALL);
-	
-	while (atomic_get(&threads_ok) != total) {
-		TPRINTF("Threads left: %" PRIua "\n",
-		    total - atomic_get(&threads_ok));
-		thread_sleep(1);
-	}
-	
-	if (atomic_get(&threads_fault) == 0)
-		return NULL;
-	
-	return "Test failed";
-}
Index: rnel/test/fpu/fpu1_skip.c
===================================================================
--- kernel/test/fpu/fpu1_skip.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,34 +1,0 @@
-/*
- * Copyright (c) 2009 Martin Decky
- * 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.
- */
-
-#include <test.h>
-
-const char *test_fpu1(void)
-{
-	return NULL;
-}
Index: rnel/test/fpu/fpu1_x86.c
===================================================================
--- kernel/test/fpu/fpu1_x86.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,170 +1,0 @@
-/*
- * Copyright (c) 2005 Jakub Vana
- * Copyright (c) 2005 Jakub Jermar
- * 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.
- */
-
-#include <print.h>
-#include <debug.h>
-
-#include <test.h>
-#include <atomic.h>
-#include <proc/thread.h>
-
-#include <arch.h>
-#include <arch/arch.h>
-
-
-#define THREADS   150
-#define ATTEMPTS  100
-
-#define E_10e8   271828182
-#define PI_10e8  314159265
-
-static inline double sqrt(double x)
-{
-	double v;
-	
-	asm (
-		"fsqrt\n"
-		: "=t" (v)
-		: "0" (x)
-	);
-	
-	return v;
-}
-
-static atomic_t threads_ok;
-static atomic_t threads_fault;
-static waitq_t can_start;
-
-static void e(void *data)
-{
-	int i;
-	double e, d, le, f;
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i<ATTEMPTS; i++) {
-		le = -1;
-		e = 0;
-		f = 1;
-		
-		for (d = 1; e != le; d *= f, f += 1) {
-			le = e;
-			e = e + 1 / d;
-		}
-		
-		if ((int) (100000000 * e) != E_10e8) {
-			TPRINTF("tid%" PRIu64 ": e*10e8=%" PRIun " should be %" PRIun "\n",
-			    THREAD->tid, (sysarg_t) (100000000 * e), (sysarg_t) E_10e8);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-static void pi(void *data)
-{
-	int i;
-	double lpi, pi;
-	double n, ab, ad;
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i < ATTEMPTS; i++) {
-		lpi = -1;
-		pi = 0;
-		
-		for (n = 2, ab = sqrt(2); lpi != pi; n *= 2, ab = ad) {
-			double sc, cd;
-			
-			sc = sqrt(1 - (ab * ab / 4));
-			cd = 1 - sc;
-			ad = sqrt(ab * ab / 4 + cd * cd);
-			lpi = pi;
-			pi = 2 * n * ad;
-		}
-		
-		if ((int) (100000000 * pi) != PI_10e8) {
-			TPRINTF("tid%" PRIu64 ": pi*10e8=%" PRIun " should be %" PRIun "\n",
-			    THREAD->tid, (sysarg_t) (100000000 * pi), (sysarg_t) PI_10e8);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-const char *test_fpu1(void)
-{
-	unsigned int i;
-	atomic_count_t total = 0;
-	
-	waitq_initialize(&can_start);
-	atomic_set(&threads_ok, 0);
-	atomic_set(&threads_fault, 0);
-	
-	TPRINTF("Creating %u threads... ", 2 * THREADS);
-	
-	for (i = 0; i < THREADS; i++) {
-		thread_t *t;
-		
-		if (!(t = thread_create(e, NULL, TASK, 0, "e", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i);
-			break;
-		}
-		thread_ready(t);
-		total++;
-		
-		if (!(t = thread_create(pi, NULL, TASK, 0, "pi", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i + 1);
-			break;
-		}
-		thread_ready(t);
-		total++;
-	}
-	
-	TPRINTF("ok\n");
-	
-	thread_sleep(1);
-	waitq_wakeup(&can_start, WAKEUP_ALL);
-	
-	while (atomic_get(&threads_ok) != total) {
-		TPRINTF("Threads left: %" PRIua "\n", total - atomic_get(&threads_ok));
-		thread_sleep(1);
-	}
-	
-	if (atomic_get(&threads_fault) == 0)
-		return NULL;
-	
-	return "Test failed";
-}
Index: rnel/test/fpu/mips2.c
===================================================================
--- kernel/test/fpu/mips2.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,154 +1,0 @@
-/*
- * Copyright (c) 2005 Ondrej Palkovsky
- * 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.
- */
-
-#include <print.h>
-#include <debug.h>
-
-#include <test.h>
-#include <atomic.h>
-#include <proc/thread.h>
-#include <time/delay.h>
-
-#include <arch.h>
-
-#define THREADS   50
-#define DELAY     10000L
-#define ATTEMPTS  5
-
-static atomic_t threads_ok;
-static atomic_t threads_fault;
-static waitq_t can_start;
-
-static void testit1(void *data)
-{
-	int i;
-	int arg __attribute__((aligned(16))) = (int) ((sysarg_t) data);
-	int after_arg __attribute__((aligned(16)));
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i < ATTEMPTS; i++) {
-		asm volatile (
-			"mtc1 %0,$1"
-			: "=r" (arg)
-		);
-		
-		delay(DELAY);
-		
-		asm volatile (
-			"mfc1 %0, $1"
-			: "=r" (after_arg)
-		);
-		
-		if (arg != after_arg) {
-			TPRINTF("General reg tid%" PRIu64 ": arg(%d) != %d\n", THREAD->tid, arg, after_arg);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-static void testit2(void *data)
-{
-	int i;
-	int arg __attribute__((aligned(16))) = (int) ((sysarg_t) data);
-	int after_arg __attribute__((aligned(16)));
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i < ATTEMPTS; i++) {
-		asm volatile (
-			"mtc1 %0,$1"
-			: "=r" (arg)
-		);
-		
-		scheduler();
-		asm volatile (
-			"mfc1 %0,$1"
-			: "=r" (after_arg)
-		);
-		
-		if (arg != after_arg) {
-			TPRINTF("General reg tid%" PRIu64 ": arg(%d) != %d\n", THREAD->tid, arg, after_arg);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-
-const char *test_mips2(void)
-{
-	unsigned int i;
-	atomic_count_t total = 0;
-	
-	waitq_initialize(&can_start);
-	atomic_set(&threads_ok, 0);
-	atomic_set(&threads_fault, 0);
-	
-	TPRINTF("Creating %u threads... ", 2 * THREADS);
-	
-	for (i = 0; i < THREADS; i++) {
-		thread_t *t;
-		
-		if (!(t = thread_create(testit1, (void *) ((sysarg_t) 2 * i), TASK, 0, "testit1", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i);
-			break;
-		}
-		thread_ready(t);
-		total++;
-		
-		if (!(t = thread_create(testit2, (void *) ((sysarg_t) 2 * i + 1), TASK, 0, "testit2", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i + 1);
-			break;
-		}
-		thread_ready(t);
-		total++;
-	}
-	
-	TPRINTF("ok\n");
-	
-	thread_sleep(1);
-	waitq_wakeup(&can_start, WAKEUP_ALL);
-	
-	while (atomic_get(&threads_ok) != total) {
-		TPRINTF("Threads left: %d\n", total - atomic_get(&threads_ok));
-		thread_sleep(1);
-	}
-	
-	if (atomic_get(&threads_fault) == 0)
-		return NULL;
-	
-	return "Test failed";
-}
Index: rnel/test/fpu/mips2.def
===================================================================
--- kernel/test/fpu/mips2.def	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"mips2",
-	"MIPS FPU test",
-	&test_mips2,
-	true
-},
Index: rnel/test/fpu/mips2_skip.c
===================================================================
--- kernel/test/fpu/mips2_skip.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,34 +1,0 @@
-/*
- * Copyright (c) 2009 Martin Decky
- * 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.
- */
-
-#include <test.h>
-
-const char *test_mips2(void)
-{
-	return NULL;
-}
Index: rnel/test/fpu/sse1.c
===================================================================
--- kernel/test/fpu/sse1.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,152 +1,0 @@
-/*
- * Copyright (c) 2005 Ondrej Palkovsky
- * 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.
- */
-
-#include <print.h>
-#include <debug.h>
-
-#include <test.h>
-#include <atomic.h>
-#include <proc/thread.h>
-#include <time/delay.h>
-
-#include <arch.h>
-
-#define THREADS   25
-#define DELAY     10000L
-#define ATTEMPTS  5
-
-static atomic_t threads_ok;
-static atomic_t threads_fault;
-static waitq_t can_start;
-
-static void testit1(void *data)
-{
-	int i;
-	int arg __attribute__((aligned(16))) = (int) ((sysarg_t) data);
-	int after_arg __attribute__((aligned(16)));
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i < ATTEMPTS; i++) {
-		asm volatile (
-			"movlpd %[arg], %%xmm2\n"
-			: [arg] "=m" (arg)
-		);
-		
-		delay(DELAY);
-		asm volatile (
-			"movlpd %%xmm2, %[after_arg]\n"
-			: [after_arg] "=m" (after_arg)
-		);
-		
-		if (arg != after_arg) {
-			TPRINTF("tid%" PRIu64 ": arg(%d) != %d\n", THREAD->tid, arg, after_arg);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-static void testit2(void *data)
-{
-	int i;
-	int arg __attribute__((aligned(16))) = (int) ((sysarg_t) data);
-	int after_arg __attribute__((aligned(16)));
-	
-	thread_detach(THREAD);
-	
-	waitq_sleep(&can_start);
-	
-	for (i = 0; i < ATTEMPTS; i++) {
-		asm volatile (
-			"movlpd %[arg], %%xmm2\n"
-			: [arg] "=m" (arg)
-		);
-		
-		scheduler();
-		asm volatile (
-			"movlpd %%xmm2, %[after_arg]\n"
-			: [after_arg] "=m" (after_arg)
-		);
-		
-		if (arg != after_arg) {
-			TPRINTF("tid%" PRIu64 ": arg(%d) != %d\n", THREAD->tid, arg, after_arg);
-			atomic_inc(&threads_fault);
-			break;
-		}
-	}
-	atomic_inc(&threads_ok);
-}
-
-const char *test_sse1(void)
-{
-	unsigned int i;
-	atomic_count_t total = 0;
-	
-	waitq_initialize(&can_start);
-	atomic_set(&threads_ok, 0);
-	atomic_set(&threads_fault, 0);
-	
-	TPRINTF("Creating %u threads... ", 2 * THREADS);
-	
-	for (i = 0; i < THREADS; i++) {
-		thread_t *t;
-		
-		if (!(t = thread_create(testit1, (void *) ((sysarg_t) 2 * i), TASK, 0, "testit1", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i);
-			break;
-		}
-		thread_ready(t);
-		total++;
-		
-		if (!(t = thread_create(testit2, (void *) ((sysarg_t) 2 * i + 1), TASK, 0, "testit2", false))) {
-			TPRINTF("could not create thread %u\n", 2 * i + 1);
-			break;
-		}
-		thread_ready(t);
-		total++;
-	}
-	
-	TPRINTF("ok\n");
-	
-	thread_sleep(1);
-	waitq_wakeup(&can_start, WAKEUP_ALL);
-	
-	while (atomic_get(&threads_ok) != total) {
-		TPRINTF("Threads left: %" PRIua "\n", total - atomic_get(&threads_ok));
-		thread_sleep(1);
-	}
-	
-	if (atomic_get(&threads_fault) == 0)
-		return NULL;
-	
-	return "Test failed";
-}
Index: rnel/test/fpu/sse1.def
===================================================================
--- kernel/test/fpu/sse1.def	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"sse1",
-	"Intel SEE test",
-	&test_sse1,
-	true
-},
Index: rnel/test/fpu/sse1_skip.c
===================================================================
--- kernel/test/fpu/sse1_skip.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,34 +1,0 @@
-/*
- * Copyright (c) 2009 Martin Decky
- * 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.
- */
-
-#include <test.h>
-
-const char *test_sse1(void)
-{
-	return NULL;
-}
Index: kernel/test/test.c
===================================================================
--- kernel/test/test.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/test/test.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -43,7 +43,4 @@
 #include <debug/mips1.def>
 #include <fault/fault1.def>
-#include <fpu/fpu1.def>
-#include <fpu/sse1.def>
-#include <fpu/mips2.def>
 #include <mm/falloc1.def>
 #include <mm/falloc2.def>
Index: kernel/test/test.h
===================================================================
--- kernel/test/test.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ kernel/test/test.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -61,7 +61,4 @@
 extern const char *test_mips1(void);
 extern const char *test_fault1(void);
-extern const char *test_fpu1(void);
-extern const char *test_sse1(void);
-extern const char *test_mips2(void);
 extern const char *test_falloc1(void);
 extern const char *test_falloc2(void);
Index: tools/filldir.py
===================================================================
--- tools/filldir.py	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ tools/filldir.py	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2011 Martin Sucha
+# 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.
+#
+
+"""
+Fill a directory with N empty directories
+"""
+
+import sys
+import os
+import os.path
+
+if len(sys.argv) < 3:
+	print 'Usage: filldir <parent-dir> <count>'
+	exit(2)
+
+parent = sys.argv[1]
+num = int(sys.argv[2])
+
+i = 0
+while i < num:
+	name = hex(i)[2:].zfill(5)
+	path = os.path.join(parent, name)
+	os.mkdir(path)
+	i += 1
Index: tools/gentestfile.py
===================================================================
--- tools/gentestfile.py	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ tools/gentestfile.py	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2011 Martin Sucha
+# 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.
+#
+
+"""
+Generate a file to be used by app/testread
+"""
+
+import struct
+import sys
+
+if len(sys.argv) < 2:
+	print "Usage: gentestfile.py <count of 64-bit numbers to output>"
+	exit()
+
+m = long(sys.argv[1])
+i = 0
+pow_2_64 = 2 ** 64
+st = struct.Struct('<Q')
+while i < m:
+	sys.stdout.write(st.pack(i))
+	i = (i + 1) % pow_2_64
+
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,5 +35,8 @@
 DIRS = \
 	app/bdsh \
+	app/blkdump \
+	app/bnchmark \
 	app/edit \
+	app/ext2info \
 	app/getterm \
 	app/init \
@@ -41,4 +44,5 @@
 	app/killall \
 	app/klog \
+	app/lsusb \
 	app/mkfat \
 	app/redir \
@@ -47,7 +51,10 @@
 	app/taskdump \
 	app/tester \
+	app/testread \
 	app/tetris \
 	app/trace \
 	app/top \
+	app/usbinfo \
+	app/vuhid \
 	app/netecho \
 	app/nettest1 \
@@ -56,4 +63,5 @@
 	app/websrv \
 	app/sysinfo \
+	app/mkbd \
 	srv/clip \
 	srv/devmap \
@@ -72,4 +80,5 @@
 	srv/fs/tmpfs \
 	srv/fs/devfs \
+	srv/fs/ext2fs \
 	srv/hid/adb_mouse \
 	srv/hid/char_mouse \
@@ -90,5 +99,17 @@
 	drv/rootvirt \
 	drv/test1 \
-	drv/test2
+	drv/test2 \
+	drv/test3 \
+	drv/ehci_hcd \
+	drv/ohci \
+	drv/uhci_hcd \
+	drv/uhci_rhd \
+	drv/usbflbk \
+	drv/usbhid \
+	drv/usbhub \
+	drv/usbmast \
+	drv/usbmid \
+	drv/usbmouse \
+	drv/vhc
 
 ## Networking
@@ -149,4 +170,10 @@
 	lib/packet \
 	lib/net \
+	lib/ext2 \
+	lib/usb \
+	lib/usbhost \
+	lib/usbdev \
+	lib/usbhid \
+	lib/usbvirt \
 	lib/posix
 
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/Makefile.common	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -112,4 +112,12 @@
 LIBCLUI_PREFIX = $(LIB_PREFIX)/clui
 
+LIBEXT2_PREFIX = $(LIB_PREFIX)/ext2
+
+LIBUSB_PREFIX = $(LIB_PREFIX)/usb
+LIBUSBHOST_PREFIX = $(LIB_PREFIX)/usbhost
+LIBUSBDEV_PREFIX = $(LIB_PREFIX)/usbdev
+LIBUSBHID_PREFIX = $(LIB_PREFIX)/usbhid
+LIBUSBVIRT_PREFIX = $(LIB_PREFIX)/usbvirt
+
 LIBDRV_PREFIX = $(LIB_PREFIX)/drv
 LIBPACKET_PREFIX = $(LIB_PREFIX)/packet
@@ -130,4 +138,10 @@
 endif
 
+# Build static whenever we use libusb because that library uses 
+# thread local variables
+ifneq ($(findstring usb, $(LIBS)),)
+	STATIC_BUILD = y
+endif
+
 ifeq ($(STATIC_BUILD), y)
 BASE_LIBS = $(LIBC_PREFIX)/libc.a $(LIBSOFTINT_PREFIX)/libsoftint.a
Index: uspace/app/bdsh/cmds/modules/bdd/bdd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -102,5 +102,5 @@
 	}
 
-	rc = block_init(handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
 	if (rc != EOK)  {
 		printf("%s: Error initializing libblock.\n", cmdname);
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -64,4 +64,6 @@
 static sysarg_t console_rows = 0;
 static bool should_quit = false;
+
+static console_ctrl_t *console = NULL;
 
 static struct option const long_options[] = {
@@ -102,18 +104,20 @@
 static void waitprompt()
 {
-	console_set_pos(fphone(stdout), 0, console_rows-1);
-	console_set_color(fphone(stdout), COLOR_BLUE, COLOR_WHITE, 0);
+	console_set_pos(console, 0, console_rows-1);
+	console_set_color(console, COLOR_BLUE, COLOR_WHITE, 0);
+	
 	printf("ENTER/SPACE/PAGE DOWN - next page, "
 	       "ESC/Q - quit, C - continue unpaged");
 	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	
+	console_set_style(console, STYLE_NORMAL);
 }
 
 static void waitkey()
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	
 	while (true) {
-		if (!console_get_event(fphone(stdin), &ev)) {
+		if (!console_get_kbd_event(console, &ev)) {
 			return;
 		}
@@ -138,7 +142,7 @@
 static void newpage()
 {
-	console_clear(fphone(stdout));
+	console_clear(console);
 	chars_remaining = console_cols;
-	lines_remaining = console_rows-1;
+	lines_remaining = console_rows - 1;
 }
 
@@ -238,4 +242,5 @@
 	console_rows = 0;
 	should_quit = false;
+	console = console_init(stdin, stdout);
 
 	argc = cli_count_args(argv);
@@ -280,5 +285,5 @@
 	
 	if (more) {
-		rc = console_get_size(fphone(stdout), &cols, &rows);
+		rc = console_get_size(console, &cols, &rows);
 		if (rc != EOK) {
 			printf("%s - cannot get console size\n", cmdname);
Index: uspace/app/bdsh/cmds/modules/kcon/kcon.c
===================================================================
--- uspace/app/bdsh/cmds/modules/kcon/kcon.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/bdsh/cmds/modules/kcon/kcon.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -32,5 +32,4 @@
 #include <stdlib.h>
 #include <io/console.h>
-#include <vfs/vfs.h>
 #include "config.h"
 #include "util.h"
@@ -42,13 +41,12 @@
 static const char *cmdname = "kcon";
 
-/* Dispays help for kcon in various levels */
+/* Display help for kcon in various levels */
 void help_cmd_kcon(unsigned int level)
 {
 	printf("`kcon' switches to the kernel debug console.\n");
-
-	if (level != HELP_SHORT) {
-		printf("Usage:  %s\n", cmdname);
-	}
-
+	
+	if (level != HELP_SHORT)
+		printf("Usage: %s\n", cmdname);
+	
 	return;
 }
@@ -57,17 +55,15 @@
 int cmd_kcon(char **argv)
 {
-	unsigned int argc;
-
-	argc = cli_count_args(argv);
-
+	unsigned int argc = cli_count_args(argv);
+	
 	if (argc != 1) {
 		printf("%s - incorrect number of arguments. Try `%s --help'\n",
-			cmdname, cmdname);
+		    cmdname, cmdname);
 		return CMD_FAILURE;
 	}
-
-	console_kcon_enable(fphone(stdout));
-
-	return CMD_SUCCESS;
+	
+	if (console_kcon())
+		return CMD_SUCCESS;
+	else
+		return CMD_FAILURE;
 }
-
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -51,5 +51,5 @@
 {
 	static char helpfmt[] =
-	    "Usage:  %s <fstype> <mp> <dev> [<moptions>]\n";
+	    "Usage:  %s <fstype> <mp> [dev] [<moptions>]\n";
 	if (level == HELP_SHORT) {
 		printf("'%s' mounts a file system.\n", cmdname);
@@ -66,4 +66,5 @@
 	unsigned int argc;
 	const char *mopts = "";
+	const char *dev = "";
 	int rc, c, opt_ind;
 
@@ -79,13 +80,15 @@
 	}
 
-	if ((argc < 4) || (argc > 5)) {
+	if ((argc < 3) || (argc > 5)) {
 		printf("%s: invalid number of arguments. Try `mount --help'\n",
 		    cmdname);
 		return CMD_FAILURE;
 	}
+	if (argc > 3)
+		dev = argv[3];
 	if (argc == 5)
 		mopts = argv[4];
 
-	rc = mount(argv[1], argv[2], argv[3], mopts, 0);
+	rc = mount(argv[1], argv[2], dev, mopts, 0);
 	if (rc != EOK) {
 		printf("Unable to mount %s filesystem to %s on %s (rc=%d)\n",
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/bdsh/input.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -110,10 +110,10 @@
 	char *str;
 	int rc;
-
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_EMPHASIS);
+	
+	console_flush(tinput->console);
+	console_set_style(tinput->console, STYLE_EMPHASIS);
 	printf("%s", usr->prompt);
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(tinput->console);
+	console_set_style(tinput->console, STYLE_NORMAL);
 
 	rc = tinput_read(tinput, &str);
Index: uspace/app/blkdump/Makefile
===================================================================
--- uspace/app/blkdump/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/blkdump/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = $(LIBBLOCK_PREFIX)/libblock.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
+BINARY = blkdump
+
+SOURCES = \
+	blkdump.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/blkdump/blkdump.c
===================================================================
--- uspace/app/blkdump/blkdump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/blkdump/blkdump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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 fs
+ * @{
+ */
+
+/**
+ * @file	blockdump.c
+ * @brief	Tool for dumping content of block devices
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#define NAME	"blkdump"
+
+static void syntax_print(void);
+static void print_hex_row(uint8_t *data, size_t length, size_t bytes_per_row);
+
+int main(int argc, char **argv)
+{
+
+	int rc;
+	char *dev_path;
+	devmap_handle_t handle;
+	size_t block_size;
+	char *endptr;
+	aoff64_t block_offset = 0;
+	aoff64_t block_count = 1;
+	aoff64_t dev_nblocks;
+	uint8_t *data;
+	size_t data_offset;
+	aoff64_t current;
+	aoff64_t limit;
+	bool relative = false;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+
+	--argc; ++argv;
+
+	if (str_cmp(*argv, "--relative") == 0) {
+		--argc; ++argv;
+		relative = true;
+	}
+	
+	if (str_cmp(*argv, "--offset") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing (offset).\n");
+			syntax_print();
+			return 1;
+		}
+
+		block_offset = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument (offset).\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+	
+	if (str_cmp(*argv, "--count") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing (count).\n");
+			syntax_print();
+			return 1;
+		}
+
+		block_count = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument (count).\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libblock.\n");
+		return 2;
+	}
+
+	rc = block_get_bsize(handle, &block_size);
+	if (rc != EOK) {
+		printf(NAME ": Error determining device block size.\n");
+		return 2;
+	}
+
+	rc = block_get_nblocks(handle, &dev_nblocks);
+	if (rc != EOK) {
+		printf(NAME ": Warning, failed to obtain block device size.\n");
+	}
+
+	printf("Device %s has %" PRIuOFF64 " blocks, %" PRIuOFF64 " bytes each\n", dev_path, dev_nblocks, (aoff64_t) block_size);
+
+	data = malloc(block_size);
+	if (data == NULL) {
+		printf(NAME ": Error allocating data buffer of %" PRIuOFF64 " bytes", (aoff64_t) block_size);
+		block_fini(handle);
+		return 3;
+	}
+	
+	limit = block_offset + block_count;
+	for (current = block_offset; current < limit; current++) {
+		rc = block_read_direct(handle, current, 1, data);
+		if (rc != EOK) {
+			printf(NAME ": Error reading block at %" PRIuOFF64 " \n", current);
+			free(data);
+			return 3;
+		}
+		
+		printf("---- Block %" PRIuOFF64 " (at %" PRIuOFF64 ") ----\n", current, current*block_size);
+		
+		for (data_offset = 0; data_offset < block_size; data_offset += 16) {
+			if (relative) {
+				printf("%8" PRIxOFF64 ": ", (aoff64_t) data_offset);
+			}
+			else {
+				printf("%8" PRIxOFF64 ": ", current*block_size + data_offset);
+			}
+			print_hex_row(data+data_offset, block_size-data_offset, 16);
+			printf("\n");
+		}
+		printf("\n");
+	}
+	
+	free(data);
+
+	block_fini(handle);
+
+	return 0;
+}
+
+/**
+ * Print a row of 16 bytes as commonly seen in hexadecimal dumps
+ */
+static void print_hex_row(uint8_t *data, size_t length, size_t bytes_per_row) {
+	size_t pos;
+	uint8_t b;
+	
+	if (length > bytes_per_row) {
+		length = bytes_per_row;
+	}
+	
+	/* Print hexadecimal values */
+	for (pos = 0; pos < length; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		printf("%02hhX ", data[pos]);
+	}
+	
+	/* Pad with spaces if we have less than 16 bytes */
+	for (pos = length; pos < bytes_per_row; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		printf("   ");
+	}
+	
+	/* Print printable characters */
+	for (pos = 0; pos < length; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		b = data[pos];
+		if (b >= 32 && b < 128) {
+			putchar(b);
+		}
+		else {
+			putchar('.');
+		}
+	}
+}
+
+static void syntax_print(void)
+{
+	printf("syntax: blkdump [--relative] [--offset <num_blocks>] [--count <num_blocks>] <device_name>\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/bnchmark/Makefile
===================================================================
--- uspace/app/bnchmark/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/bnchmark/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2011 Martin Sucha
+# 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 = ../..
+BINARY = bnchmark
+
+SOURCES = \
+	bnchmark.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/bnchmark/bnchmark.c
===================================================================
--- uspace/app/bnchmark/bnchmark.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/bnchmark/bnchmark.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 test
+ * @{
+ */
+
+/**
+ * @file	bnchmark.c
+ * This program measures time for various actions and writes the results
+ * to a file.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+
+#define NAME	"bnchmark"
+#define BUFSIZE 8096
+#define MBYTE (1024*1024)
+
+typedef int(*measure_func_t)(void *);
+typedef unsigned long umseconds_t; /* milliseconds */
+
+static void syntax_print(void);
+
+static int measure(measure_func_t fn, void* data, umseconds_t *result)
+{
+	struct timeval start_time;
+	int rc;
+	rc = gettimeofday(&start_time, NULL);
+	if (rc != EOK) {
+		fprintf(stderr, "gettimeofday failed\n");
+		return rc;
+	}
+	
+	rc = fn(data);
+	if (rc != EOK) {
+		fprintf(stderr, "measured function failed\n");
+		return rc;
+	}
+
+	struct timeval final_time;
+	rc = gettimeofday(&final_time, NULL);
+	if (rc != EOK) {
+		fprintf(stderr, "gettimeofday failed\n");
+		return rc;
+	}
+	
+	/* Calculate time difference in milliseconds */
+	*result = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
+	    ((final_time.tv_sec - start_time.tv_sec) * 1000);
+	return EOK;
+}
+
+static int sequential_read_file(void *data)
+{
+	char *path = (char *) data;
+	char *buf = malloc(BUFSIZE);
+
+	if (buf == NULL) {
+		return ENOMEM;
+	}
+	
+	FILE *file = fopen(path, "r");
+	if (file == NULL) {
+		fprintf(stderr, "Failed opening file: %s\n", path);
+		free(buf);
+		return EIO;
+	}
+	
+	while (!feof(file)) {
+		fread(buf, 1, BUFSIZE, file);
+		if (ferror(file)) {
+			fprintf(stderr, "Failed reading file\n");
+			fclose(file);
+			free(buf);
+			return EIO;
+		}
+	}
+	
+	fclose(file);
+	free(buf);
+	return EOK;
+}
+
+static int sequential_read_dir(void *data)
+{
+	char *path = (char *) data;
+	
+	DIR *dir = opendir(path);
+	if (dir == NULL) {
+		fprintf(stderr, "Failed opening directory: %s\n", path);
+		return EIO;
+	}
+
+	struct dirent *dp;
+	
+	while ((dp = readdir(dir))) {
+		/* Do nothing */
+	}
+	
+	closedir(dir);
+	return EOK;
+}
+
+int main(int argc, char **argv)
+{
+	int rc;
+	umseconds_t milliseconds_taken;
+	char *path = NULL;
+	measure_func_t fn = NULL;
+	int iteration;
+	int iterations;
+	char *log_str = NULL;
+	char *test_type = NULL;
+	char *endptr;
+	
+	if (argc < 5) {
+		fprintf(stderr, NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	if (argc > 5) {
+		fprintf(stderr, NAME ": Error, too many arguments.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	// Skip program name
+	--argc; ++argv;
+
+	iterations = strtol(*argv, &endptr, 10);
+	if (*endptr != '\0') {
+		printf(NAME ": Error, invalid argument (iterations).\n");
+		syntax_print();
+		return 1;
+	}
+	
+	--argc; ++argv;
+	test_type = *argv;
+
+	--argc; ++argv;
+	log_str = *argv;
+
+	--argc; ++argv;
+	path = *argv;
+	
+	if (str_cmp(test_type, "sequential-file-read") == 0) {
+		fn = sequential_read_file;
+	}
+	else if (str_cmp(test_type, "sequential-dir-read") == 0) {
+		fn = sequential_read_dir;
+	}
+	else {
+		fprintf(stderr, "Error, unknown test type\n");
+		syntax_print();
+		return 1;
+	}
+
+	for (iteration = 0; iteration < iterations; iteration++) {
+		rc = measure(fn, path, &milliseconds_taken);
+		if (rc != EOK) {
+			fprintf(stderr, "Error %d\n", rc);
+			return 1;
+		}
+	
+		printf("%s;%s;%s;%lu;ms\n", test_type, path, log_str, milliseconds_taken);
+	}
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	fprintf(stderr, "syntax: " NAME " <iterations> <test type> <log-str> <path>\n");
+	fprintf(stderr, "  <iterations>    number of times to run a given test\n");
+	fprintf(stderr, "  <test-type>     one of:\n");
+	fprintf(stderr, "                    sequential-file-read\n");
+	fprintf(stderr, "                    sequential-dir-read\n");
+	fprintf(stderr, "  <log-str>       a string to attach to results\n");
+	fprintf(stderr, "  <path>          file/directory to use for testing\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/edit/edit.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -94,5 +94,5 @@
 } doc_t;
 
-static int con;
+static console_ctrl_t *con;
 static doc_t doc;
 static bool done;
@@ -115,7 +115,7 @@
 static void cursor_setvis(bool visible);
 
-static void key_handle_unmod(console_event_t const *ev);
-static void key_handle_ctrl(console_event_t const *ev);
-static void key_handle_shift(console_event_t const *ev);
+static void key_handle_unmod(kbd_event_t const *ev);
+static void key_handle_ctrl(kbd_event_t const *ev);
+static void key_handle_shift(kbd_event_t const *ev);
 static void key_handle_movement(unsigned int key, bool shift);
 
@@ -158,5 +158,5 @@
 int main(int argc, char *argv[])
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	coord_t coord;
 	bool new_file;
@@ -164,5 +164,5 @@
 	spt_t pt;
 
-	con = fphone(stdout);
+	con = console_init(stdin, stdout);
 	console_clear(con);
 
@@ -219,5 +219,5 @@
 
 	while (!done) {
-		console_get_event(con, &ev);
+		console_get_kbd_event(con, &ev);
 		pane.rflags = 0;
 
@@ -277,5 +277,5 @@
 
 /** Handle key without modifier. */
-static void key_handle_unmod(console_event_t const *ev)
+static void key_handle_unmod(kbd_event_t const *ev)
 {
 	switch (ev->key) {
@@ -320,5 +320,5 @@
 
 /** Handle Shift-key combination. */
-static void key_handle_shift(console_event_t const *ev)
+static void key_handle_shift(kbd_event_t const *ev)
 {
 	switch (ev->key) {
@@ -344,5 +344,5 @@
 
 /** Handle Ctrl-key combination. */
-static void key_handle_ctrl(console_event_t const *ev)
+static void key_handle_ctrl(kbd_event_t const *ev)
 {
 	switch (ev->key) {
@@ -497,5 +497,5 @@
 static char *filename_prompt(char const *prompt, char const *init_value)
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	char *str;
 	wchar_t buffer[INFNAME_MAX_LEN + 1];
@@ -517,5 +517,5 @@
 
 	while (!done) {
-		console_get_event(con, &ev);
+		console_get_kbd_event(con, &ev);
 
 		if (ev.type == KEY_PRESS) {
@@ -531,5 +531,5 @@
 					if (nc > 0) {
 						putchar('\b');
-						fflush(stdout);
+						console_flush(con);
 						--nc;
 					}
@@ -541,5 +541,5 @@
 					if (ev.c >= 32 && nc < max_len) {
 						putchar(ev.c);
-						fflush(stdout);
+						console_flush(con);
 						buffer[nc++] = ev.c;
 					}
@@ -689,5 +689,5 @@
 		for (j = 0; j < scr_columns; ++j)
 			putchar(' ');
-		fflush(stdout);
+		console_flush(con);
 	}
 
@@ -757,7 +757,7 @@
 		if (coord_cmp(&csel_start, &rbc) <= 0 &&
 		    coord_cmp(&rbc, &csel_end) < 0) {
-			fflush(stdout);
+			console_flush(con);
 			console_set_style(con, STYLE_SELECTED);
-			fflush(stdout);
+			console_flush(con);
 		}
 
@@ -768,13 +768,13 @@
 		while (pos < size) {
 			if ((csel_start.row == rbc.row) && (csel_start.column == s_column)) {
-				fflush(stdout);
+				console_flush(con);
 				console_set_style(con, STYLE_SELECTED);
-				fflush(stdout);
+				console_flush(con);
 			}
 	
 			if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
-				fflush(stdout);
+				console_flush(con);
 				console_set_style(con, STYLE_NORMAL);
-				fflush(stdout);
+				console_flush(con);
 			}
 	
@@ -794,7 +794,7 @@
 
 		if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
-			fflush(stdout);
+			console_flush(con);
 			console_set_style(con, STYLE_NORMAL);
-			fflush(stdout);
+			console_flush(con);
 		}
 
@@ -808,5 +808,5 @@
 		for (j = 0; j < fill; ++j)
 			putchar(' ');
-		fflush(stdout);
+		console_flush(con);
 		console_set_style(con, STYLE_NORMAL);
 	}
@@ -833,5 +833,5 @@
 	int pos = scr_columns - 1 - n;
 	printf("%*s", pos, "");
-	fflush(stdout);
+	console_flush(con);
 	console_set_style(con, STYLE_NORMAL);
 
@@ -1158,5 +1158,5 @@
 	int pos = -(scr_columns - 3);
 	printf(" %*s ", pos, str);
-	fflush(stdout);
+	console_flush(con);
 	console_set_style(con, STYLE_NORMAL);
 
Index: uspace/app/ext2info/Makefile
===================================================================
--- uspace/app/ext2info/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/ext2info/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = $(LIBBLOCK_PREFIX)/libblock.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
+BINARY = ext2info
+
+SOURCES = \
+	ext2info.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ext2info/ext2info.c
===================================================================
--- uspace/app/ext2info/ext2info.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/ext2info/ext2info.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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 fs
+ * @{
+ */
+
+/**
+ * @file	ext2info.c
+ * @brief	Tool for displaying information about ext2 filesystem
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <libext2.h>
+#include <assert.h>
+
+#define NAME	"ext2info"
+
+static void syntax_print(void);
+static void print_superblock(ext2_superblock_t *);
+static void print_block_groups(ext2_filesystem_t *);
+static void print_block_group(ext2_block_group_t *);
+static void print_inode_by_number(ext2_filesystem_t *, uint32_t, bool, uint32_t,
+    bool, bool);
+static void print_data(unsigned char *, size_t);
+static void print_inode(ext2_filesystem_t *, ext2_inode_t *, bool);
+static void print_inode_data(ext2_filesystem_t *, ext2_inode_t *, uint32_t);
+static void print_directory_contents(ext2_filesystem_t *, ext2_inode_ref_t *);
+
+#define ARG_SUPERBLOCK 1
+#define ARG_BLOCK_GROUPS 2
+#define ARG_INODE 4
+#define ARG_NO_CHECK 8
+#define ARG_INODE_DATA 16
+#define ARG_INODE_LIST 32
+#define ARG_INODE_BLOCKS 64
+#define ARG_COMMON (ARG_SUPERBLOCK)
+#define ARG_ALL 127
+
+
+int main(int argc, char **argv)
+{
+
+	int rc;
+	char *endptr;
+	char *dev_path;
+	devmap_handle_t handle;
+	ext2_filesystem_t filesystem;
+	int arg_flags;
+	uint32_t inode = 0;
+	uint32_t inode_data = 0;
+	
+	arg_flags = 0;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	/* Skip program name */
+	--argc; ++argv;
+	
+	if (argc > 0 && str_cmp(*argv, "--no-check") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_NO_CHECK;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--superblock") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_SUPERBLOCK;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--block-groups") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_BLOCK_GROUPS;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--inode") == 0) {
+		--argc; ++argv;
+		if (argc == 0) {
+			printf(NAME ": Argument expected for --inode\n");
+			return 2;
+		}
+		
+		inode = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument for --inode.\n");
+			syntax_print();
+			return 1;
+		}
+		
+		arg_flags |= ARG_INODE;
+		--argc; ++argv;
+		
+		if (argc > 0 && str_cmp(*argv, "--blocks") == 0) {
+			--argc; ++argv;
+			arg_flags |= ARG_INODE_BLOCKS;
+		}
+		
+		if (argc > 0 && str_cmp(*argv, "--data") == 0) {
+			--argc; ++argv;
+			if (argc == 0) {
+				printf(NAME ": Argument expected for --data\n");
+				return 2;
+			}
+			
+			inode_data = strtol(*argv, &endptr, 10);
+			if (*endptr != '\0') {
+				printf(NAME ": Error, invalid argument for --data.\n");
+				syntax_print();
+				return 1;
+			}
+			
+			arg_flags |= ARG_INODE_DATA;
+			--argc; ++argv;
+		}
+		
+		if (argc > 0 && str_cmp(*argv, "--list") == 0) {
+			--argc; ++argv;
+			arg_flags |= ARG_INODE_LIST;
+		}
+	}
+
+	if (argc < 1) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	else if (argc > 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+	assert(argc == 1);
+	
+	/* Display common things by default */
+	if ((arg_flags & ARG_ALL) == 0) {
+		arg_flags = ARG_COMMON;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = ext2_filesystem_init(&filesystem, handle);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libext2.\n");
+		return 3;
+	}
+	
+	rc = ext2_filesystem_check_sanity(&filesystem);
+	if (rc != EOK) {
+		printf(NAME ": Filesystem did not pass sanity check.\n");
+		if (!(arg_flags & ARG_NO_CHECK)) {
+			return 3;
+		}
+	}
+	
+	if (arg_flags & ARG_SUPERBLOCK) {
+		print_superblock(filesystem.superblock);
+	}
+	
+	if (arg_flags & ARG_BLOCK_GROUPS) {
+		print_block_groups(&filesystem);
+	}
+	
+	if (arg_flags & ARG_INODE) {
+		print_inode_by_number(&filesystem, inode, arg_flags & ARG_INODE_DATA,
+		    inode_data, arg_flags & ARG_INODE_LIST,
+		    arg_flags & ARG_INODE_BLOCKS);
+	}
+
+	ext2_filesystem_fini(&filesystem);
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	printf("syntax: ext2info [--no-check] [--superblock] [--block-groups] "
+	    "[--inode <i-number> [--blocks] [--data <block-number>] [--list]] "
+	    "<device_name>\n");
+}
+
+static void print_superblock(ext2_superblock_t *superblock)
+{
+	uint16_t magic;
+	uint32_t first_block;
+	uint32_t block_size;
+	uint32_t fragment_size;
+	uint32_t blocks_per_group;
+	uint32_t fragments_per_group;
+	uint32_t rev_major;
+	uint16_t rev_minor;
+	uint16_t state;
+	uint32_t first_inode;
+	uint16_t inode_size;
+	uint32_t total_blocks;
+	uint32_t reserved_blocks;
+	uint32_t free_blocks;
+	uint32_t total_inodes;
+	uint32_t free_inodes;	
+	uint32_t os;
+	
+	int pos;
+	unsigned char c;
+	
+	magic = ext2_superblock_get_magic(superblock);
+	first_block = ext2_superblock_get_first_block(superblock);
+	block_size = ext2_superblock_get_block_size(superblock);
+	fragment_size = ext2_superblock_get_fragment_size(superblock);
+	blocks_per_group = ext2_superblock_get_blocks_per_group(superblock);
+	fragments_per_group = ext2_superblock_get_fragments_per_group(superblock);
+	rev_major = ext2_superblock_get_rev_major(superblock);
+	rev_minor = ext2_superblock_get_rev_minor(superblock);
+	state = ext2_superblock_get_state(superblock);
+	first_inode = ext2_superblock_get_first_inode(superblock);
+	inode_size = ext2_superblock_get_inode_size(superblock);
+	total_blocks = ext2_superblock_get_total_block_count(superblock);
+	reserved_blocks = ext2_superblock_get_reserved_block_count(superblock);
+	free_blocks = ext2_superblock_get_free_block_count(superblock);
+	total_inodes = ext2_superblock_get_total_inode_count(superblock);
+	free_inodes = ext2_superblock_get_free_inode_count(superblock);
+	os = ext2_superblock_get_os(superblock);
+	
+	printf("Superblock:\n");
+	
+	if (magic == EXT2_SUPERBLOCK_MAGIC) {
+		printf("  Magic value: %X (correct)\n", magic);
+	}
+	else {
+		printf("  Magic value: %X (incorrect)\n", magic);
+	}
+	
+	printf("  Revision: %u.%hu\n", rev_major, rev_minor);
+	printf("  State: %hu\n", state);
+	printf("  Creator OS: %u\n", os);
+	printf("  First block: %u\n", first_block);
+	printf("  Block size: %u bytes (%u KiB)\n", block_size, block_size/1024);
+	printf("  Blocks per group: %u\n", blocks_per_group);
+	printf("  Total blocks: %u\n", total_blocks);
+	printf("  Reserved blocks: %u\n", reserved_blocks);
+	printf("  Free blocks: %u\n", free_blocks);
+	printf("  Fragment size: %u bytes (%u KiB)\n", fragment_size,
+	    fragment_size/1024);
+	printf("  Fragments per group: %u\n", fragments_per_group);
+	printf("  First inode: %u\n", first_inode);
+	printf("  Inode size: %hu bytes\n", inode_size);
+	printf("  Total inodes: %u\n", total_inodes);
+	printf("  Free inodes: %u\n", free_inodes);
+	
+	
+	if (rev_major == 1) {
+		printf("  UUID: ");
+		for (pos = 0; pos < 16; pos++) {
+			printf("%02x", superblock->uuid[pos]);
+		}
+		printf("\n");
+		
+		printf("  Volume label: ");
+		for (pos = 0; pos < 16; pos++) {
+			c = superblock->volume_name[pos];
+			if (c >= 32 && c < 128) {
+				putchar(c);
+			}
+			else {
+				putchar(' ');
+			}
+		}
+		printf("\n");
+	}
+	
+}
+
+void print_block_groups(ext2_filesystem_t *filesystem)
+{
+	uint32_t block_group_count;
+	uint32_t i;
+	ext2_block_group_ref_t *block_group_ref;
+	int rc;
+	
+	printf("Block groups:\n");
+	
+	block_group_count = ext2_superblock_get_block_group_count(
+	    filesystem->superblock);
+	
+	for (i = 0; i < block_group_count; i++) {
+		printf("  Block group %u\n", i);
+		rc = ext2_filesystem_get_block_group_ref(filesystem, i, &block_group_ref);
+		if (rc != EOK) {
+			printf("    Failed reading block group\n");
+			continue;
+		}
+		
+		print_block_group(block_group_ref->block_group);
+		
+		rc = ext2_filesystem_put_block_group_ref(block_group_ref);
+		if (rc != EOK) {
+			printf("    Failed freeing block group\n");
+		}
+	}
+	
+}
+
+void print_block_group(ext2_block_group_t *bg)
+{
+	uint32_t block_bitmap_block;
+	uint32_t inode_bitmap_block;
+	uint32_t inode_table_first_block;
+	uint16_t free_block_count;
+	uint16_t free_inode_count;
+	uint16_t directory_inode_count;
+	
+	block_bitmap_block = ext2_block_group_get_block_bitmap_block(bg);
+	inode_bitmap_block = ext2_block_group_get_inode_bitmap_block(bg);
+	inode_table_first_block = ext2_block_group_get_inode_table_first_block(bg);
+	free_block_count = ext2_block_group_get_free_block_count(bg);
+	free_inode_count = ext2_block_group_get_free_inode_count(bg);
+	directory_inode_count = ext2_block_group_get_directory_inode_count(bg);
+	
+	printf("    Block bitmap block: %u\n", block_bitmap_block);
+	printf("    Inode bitmap block: %u\n", inode_bitmap_block);
+	printf("    Inode table's first block: %u\n", inode_table_first_block);
+	printf("    Free blocks: %u\n", free_block_count);
+	printf("    Free inodes: %u\n", free_inode_count);
+	printf("    Directory inodes: %u\n", directory_inode_count);
+}
+
+void print_inode_by_number(ext2_filesystem_t *fs, uint32_t inode, 
+    bool print_data, uint32_t data, bool list, bool blocks)
+{
+	int rc;
+	ext2_inode_ref_t *inode_ref;
+	
+	printf("Inode %u\n", inode);
+	
+	rc = ext2_filesystem_get_inode_ref(fs, inode, &inode_ref);
+	if (rc != EOK) {
+		printf("  Failed getting inode ref\n");
+		return;
+	}
+	
+	print_inode(fs, inode_ref->inode, blocks);
+	if (print_data) {
+		print_inode_data(fs, inode_ref->inode, data);
+	}
+	
+	if (list && ext2_inode_is_type(fs->superblock, inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		print_directory_contents(fs, inode_ref);
+	}
+	
+	rc = ext2_filesystem_put_inode_ref(inode_ref);
+	if (rc != EOK) {
+		printf("  Failed putting inode ref\n");
+	}
+}
+
+void print_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, bool blocks)
+{
+	uint32_t mode;
+	uint32_t mode_type;
+	uint32_t user_id;
+	uint32_t group_id;
+	uint64_t size;
+	uint16_t usage_count;
+	uint32_t flags;
+	uint16_t access;
+	const char *type;
+	uint32_t total_blocks;
+	uint32_t i;
+	uint32_t range_start;
+	uint32_t range_last;
+	uint32_t range_start_file;
+	uint32_t range_last_file;
+	uint32_t range_current;
+	uint32_t range_expected;
+	uint32_t block_size;
+	uint64_t file_blocks;
+	bool printed_range;
+	int rc;
+	
+	block_size = ext2_superblock_get_block_size(fs->superblock);
+	mode = ext2_inode_get_mode(fs->superblock, inode);
+	mode_type = mode & EXT2_INODE_MODE_TYPE_MASK;
+	user_id = ext2_inode_get_user_id(fs->superblock, inode);
+	group_id = ext2_inode_get_group_id(fs->superblock, inode);
+	size = ext2_inode_get_size(fs->superblock, inode);
+	usage_count = ext2_inode_get_usage_count(inode);
+	flags = ext2_inode_get_flags(inode);
+	total_blocks = ext2_inode_get_reserved_blocks(fs->superblock, inode);
+	file_blocks = 0;
+	if (size > 0) {
+		file_blocks = ((size-1)/block_size)+1;
+	}
+	
+	type = "Unknown";
+	if (mode_type == EXT2_INODE_MODE_BLOCKDEV) {
+		type = "Block device";
+	}
+	else if (mode_type == EXT2_INODE_MODE_FIFO) {
+		type = "Fifo (pipe)";
+	}
+	else if (mode_type == EXT2_INODE_MODE_CHARDEV) {
+		type = "Character device";
+	}
+	else if (mode_type == EXT2_INODE_MODE_DIRECTORY) {
+		type = "Directory";
+	}
+	else if (mode_type == EXT2_INODE_MODE_FILE) {
+		type = "File";
+	}
+	else if (mode_type == EXT2_INODE_MODE_SOFTLINK) {
+		type = "Soft link";
+	}
+	else if (mode_type == EXT2_INODE_MODE_SOCKET) {
+		type = "Socket";
+	}
+	
+	access = mode & EXT2_INODE_MODE_ACCESS_MASK;
+	
+	
+	printf("  Mode: %08x (Type: %s, Access bits: %04ho)\n", mode, type, access);
+	printf("  User ID: %u\n", user_id);
+	printf("  Group ID: %u\n", group_id);
+	printf("  Size: %" PRIu64 "\n", size);
+	printf("  Usage (link) count: %u\n", usage_count);
+	printf("  Flags: %u\n", flags);
+	printf("  Total allocated blocks: %u\n", total_blocks);
+	
+	if (blocks) {
+		printf("  Block list: ");
+		
+		range_start = 0;
+		range_current = 0;
+		range_last = 0;
+		
+		printed_range = false;
+		
+		for (i = 0; i <= file_blocks; i++) {
+			if (i < file_blocks) {
+				rc = ext2_filesystem_get_inode_data_block_index(fs, inode, i, &range_current);
+				if (rc != EOK) {
+					printf("Error reading data block indexes\n");
+					return;
+				}
+			}
+			if (range_last == 0) {
+				range_expected = 0;
+			}
+			else {
+				range_expected = range_last + 1;
+			}
+			if (range_current != range_expected) {
+				if (i > 0) {
+					if (printed_range) {
+						printf(", ");
+					}
+					if (range_start == 0 && range_last == 0) {
+						if (range_start_file == range_last_file) {
+							printf("%u N/A", range_start_file);
+						}
+						else {
+							printf("[%u, %u] N/A", range_start_file,
+								range_last_file);
+						}
+					}
+					else {
+						if (range_start_file == range_last_file) {
+							printf("%u -> %u", range_start_file, range_start);
+						}
+						else {
+							printf("[%u, %u] -> [%u, %u]", range_start_file,
+								range_last_file, range_start, range_last);
+						}
+					}
+					printed_range = true;
+				}
+				range_start = range_current;
+				range_start_file = i;
+			}
+			range_last = range_current;
+			range_last_file = i;
+		}
+		printf("\n");
+	}
+}
+
+void print_data(unsigned char *data, size_t size)
+{
+	unsigned char c;
+	size_t i;
+	
+	for (i = 0; i < size; i++) {
+		c = data[i];
+		if (c >= 32 && c < 127) {
+			putchar(c);
+		}
+		else {
+			putchar('.');
+		}
+	}
+}
+
+void print_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t data)
+{
+	int rc;
+	uint32_t data_block_index;
+	block_t *block;
+	
+	rc = ext2_filesystem_get_inode_data_block_index(fs, inode, data,
+	    &data_block_index);
+	
+	if (rc != EOK) {
+		printf("Failed getting data block #%u\n", data);
+		return;
+	}
+	
+	printf("Data for inode contents block #%u is located in filesystem "
+	    "block %u\n", data, data_block_index);
+	
+	printf("Data preview (only printable characters):\n");
+	
+	rc = block_get(&block, fs->device, data_block_index, 0);
+	if (rc != EOK) {
+		printf("Failed reading filesystem block %u\n", data_block_index);
+		return;
+	}
+	
+	print_data(block->data, block->size);
+	printf("\n");	
+	
+	rc = block_put(block);
+	if (rc != EOK) {
+		printf("Failed putting filesystem block\n");
+	}
+	
+}
+
+void print_directory_contents(ext2_filesystem_t *fs,
+    ext2_inode_ref_t *inode_ref)
+{
+	int rc;
+	ext2_directory_iterator_t it;
+	size_t name_size;
+	uint32_t inode;
+	
+	printf("  Directory contents:\n");
+	
+	rc = ext2_directory_iterator_init(&it, fs, inode_ref);
+	if (rc != EOK) {
+		printf("Failed initializing directory iterator\n");
+		return;
+	}
+	
+	while (it.current != NULL) {
+		name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+		    it.current);
+		printf("    ");
+		print_data(&it.current->name, name_size);
+		
+		inode = ext2_directory_entry_ll_get_inode(it.current);
+		printf(" --> %u\n", inode);
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			printf("Failed reading directory contents\n");
+			goto cleanup;
+		}
+	}
+
+cleanup:
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		printf("Failed cleaning-up directory iterator\n");
+	}
+	
+}
+
+/**
+ * @}
+ */
Index: uspace/app/getterm/version.c
===================================================================
--- uspace/app/getterm/version.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/getterm/version.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -61,5 +61,5 @@
 	printf("HelenOS release %s (%s)%s%s\n", release, name, revision, timestamp);
 	printf("Running on %s (%s)\n", arch, term);
-	printf("Copyright (c) 2001-2010 HelenOS project\n\n");
+	printf("Copyright (c) 2001-2011 HelenOS project\n\n");
 }
 
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/init/init.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -176,24 +176,19 @@
 static void console(const char *dev)
 {
-	char hid_in[DEVMAP_NAME_MAXLEN];
-	int rc;
-	
-	snprintf(hid_in, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
-	
-	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, hid_in);
+	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, dev);
 	
 	/* Wait for the input device to be ready */
 	devmap_handle_t handle;
-	rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING);
-	if (rc != EOK) {
-		printf("%s: Error waiting on %s (%s)\n", NAME, hid_in,
-		    str_error(rc));
-		return;
-	}
-	
-	rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, hid_in, NULL);
+	int rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("%s: Error waiting on %s (%s)\n", NAME, dev,
+		    str_error(rc));
+		return;
+	}
+	
+	rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, dev, NULL);
 	if (rc != EOK) {
 		printf("%s: Error spawning %s %s (%s)\n", NAME, SRV_CONSOLE,
-		    hid_in, str_error(rc));
+		    dev, str_error(rc));
 	}
 }
@@ -272,7 +267,5 @@
 	mount_tmpfs();
 	
-#ifdef CONFIG_START_DEVMAN
 	spawn("/srv/devman");
-#endif
 	spawn("/srv/apic");
 	spawn("/srv/i8259");
Index: uspace/app/lsusb/Makefile
===================================================================
--- uspace/app/lsusb/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/lsusb/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = lsusb
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/lsusb/main.c
===================================================================
--- uspace/app/lsusb/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/lsusb/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010-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 lsusb
+ * @{
+ */
+/**
+ * @file
+ * Listing of USB host controllers.
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <getopt.h>
+#include <devman.h>
+#include <devmap.h>
+#include <usb/dev/hub.h>
+#include <usb/hc.h>
+
+#define NAME "lsusb"
+
+#define MAX_USB_ADDRESS USB11_ADDRESS_MAX
+#define MAX_FAILED_ATTEMPTS 10
+#define MAX_PATH_LENGTH 1024
+
+static void print_found_hc(size_t class_index, const char *path)
+{
+	// printf(NAME ": host controller %zu is `%s'.\n", class_index, path);
+	printf("Bus %02zu: %s\n", class_index, path);
+}
+static void print_found_dev(usb_address_t addr, const char *path)
+{
+	// printf(NAME ":     device with address %d is `%s'.\n", addr, path);
+	printf("  Device %02d: %s\n", addr, path);
+}
+
+static void print_hc_devices(devman_handle_t hc_handle)
+{
+	int rc;
+	usb_hc_connection_t conn;
+
+	usb_hc_connection_initialize(&conn, hc_handle);
+	rc = usb_hc_connection_open(&conn);
+	if (rc != EOK) {
+		printf(NAME ": failed to connect to HC: %s.\n",
+		    str_error(rc));
+		return;
+	}
+	usb_address_t addr;
+	for (addr = 1; addr < MAX_USB_ADDRESS; addr++) {
+		devman_handle_t dev_handle;
+		rc = usb_hc_get_handle_by_address(&conn, addr, &dev_handle);
+		if (rc != EOK) {
+			continue;
+		}
+		char path[MAX_PATH_LENGTH];
+		rc = devman_get_device_path(dev_handle, path, MAX_PATH_LENGTH);
+		if (rc != EOK) {
+			continue;
+		}
+		print_found_dev(addr, path);
+	}
+	usb_hc_connection_close(&conn);
+}
+
+int main(int argc, char *argv[])
+{
+	size_t class_index = 0;
+	size_t failed_attempts = 0;
+
+	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
+		class_index++;
+		devman_handle_t hc_handle = 0;
+		int rc = usb_ddf_get_hc_handle_by_class(class_index, &hc_handle);
+		if (rc != EOK) {
+			failed_attempts++;
+			continue;
+		}
+		char path[MAX_PATH_LENGTH];
+		rc = devman_get_device_path(hc_handle, path, MAX_PATH_LENGTH);
+		if (rc != EOK) {
+			continue;
+		}
+		print_found_hc(class_index, path);
+		print_hc_devices(hc_handle);
+	}
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/mkbd/Makefile
===================================================================
--- uspace/app/mkbd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/mkbd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = mkbd
+
+LIBS = \
+	$(LIBUSBHID_PREFIX)/libusbhid.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a 
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include \
+	-I$(LIBUSBHID_PREFIX)/include 
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/mkbd/main.c
===================================================================
--- uspace/app/mkbd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/mkbd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,270 @@
+/*
+ * 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 mkbd
+ * @{
+ */
+/**
+ * @file
+ * Sample application using the data from multimedia keys on keyboard
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <getopt.h>
+#include <devman.h>
+#include <devmap.h>
+#include <usb/dev/hub.h>
+#include <usb/hid/iface.h>
+#include <usb/dev/pipes.h>
+#include <async.h>
+#include <usb/hid/usages/core.h>
+#include <usb/hid/hidparser.h>
+#include <usb/hid/hiddescriptor.h>
+#include <usb/hid/usages/consumer.h>
+#include <assert.h>
+
+#define NAME "mkbd"
+
+static async_sess_t *dev_sess = NULL;
+
+static int initialize_report_parser(async_sess_t *dev_sess,
+    usb_hid_report_t **report)
+{
+	*report = (usb_hid_report_t *) malloc(sizeof(usb_hid_report_t));
+	if (*report == NULL)
+		return ENOMEM;
+	
+	int rc = usb_hid_report_init(*report);
+	if (rc != EOK) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		return rc;
+	}
+	
+	/* Get the report descriptor length from the device */
+	size_t report_desc_size;
+	rc = usbhid_dev_get_report_descriptor_length(dev_sess,
+	    &report_desc_size);
+	if (rc != EOK) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		return rc;
+	}
+	
+	if (report_desc_size == 0) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		// TODO: other error code?
+		return EINVAL;
+	}
+	
+	uint8_t *desc = (uint8_t *) malloc(report_desc_size);
+	if (desc == NULL) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		return ENOMEM;
+	}
+	
+	/* Get the report descriptor from the device */
+	size_t actual_size;
+	rc = usbhid_dev_get_report_descriptor(dev_sess, desc, report_desc_size,
+	    &actual_size);
+	if (rc != EOK) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		free(desc);
+		return rc;
+	}
+	
+	if (actual_size != report_desc_size) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		free(desc);
+		// TODO: other error code?
+		return EINVAL;
+	}
+	
+	/* Initialize the report parser */
+	
+	rc = usb_hid_parse_report_descriptor(*report, desc, report_desc_size);
+	free(desc);
+	
+	if (rc != EOK) {
+		free(desc);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static void print_key(uint8_t *buffer, size_t size, usb_hid_report_t *report)
+{
+	assert(buffer != NULL);
+	assert(report != NULL);
+	
+	uint8_t report_id;
+	int rc = usb_hid_parse_report(report, buffer, size, &report_id);
+	if (rc != EOK)
+		return;
+	
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	if (path == NULL) {
+		return;
+	}
+	
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
+	
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+	    USB_HID_REPORT_TYPE_INPUT);
+	
+	while (field != NULL) {
+		if (field->value != 0) {
+			const char *key_str = 
+			    usbhid_multimedia_usage_to_str(field->usage);
+			printf("Pressed key: %s\n", key_str);
+		}
+		
+		field = usb_hid_report_get_sibling(
+		    report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+	
+	usb_hid_report_path_free(path);
+}
+
+#define MAX_PATH_LENGTH 1024
+
+static void print_usage(char *app_name)
+{
+#define _INDENT "      "
+	printf(NAME ": Print out what multimedia keys were pressed.\n\n");
+	printf("Usage: %s device\n", app_name);
+	printf(_INDENT "The device is a devman path to the device.\n");
+#undef _OPTION
+#undef _INDENT
+}
+
+int main(int argc, char *argv[])
+{
+	int act_event = -1;
+	
+	if (argc <= 1) {
+		print_usage(argv[0]);
+		return -1;
+	}
+	
+	char *devpath = argv[1];
+	
+	devman_handle_t dev_handle = 0;
+	
+	int rc = usb_resolve_device_handle(devpath, NULL, NULL, &dev_handle);
+	if (rc != EOK) {
+		printf("Device not found or not of USB kind: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	async_sess_t *sess = devman_device_connect(EXCHANGE_SERIALIZE,
+	    dev_handle, 0);
+	if (!sess) {
+		printf(NAME ": failed to connect to the device (handle %"
+		       PRIun "): %s.\n", dev_handle, str_error(errno));
+		return errno;
+	}
+	
+	dev_sess = sess;
+	
+	char path[MAX_PATH_LENGTH];
+	rc = devman_get_device_path(dev_handle, path, MAX_PATH_LENGTH);
+	if (rc != EOK) {
+		return ENOMEM;
+	}
+	
+	printf("Device path: %s\n", path);
+	
+	
+	usb_hid_report_t *report = NULL;
+	rc = initialize_report_parser(dev_sess, &report);
+	if (rc != EOK) {
+		printf("Failed to initialize report parser: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	assert(report != NULL);
+	
+	size_t size;
+	rc = usbhid_dev_get_event_length(dev_sess, &size);
+	if (rc != EOK) {
+		printf("Failed to get event length: %s.\n", str_error(rc));
+		return rc;
+	}
+	
+	uint8_t *event = (uint8_t *)malloc(size);
+	if (event == NULL) {
+		// TODO: hangup phone?
+		return ENOMEM;
+	}
+	
+	size_t actual_size;
+	int event_nr;
+	
+	while (true) {
+		/** @todo Try blocking call. */
+		rc = usbhid_dev_get_event(dev_sess, event, size, &actual_size, 
+		    &event_nr, 0);
+		if (rc != EOK) {
+			// TODO: hangup phone?
+			printf("Error in getting event from the HID driver:"
+			    "%s.\n", str_error(rc));
+			break;
+		}
+		
+		if (event_nr > act_event) {
+			print_key(event, size, report);
+			act_event = event_nr;
+		}
+		
+		async_usleep(10000);
+	}
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/mkfat/mkfat.c
===================================================================
--- uspace/app/mkfat/mkfat.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/mkfat/mkfat.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -144,5 +144,5 @@
 	}
 
-	rc = block_init(handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": Error initializing libblock.\n");
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/ping/ping.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -36,4 +36,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <stdio.h>
 #include <str.h>
@@ -355,5 +356,5 @@
 			    str_error(ret));
 			
-			async_hangup(icmp_phone);
+			async_obsolete_hangup(icmp_phone);
 			return ret;
 		}
@@ -370,5 +371,5 @@
 			    str_error(ret));
 			
-			async_hangup(icmp_phone);
+			async_obsolete_hangup(icmp_phone);
 			return ret;
 		}
@@ -390,5 +391,5 @@
 	}
 	
-	async_hangup(icmp_phone);
+	async_obsolete_hangup(icmp_phone);
 	
 	return 0;
Index: uspace/app/redir/redir.c
===================================================================
--- uspace/app/redir/redir.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/redir/redir.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -49,5 +49,5 @@
 static void usage(void)
 {
-	printf("Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
+	fprintf(stderr, "Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
 	    NAME);
 }
@@ -83,5 +83,5 @@
 	args = (const char **) calloc(argc + 1, sizeof(char *));
 	if (!args) {
-		printf("No memory available\n");
+		fprintf(stderr, "No memory available\n");
 		return 0;
 	}
@@ -98,6 +98,7 @@
 	
 	if (rc != EOK) {
-		printf("%s: Error spawning %s (%s)\n", NAME, argv[0],
+		fprintf(stderr, "%s: Error spawning %s (%s)\n", NAME, argv[0],
 		    str_error(rc));
+		return 0;
 	}
 	
Index: uspace/app/taskdump/elf_core.c
===================================================================
--- uspace/app/taskdump/elf_core.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/taskdump/elf_core.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -62,7 +62,7 @@
 #include "include/elf_core.h"
 
-static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size);
-static int write_all(int fd, void *data, size_t len);
-static int write_mem_area(int fd, as_area_info_t *area, int phoneid);
+static off64_t align_foff_up(off64_t, uintptr_t, size_t);
+static int write_all(int, void *, size_t);
+static int write_mem_area(int, as_area_info_t *, async_sess_t *);
 
 #define BUFFER_SIZE 0x1000
@@ -71,13 +71,17 @@
 /** Save ELF core file.
  *
- * @param file_name	Name of file to save to.
- * @param ainfo		Array of @a n memory area info structures.
- * @param n		Number of memory areas.
- * @param phoneid	Debugging phone.
- *
- * @return		EOK on sucess, ENOENT if file cannot be created,
- *			ENOMEM on out of memory, EIO on write error.
- */
-int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n, int phoneid)
+ * @param file_name Name of file to save to.
+ * @param ainfo     Array of @a n memory area info structures.
+ * @param n         Number of memory areas.
+ * @param sess      Debugging session.
+ *
+ * @return EOK on sucess.
+ * @return ENOENT if file cannot be created.
+ * @return ENOMEM on out of memory.
+ * @return EIO on write error.
+ *
+ */
+int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
+    async_sess_t *sess)
 {
 	elf_header_t elf_hdr;
@@ -189,5 +193,5 @@
 			return EIO;
 		}
-		if (write_mem_area(fd, &ainfo[i], phoneid) != EOK) {
+		if (write_mem_area(fd, &ainfo[i], sess) != EOK) {
 			printf("Failed writing memory data.\n");
 			free(p_hdr);
@@ -215,11 +219,12 @@
 /** Write memory area from application to core file.
  *
- * @param fd		File to write to.
- * @param area		Memory area info structure.
- * @param phoneid	Debugging phone.
- *
- * @return		EOK on success, EIO on failure.
- */
-static int write_mem_area(int fd, as_area_info_t *area, int phoneid)
+ * @param fd   File to write to.
+ * @param area Memory area info structure.
+ * @param sess Debugging session.
+ *
+ * @return EOK on success, EIO on failure.
+ *
+ */
+static int write_mem_area(int fd, as_area_info_t *area, async_sess_t *sess)
 {
 	size_t to_copy;
@@ -233,5 +238,5 @@
 	while (total < area->size) {
 		to_copy = min(area->size - total, BUFFER_SIZE);
-		rc = udebug_mem_read(phoneid, buffer, addr, to_copy);
+		rc = udebug_mem_read(sess, buffer, addr, to_copy);
 		if (rc < 0) {
 			printf("Failed reading task memory.\n");
Index: uspace/app/taskdump/include/elf_core.h
===================================================================
--- uspace/app/taskdump/include/elf_core.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/taskdump/include/elf_core.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -36,5 +36,8 @@
 #define ELF_CORE_H_
 
-int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n, int phoneid);
+#include <async.h>
+
+extern int elf_core_save(const char *, as_area_info_t *, unsigned int,
+    async_sess_t *);
 
 #endif
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/taskdump/taskdump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -54,5 +54,5 @@
 #define LINE_BYTES 16
 
-static int phoneid;
+static async_sess_t *sess;
 static task_id_t task_id;
 static bool write_core_file;
@@ -104,6 +104,6 @@
 		printf("Failed dumping address space areas.\n");
 
-	udebug_end(phoneid);
-	async_hangup(phoneid);
+	udebug_end(sess);
+	async_hangup(sess);
 
 	return 0;
@@ -112,30 +112,27 @@
 static int connect_task(task_id_t task_id)
 {
-	int rc;
-
-	rc = async_connect_kbox(task_id);
-
-	if (rc == ENOTSUP) {
-		printf("You do not have userspace debugging support "
-		    "compiled in the kernel.\n");
-		printf("Compile kernel with 'Support for userspace debuggers' "
-		    "(CONFIG_UDEBUG) enabled.\n");
-		return rc;
-	}
-
-	if (rc < 0) {
+	async_sess_t *ksess = async_connect_kbox(task_id);
+	
+	if (!ksess) {
+		if (errno == ENOTSUP) {
+			printf("You do not have userspace debugging support "
+			    "compiled in the kernel.\n");
+			printf("Compile kernel with 'Support for userspace debuggers' "
+			    "(CONFIG_UDEBUG) enabled.\n");
+			return errno;
+		}
+		
 		printf("Error connecting\n");
-		printf("async_connect_kbox(%" PRIu64 ") -> %d ", task_id, rc);
-		return rc;
-	}
-
-	phoneid = rc;
-
-	rc = udebug_begin(phoneid);
+		printf("async_connect_kbox(%" PRIu64 ") -> %d ", task_id, errno);
+		return errno;
+	}
+	
+	int rc = udebug_begin(ksess);
 	if (rc < 0) {
 		printf("udebug_begin() -> %d\n", rc);
 		return rc;
 	}
-
+	
+	sess = ksess;
 	return 0;
 }
@@ -213,5 +210,5 @@
 
 	/* TODO: See why NULL does not work. */
-	rc = udebug_thread_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	rc = udebug_thread_read(sess, &dummy_buf, 0, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_thread_read() -> %d\n", rc);
@@ -227,5 +224,5 @@
 	thash_buf = malloc(buf_size);
 
-	rc = udebug_thread_read(phoneid, thash_buf, buf_size, &copied, &needed);
+	rc = udebug_thread_read(sess, thash_buf, buf_size, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_thread_read() -> %d\n", rc);
@@ -262,5 +259,5 @@
 	int rc;
 
-	rc = udebug_areas_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	rc = udebug_areas_read(sess, &dummy_buf, 0, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_areas_read() -> %d\n", rc);
@@ -271,5 +268,5 @@
 	ainfo_buf = malloc(buf_size);
 
-	rc = udebug_areas_read(phoneid, ainfo_buf, buf_size, &copied, &needed);
+	rc = udebug_areas_read(sess, ainfo_buf, buf_size, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_areas_read() -> %d\n", rc);
@@ -296,5 +293,5 @@
 	if (write_core_file) {
 		printf("Writing core file '%s'\n", core_file_name);
-		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, phoneid);
+		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, sess);
 		if (rc != EOK) {
 			printf("Failed writing core file.\n");
@@ -316,5 +313,5 @@
 	int rc;
 
-	rc = udebug_regs_read(phoneid, thash, &istate);
+	rc = udebug_regs_read(sess, thash, &istate);
 	if (rc < 0) {
 		printf("Failed reading registers (%d).\n", rc);
@@ -359,5 +356,5 @@
 	(void) arg;
 
-	rc = udebug_mem_read(phoneid, &data, addr, sizeof(data));
+	rc = udebug_mem_read(sess, &data, addr, sizeof(data));
 	if (rc < 0) {
 		printf("Warning: udebug_mem_read() failed.\n");
@@ -430,5 +427,5 @@
 	int rc;
 
-	rc = udebug_name_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	rc = udebug_name_read(sess, &dummy_buf, 0, &copied, &needed);
 	if (rc < 0)
 		return NULL;
@@ -436,5 +433,5 @@
 	name_size = needed;
 	name = malloc(name_size + 1);
-	rc = udebug_name_read(phoneid, name, name_size, &copied, &needed);
+	rc = udebug_name_read(sess, name, name_size, &copied, &needed);
 	if (rc < 0) {
 		free(name);
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -29,8 +29,11 @@
 
 USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
 BINARY = tester
 
 SOURCES = \
 	tester.c \
+	util.c \
 	thread/thread1.c \
 	print/print1.c \
@@ -52,7 +55,10 @@
 	mm/malloc2.c \
 	mm/malloc3.c \
+	mm/mapping1.c \
 	devs/devman1.c \
+	devs/devman2.c \
 	hw/misc/virtchar1.c \
-	hw/serial/serial1.c
+	hw/serial/serial1.c \
+	libext2/libext2_1.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tester/console/console1.c
===================================================================
--- uspace/app/tester/console/console1.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/console/console1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -50,19 +50,21 @@
 {
 	if (!test_quiet) {
+		console_ctrl_t *console = console_init(stdin, stdout);
+		
 		printf("Style test: ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_NORMAL);
+		console_flush(console);
+		console_set_style(console, STYLE_NORMAL);
 		printf(" normal ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_EMPHASIS);
+		console_flush(console);
+		console_set_style(console, STYLE_EMPHASIS);
 		printf(" emphasized ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_INVERTED);
+		console_flush(console);
+		console_set_style(console, STYLE_INVERTED);
 		printf(" inverted ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_SELECTED);
+		console_flush(console);
+		console_set_style(console, STYLE_SELECTED);
 		printf(" selected ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_NORMAL);
+		console_flush(console);
+		console_set_style(console, STYLE_NORMAL);
 		printf("\n");
 		
@@ -73,11 +75,11 @@
 		for (j = 0; j < 2; j++) {
 			for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) {
-				fflush(stdout);
-				console_set_color(fphone(stdout), i, COLOR_WHITE,
+				console_flush(console);
+				console_set_color(console, i, COLOR_WHITE,
 				    j ? CATTR_BRIGHT : 0);
 				printf(" %s ", color_name[i]);
 			}
-			fflush(stdout);
-			console_set_style(fphone(stdout), STYLE_NORMAL);
+			console_flush(console);
+			console_set_style(console, STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -86,11 +88,11 @@
 		for (j = 0; j < 2; j++) {
 			for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) {
-				fflush(stdout);
-				console_set_color(fphone(stdout), COLOR_WHITE, i,
+				console_flush(console);
+				console_set_color(console, COLOR_WHITE, i,
 				    j ? CATTR_BRIGHT : 0);
 				printf(" %s ", color_name[i]);
 			}
-			fflush(stdout);
-			console_set_style(fphone(stdout), STYLE_NORMAL);
+			console_flush(console);
+			console_set_style(console, STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -99,28 +101,28 @@
 		
 		for (i = 0; i < 255; i += 16) {
-			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), (255 - i) << 16, i << 16);
+			console_flush(console);
+			console_set_rgb_color(console, (255 - i) << 16, i << 16);
 			putchar('X');
 		}
-		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+		console_flush(console);
+		console_set_color(console, COLOR_BLACK, COLOR_WHITE, 0);
 		putchar('\n');
 		
 		for (i = 0; i < 255; i += 16) {
-			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), (255 - i) << 8, i << 8);
+			console_flush(console);
+			console_set_rgb_color(console, (255 - i) << 8, i << 8);
 			putchar('X');
 		}
-		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+		console_flush(console);
+		console_set_color(console, COLOR_BLACK, COLOR_WHITE, 0);
 		putchar('\n');
 		
 		for (i = 0; i < 255; i += 16) {
-			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 255 - i, i);
+			console_flush(console);
+			console_set_rgb_color(console, 255 - i, i);
 			putchar('X');
 		}
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_NORMAL);
+		console_flush(console);
+		console_set_style(console, STYLE_NORMAL);
 		putchar('\n');
 	}
Index: uspace/app/tester/devs/devman2.c
===================================================================
--- uspace/app/tester/devs/devman2.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/devs/devman2.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,94 @@
+/*
+ * 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 tester
+ * @brief Test devman service.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <inttypes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <sys/types.h>
+#include <async.h>
+#include <devman.h>
+#include <str.h>
+#include <async.h>
+#include <vfs/vfs.h>
+#include <vfs/vfs_sess.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../tester.h"
+
+#define DEVICE_CLASS "test3"
+
+const char *test_devman2(void)
+{
+	size_t idx = 1;
+	int rc = EOK;
+	const char *err_msg = NULL;
+	char *path = NULL;
+	while (rc == EOK) {
+		rc = asprintf(&path, "/dev/class/%s\\%zu", DEVICE_CLASS, idx);
+		if (rc < 0) {
+			continue;
+		}
+		int fd = open(path, O_RDONLY);
+		if (fd < 0) {
+			TPRINTF("Failed opening `%s': %s.\n",
+			    path, str_error(fd));
+			rc = fd;
+			err_msg = "Failed opening file";
+			continue;
+		}
+		async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
+		close(fd);
+		if (sess == NULL) {
+			TPRINTF("Failed opening phone: %s.\n", str_error(errno));
+			rc = errno;
+			err_msg = "Failed opening file descriptor phone";
+			continue;
+		}
+		async_hangup(sess);
+		TPRINTF("Path `%s' okay.\n", path);
+		free(path);
+		idx++;
+		rc = EOK;
+	}
+	
+	if (path != NULL)
+		free(path);
+	
+	return err_msg;
+}
+
+/** @}
+ */
Index: uspace/app/tester/devs/devman2.def
===================================================================
--- uspace/app/tester/devs/devman2.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/devs/devman2.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,6 @@
+{
+	"devman2",
+	"devman test",
+	&test_devman2,
+	false
+},
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -43,4 +43,5 @@
 #include <str.h>
 #include <vfs/vfs.h>
+#include <vfs/vfs_sess.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -66,17 +67,17 @@
 	TPRINTF("   ...file handle %d\n", fd);
 
-	TPRINTF(" Asking for phone...\n");
-	int phone = fd_phone(fd);
-	if (phone < 0) {
+	TPRINTF(" Asking for session...\n");
+	async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
+	if (!sess) {
 		close(fd);
-		TPRINTF("   ...error: %s\n", str_error(phone));
-		return "Failed to get phone to device";
+		TPRINTF("   ...error: %s\n", str_error(errno));
+		return "Failed to get session to device";
 	}
-	TPRINTF("   ...phone is %d\n", phone);
+	TPRINTF("   ...session is %p\n", sess);
 	
 	TPRINTF(" Will try to read...\n");
 	size_t i;
 	char buffer[BUFFER_SIZE];
-	char_dev_read(phone, buffer, BUFFER_SIZE);
+	char_dev_read(sess, buffer, BUFFER_SIZE);
 	TPRINTF(" ...verifying that we read zeroes only...\n");
 	for (i = 0; i < BUFFER_SIZE; i++) {
@@ -88,6 +89,6 @@
 	
 	/* Clean-up. */
-	TPRINTF(" Closing phones and file descriptors\n");
-	async_hangup(phone);
+	TPRINTF(" Closing session and file descriptor\n");
+	async_hangup(sess);
 	close(fd);
 	
Index: uspace/app/tester/hw/serial/serial1.c
===================================================================
--- uspace/app/tester/hw/serial/serial1.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/hw/serial/serial1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -71,22 +71,18 @@
 		}
 	
-	int res = devman_get_phone(DEVMAN_CLIENT, IPC_FLAG_BLOCKING);
-	
 	devman_handle_t handle;
-	res = devman_device_get_handle("/hw/pci0/00:01.0/com1/a", &handle,
+	int res = devman_device_get_handle("/hw/pci0/00:01.0/com1/a", &handle,
 	    IPC_FLAG_BLOCKING);
 	if (res != EOK)
 		return "Could not get serial device handle";
 	
-	int phone = devman_device_connect(handle, IPC_FLAG_BLOCKING);
-	if (phone < 0) {
-		devman_hangup_phone(DEVMAN_CLIENT);
+	async_sess_t *sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
+	    IPC_FLAG_BLOCKING);
+	if (!sess)
 		return "Unable to connect to serial device";
-	}
 	
 	char *buf = (char *) malloc(cnt + 1);
 	if (buf == NULL) {
-		async_hangup(phone);
-		devman_hangup_phone(DEVMAN_CLIENT);
+		async_hangup(sess);
 		return "Failed to allocate input buffer";
 	}
@@ -97,19 +93,23 @@
 	sysarg_t old_word_size;
 	
-	res = async_req_0_4(phone, SERIAL_GET_COM_PROPS, &old_baud,
+	async_exch_t *exch = async_exchange_begin(sess);
+	res = async_req_0_4(exch, SERIAL_GET_COM_PROPS, &old_baud,
 	    &old_par, &old_word_size, &old_stop);
+	async_exchange_end(exch);
+	
 	if (res != EOK) {
 		free(buf);
-		async_hangup(phone);
-		devman_hangup_phone(DEVMAN_CLIENT);
+		async_hangup(sess);
 		return "Failed to get old serial communication parameters";
 	}
 	
-	res = async_req_4_0(phone, SERIAL_SET_COM_PROPS, 1200,
+	exch = async_exchange_begin(sess);
+	res = async_req_4_0(exch, SERIAL_SET_COM_PROPS, 1200,
 	    SERIAL_NO_PARITY, 8, 1);
+	async_exchange_end(exch);
+	
 	if (EOK != res) {
 		free(buf);
-		async_hangup(phone);
-		devman_hangup_phone(DEVMAN_CLIENT);
+		async_hangup(sess);
 		return "Failed to set serial communication parameters";
 	}
@@ -120,21 +120,25 @@
 	size_t total = 0;
 	while (total < cnt) {
-		ssize_t read = char_dev_read(phone, buf, cnt - total);
+		ssize_t read = char_dev_read(sess, buf, cnt - total);
 		
 		if (read < 0) {
-			async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+			exch = async_exchange_begin(sess);
+			async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 			    old_par, old_word_size, old_stop);
+			async_exchange_end(exch);
+			
 			free(buf);
-			async_hangup(phone);
-			devman_hangup_phone(DEVMAN_CLIENT);
+			async_hangup(sess);
 			return "Failed read from serial device";
 		}
 		
 		if ((size_t) read > cnt - total) {
-			async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+			exch = async_exchange_begin(sess);
+			async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 			    old_par, old_word_size, old_stop);
+			async_exchange_end(exch);
+			
 			free(buf);
-			async_hangup(phone);
-			devman_hangup_phone(DEVMAN_CLIENT);
+			async_hangup(sess);
 			return "Read more data than expected";
 		}
@@ -151,21 +155,25 @@
 			 * direction of data transfer.
 			 */
-			ssize_t written = char_dev_write(phone, buf, read);
+			ssize_t written = char_dev_write(sess, buf, read);
 			
 			if (written < 0) {
-				async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+				exch = async_exchange_begin(sess);
+				async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 				    old_par, old_word_size, old_stop);
+				async_exchange_end(exch);
+				
 				free(buf);
-				async_hangup(phone);
-				devman_hangup_phone(DEVMAN_CLIENT);
+				async_hangup(sess);
 				return "Failed write to serial device";
 			}
 			
 			if (written != read) {
-				async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+				exch = async_exchange_begin(sess);
+				async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 				    old_par, old_word_size, old_stop);
+				async_exchange_end(exch);
+				
 				free(buf);
-				async_hangup(phone);
-				devman_hangup_phone(DEVMAN_CLIENT);
+				async_hangup(sess);
 				return "Written less data than read from serial device";
 			}
@@ -180,11 +188,13 @@
 	
 	size_t eot_size = str_size(EOT);
-	ssize_t written = char_dev_write(phone, (void *) EOT, eot_size);
-	
-	async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+	ssize_t written = char_dev_write(sess, (void *) EOT, eot_size);
+	
+	exch = async_exchange_begin(sess);
+	async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 	    old_par, old_word_size, old_stop);
+	async_exchange_end(exch);
+	
 	free(buf);
-	async_hangup(phone);
-	devman_hangup_phone(DEVMAN_CLIENT);
+	async_hangup(sess);
 	
 	if (written < 0)
Index: uspace/app/tester/ipc/ping_pong.c
===================================================================
--- uspace/app/tester/ipc/ping_pong.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/ipc/ping_pong.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -30,5 +30,5 @@
 #include <stdlib.h>
 #include <sys/time.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <errno.h>
@@ -61,5 +61,5 @@
 		size_t i;
 		for (i = 0; i < COUNT_GRANULARITY; i++) {
-			int retval = async_req_0_0(PHONE_NS, NS_PING);
+			int retval = ns_ping();
 			
 			if (retval != EOK) {
Index: uspace/app/tester/libext2/libext2_1.c
===================================================================
--- uspace/app/tester/libext2/libext2_1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/libext2/libext2_1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+#include "../util.h"
+#include <libext2.h>
+#include <malloc.h>
+
+static ext2_superblock_t *fake_superblock1()
+{
+	uint8_t *buf;
+	int i;
+	
+	buf = malloc(EXT2_SUPERBLOCK_SIZE);
+	if (buf == NULL) {
+		return NULL;
+	}
+	
+	for (i = 0; i < EXT2_SUPERBLOCK_SIZE; i++) {
+		buf[i] = i % 256;
+	}
+	
+	return (ext2_superblock_t *) buf;
+}
+
+const char *test_libext2_1(void)
+{
+	ext2_superblock_t *fake1;
+	
+	TPRINTF("Testing libext2 superblock getters...\n");
+	TPRINTF("Simple test for correct position and byte order\n");
+	
+	fake1 = fake_superblock1();
+	if (fake1 == NULL) {
+		return "Failed allocating memory for test superblock 1";
+	}
+	
+	ASSERT_EQ_32(0x03020100, ext2_superblock_get_total_inode_count(fake1),
+	    "Failed getting total inode count");
+	ASSERT_EQ_32(0x07060504, ext2_superblock_get_total_block_count(fake1),
+	    "Failed getting total block count");
+	ASSERT_EQ_32(0x0B0A0908, ext2_superblock_get_reserved_block_count(fake1),
+	    "Failed getting reserved block count");
+	ASSERT_EQ_32(0x0F0E0D0C, ext2_superblock_get_free_block_count(fake1),
+	    "Failed getting free block count");
+	ASSERT_EQ_32(0x13121110, ext2_superblock_get_free_inode_count(fake1),
+	    "Failed getting free inode count");
+	ASSERT_EQ_32(0x17161514, ext2_superblock_get_first_block(fake1),
+	    "Failed getting first block number");
+	ASSERT_EQ_32(0x1B1A1918, ext2_superblock_get_block_size_log2(fake1),
+	    "Failed getting log block size");
+	ASSERT_EQ_32(0x1F1E1D1C, ext2_superblock_get_fragment_size_log2(fake1),
+	    "Failed getting log fragment size");
+	ASSERT_EQ_32(0x23222120, ext2_superblock_get_blocks_per_group(fake1),
+	    "Failed getting blocks per group");
+	ASSERT_EQ_32(0x27262524, ext2_superblock_get_fragments_per_group(fake1),
+	    "Failed getting fragments per group");
+	ASSERT_EQ_32(0x2B2A2928, ext2_superblock_get_inodes_per_group(fake1),
+	    "Failed getting inodes per group");
+	ASSERT_EQ_16(0x3938, ext2_superblock_get_magic(fake1),
+	    "Failed getting magic number");
+	ASSERT_EQ_16(0x3B3A, ext2_superblock_get_state(fake1),
+	    "Failed getting state");
+	ASSERT_EQ_16(0x3F3E, ext2_superblock_get_rev_minor(fake1),
+	    "Failed getting minor revision number");
+	ASSERT_EQ_32(0x4B4A4948, ext2_superblock_get_os(fake1),
+	    "Failed getting OS");
+	ASSERT_EQ_32(0x4F4E4D4C, ext2_superblock_get_rev_major(fake1),
+	    "Failed getting major revision number");
+	ASSERT_EQ_32(0x57565554, ext2_superblock_get_first_inode(fake1),
+	    "Failed getting first inode number");
+	ASSERT_EQ_16(0x5958, ext2_superblock_get_inode_size(fake1),
+	    "Failed getting size");
+	ASSERT_EQ_8(0x68, fake1->uuid[0], "UUID position is incorrect");
+	ASSERT_EQ_8(0x78, fake1->volume_name[0],
+	    "Volume name position is incorrect");
+	
+	return NULL;
+}
Index: uspace/app/tester/libext2/libext2_1.def
===================================================================
--- uspace/app/tester/libext2/libext2_1.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/libext2/libext2_1.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,6 @@
+{
+	"libext2_1",
+	"Superblock getters test",
+	&test_libext2_1,
+	true
+},
Index: uspace/app/tester/mm/mapping1.c
===================================================================
--- uspace/app/tester/mm/mapping1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/mm/mapping1.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <as.h>
+#include <errno.h>
+#include "../tester.h"
+
+#define BUFFER1_PAGES 4
+#define BUFFER2_PAGES 2
+
+static void *create_as_area(size_t size)
+{
+	void *result = as_get_mappable_page(size);
+	TPRINTF("Creating AS area...\n");
+	if (as_area_create(result, size,
+	    AS_AREA_READ | AS_AREA_WRITE) != result) {
+		return NULL;
+	}
+	return result;
+}
+
+static void touch_area(void *area, size_t size)
+{
+	TPRINTF("Touching (faulting-in) AS area...\n");
+	
+	char *ptr = (char *)area;
+	
+	while (size > 0) {
+		*ptr = 0;
+		size--;
+		ptr++;
+	}
+}
+
+#define VERIFY_MAPPING(area, page_count, expected_rc) \
+    verify_mapping((area), (page_count), (expected_rc), #expected_rc)
+
+static bool verify_mapping(void *area, int page_count, int expected_rc,
+    const char *expected_rc_str)
+{
+	TPRINTF("Verifying mapping (expected: %s).\n", expected_rc_str);
+	int i;
+	for (i = 0; i < page_count; i++) {
+		void *page_start = ((char *)area) + PAGE_SIZE * i;
+		int rc = as_get_physical_mapping(page_start, NULL);
+		if (rc != expected_rc) {
+			TPRINTF("as_get_physical_mapping() = %d != %d\n",
+			    rc, expected_rc);
+			return false;
+		}
+	}
+	return true;
+}
+
+const char *test_mapping1(void)
+{
+	int rc;
+	
+	size_t buffer1_len = BUFFER1_PAGES * PAGE_SIZE;
+	size_t buffer2_len = BUFFER2_PAGES * PAGE_SIZE;
+	void *buffer1 = create_as_area(buffer1_len);
+	void *buffer2 = create_as_area(buffer2_len);
+	if (!buffer1 || !buffer2) {
+		return "Cannot allocate memory";
+	}
+	
+	touch_area(buffer1, buffer1_len);
+	touch_area(buffer2, buffer2_len);
+	
+	/* Now verify that mapping to physical frames exist. */
+	if (!VERIFY_MAPPING(buffer1, BUFFER1_PAGES, EOK)) {
+		return "Failed to find mapping (buffer1)";
+	}
+	if (!VERIFY_MAPPING(buffer2, BUFFER2_PAGES, EOK)) {
+		return "Failed to find mapping (buffer2)";
+	}
+	
+	/* Let's destroy the buffer1 area and access it again. */
+	rc = as_area_destroy(buffer1);
+	if (rc != EOK) {
+		return "Failed to destroy AS area";
+	}
+	if (!VERIFY_MAPPING(buffer1, BUFFER1_PAGES, ENOENT)) {
+		return "Mapping of destroyed area still exists";
+	}
+	
+	/* clean-up */
+	rc = as_area_destroy(buffer2);
+	if (rc != EOK) {
+		return "Failed to destroy AS area";
+	}
+	
+	return NULL;
+}
Index: uspace/app/tester/mm/mapping1.def
===================================================================
--- uspace/app/tester/mm/mapping1.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/mm/mapping1.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,6 @@
+{
+	"mapping1",
+	"Page mapping test",
+	&test_mapping1,
+	true
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/tester.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -64,7 +64,10 @@
 #include "mm/malloc2.def"
 #include "mm/malloc3.def"
+#include "mm/mapping1.def"
 #include "hw/serial/serial1.def"
 #include "hw/misc/virtchar1.def"
+#include "libext2/libext2_1.def"
 #include "devs/devman1.def"
+#include "devs/devman2.def"
 	{NULL, NULL, NULL, false}
 };
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tester/tester.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -97,7 +97,10 @@
 extern const char *test_malloc2(void);
 extern const char *test_malloc3(void);
+extern const char *test_mapping1(void);
 extern const char *test_serial1(void);
 extern const char *test_virtchar1(void);
+extern const char *test_libext2_1(void);
 extern const char *test_devman1(void);
+extern const char *test_devman2(void);
 
 extern test_t tests[];
Index: uspace/app/tester/util.c
===================================================================
--- uspace/app/tester/util.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/util.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 tester
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "util.h"
+#undef ASSERT_EQ_FN_DEF
+#define ASSERT_EQ_FN_DEF(type, fmt, fmtx) \
+bool assert_eq_fn_##type(type exp, type act, const char *act_desc) \
+{ \
+	if (exp != act) { \
+		fprintf(stderr, "Expected %s to be %" fmt " (0x%" fmtx "),"\
+		    " but was %" fmt " (0x%" fmtx ") \n", \
+		    act_desc, exp, exp, act, act); \
+	} \
+	return exp != act; \
+}
+
+#include "util_functions.def"
+
+
+/** @}
+ */
Index: uspace/app/tester/util.h
===================================================================
--- uspace/app/tester/util.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/util.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 tester
+ * @{
+ */
+/** @file
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <stdio.h>
+#include "tester.h"
+
+#define ASSERT_EQ_FN_DEF(type, fmt, fmtx) \
+extern bool assert_eq_fn_##type(type, type, const char *);
+
+#include "util_functions.def"
+
+#define ASSERT_EQ_64(exp, act, msg) \
+{if (assert_eq_fn_uint64_t(exp, act, #act)) {return msg;}}
+
+#define ASSERT_EQ_32(exp, act, msg) \
+{if (assert_eq_fn_uint32_t(exp, act, #act)) {return msg;}}
+
+#define ASSERT_EQ_16(exp, act, msg) \
+{if (assert_eq_fn_uint16_t(exp, act, #act)) {return msg;}}
+
+#define ASSERT_EQ_8(exp, act, msg) \
+{if (assert_eq_fn_uint8_t(exp, act, #act)) {return msg;}}
+
+#endif
+
+/** @}
+ */
Index: uspace/app/tester/util_functions.def
===================================================================
--- uspace/app/tester/util_functions.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/tester/util_functions.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,4 @@
+ASSERT_EQ_FN_DEF(uint8_t, "hhu", "hhx")
+ASSERT_EQ_FN_DEF(uint16_t, "hu", "hx")
+ASSERT_EQ_FN_DEF(uint32_t, "u", "x")
+ASSERT_EQ_FN_DEF(uint64_t, PRIu64, PRIx64)
Index: uspace/app/testread/Makefile
===================================================================
--- uspace/app/testread/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/testread/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2011 Martin Sucha
+# 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 = ../..
+BINARY = testread
+
+SOURCES = \
+	testread.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/testread/testread.c
===================================================================
--- uspace/app/testread/testread.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/testread/testread.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 test
+ * @{
+ */
+
+/**
+ * @file	testread.c
+ * This program checks if the file contains a pattern of increasing
+ * 64 bit unsigned integers (that may overflow at some point)
+ * stored in little endian byte order.
+ * This is to verify that the filesystem reads
+ * the files correctly.
+ * If the file does not contain specified pattern, it stops
+ * at the point where the file does not match and prints
+ * the byte offset at which the error occured.
+ * While checking the file, the program displays how many megabytes
+ * it has already read, how long it took to read the last megabyte
+ * and current and average read speed.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <time.h>
+
+#define NAME	"testread"
+#define BUFELEMS 1024
+#define MBYTE (1024*1024)
+
+static void syntax_print(void);
+
+int main(int argc, char **argv)
+{
+
+	FILE *file;
+	char *file_name;
+	uint64_t *buf;
+	uint64_t expected;
+	aoff64_t offset;
+	aoff64_t next_mark;
+	aoff64_t last_mark;
+	unsigned int i;
+	bool check_enabled = true;
+	bool progress = true;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	/* Skip program name */
+	--argc; ++argv;
+	
+	if (argc > 0 && str_cmp(*argv, "--no-check") == 0) {
+		check_enabled = false;
+		--argc; ++argv;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--no-progress") == 0) {
+		progress = false;
+		--argc; ++argv;
+	}
+	
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	file_name = *argv;
+	
+	buf = calloc(BUFELEMS, sizeof(uint64_t));
+	if (buf == NULL) {
+		printf("Failed allocating buffer\n");
+		return 1;
+	}
+	
+	file = fopen(file_name, "r");
+	if (file == NULL) {
+		printf("Failed opening file\n");
+		return 1;
+	}
+	
+	expected = 0;
+	offset = 0;
+	next_mark = 0;
+	last_mark = 0;
+	struct timeval prev_time;
+	struct timeval start_time;
+	int rc;
+	rc = gettimeofday(&start_time, NULL);
+	if (rc != EOK) {
+		printf("gettimeofday failed\n");
+		fclose(file);
+		free(buf);
+		return 1;
+	}
+	prev_time = start_time;
+	
+	while (!feof(file)) {
+		size_t elems = fread(buf, sizeof(uint64_t), BUFELEMS, file);
+		if (ferror(file)) {
+			printf("Failed reading file\n");
+			fclose(file);
+			free(buf);
+			return 1;
+		}
+		
+		for (i = 0; i < elems; i++) {
+			if (check_enabled && uint64_t_le2host(buf[i]) != expected) {
+				printf("Unexpected value at offset %" PRIuOFF64 "\n", offset);
+				fclose(file);
+				free(buf);
+				return 2;
+			}
+			expected++;
+			offset += sizeof(uint64_t);
+		}
+		
+		if (progress && offset >= next_mark) {
+			struct timeval cur_time;
+			rc = gettimeofday(&cur_time, NULL);
+			if (rc != EOK) {
+				printf("gettimeofday failed\n");
+				fclose(file);
+				free(buf);
+				return 1;
+			}
+			uint32_t last_run = cur_time.tv_sec - prev_time.tv_sec;
+			uint32_t total_time = cur_time.tv_sec - start_time.tv_sec;
+			if (last_run > 0 && total_time > 0) {
+				printf("%" PRIuOFF64 "M - time: %u s, "
+				    "cur: %"PRIuOFF64 " B/s, avg: %" PRIuOFF64 " B/s\n",
+				    offset / MBYTE, last_run,
+				    (offset-last_mark)/last_run,
+				    offset/total_time);
+				prev_time = cur_time;
+				last_mark = offset;
+			}
+			next_mark += MBYTE;
+		}
+	}
+	
+	struct timeval final_time;
+	rc = gettimeofday(&final_time, NULL);
+	if (rc != EOK) {
+		printf("gettimeofday failed\n");
+		fclose(file);
+		free(buf);
+		return 1;
+	}
+	
+	uint32_t total_run_time = final_time.tv_sec - start_time.tv_sec;
+	if (total_run_time > 0) {
+		printf("total bytes: %" PRIuOFF64 
+		    ", total time: %u s, avg speed: %" PRIuOFF64 " B/s\n",
+		    offset,
+		    total_run_time,
+		    offset/total_run_time);
+	}
+	
+	fclose(file);
+	free(buf);
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	printf("syntax: testread <filename>\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/tetris/Makefile
===================================================================
--- uspace/app/tetris/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -34,5 +34,4 @@
 	shapes.c \
 	scores.c \
-	input.c \
 	tetris.c \
 	screen.c
Index: pace/app/tetris/input.c
===================================================================
--- uspace/app/tetris/input.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,197 +1,0 @@
-/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
-/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)input.c	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup tetris
- * @{
- */
-/** @file
- */
-
-/*
- * Tetris input.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-
-#include <errno.h>
-#include <unistd.h>
-#include <str.h>
-
-#include "input.h"
-#include "tetris.h"
-
-#include <async.h>
-#include <vfs/vfs.h>
-#include <io/console.h>
-#include <ipc/console.h>
-
-/* return true iff the given timeval is positive */
-#define	TV_POS(tv) \
-	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
-
-/* subtract timeval `sub' from `res' */
-#define	TV_SUB(res, sub) \
-	(res)->tv_sec -= (sub)->tv_sec; \
-	(res)->tv_usec -= (sub)->tv_usec; \
-	if ((res)->tv_usec < 0) { \
-		(res)->tv_usec += 1000000; \
-		(res)->tv_sec--; \
-	}
-
-/* We will use a hack here - if lastchar is non-zero, it is
- * the last character read. We will somehow simulate the select
- * semantics.
- */
-static aid_t getchar_inprog = 0;
-static char lastchar = '\0';
-
-/*
- * Do a `read wait': select for reading from stdin, with timeout *tvp.
- * On return, modify *tvp to reflect the amount of time spent waiting.
- * It will be positive only if input appeared before the time ran out;
- * otherwise it will be zero or perhaps negative.
- *
- * If tvp is nil, wait forever, but return if select is interrupted.
- *
- * Return 0 => no input, 1 => can read() from stdin
- *
- */
-int rwait(struct timeval *tvp)
-{
-	struct timeval starttv, endtv, *s;
-	static ipc_call_t charcall;
-	sysarg_t rc;
-	
-	/*
-	 * Someday, select() will do this for us.
-	 * Just in case that day is now, and no one has
-	 * changed this, we use a temporary.
-	 */
-	if (tvp) {
-		(void) gettimeofday(&starttv, NULL);
-		endtv = *tvp;
-		s = &endtv;
-	} else
-		s = NULL;
-	
-	if (!lastchar) {
-again:
-		if (!getchar_inprog) {
-			getchar_inprog = async_send_0(fphone(stdin),
-			    CONSOLE_GET_EVENT, &charcall);
-		}
-		
-		if (!s)
-			async_wait_for(getchar_inprog, &rc);
-		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
-			tvp->tv_sec = 0;
-			tvp->tv_usec = 0;
-			return (0);
-		}
-		
-		getchar_inprog = 0;
-		if (rc)
-			stop("end of file, help");
-		
-		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
-			goto again;
-		
-		lastchar = IPC_GET_ARG4(charcall);
-	}
-	
-	if (tvp) {
-		/* since there is input, we may not have timed out */
-		(void) gettimeofday(&endtv, NULL);
-		TV_SUB(&endtv, &starttv);
-		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
-	}
-	
-	return 1;
-}
-
-/*
- * `sleep' for the current turn time (using select).
- * Eat any input that might be available.
- */
-void tsleep(void)
-{
-	struct timeval tv;
-	
-	tv.tv_sec = 0;
-	tv.tv_usec = fallrate;
-	while (TV_POS(&tv))
-		if (rwait(&tv)) {
-			lastchar = '\0';
-		} else
-			break;
-}
-
-/*
- * getchar with timeout.
- */
-int tgetchar(void)
-{
-	static struct timeval timeleft;
-	char c;
-	
-	/*
-	 * Reset timeleft to fallrate whenever it is not positive.
-	 * In any case, wait to see if there is any input.  If so,
-	 * take it, and update timeleft so that the next call to
-	 * tgetchar() will not wait as long.  If there is no input,
-	 * make timeleft zero or negative, and return -1.
-	 *
-	 * Most of the hard work is done by rwait().
-	 */
-	if (!TV_POS(&timeleft)) {
-		faster();  /* go faster */
-		timeleft.tv_sec = 0;
-		timeleft.tv_usec = fallrate;
-	}
-	
-	if (!rwait(&timeleft))
-		return -1;
-	
-	c = lastchar;
-	lastchar = '\0';
-	return ((int) (unsigned char) c);
-}
-
-/** @}
- */
Index: pace/app/tetris/input.h
===================================================================
--- uspace/app/tetris/input.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,49 +1,0 @@
-/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)input.h	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup tetris
- * @{
- */
-/** @file
- */
-
-extern int rwait(struct timeval *);
-extern int tgetchar(void);
-extern void tsleep(void);
-
-/** @}
- */
Index: uspace/app/tetris/scores.c
===================================================================
--- uspace/app/tetris/scores.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/scores.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: scores.c,v 1.11 2006/04/20 03:25:36 ray Exp $	*/
-/*	$NetBSD: scores.c,v 1.2 1995/04/22 07:42:38 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)scores.c	8.1 (Berkeley) 5/31/93
+ *
+ * - 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.
+ */
+
+/** Attributations
+ *
+ * scores.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: scores.c,v 1.2 1995/04/22 07:42:38 cgd
+ * OpenBSD: scores.c,v 1.11 2006/04/20 03:25:36 ray
+ *
+ * Based upon BSD Tetris
+ *
+ * Copyright (c) 1992, 1993
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
  */
 
@@ -60,5 +68,4 @@
 #include <err.h>
 #include <time.h>
-
 #include "screen.h"
 #include "tetris.h"
@@ -118,5 +125,5 @@
 	int j;
 	size_t off;
-	console_event_t ev;
+	kbd_event_t ev;
 	
 	clear_screen();
@@ -133,6 +140,6 @@
 	
 	while (1) {
-		fflush(stdout);
-		if (!console_get_event(fphone(stdin), &ev))
+		console_flush(console);
+		if (!console_get_kbd_event(console, &ev))
 			exit(1);
 		
Index: uspace/app/tetris/scores.h
===================================================================
--- uspace/app/tetris/scores.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/scores.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: scores.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: scores.h,v 1.2 1995/04/22 07:42:40 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
 
-/*-
+/** Attributations
+ *
+ * scores.h 8.1 (Berkeley) 5/31/93
+ * NetBSD: scores.h,v 1.2 1995/04/22 07:42:40 cgd
+ * OpenBSD: scores.h,v 1.5 2003/06/03 03:01:41 millert
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)scores.h	8.1 (Berkeley) 5/31/93
  */
 
@@ -41,5 +49,4 @@
 /** @file
  */
-
 
 /*
Index: uspace/app/tetris/screen.c
===================================================================
--- uspace/app/tetris/screen.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/screen.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray Exp $	*/
-/*	$NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)screen.c	8.1 (Berkeley) 5/31/93
+ *
+ * - 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.
+ */
+
+/** Attributations
+ *
+ * screen.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft
+ * OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray
+ *
+ * Based upon BSD Tetris
+ *
+ * Copyright (c) 1992, 1993
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
  */
 
@@ -69,4 +77,8 @@
 static const struct shape *lastshape;
 
+static suseconds_t timeleft = 0;
+
+console_ctrl_t *console;
+
 
 /*
@@ -82,6 +94,6 @@
 static void start_standout(uint32_t color)
 {
-	fflush(stdout);
-	console_set_rgb_color(fphone(stdout), 0xffffff,
+	console_flush(console);
+	console_set_rgb_color(console, 0xffffff,
 	    use_color ? color : 0x000000);
 }
@@ -89,11 +101,11 @@
 static void resume_normal(void)
 {
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(console);
+	console_set_style(console, STYLE_NORMAL);
 }
 
 void clear_screen(void)
 {
-	console_clear(fphone(stdout));
+	console_clear(console);
 	moveto(0, 0);
 }
@@ -105,5 +117,5 @@
 {
 	resume_normal();
-	console_clear(fphone(stdout));
+	console_clear(console);
 	curscore = -1;
 	memset(curscreen, 0, sizeof(curscreen));
@@ -115,5 +127,5 @@
 void scr_init(void)
 {
-	console_cursor_visibility(fphone(stdout), 0);
+	console_cursor_visibility(console, 0);
 	resume_normal();
 	scr_clear();
@@ -122,6 +134,6 @@
 void moveto(sysarg_t r, sysarg_t c)
 {
-	fflush(stdout);
-	console_set_pos(fphone(stdout), c, r);
+	console_flush(console);
+	console_set_pos(console, c, r);
 }
 
@@ -130,5 +142,5 @@
 static int get_display_size(winsize_t *ws)
 {
-	return console_get_size(fphone(stdout), &ws->ws_col, &ws->ws_row);
+	return console_get_size(console, &ws->ws_col, &ws->ws_row);
 }
 
@@ -136,5 +148,5 @@
 {
 	sysarg_t ccap;
-	int rc = console_get_color_cap(fphone(stdout), &ccap);
+	int rc = console_get_color_cap(console, &ccap);
 	
 	if (rc != 0)
@@ -179,5 +191,5 @@
 void scr_end(void)
 {
-	console_cursor_visibility(fphone(stdout), 1);
+	console_cursor_visibility(console, 1);
 }
 
@@ -302,5 +314,5 @@
 		resume_normal();
 	
-	fflush(stdout);
+	console_flush(console);
 }
 
@@ -322,4 +334,80 @@
 }
 
+/** Sleep for the current turn time
+ *
+ * Eat any input that might be available.
+ *
+ */
+void tsleep(void)
+{
+	suseconds_t timeout = fallrate;
+	
+	while (timeout > 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event_timeout(console, &event, &timeout))
+			break;
+	}
+}
+
+/** Get char with timeout
+ *
+ */
+int tgetchar(void)
+{
+	/*
+	 * Reset timeleft to fallrate whenever it is not positive
+	 * and increase speed.
+	 */
+	
+	if (timeleft <= 0) {
+		faster();
+		timeleft = fallrate;
+	}
+	
+	/*
+	 * Wait to see if there is any input. If so, take it and
+	 * update timeleft so that the next call to tgetchar()
+	 * will not wait as long. If there is no input,
+	 * make timeleft zero and return -1.
+	 */
+	
+	wchar_t c = 0;
+	
+	while (c == 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event_timeout(console, &event, &timeleft)) {
+			timeleft = 0;
+			return -1;
+		}
+		
+		if (event.type == KEY_PRESS)
+			c = event.c;
+	}
+	
+	return (int) c;
+}
+
+/** Get char without timeout
+ *
+ */
+int twait(void)
+{
+	wchar_t c = 0;
+	
+	while (c == 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event(console, &event))
+			return -1;
+		
+		if (event.type == KEY_PRESS)
+			c = event.c;
+	}
+	
+	return (int) c;
+}
+
 /** @}
  */
Index: uspace/app/tetris/screen.h
===================================================================
--- uspace/app/tetris/screen.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/screen.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: screen.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: screen.h,v 1.2 1995/04/22 07:42:42 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
 
-/*-
+/** Attributations
+ *
+ * screen.h 8.1 (Berkeley) 5/31/93
+ * NetBSD: screen.h,v 1.2 1995/04/22 07:42:42 cgd
+ * OpenBSD: screen.h,v 1.5 2003/06/03 03:01:41 millert
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)screen.h	8.1 (Berkeley) 5/31/93
  */
 
@@ -48,4 +56,5 @@
 
 #include <sys/types.h>
+#include <io/console.h>
 #include <async.h>
 #include <bool.h>
@@ -56,4 +65,5 @@
 } winsize_t;
 
+extern console_ctrl_t *console;
 extern winsize_t winsize;
 
@@ -61,5 +71,4 @@
 extern void clear_screen(void);
 
-/* just calls putchar; for tputs */
 extern int put(int);
 extern void scr_clear(void);
@@ -70,4 +79,8 @@
 extern void scr_update(void);
 
+extern void tsleep(void);
+extern int tgetchar(void);
+extern int twait(void);
+
 /** @}
  */
Index: uspace/app/tetris/shapes.c
===================================================================
--- uspace/app/tetris/shapes.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/shapes.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: shapes.c,v 1.8 2004/07/10 07:26:24 deraadt Exp $	*/
-/*	$NetBSD: shapes.c,v 1.2 1995/04/22 07:42:44 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
 
-/*-
+/** Attributations
+ *
+ * shapes.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: shapes.c,v 1.2 1995/04/22 07:42:44 cgd
+ * OpenBSD: shapes.c,v 1.8 2004/07/10 07:26:24 deraadt
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)shapes.c	8.1 (Berkeley) 5/31/93
  */
 
Index: uspace/app/tetris/tetris.c
===================================================================
--- uspace/app/tetris/tetris.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/tetris.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray Exp $	*/
-/*	$NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)tetris.c	8.1 (Berkeley) 5/31/93
+ *
+ * - 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.
+ */
+
+/** Attributations
+ *
+ * tetris.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd
+ * OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray
+ *
+ * Based upon BSD Tetris
+ *
+ * Copyright (c) 1992, 1993
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
  */
 
@@ -56,6 +64,4 @@
 #include <unistd.h>
 #include <getopt.h>
-
-#include "input.h"
 #include "scores.h"
 #include "screen.h"
@@ -245,8 +251,10 @@
 	int ch;
 	
+	console = console_init(stdin, stdout);
+	
 	keys = "jkl pq";
 	
 	classic = 0;
-	showpreview = 1; 
+	showpreview = 1;
 	
 	while ((ch = getopt(argc, argv, "ck:ps")) != -1)
@@ -371,6 +379,6 @@
 					scr_msg(key_msg, 0);
 					scr_msg(msg, 1);
-					(void) fflush(stdout);
-				} while (rwait((struct timeval *) NULL) == -1);
+					console_flush(console);
+				} while (!twait());
 				
 				scr_msg(msg, 0);
Index: uspace/app/tetris/tetris.h
===================================================================
--- uspace/app/tetris/tetris.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/tetris/tetris.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: tetris.h,v 1.9 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: tetris.h,v 1.2 1995/04/22 07:42:48 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
 
-/*-
+/** Attributations
+ *
+ * tetris.h 8.1 (Berkeley) 5/31/93
+ * NetBSD: tetris.h,v 1.2 1995/04/22 07:42:48 cgd
+ * OpenBSD: tetris.h,v 1.9 2003/06/03 03:01:41 millert
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)tetris.h	8.1 (Berkeley) 5/31/93
  */
 
Index: uspace/app/top/Makefile
===================================================================
--- uspace/app/top/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/top/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -33,6 +33,5 @@
 SOURCES = \
 	top.c \
-	screen.c \
-	input.c
+	screen.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: pace/app/top/input.c
===================================================================
--- uspace/app/top/input.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,200 +1,0 @@
-/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
-/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)input.c	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup top
- * @{
- */
-/** @file
- */
-
-/*
- * Top input.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <str.h>
-
-#include "input.h"
-
-#include <async.h>
-#include <vfs/vfs.h>
-#include <io/console.h>
-#include <ipc/console.h>
-
-#define USEC_COUNT 1000000
-
-/* return true iff the given timeval is positive */
-#define	TV_POS(tv) \
-	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
-
-/* subtract timeval `sub' from `res' */
-#define	TV_SUB(res, sub) \
-	(res)->tv_sec -= (sub)->tv_sec; \
-	(res)->tv_usec -= (sub)->tv_usec; \
-	if ((res)->tv_usec < 0) { \
-		(res)->tv_usec += 1000000; \
-		(res)->tv_sec--; \
-	}
-
-/* We will use a hack here - if lastchar is non-zero, it is
- * the last character read. We will somehow simulate the select
- * semantics.
- */
-static aid_t getchar_inprog = 0;
-static char lastchar = '\0';
-
-/*
- * Do a `read wait': select for reading from stdin, with timeout *tvp.
- * On return, modify *tvp to reflect the amount of time spent waiting.
- * It will be positive only if input appeared before the time ran out;
- * otherwise it will be zero or perhaps negative.
- *
- * If tvp is nil, wait forever, but return if select is interrupted.
- *
- * Return 0 => no input, 1 => can read() from stdin
- *
- */
-int rwait(struct timeval *tvp)
-{
-	struct timeval starttv, endtv, *s;
-	static ipc_call_t charcall;
-	sysarg_t rc;
-	
-	/*
-	 * Someday, select() will do this for us.
-	 * Just in case that day is now, and no one has
-	 * changed this, we use a temporary.
-	 */
-	if (tvp) {
-		(void) gettimeofday(&starttv, NULL);
-		endtv = *tvp;
-		s = &endtv;
-	} else
-		s = NULL;
-	
-	if (!lastchar) {
-again:
-		if (!getchar_inprog) {
-			getchar_inprog = async_send_0(fphone(stdin),
-			    CONSOLE_GET_EVENT, &charcall);
-		}
-		
-		if (!s)
-			async_wait_for(getchar_inprog, &rc);
-		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
-			tvp->tv_sec = 0;
-			tvp->tv_usec = 0;
-			return (0);
-		}
-		
-		getchar_inprog = 0;
-		if (rc) {
-			printf("End of file, bug?\n");
-			exit(1);
-		}
-		
-		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
-			goto again;
-		
-		lastchar = IPC_GET_ARG4(charcall);
-	}
-	
-	if (tvp) {
-		/* since there is input, we may not have timed out */
-		(void) gettimeofday(&endtv, NULL);
-		TV_SUB(&endtv, &starttv);
-		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
-	}
-	
-	return 1;
-}
-
-/*
- * `sleep' for the current turn time (using select).
- * Eat any input that might be available.
- */
-void tsleep(unsigned int sec)
-{
-	struct timeval tv;
-	
-	tv.tv_sec = 0;
-	tv.tv_usec = sec * USEC_COUNT;
-	while (TV_POS(&tv))
-		if (rwait(&tv)) {
-			lastchar = '\0';
-		} else
-			break;
-}
-
-/*
- * getchar with timeout.
- */
-int tgetchar(unsigned int sec)
-{
-	static struct timeval timeleft;
-	char c;
-	
-	/*
-	 * Reset timeleft to USEC_COUNT whenever it is not positive.
-	 * In any case, wait to see if there is any input.  If so,
-	 * take it, and update timeleft so that the next call to
-	 * tgetchar() will not wait as long.  If there is no input,
-	 * make timeleft zero or negative, and return -1.
-	 *
-	 * Most of the hard work is done by rwait().
-	 */
-	if (!TV_POS(&timeleft)) {
-		timeleft.tv_sec = 0;
-		timeleft.tv_usec = sec * USEC_COUNT;
-	}
-	
-	if (!rwait(&timeleft))
-		return -1;
-	
-	c = lastchar;
-	lastchar = '\0';
-	return ((int) (unsigned char) c);
-}
-
-/** @}
- */
Index: pace/app/top/input.h
===================================================================
--- uspace/app/top/input.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,56 +1,0 @@
-/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
- *
- *	@(#)input.h	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup top
- * @{
- */
-/** @file
- */
-
-#ifndef TOP_INPUT_
-#define TOP_INPUT_
-
-#include <sys/time.h>
-
-extern int rwait(struct timeval *);
-extern int tgetchar(unsigned int sec);
-extern void tsleep(unsigned int sec);
-
-#endif
-
-/** @}
- */
Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/top/screen.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -46,35 +46,40 @@
 #include "top.h"
 
+#define USEC_COUNT  1000000
+
 static sysarg_t warn_col = 0;
 static sysarg_t warn_row = 0;
+static suseconds_t timeleft = 0;
+
+console_ctrl_t *console;
 
 static void screen_style_normal(void)
 {
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(console);
+	console_set_style(console, STYLE_NORMAL);
 }
 
 static void screen_style_inverted(void)
 {
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_INVERTED);
+	console_flush(console);
+	console_set_style(console, STYLE_INVERTED);
 }
 
 static void screen_moveto(sysarg_t col, sysarg_t row)
 {
-	fflush(stdout);
-	console_set_pos(fphone(stdout), col, row);
+	console_flush(console);
+	console_set_pos(console, col, row);
 }
 
 static void screen_get_pos(sysarg_t *col, sysarg_t *row)
 {
-	fflush(stdout);
-	console_get_pos(fphone(stdout), col, row);
+	console_flush(console);
+	console_get_pos(console, col, row);
 }
 
 static void screen_get_size(sysarg_t *col, sysarg_t *row)
 {
-	fflush(stdout);
-	console_get_size(fphone(stdout), col, row);
+	console_flush(console);
+	console_get_size(console, col, row);
 }
 
@@ -84,6 +89,6 @@
 	
 	if (clear) {
-		fflush(stdout);
-		console_clear(fphone(stdout));
+		console_flush(console);
+		console_clear(console);
 	}
 	
@@ -111,6 +116,8 @@
 void screen_init(void)
 {
-	fflush(stdout);
-	console_cursor_visibility(fphone(stdout), false);
+	console = console_init(stdin, stdout);
+	
+	console_flush(console);
+	console_cursor_visibility(console, false);
 	
 	screen_restart(true);
@@ -121,6 +128,6 @@
 	screen_restart(true);
 	
-	fflush(stdout);
-	console_cursor_visibility(fphone(stdout), true);
+	console_flush(console);
+	console_cursor_visibility(console, true);
 }
 
@@ -508,5 +515,5 @@
 	}
 	
-	fflush(stdout);
+	console_flush(console);
 }
 
@@ -521,5 +528,41 @@
 	
 	screen_newline();
-	fflush(stdout);
+	console_flush(console);
+}
+
+/** Get char with timeout
+ *
+ */
+int tgetchar(unsigned int sec)
+{
+	/*
+	 * Reset timeleft whenever it is not positive.
+	 */
+	
+	if (timeleft <= 0)
+		timeleft = sec * USEC_COUNT;
+	
+	/*
+	 * Wait to see if there is any input. If so, take it and
+	 * update timeleft so that the next call to tgetchar()
+	 * will not wait as long. If there is no input,
+	 * make timeleft zero and return -1.
+	 */
+	
+	wchar_t c = 0;
+	
+	while (c == 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event_timeout(console, &event, &timeleft)) {
+			timeleft = 0;
+			return -1;
+		}
+		
+		if (event.type == KEY_PRESS)
+			c = event.c;
+	}
+	
+	return (int) c;
 }
 
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/top/screen.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,5 +35,8 @@
 #define TOP_SCREEN_H_
 
+#include <io/console.h>
 #include "top.h"
+
+extern console_ctrl_t *console;
 
 extern void screen_init(void);
@@ -42,4 +45,6 @@
 extern void print_warning(const char *, ...);
 
+extern int tgetchar(unsigned int);
+
 #endif
 
Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/top/top.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -46,5 +46,4 @@
 #include <sort.h>
 #include "screen.h"
-#include "input.h"
 #include "top.h"
 
Index: uspace/app/trace/ipc_desc.c
===================================================================
--- uspace/app/trace/ipc_desc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/trace/ipc_desc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -33,5 +33,6 @@
  */
 
-#include <ipc/common.h>
+#include <kernel/ipc/ipc.h>
+#include <kernel/ipc/ipc_methods.h>
 #include <stdlib.h>
 #include "ipc_desc.h"
@@ -39,16 +40,14 @@
 ipc_m_desc_t ipc_methods[] = {
 	/* System methods */
-	{ IPC_M_CONNECT_TO_ME,	"CONNECT_TO_ME" },
-	{ IPC_M_CONNECT_ME_TO,	"CONNECT_ME_TO" },
-	{ IPC_M_PHONE_HUNGUP,	"PHONE_HUNGUP" },
-	{ IPC_M_SHARE_OUT,	"SHARE_OUT" },
-	{ IPC_M_SHARE_IN,	"SHARE_IN" },
-	{ IPC_M_DATA_WRITE,	"DATA_WRITE" },
-	{ IPC_M_DATA_READ,	"DATA_READ" },
-	{ IPC_M_DEBUG_ALL,	"DEBUG_ALL" },
-
-	/* Well-known methods */
-	{ IPC_M_PING,		"PING" },
-
+	{ IPC_M_PHONE_HUNGUP,  "PHONE_HUNGUP" },
+	{ IPC_M_CONNECT_ME,    "CONNECT_ME" },
+	{ IPC_M_CONNECT_ME_TO, "CONNECT_ME_TO" },
+	{ IPC_M_CONNECT_TO_ME, "CONNECT_TO_ME" },
+	{ IPC_M_SHARE_OUT,     "SHARE_OUT" },
+	{ IPC_M_SHARE_IN,      "SHARE_IN" },
+	{ IPC_M_DATA_WRITE,    "DATA_WRITE" },
+	{ IPC_M_DATA_READ,     "DATA_READ" },
+	{ IPC_M_DEBUG,         "DEBUG" },
+	
 	/* Terminating entry */
 	{ 0, NULL }
Index: uspace/app/trace/ipcp.c
===================================================================
--- uspace/app/trace/ipcp.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/trace/ipcp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,5 +37,5 @@
 #include <adt/hash_table.h>
 #include <sys/typefmt.h>
-
+#include <kernel/ipc/ipc_methods.h>
 #include "ipc_desc.h"
 #include "proto.h"
@@ -268,17 +268,15 @@
 	proto_t *proto;
 	int cphone;
-
+	
 	sysarg_t *resp;
 	oper_t *oper;
 	int i;
-
-//	printf("parse_answer\n");
-
+	
 	phone = pcall->phone_hash;
 	method = IPC_GET_IMETHOD(pcall->question);
 	retval = IPC_GET_RETVAL(*answer);
-
+	
 	resp = answer->args;
-
+	
 	if ((display_mask & DM_IPC) != 0) {
 		printf("Response to %p: retval=%" PRIdn ", args = (%" PRIun ", "
@@ -288,11 +286,12 @@
 		    IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
 	}
-
+	
 	if ((display_mask & DM_USER) != 0) {
 		oper = pcall->oper;
-
-		if (oper != NULL && (oper->rv_type != V_VOID || oper->respc > 0)) {
+		
+		if ((oper != NULL) &&
+		    ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
 			printf("->");
-
+			
 			if (oper->rv_type != V_VOID) {
 				putchar(' ');
@@ -304,25 +303,29 @@
 				putchar('(');
 				for (i = 1; i <= oper->respc; ++i) {
-					if (i > 1) printf(", ");
+					if (i > 1)
+						printf(", ");
 					val_print(resp[i], oper->resp_type[i - 1]);
 				}
 				putchar(')');
 			}
-
+			
 			putchar('\n');
 		}
 	}
-
-	if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
+	
+	if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
+	    (retval == 0)) {
 		/* Connected to a service (through NS) */
 		service = IPC_GET_ARG1(pcall->question);
 		proto = proto_get_by_srv(service);
-		if (proto == NULL) proto = proto_unknown;
-
+		if (proto == NULL)
+			proto = proto_unknown;
+		
 		cphone = IPC_GET_ARG5(*answer);
 		if ((display_mask & DM_SYSTEM) != 0) {
 			printf("Registering connection (phone %d, protocol: %s)\n", cphone,
-		    		proto->name);
-		}
+		    proto->name);
+		}
+		
 		ipcp_connection_set(cphone, 0, proto);
 	}
@@ -334,7 +337,5 @@
 	pending_call_t *pcall;
 	unsigned long key[1];
-
-//	printf("ipcp_call_in()\n");
-
+	
 	if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
 		/* Not a response */
@@ -344,11 +345,12 @@
 		return;
 	}
-
+	
 	hash = hash & ~IPC_CALLID_ANSWERED;
 	key[0] = hash;
-
+	
 	item = hash_table_find(&pending_calls, key);
-	if (item == NULL) return; // No matching question found
-
+	if (item == NULL)
+		return; /* No matching question found */
+	
 	/*
 	 * Response matched to question.
@@ -357,5 +359,5 @@
 	pcall = hash_table_get_instance(item, pending_call_t, link);
 	hash_table_remove(&pending_calls, key, 1);
-
+	
 	parse_answer(hash, pcall, call);
 	free(pcall);
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/trace/syscalls.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,4 +40,5 @@
     [SYS_KLOG] ={ "klog",				3,	V_INT_ERRNO },
     [SYS_TLS_SET] = { "tls_set",			1,	V_ERRNO },
+
     [SYS_THREAD_CREATE] = { "thread_create",		3,	V_ERRNO },
     [SYS_THREAD_EXIT] = { "thread_exit",		1,	V_ERRNO },
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/app/trace/trace.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -72,5 +72,5 @@
 ipc_call_t thread_ipc_req[THBUF_SIZE];
 
-int phoneid;
+async_sess_t *sess;
 bool abort_trace;
 
@@ -81,5 +81,5 @@
 
 static bool cev_valid;
-static console_event_t cev;
+static kbd_event_t cev;
 
 void thread_trace_start(uintptr_t thread_hash);
@@ -146,36 +146,33 @@
 static int connect_task(task_id_t task_id)
 {
-	int rc;
-
-	rc = async_connect_kbox(task_id);
-
-	if (rc == ENOTSUP) {
-		printf("You do not have userspace debugging support "
-		    "compiled in the kernel.\n");
-		printf("Compile kernel with 'Support for userspace debuggers' "
-		    "(CONFIG_UDEBUG) enabled.\n");
-		return rc;
-	}
-
-	if (rc < 0) {
+	async_sess_t *ksess = async_connect_kbox(task_id);
+	
+	if (!ksess) {
+		if (errno == ENOTSUP) {
+			printf("You do not have userspace debugging support "
+			    "compiled in the kernel.\n");
+			printf("Compile kernel with 'Support for userspace debuggers' "
+			    "(CONFIG_UDEBUG) enabled.\n");
+			return errno;
+		}
+		
 		printf("Error connecting\n");
-		printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, rc);
-		return rc;
-	}
-
-	phoneid = rc;
-
-	rc = udebug_begin(phoneid);
+		printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, errno);
+		return errno;
+	}
+	
+	int rc = udebug_begin(ksess);
 	if (rc < 0) {
 		printf("udebug_begin() -> %d\n", rc);
 		return rc;
 	}
-
-	rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
+	
+	rc = udebug_set_evmask(ksess, UDEBUG_EM_ALL);
 	if (rc < 0) {
 		printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
 		return rc;
 	}
-
+	
+	sess = ksess;
 	return 0;
 }
@@ -188,5 +185,5 @@
 	int i;
 
-	rc = udebug_thread_read(phoneid, thread_hash_buf,
+	rc = udebug_thread_read(sess, thread_hash_buf,
 		THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
 	if (rc < 0) {
@@ -314,5 +311,5 @@
 
 	memset(&call, 0, sizeof(call));
-	rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
+	rc = udebug_mem_read(sess, &call.args, sc_args[1], sizeof(call.args));
 
 	if (rc >= 0) {
@@ -325,8 +322,7 @@
 	ipc_call_t question, reply;
 	int rc;
-	int phoneidx;
-
-//	printf("sc_ipc_call_sync_fast()\n");
-	phoneidx = sc_args[0];
+	int phoneid;
+
+	phoneid = sc_args[0];
 
 	IPC_SET_IMETHOD(question, sc_args[1]);
@@ -337,14 +333,10 @@
 	IPC_SET_ARG5(question, 0);
 
-//	printf("memset\n");
 	memset(&reply, 0, sizeof(reply));
-//	printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
-//		phoneid, &reply.args, sc_args[5], sizeof(reply.args));
-	rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
-//	printf("dmr->%d\n", rc);
-	if (rc < 0) return;
-
-//	printf("call ipc_call_sync\n");
-	ipcp_call_sync(phoneidx, &question, &reply);
+	rc = udebug_mem_read(sess, &reply.args, sc_args[5], sizeof(reply.args));
+	if (rc < 0)
+		return;
+	
+	ipcp_call_sync(phoneid, &question, &reply);
 }
 
@@ -355,5 +347,5 @@
 
 	memset(&question, 0, sizeof(question));
-	rc = udebug_mem_read(phoneid, &question.args, sc_args[1],
+	rc = udebug_mem_read(sess, &question.args, sc_args[1],
 	    sizeof(question.args));
 
@@ -372,5 +364,5 @@
 
 	memset(&reply, 0, sizeof(reply));
-	rc = udebug_mem_read(phoneid, &reply.args, sc_args[2],
+	rc = udebug_mem_read(sess, &reply.args, sc_args[2],
 	    sizeof(reply.args));
 
@@ -391,11 +383,8 @@
 
 	memset(&call, 0, sizeof(call));
-	rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
-//	printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
-//		phoneid, (int)&call, sc_args[0], sizeof(call), rc);
-
-	if (rc >= 0) {
+	rc = udebug_mem_read(sess, &call, sc_args[0], sizeof(call));
+	
+	if (rc >= 0)
 		ipcp_call_in(&call, sc_rc);
-	}
 }
 
@@ -407,13 +396,8 @@
 
 	/* Read syscall arguments */
-	rc = udebug_args_read(phoneid, thread_hash, sc_args);
-
-	async_serialize_start();
-
-//	printf("[%d] ", thread_id);
+	rc = udebug_args_read(sess, thread_hash, sc_args);
 
 	if (rc < 0) {
 		printf("error\n");
-		async_serialize_end();
 		return;
 	}
@@ -432,6 +416,4 @@
 		break;
 	}
-
-	async_serialize_end();
 }
 
@@ -444,7 +426,5 @@
 
 	/* Read syscall arguments */
-	rc = udebug_args_read(phoneid, thread_hash, sc_args);
-
-	async_serialize_start();
+	rc = udebug_args_read(sess, thread_hash, sc_args);
 
 //	printf("[%d] ", thread_id);
@@ -452,5 +432,4 @@
 	if (rc < 0) {
 		printf("error\n");
-		async_serialize_end();
 		return;
 	}
@@ -481,14 +460,9 @@
 		break;
 	}
-
-	async_serialize_end();
 }
 
 static void event_thread_b(uintptr_t hash)
 {
-	async_serialize_start();
 	printf("New thread, hash %p\n", (void *) hash);
-	async_serialize_end();
-
 	thread_trace_start(hash);
 }
@@ -527,5 +501,5 @@
 
 		/* Run thread until an event occurs */
-		rc = udebug_go(phoneid, thread_hash,
+		rc = udebug_go(sess, thread_hash,
 		    &ev_type, &val0, &val1);
 
@@ -656,5 +630,7 @@
 {
 	(void) arg;
-
+	
+	console_ctrl_t *console = console_init(stdin, stdout);
+	
 	while (true) {
 		fibril_mutex_lock(&state_lock);
@@ -662,12 +638,12 @@
 			fibril_condvar_wait(&state_cv, &state_lock);
 		fibril_mutex_unlock(&state_lock);
-
-		if (!console_get_event(fphone(stdin), &cev))
+		
+		if (!console_get_kbd_event(console, &cev))
 			return -1;
-
+		
 		fibril_mutex_lock(&state_lock);
 		cev_valid = true;
 		fibril_condvar_broadcast(&state_cv);
-		fibril_mutex_unlock(&state_lock);		
+		fibril_mutex_unlock(&state_lock);
 	}
 }
@@ -675,5 +651,5 @@
 static void trace_task(task_id_t task_id)
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	bool done;
 	int i;
@@ -727,5 +703,5 @@
 		case KC_P:
 			printf("Pause...\n");
-			rc = udebug_stop(phoneid, thash);
+			rc = udebug_stop(sess, thash);
 			if (rc != EOK)
 				printf("Error: stop -> %d\n", rc);
@@ -743,6 +719,6 @@
 	printf("\nTerminate debugging session...\n");
 	abort_trace = true;
-	udebug_end(phoneid);
-	async_hangup(phoneid);
+	udebug_end(sess);
+	async_hangup(sess);
 
 	ipcp_cleanup();
Index: uspace/app/usbinfo/Makefile
===================================================================
--- uspace/app/usbinfo/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2010 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = usbinfo
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+SOURCES = \
+	desctree.c \
+	dev.c \
+	dump.c \
+	info.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/usbinfo/desctree.c
===================================================================
--- uspace/app/usbinfo/desctree.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/desctree.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010 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 usbinfo
+ * @{
+ */
+/**
+ * @file
+ * Descriptor tree dump.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+
+#include "usbinfo.h"
+#include <usb/dev/dp.h>
+
+static void browse_descriptor_tree_internal(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
+    dump_descriptor_in_tree_t callback, void *arg)
+{
+	if (root == NULL) {
+		return;
+	}
+	callback(root, depth, arg);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		browse_descriptor_tree_internal(parser, data, child, depth + 1,
+		    callback, arg);
+		child = usb_dp_get_sibling_descriptor(parser, data,
+		    root, child);
+	} while (child != NULL);
+}
+
+void browse_descriptor_tree(uint8_t *descriptors, size_t descriptors_size,
+    usb_dp_descriptor_nesting_t *descriptor_nesting,
+    dump_descriptor_in_tree_t callback, size_t initial_depth, void *arg)
+{
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = descriptors_size,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = descriptor_nesting
+	};
+
+	browse_descriptor_tree_internal(&parser, &data, descriptors,
+	    initial_depth, callback, arg);
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/dev.c
===================================================================
--- uspace/app/usbinfo/dev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/dev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,127 @@
+/*
+ * 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 usbinfo
+ * @{
+ */
+/**
+ * @file
+ * Representation of queried device.
+ */
+#include <usb/dev/pipes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/dev/request.h>
+#include "usbinfo.h"
+
+usbinfo_device_t *prepare_device(const char *name,
+    devman_handle_t hc_handle, usb_address_t dev_addr)
+{
+	usbinfo_device_t *dev = malloc(sizeof(usbinfo_device_t));
+	if (dev == NULL) {
+		fprintf(stderr, NAME ": memory allocation failed.\n");
+		return NULL;
+	}
+
+	int rc;
+	bool transfer_started = false;
+
+	rc = usb_device_connection_initialize(&dev->wire, hc_handle, dev_addr);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to create connection to device %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
+	    &dev->wire);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to create default control pipe to %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	rc = usb_pipe_probe_default_control(&dev->ctrl_pipe);
+	if (rc != EOK) {
+		if (rc == ENOENT) {
+			fprintf(stderr, NAME ": " \
+			    "device %s not present or malfunctioning.\n",
+			    name);
+		} else {
+			fprintf(stderr, NAME ": " \
+			    "probing default control pipe of %s failed: %s.\n",
+			    name, str_error(rc));
+		}
+		goto leave;
+	}
+
+	usb_pipe_start_long_transfer(&dev->ctrl_pipe);
+	transfer_started = true;
+
+	rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
+	    &dev->device_descriptor);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to retrieve device descriptor of %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    &dev->ctrl_pipe, 0, (void **)&dev->full_configuration_descriptor,
+	    &dev->full_configuration_descriptor_size);
+	if (rc != EOK) {
+		fprintf(stderr, NAME ": " \
+		    "failed to retrieve configuration descriptor of %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	return dev;
+
+
+leave:
+	if (transfer_started) {
+		usb_pipe_end_long_transfer(&dev->ctrl_pipe);
+	}
+
+	free(dev);
+
+	return NULL;
+}
+
+void destroy_device(usbinfo_device_t *dev)
+{
+	usb_pipe_end_long_transfer(&dev->ctrl_pipe);
+	free(dev);
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2010 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 usbinfo
+ * @{
+ */
+/**
+ * @file
+ * USB querying.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+
+#include "usbinfo.h"
+#include <usb/dev/dp.h>
+
+#define INDENT "  "
+#define BYTES_PER_LINE 12
+
+
+const char *get_indent(size_t level)
+{
+	static const char *indents[] = {
+		INDENT,
+		INDENT INDENT,
+		INDENT INDENT INDENT,
+		INDENT INDENT INDENT INDENT,
+		INDENT INDENT INDENT INDENT INDENT
+	};
+	static size_t indents_count = sizeof(indents)/sizeof(indents[0]);
+	if (level >= indents_count) {
+		return indents[indents_count - 1];
+	}
+	return indents[level];
+}
+
+void dump_buffer(const char *msg, size_t indent,
+    const uint8_t *buffer, size_t length)
+{
+	if (msg != NULL) {
+		printf("%s\n", msg);
+	}
+
+	size_t i;
+	if (length > 0) {
+		printf("%s", get_indent(indent));
+	}
+	for (i = 0; i < length; i++) {
+		printf("0x%02X", buffer[i]);
+		if (((i > 0) && (((i+1) % BYTES_PER_LINE) == 0))
+		    || (i + 1 == length)) {
+			printf("\n");
+			if (i + 1 < length) {
+				printf("%s", get_indent(indent));
+			}
+		} else {
+			printf("  ");
+		}
+	}
+}
+
+void dump_usb_descriptor(uint8_t *descriptor, size_t size)
+{
+	printf("Device descriptor:\n");
+	usb_dump_standard_descriptor(stdout, get_indent(0), "\n",
+	    descriptor, size);
+}
+
+void dump_match_ids(match_id_list_t *matches, const char *line_prefix)
+{
+	link_t *link;
+	for (link = matches->ids.next;
+	    link != &matches->ids;
+	    link = link->next) {
+		match_id_t *match = list_get_instance(link, match_id_t, link);
+
+		printf("%s%3d %s\n", line_prefix, match->score, match->id);
+	}
+}
+
+static void dump_tree_descriptor(uint8_t *descriptor, size_t depth)
+{
+	if (descriptor == NULL) {
+		return;
+	}
+	int type = (int) *(descriptor + 1);
+	const char *name = "unknown";
+	switch (type) {
+#define _TYPE(descriptor_type) \
+		case USB_DESCTYPE_##descriptor_type: name = #descriptor_type; break
+		_TYPE(DEVICE);
+		_TYPE(CONFIGURATION);
+		_TYPE(STRING);
+		_TYPE(INTERFACE);
+		_TYPE(ENDPOINT);
+		_TYPE(HID);
+		_TYPE(HID_REPORT);
+		_TYPE(HID_PHYSICAL);
+		_TYPE(HUB);
+#undef _TYPE
+	}
+	printf("%s%s (0x%02X):\n", get_indent(depth), name, type);
+	usb_dump_standard_descriptor(stdout, get_indent(depth), "\n",
+	    descriptor, descriptor[0]);
+}
+
+static void dump_tree_internal(usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
+    uint8_t *root, size_t depth)
+{
+	if (root == NULL) {
+		return;
+	}
+	dump_tree_descriptor(root, depth);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		dump_tree_internal(parser, data, child, depth + 1);
+		child = usb_dp_get_sibling_descriptor(parser, data, root, child);
+	} while (child != NULL);
+}
+
+static void dump_tree(usb_dp_parser_t *parser, usb_dp_parser_data_t *data)
+{
+	uint8_t *ptr = data->data;
+	printf("Descriptor tree:\n");
+	dump_tree_internal(parser, data, ptr, 0);
+}
+
+#define NESTING(parentname, childname) \
+	{ \
+		.child = USB_DESCTYPE_##childname, \
+		.parent = USB_DESCTYPE_##parentname, \
+	}
+#define LAST_NESTING { -1, -1 }
+
+static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
+	NESTING(CONFIGURATION, INTERFACE),
+	NESTING(INTERFACE, ENDPOINT),
+	NESTING(INTERFACE, HUB),
+	NESTING(INTERFACE, HID),
+	NESTING(HID, HID_REPORT),
+	LAST_NESTING
+};
+
+static usb_dp_parser_t parser = {
+	.nesting = descriptor_nesting
+};
+
+void dump_descriptor_tree(uint8_t *descriptors, size_t length)
+{
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = length,
+		.arg = NULL
+	};
+
+	dump_tree(&parser, &data);
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/info.c
===================================================================
--- uspace/app/usbinfo/info.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/info.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,394 @@
+/*
+ * 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 usbinfo
+ * @{
+ */
+/**
+ * @file
+ * Dumping of generic device properties.
+ */
+#include <stdio.h>
+#include <str_error.h>
+#include <errno.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/recognise.h>
+#include <usb/dev/request.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hub.h>
+#include "usbinfo.h"
+
+void dump_short_device_identification(usbinfo_device_t *dev)
+{
+	printf("%sDevice 0x%04x by vendor 0x%04x\n", get_indent(0),
+	    (int) dev->device_descriptor.product_id,
+	    (int) dev->device_descriptor.vendor_id);
+}
+
+static void dump_match_ids_from_interface(uint8_t *descriptor, size_t depth,
+    void *arg)
+{
+	if (depth != 1) {
+		return;
+	}
+	size_t descr_size = descriptor[0];
+	if (descr_size < sizeof(usb_standard_interface_descriptor_t)) {
+		return;
+	}
+	int descr_type = descriptor[1];
+	if (descr_type != USB_DESCTYPE_INTERFACE) {
+		return;
+	}
+
+	usbinfo_device_t *dev = (usbinfo_device_t *) arg;
+
+	usb_standard_interface_descriptor_t *iface
+	    = (usb_standard_interface_descriptor_t *) descriptor;
+
+	printf("%sInterface #%d match ids (%s, 0x%02x, 0x%02x)\n",
+	    get_indent(0),
+	    (int) iface->interface_number,
+	    usb_str_class(iface->interface_class),
+	    (int) iface->interface_subclass,
+	    (int) iface->interface_protocol);
+
+	match_id_list_t matches;
+	init_match_ids(&matches);
+	usb_device_create_match_ids_from_interface(&dev->device_descriptor,
+	    iface, &matches);
+	dump_match_ids(&matches, get_indent(1));
+	clean_match_ids(&matches);
+}
+
+void dump_device_match_ids(usbinfo_device_t *dev)
+{
+	match_id_list_t matches;
+	init_match_ids(&matches);
+	usb_device_create_match_ids_from_device_descriptor(
+	    &dev->device_descriptor, &matches);
+	printf("%sDevice match ids (0x%04x by 0x%04x, %s)\n", get_indent(0),
+	    (int) dev->device_descriptor.product_id,
+	    (int) dev->device_descriptor.vendor_id,
+	    usb_str_class(dev->device_descriptor.device_class));
+	dump_match_ids(&matches, get_indent(1));
+	clean_match_ids(&matches);
+
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_match_ids_from_interface,
+	    dev);
+}
+
+static void dump_descriptor_tree_brief_device(const char *prefix,
+    usb_standard_device_descriptor_t *descriptor)
+{
+	printf("%sDevice (0x%04x by 0x%04x, %s, %zu configurations)\n", prefix,
+	    (int) descriptor->product_id,
+	    (int) descriptor->vendor_id,
+	    usb_str_class(descriptor->device_class),
+	    (size_t) descriptor->configuration_count);
+}
+
+static void dump_descriptor_tree_brief_configuration(const char *prefix,
+    usb_standard_configuration_descriptor_t *descriptor)
+{
+	printf("%sConfiguration #%d (%zu interfaces, total %zuB)\n", prefix,
+	    (int) descriptor->configuration_number,
+	    (size_t) descriptor->interface_count,
+	    (size_t) descriptor->total_length);
+}
+
+static void dump_descriptor_tree_brief_interface(const char *prefix,
+    usb_standard_interface_descriptor_t *descriptor)
+{
+	printf("%sInterface #%d (%s, 0x%02x, 0x%02x), alternate %d\n", prefix,
+	    (int) descriptor->interface_number,
+	    usb_str_class(descriptor->interface_class),
+	    (int) descriptor->interface_subclass,
+	    (int) descriptor->interface_protocol,
+	    (int) descriptor->alternate_setting);
+}
+
+static void dump_descriptor_tree_brief_endpoint(const char *prefix,
+    usb_standard_endpoint_descriptor_t *descriptor)
+{
+	usb_endpoint_t endpoint_no = descriptor->endpoint_address & 0xF;
+	usb_transfer_type_t transfer = descriptor->attributes & 0x3;
+	usb_direction_t direction = descriptor->endpoint_address & 0x80
+	    ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
+	printf("%sEndpoint #%d (%s %s, %zu)\n", prefix,
+	    endpoint_no, usb_str_transfer_type(transfer),
+	    direction == USB_DIRECTION_IN ? "in" : "out",
+	    (size_t) descriptor->max_packet_size);
+}
+
+static void dump_descriptor_tree_brief_hid(const char *prefix,
+    usb_standard_hid_descriptor_t *descriptor)
+{
+	printf("%sHID (country %d, %d descriptors)\n", prefix,
+	    (int) descriptor->country_code,
+	    (int) descriptor->class_desc_count);
+}
+
+static void dump_descriptor_tree_brief_hub(const char *prefix,
+    usb_hub_descriptor_header_t *descriptor)
+{
+	printf("%shub (%d ports)\n", prefix,
+	    (int) descriptor->port_count);
+}
+
+
+static void dump_descriptor_tree_callback(uint8_t *descriptor,
+    size_t depth, void *arg)
+{
+	const char *indent = get_indent(depth + 1);
+
+	int descr_type = -1;
+	size_t descr_size = descriptor[0];
+	if (descr_size > 0) {
+		descr_type = descriptor[1];
+	}
+
+	switch (descr_type) {
+
+#define _BRANCH(type_enum, descriptor_type, callback) \
+	case type_enum: \
+		if (descr_size >= sizeof(descriptor_type)) { \
+			callback(indent, (descriptor_type *) descriptor); \
+			if (arg != NULL) { \
+				usb_dump_standard_descriptor(stdout, \
+				    get_indent(depth +2), "\n", \
+				    descriptor, descr_size); \
+			} \
+		} else { \
+			descr_type = -1; \
+		} \
+		break;
+
+		_BRANCH(USB_DESCTYPE_DEVICE,
+		    usb_standard_device_descriptor_t,
+		    dump_descriptor_tree_brief_device);
+		_BRANCH(USB_DESCTYPE_CONFIGURATION,
+		    usb_standard_configuration_descriptor_t,
+		    dump_descriptor_tree_brief_configuration);
+		_BRANCH(USB_DESCTYPE_INTERFACE,
+		    usb_standard_interface_descriptor_t,
+		    dump_descriptor_tree_brief_interface);
+		_BRANCH(USB_DESCTYPE_ENDPOINT,
+		    usb_standard_endpoint_descriptor_t,
+		    dump_descriptor_tree_brief_endpoint);
+		_BRANCH(USB_DESCTYPE_HID,
+		    usb_standard_hid_descriptor_t,
+		    dump_descriptor_tree_brief_hid);
+		/*
+		 * Probably useless, hub descriptor shall not be part of
+		 * configuration descriptor.
+		 */
+		_BRANCH(USB_DESCTYPE_HUB,
+		    usb_hub_descriptor_header_t,
+		    dump_descriptor_tree_brief_hub);
+
+		default:
+			break;
+	}
+
+	if (descr_type == -1) {
+		printf("%sInvalid descriptor.\n", indent);
+	}
+}
+
+void dump_descriptor_tree_brief(usbinfo_device_t *dev)
+{
+	dump_descriptor_tree_callback((uint8_t *)&dev->device_descriptor,
+	    (size_t) -1, NULL);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_descriptor_tree_callback,
+	    NULL);
+}
+
+void dump_descriptor_tree_full(usbinfo_device_t *dev)
+{
+	dump_descriptor_tree_callback((uint8_t *)&dev->device_descriptor,
+	    (size_t) -1, dev);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_descriptor_tree_callback,
+	    dev);
+}
+
+static void find_string_indexes_callback(uint8_t *descriptor,
+    size_t depth, void *arg)
+{
+	size_t descriptor_length = descriptor[0];
+	if (descriptor_length <= 1) {
+		return;
+	}
+
+	/*printf("Found string in %s->%s: %zu\n",
+	    #descr_struct, #descr_item, __str_index); */
+#define SET_STRING_INDEX(descr, mask, descr_type, descr_struct, descr_item) \
+	do { \
+		if ((descr)[1] == (descr_type)) { \
+			descr_struct *__type_descr = (descr_struct *) (descr); \
+			size_t __str_index = __type_descr->descr_item; \
+			if ((__str_index > 0) && (__str_index < 64)) { \
+				mask = (mask) | (1 << __str_index); \
+			} \
+		} \
+	} while (0)
+
+	uint64_t *mask = arg;
+
+#define SET_STR(descr_type, descr_struct, descr_item) \
+	SET_STRING_INDEX(descriptor, (*mask), descr_type, descr_struct, descr_item)
+
+	SET_STR(USB_DESCTYPE_DEVICE, usb_standard_device_descriptor_t,
+	    str_manufacturer);
+	SET_STR(USB_DESCTYPE_DEVICE, usb_standard_device_descriptor_t,
+	    str_product);
+	SET_STR(USB_DESCTYPE_DEVICE, usb_standard_device_descriptor_t,
+	    str_serial_number);
+	SET_STR(USB_DESCTYPE_CONFIGURATION, usb_standard_configuration_descriptor_t,
+	    str_configuration);
+	SET_STR(USB_DESCTYPE_INTERFACE, usb_standard_interface_descriptor_t,
+	    str_interface);
+}
+
+
+void dump_strings(usbinfo_device_t *dev)
+{
+	/* Get supported languages. */
+	l18_win_locales_t *langs;
+	size_t langs_count;
+	int rc = usb_request_get_supported_languages(&dev->ctrl_pipe,
+	    &langs, &langs_count);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to get list of supported languages: %s.\n",
+		    str_error(rc));
+		return;
+	}
+
+	printf("%sString languages (%zu):", get_indent(0), langs_count);
+	size_t i;
+	for (i = 0; i < langs_count; i++) {
+		printf(" 0x%04x", (int) langs[i]);
+	}
+	printf(".\n");
+
+	/* Find used indexes. Device with more than 64 strings are very rare.
+	 */
+	uint64_t str_mask = 0;
+	find_string_indexes_callback((uint8_t *)&dev->device_descriptor, 0,
+	    &str_mask);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    find_string_indexes_callback,
+	    &str_mask);
+
+	/* Get all strings and dump them. */
+	for (i = 0; i < langs_count; i++) {
+		l18_win_locales_t lang = langs[i];
+
+		printf("%sStrings in %s:\n", get_indent(0),
+		    str_l18_win_locale(lang));
+
+		size_t idx;
+		for (idx = 1; idx < 64; idx++) {
+			if ((str_mask & ((uint64_t)1 << idx)) == 0) {
+				continue;
+			}
+			char *string = NULL;
+			rc = usb_request_get_string(&dev->ctrl_pipe, idx, lang,
+			    &string);
+			if ((rc != EOK) && (rc != EEMPTY)) {
+				printf("%sWarn: failed to retrieve string #%zu: %s.\n",
+				    get_indent(1), idx, str_error(rc));
+				continue;
+			}
+			printf("%sString #%zu: \"%s\"\n", get_indent(1),
+			    idx, rc == EOK ? string : "");
+			if (string != NULL) {
+				free(string);
+			}
+		}
+	}
+}
+
+
+void dump_status(usbinfo_device_t *dev)
+{
+	int rc;
+	uint16_t device_status = 0;
+	uint16_t ctrl_pipe_status = 0;
+
+	/* Device status first. */
+	rc = usb_request_get_status(&dev->ctrl_pipe,
+	    USB_REQUEST_RECIPIENT_DEVICE, 0,
+	    &device_status);
+	if (rc != EOK) {
+		printf("%sFailed to get device status: %s.\n",
+		    get_indent(0), str_error(rc));
+		goto try_ctrl_pipe_status;
+	}
+
+	printf("%sDevice status 0x%04x: power=%s, remote-wakeup=%s.\n",
+	    get_indent(0),
+	    device_status,
+	    device_status & USB_DEVICE_STATUS_SELF_POWERED ? "self" : "bus",
+	    device_status & USB_DEVICE_STATUS_REMOTE_WAKEUP ? "yes" : "no");
+
+	/* Interface is not interesting, skipping ;-). */
+
+	/* Control endpoint zero. */
+try_ctrl_pipe_status:
+	rc = usb_request_get_status(&dev->ctrl_pipe,
+	    USB_REQUEST_RECIPIENT_ENDPOINT, 0,
+	    &ctrl_pipe_status);
+	if (rc != EOK) {
+		printf("%sFailed to get control endpoint status: %s.\n",
+		    get_indent(0), str_error(rc));
+		goto leave;
+	}
+
+	printf("%sControl endpoint zero status %04X: halted=%s.\n",
+	    get_indent(0),
+	    ctrl_pipe_status,
+	    ctrl_pipe_status & USB_ENDPOINT_STATUS_HALTED ? "yes" : "no");
+
+leave:
+	return;
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2010-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 usbinfo
+ * @{
+ */
+/**
+ * @file
+ * USB querying.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <getopt.h>
+#include <devman.h>
+#include <devmap.h>
+#include <usb/hc.h>
+#include <usb/dev/pipes.h>
+#include "usbinfo.h"
+
+static void print_usage(char *app_name)
+{
+#define _INDENT "      "
+#define _OPTION(opt, description) \
+	printf(_INDENT opt "\n" _INDENT _INDENT description "\n")
+
+	printf(NAME ": query USB devices for descriptors\n\n");
+	printf("Usage: %s [options] device [device [device [ ... ]]]\n",
+	    app_name);
+	printf(_INDENT "The device is a devman path to the device.\n");
+
+	_OPTION("-h --help", "Print this help and exit.");
+	_OPTION("-i --identification", "Brief device identification.");
+	_OPTION("-m --match-ids", "Print match ids generated for the device.");
+	_OPTION("-t --descriptor-tree", "Print descriptor tree.");
+	_OPTION("-T --descriptor-tree-full", "Print detailed descriptor tree");
+	_OPTION("-s --strings", "Try to print all string descriptors.");
+	_OPTION("-S --status", "Get status of the device.");
+
+	printf("\n");
+	printf("If no option is specified, `-i' is considered default.\n");
+	printf("\n");
+
+#undef _OPTION
+#undef _INDENT
+}
+
+static struct option long_options[] = {
+	{"help", no_argument, NULL, 'h'},
+	{"identification", no_argument, NULL, 'i'},
+	{"match-ids", no_argument, NULL, 'm'},
+	{"descriptor-tree", no_argument, NULL, 't'},
+	{"descriptor-tree-full", no_argument, NULL, 'T'},
+	{"strings", no_argument, NULL, 's'},
+	{"status", no_argument, NULL, 'S'},
+	{0, 0, NULL, 0}
+};
+static const char *short_options = "himtTsS";
+
+static usbinfo_action_t actions[] = {
+	{
+		.opt = 'i',
+		.action = dump_short_device_identification,
+		.active = false
+	},
+	{
+		.opt = 'm',
+		.action = dump_device_match_ids,
+		.active = false
+	},
+	{
+		.opt = 't',
+		.action = dump_descriptor_tree_brief,
+		.active = false
+	},
+	{
+		.opt = 'T',
+		.action = dump_descriptor_tree_full,
+		.active = false
+	},
+	{
+		.opt = 's',
+		.action = dump_strings,
+		.active = false
+	},
+	{
+		.opt = 'S',
+		.action = dump_status,
+		.active = false
+	},
+	{
+		.opt = 0
+	}
+};
+
+int main(int argc, char *argv[])
+{
+	if (argc <= 1) {
+		print_usage(argv[0]);
+		return -1;
+	}
+
+	/*
+	 * Process command-line options. They determine what shall be
+	 * done with the device.
+	 */
+	int opt;
+	do {
+		opt = getopt_long(argc, argv,
+		    short_options, long_options, NULL);
+		switch (opt) {
+			case -1:
+				break;
+			case '?':
+				print_usage(argv[0]);
+				return 1;
+			case 'h':
+				print_usage(argv[0]);
+				return 0;
+			default: {
+				int idx = 0;
+				while (actions[idx].opt != 0) {
+					if (actions[idx].opt == opt) {
+						actions[idx].active = true;
+						break;
+					}
+					idx++;
+				}
+				break;
+			}
+		}
+	} while (opt > 0);
+
+	/* Set the default action. */
+	int idx = 0;
+	bool something_active = false;
+	while (actions[idx].opt != 0) {
+		if (actions[idx].active) {
+			something_active = true;
+			break;
+		}
+		idx++;
+	}
+	if (!something_active) {
+		actions[0].active = true;
+	}
+
+	/*
+	 * Go through all devices given on the command line and run the
+	 * specified actions.
+	 */
+	int i;
+	for (i = optind; i < argc; i++) {
+		char *devpath = argv[i];
+
+		/* The initialization is here only to make compiler happy. */
+		devman_handle_t hc_handle = 0;
+		usb_address_t dev_addr = 0;
+		int rc = usb_resolve_device_handle(devpath,
+		    &hc_handle, &dev_addr, NULL);
+		if (rc != EOK) {
+			fprintf(stderr, NAME ": device `%s' not found "
+			    "or not of USB kind, skipping.\n",
+			    devpath);
+			continue;
+		}
+
+		usbinfo_device_t *dev = prepare_device(devpath,
+		    hc_handle, dev_addr);
+		if (dev == NULL) {
+			continue;
+		}
+
+		/* Run actions the user specified. */
+		printf("%s\n", devpath);
+
+		int action = 0;
+		while (actions[action].opt != 0) {
+			if (actions[action].active) {
+				actions[action].action(dev);
+			}
+			action++;
+		}
+
+		/* Destroy the control pipe (close the session etc.). */
+		destroy_device(dev);
+	}
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/usbinfo/usbinfo.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010 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 usbinfo
+ * @{
+ */
+/** @file
+ * Common header for usbinfo application.
+ */
+#ifndef USBINFO_USBINFO_H_
+#define USBINFO_USBINFO_H_
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <usb/dev/dp.h>
+#include <ipc/devman.h>
+
+typedef struct {
+	usb_pipe_t ctrl_pipe;
+	usb_device_connection_t wire;
+	usb_standard_device_descriptor_t device_descriptor;
+	uint8_t *full_configuration_descriptor;
+	size_t full_configuration_descriptor_size;
+} usbinfo_device_t;
+
+typedef struct {
+	int opt;
+	void (*action)(usbinfo_device_t *dev);
+	bool active;
+} usbinfo_action_t;
+
+
+#define NAME "usbinfo"
+
+void dump_buffer(const char *, size_t, const uint8_t *, size_t);
+const char *get_indent(size_t);
+void dump_match_ids(match_id_list_t *, const char *);
+void dump_usb_descriptor(uint8_t *, size_t);
+void dump_descriptor_tree(uint8_t *, size_t);
+
+static inline void internal_error(int err)
+{
+	fprintf(stderr, NAME ": internal error (%s).\n", str_error(err));
+}
+
+usbinfo_device_t *prepare_device(const char *, devman_handle_t, usb_address_t);
+void destroy_device(usbinfo_device_t *);
+
+typedef void (*dump_descriptor_in_tree_t)(uint8_t *, size_t, void *);
+void browse_descriptor_tree(uint8_t *, size_t, usb_dp_descriptor_nesting_t *,
+    dump_descriptor_in_tree_t, size_t, void *);
+
+
+void dump_short_device_identification(usbinfo_device_t *);
+void dump_device_match_ids(usbinfo_device_t *);
+void dump_descriptor_tree_brief(usbinfo_device_t *);
+void dump_descriptor_tree_full(usbinfo_device_t *);
+void dump_strings(usbinfo_device_t *);
+void dump_status(usbinfo_device_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/Makefile
===================================================================
--- uspace/app/vuhid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,58 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+# acronym for virtual USB human input device
+# (it is really annoying to write long names)
+BINARY = vuh
+
+LIBS = \
+	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
+	$(LIBUSBHID_PREFIX)/libusbhid.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBUSBHID_PREFIX)/include \
+	-I$(LIBUSBVIRT_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+
+SOURCES_INTERFACES = \
+	hids/bootkbd.c
+
+SOURCES = \
+	main.c \
+	device.c \
+	ifaces.c \
+	stdreq.c \
+	$(SOURCES_INTERFACES)
+	
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/vuhid/device.c
===================================================================
--- uspace/app/vuhid/device.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/device.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,360 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/**
+ * @file
+ * Virtual USB HID device.
+ */
+#include "virthid.h"
+#include <errno.h>
+#include <stdio.h>
+#include <str.h>
+#include <assert.h>
+#include <usb/classes/classes.h>
+
+static int on_data_from_device(usbvirt_device_t *dev,
+    usb_endpoint_t ep, usb_transfer_type_t tr_type,
+    void *data, size_t data_size, size_t *actual_size)
+{
+	vuhid_data_t *vuhid = dev->device_data;
+	vuhid_interface_t *iface = vuhid->in_endpoints_mapping[ep];
+	if (iface == NULL) {
+		return ESTALL;
+	}
+
+	if (iface->on_data_in == NULL) {
+		return EBADCHECKSUM;
+	}
+
+	return iface->on_data_in(iface, data, data_size, actual_size);
+}
+
+static int on_data_to_device(usbvirt_device_t *dev,
+    usb_endpoint_t ep, usb_transfer_type_t tr_type,
+    void *data, size_t data_size)
+{
+	vuhid_data_t *vuhid = dev->device_data;
+	vuhid_interface_t *iface = vuhid->out_endpoints_mapping[ep];
+	if (iface == NULL) {
+		return ESTALL;
+	}
+
+	if (iface->on_data_out == NULL) {
+		return EBADCHECKSUM;
+	}
+
+	return iface->on_data_out(iface, data, data_size);
+}
+
+static int interface_life_fibril(void *arg)
+{
+	vuhid_interface_t *iface = arg;
+	vuhid_data_t *hid_data = iface->vuhid_data;
+
+	if (iface->live != NULL) {
+		iface->live(iface);
+	}
+
+	fibril_mutex_lock(&hid_data->iface_count_mutex);
+	hid_data->iface_died_count++;
+	fibril_condvar_broadcast(&hid_data->iface_count_cv);
+	fibril_mutex_unlock(&hid_data->iface_count_mutex);
+
+	return EOK;
+}
+
+
+static vuhid_interface_t *find_interface_by_id(vuhid_interface_t **ifaces,
+    const char *id)
+{
+	if ((ifaces == NULL) || (id == NULL)) {
+		return NULL;
+	}
+	while (*ifaces != NULL) {
+		if (str_cmp((*ifaces)->id, id) == 0) {
+			return *ifaces;
+		}
+		ifaces++;
+	}
+
+	return NULL;
+}
+
+int add_interface_by_id(vuhid_interface_t **interfaces, const char *id,
+    usbvirt_device_t *dev)
+{
+	vuhid_interface_t *iface = find_interface_by_id(interfaces, id);
+	if (iface == NULL) {
+		return ENOENT;
+	}
+
+	if ((iface->in_data_size == 0) && (iface->out_data_size == 0)) {
+		return EEMPTY;
+	}
+
+	/* Already used interface. */
+	if (iface->vuhid_data != NULL) {
+		return EEXISTS;
+	}
+
+	vuhid_data_t *hid_data = dev->device_data;
+
+	/* Check that we have not run out of available endpoints. */
+	if ((iface->in_data_size > 0)
+	    && (hid_data->in_endpoint_first_free >= VUHID_ENDPOINT_MAX)) {
+		return ELIMIT;
+	}
+	if ((iface->out_data_size > 0)
+	    && (hid_data->out_endpoint_first_free >= VUHID_ENDPOINT_MAX)) {
+		return ELIMIT;
+	}
+
+	if (dev->descriptors->configuration->descriptor->interface_count >=
+	    VUHID_INTERFACE_MAX) {
+		return ELIMIT;
+	}
+
+	/*
+	 * How may descriptors we would add?
+	 */
+	/* Start with interface descriptor. */
+	size_t new_descriptor_count = 1;
+	/* Having in/out data size positive means we would need endpoint. */
+	if (iface->in_data_size > 0) {
+		new_descriptor_count++;
+	}
+	if (iface->out_data_size > 0) {
+		new_descriptor_count++;
+	}
+	/* Having report descriptor means adding the HID descriptor. */
+	if (iface->report_descriptor != NULL) {
+		new_descriptor_count++;
+	}
+
+	/* From now on, in case of errors, we goto to error_leave */
+	int rc;
+
+	/*
+	 * Prepare new descriptors.
+	 */
+	size_t descr_count = 0;
+	size_t total_descr_size = 0;
+	usb_standard_interface_descriptor_t *descr_iface = NULL;
+	hid_descriptor_t *descr_hid = NULL;
+	usb_standard_endpoint_descriptor_t *descr_ep_in = NULL;
+	usb_standard_endpoint_descriptor_t *descr_ep_out = NULL;
+
+	size_t ep_count = 0;
+	if (iface->in_data_size > 0) {
+		ep_count++;
+	}
+	if (iface->out_data_size > 0) {
+		ep_count++;
+	}
+	assert(ep_count > 0);
+
+	/* Interface would be needed always. */
+	descr_iface = malloc(sizeof(usb_standard_interface_descriptor_t));
+	if (descr_iface == NULL) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+	descr_count++;
+	total_descr_size += sizeof(usb_standard_interface_descriptor_t);
+	descr_iface->length = sizeof(usb_standard_interface_descriptor_t);
+	descr_iface->descriptor_type = USB_DESCTYPE_INTERFACE;
+	descr_iface->interface_number
+	    = dev->descriptors->configuration->descriptor->interface_count;
+	descr_iface->alternate_setting = 0;
+	descr_iface->endpoint_count = ep_count;
+	descr_iface->interface_class = USB_CLASS_HID;
+	descr_iface->interface_subclass = iface->usb_subclass;
+	descr_iface->interface_protocol = iface->usb_protocol;
+	descr_iface->str_interface = 0;
+
+	/* Create the HID descriptor. */
+	if (iface->report_descriptor != NULL) {
+		descr_hid = malloc(sizeof(hid_descriptor_t));
+		if (descr_hid == NULL) {
+			rc = ENOMEM;
+			goto error_leave;
+		}
+		descr_count++;
+		total_descr_size += sizeof(hid_descriptor_t);
+		descr_hid->length = sizeof(hid_descriptor_t);
+		descr_hid->type = USB_DESCTYPE_HID;
+		descr_hid->hid_spec_release = 0x101;
+		descr_hid->country_code = 0;
+		descr_hid->descriptor_count = 1;
+		descr_hid->descriptor1_type = USB_DESCTYPE_HID_REPORT;
+		descr_hid->descriptor1_length = iface->report_descriptor_size;
+	}
+
+	/* Prepare the endpoint descriptors. */
+	if (iface->in_data_size > 0) {
+		descr_ep_in = malloc(sizeof(usb_standard_endpoint_descriptor_t));
+		if (descr_ep_in == NULL) {
+			rc = ENOMEM;
+			goto error_leave;
+		}
+		descr_count++;
+		total_descr_size += sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_in->length = sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_in->descriptor_type = USB_DESCTYPE_ENDPOINT;
+		descr_ep_in->endpoint_address
+		    = 0x80 | hid_data->in_endpoint_first_free;
+		descr_ep_in->attributes = 3;
+		descr_ep_in->max_packet_size = iface->in_data_size;
+		descr_ep_in->poll_interval = 10;
+	}
+	if (iface->out_data_size > 0) {
+		descr_ep_out = malloc(sizeof(usb_standard_endpoint_descriptor_t));
+		if (descr_ep_out == NULL) {
+			rc = ENOMEM;
+			goto error_leave;
+		}
+		descr_count++;
+		total_descr_size += sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_out->length = sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_out->descriptor_type = USB_DESCTYPE_ENDPOINT;
+		descr_ep_out->endpoint_address
+		    = 0x00 | hid_data->out_endpoint_first_free;
+		descr_ep_out->attributes = 3;
+		descr_ep_out->max_packet_size = iface->out_data_size;
+		descr_ep_out->poll_interval = 10;
+	}
+
+	/* Extend existing extra descriptors with these ones. */
+	usbvirt_device_configuration_extras_t *extra_descriptors
+	    = dev->descriptors->configuration->extra;
+	extra_descriptors = realloc(extra_descriptors,
+	    sizeof(usbvirt_device_configuration_extras_t)
+	    * (dev->descriptors->configuration->extra_count + descr_count));
+	if (extra_descriptors == NULL) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+
+	/* Launch the "life" fibril. */
+	iface->vuhid_data = hid_data;
+	fid_t life_fibril = fibril_create(interface_life_fibril, iface);
+	if (life_fibril == 0) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+
+	/* Allocation is okay, we can (actually have to now) overwrite the
+	 * original pointer.
+	 */
+	dev->descriptors->configuration->extra = extra_descriptors;
+	extra_descriptors += dev->descriptors->configuration->extra_count;
+
+	/* Initialize them. */
+#define _APPEND_DESCRIPTOR(descriptor) \
+	do { \
+		if ((descriptor) != NULL) { \
+			extra_descriptors->data = (uint8_t *) (descriptor); \
+			extra_descriptors->length = (descriptor)->length; \
+			extra_descriptors++; \
+		} \
+	} while (0)
+
+	_APPEND_DESCRIPTOR(descr_iface);
+	_APPEND_DESCRIPTOR(descr_hid);
+	_APPEND_DESCRIPTOR(descr_ep_in);
+	_APPEND_DESCRIPTOR(descr_ep_out);
+#undef _APPEND_DESCRIPTOR
+	dev->descriptors->configuration->extra_count += descr_count;
+
+	/*
+	 * Final changes.
+	 * Increase the necessary counters, make endpoint mapping.
+	 *
+	 */
+	if (iface->in_data_size > 0) {
+		hid_data->in_endpoints_mapping[hid_data->in_endpoint_first_free]
+		    = iface;
+		dev->ops->data_in[hid_data->in_endpoint_first_free]
+		    = on_data_from_device;
+		hid_data->in_endpoint_first_free++;
+	}
+	if (iface->out_data_size > 0) {
+		hid_data->out_endpoints_mapping[hid_data->out_endpoint_first_free]
+		    = iface;
+		dev->ops->data_out[hid_data->out_endpoint_first_free]
+		    = on_data_to_device;
+		hid_data->out_endpoint_first_free++;
+	}
+
+	hid_data->interface_mapping[
+	    dev->descriptors->configuration->descriptor->interface_count]
+	    = iface;
+
+	dev->descriptors->configuration->descriptor->interface_count++;
+	dev->descriptors->configuration->descriptor->total_length
+	    += total_descr_size;
+
+	hid_data->iface_count++;
+	fibril_add_ready(life_fibril);
+
+	return EOK;
+
+error_leave:
+	if (descr_iface != NULL) {
+		free(descr_iface);
+	}
+	if (descr_hid != NULL) {
+		free(descr_hid);
+	}
+	if (descr_ep_in != NULL) {
+		free(descr_ep_in);
+	}
+	if (descr_ep_out != NULL) {
+		free(descr_ep_out);
+	}
+
+	return rc;
+}
+
+void wait_for_interfaces_death(usbvirt_device_t *dev)
+{
+	vuhid_data_t *hid_data = dev->device_data;
+
+	fibril_mutex_lock(&hid_data->iface_count_mutex);
+	while (hid_data->iface_died_count < hid_data->iface_count) {
+		fibril_condvar_wait(&hid_data->iface_count_cv,
+		    &hid_data->iface_count_mutex);
+	}
+	fibril_mutex_unlock(&hid_data->iface_count_mutex);
+}
+
+/** @}
+ */
Index: uspace/app/vuhid/hids/bootkbd.c
===================================================================
--- uspace/app/vuhid/hids/bootkbd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/hids/bootkbd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,178 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/** @file
+ *
+ */
+#include "../virthid.h"
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/usages/core.h>
+
+#include "../report.h"
+
+uint8_t report_descriptor[] = {
+	STD_USAGE_PAGE(USB_HIDUT_PAGE_GENERIC_DESKTOP),
+	USAGE1(USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD),
+	START_COLLECTION(COLLECTION_APPLICATION),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_KEYBOARD),
+		USAGE_MINIMUM1(224),
+		USAGE_MAXIMUM1(231),
+		LOGICAL_MINIMUM1(0),
+		LOGICAL_MAXIMUM1(1),
+		REPORT_SIZE1(1),
+		REPORT_COUNT1(8),
+		/* Modifiers */
+		INPUT(IOF_DATA | IOF_VARIABLE | IOF_ABSOLUTE),
+		REPORT_COUNT1(1),
+		REPORT_SIZE1(8),
+		/* Reserved */
+		INPUT(IOF_CONSTANT),
+		REPORT_COUNT1(5),
+		REPORT_SIZE1(1),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_LED),
+		USAGE_MINIMUM1(1),
+		USAGE_MAXIMUM1(5),
+		/* LED states */
+		OUTPUT(IOF_DATA | IOF_VARIABLE | IOF_ABSOLUTE),
+		REPORT_COUNT1(1),
+		REPORT_SIZE1(3),
+		/* LED states padding */
+		OUTPUT(IOF_CONSTANT),
+		REPORT_COUNT1(6),
+		REPORT_SIZE1(8),
+		LOGICAL_MINIMUM1(0),
+		LOGICAL_MAXIMUM1(101),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_KEYBOARD),
+		USAGE_MINIMUM1(0),
+		USAGE_MAXIMUM1(101),
+		/* Key array */
+		INPUT(IOF_DATA | IOF_ARRAY),
+	END_COLLECTION()
+};
+
+#define INPUT_SIZE 8
+
+static uint8_t in_data[] = {
+	     0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	     0, 0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, // Caps Lock
+	     0, 0, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, // Num Lock
+	     0, 0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, // Caps Lock
+	1 << 2, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	1 << 2, 0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
+	1 << 2, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	     0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static size_t in_data_count = sizeof(in_data)/INPUT_SIZE;
+// FIXME - locking
+static size_t in_data_position = 0;
+
+static int on_data_in(vuhid_interface_t *iface,
+    void *buffer, size_t buffer_size, size_t *act_buffer_size)
+{
+	static size_t last_pos = (size_t) -1;
+	size_t pos = in_data_position;
+	if (pos >= in_data_count) {
+		return EBADCHECKSUM;
+	}
+
+	if (last_pos == pos) {
+		return ENAK;
+	}
+
+	if (buffer_size > INPUT_SIZE) {
+		buffer_size = INPUT_SIZE;
+	}
+
+	if (act_buffer_size != NULL) {
+		*act_buffer_size = buffer_size;
+	}
+
+	memcpy(buffer, in_data + pos * INPUT_SIZE, buffer_size);
+	last_pos = pos;
+
+	return EOK;
+}
+
+static int on_data_out(vuhid_interface_t *iface,
+    void *buffer, size_t buffer_size)
+{
+	if (buffer_size == 0) {
+		return EEMPTY;
+	}
+	uint8_t leds = ((uint8_t *) buffer)[0];
+#define _GET_LED(index, signature) \
+	(((leds) & (1 << index)) ? (signature) : '-')
+	usb_log_info("%s: LEDs = %c%c%c%c%c\n",
+	    iface->name,
+	    _GET_LED(0, '0'), _GET_LED(1, 'A'), _GET_LED(2, 's'),
+	    _GET_LED(3, 'c'), _GET_LED(4, 'k'));
+#undef _GET_LED
+	return EOK;
+}
+
+
+static void live(vuhid_interface_t *iface)
+{
+	async_usleep(1000 * 1000 * 5);
+	usb_log_debug("Boot keyboard comes to life...\n");
+	while (in_data_position < in_data_count) {
+		async_usleep(1000 * 500);
+		in_data_position++;
+	}
+	usb_log_debug("Boot keyboard died.\n");
+}
+
+
+vuhid_interface_t vuhid_interface_bootkbd = {
+	.id = "boot",
+	.name = "boot keyboard",
+	.usb_subclass = USB_HID_SUBCLASS_BOOT,
+	.usb_protocol = USB_HID_PROTOCOL_KEYBOARD,
+
+	.report_descriptor = report_descriptor,
+	.report_descriptor_size = sizeof(report_descriptor),
+
+	.in_data_size = INPUT_SIZE,
+	.on_data_in = on_data_in,
+
+	.out_data_size = 1,
+	.on_data_out = on_data_out,
+
+	.live = live,
+
+	.vuhid_data = NULL
+};
+
+/**
+ * @}
+ */
Index: uspace/app/vuhid/ifaces.c
===================================================================
--- uspace/app/vuhid/ifaces.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/ifaces.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -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 usbvirthid
+ * @{
+ */
+/**
+ * @file
+ * List of known interfaces.
+ */
+#include <stdlib.h>
+#include "ifaces.h"
+
+extern vuhid_interface_t vuhid_interface_bootkbd;
+
+vuhid_interface_t *available_hid_interfaces[] = {
+	&vuhid_interface_bootkbd,
+	NULL
+};
+
+
+/** @}
+ */
Index: uspace/app/vuhid/ifaces.h
===================================================================
--- uspace/app/vuhid/ifaces.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/ifaces.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/** @file
+ *
+ */
+#ifndef VUHID_IFACES_H_
+#define VUHID_IFACES_H_
+
+#include "virthid.h"
+
+extern vuhid_interface_t *available_hid_interfaces[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/items.h
===================================================================
--- uspace/app/vuhid/items.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/items.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010 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 usbvirtkbd
+ * @{
+ */
+/** @file
+ * @brief HID Item related functions.
+ */
+#ifndef VUK_ITEM_H_
+#define VUK_ITEM_H_
+
+#include <sys/types.h>
+
+typedef uint8_t report_descriptor_data_t[];
+
+/* Item types. */
+#define ITEM_MAIN 0
+#define ITEM_GLOBAL 1
+#define ITEM_LOCAL 2
+
+
+
+/* Item tags. */
+
+/* Main item tags. */
+#define TAG_INPUT 8
+#define TAG_OUTPUT 9
+#define TAG_FEATURE 11
+#define TAG_COLLECTION 10
+#define TAG_END_COLLECTION 12
+
+/* Global item tags. */
+#define TAG_USAGE_PAGE 0
+#define TAG_LOGICAL_MINIMUM 1
+#define TAG_LOGICAL_MAXIMUM 2
+#define TAG_REPORT_SIZE 7
+#define TAG_REPORT_COUNT 9
+
+/* Local item tags. */
+#define TAG_USAGE 0
+#define TAG_USAGE_MINIMUM 1
+#define TAG_USAGE_MAXIMUM 2
+
+
+/* Bits for Input, Output and Feature items. */
+#define _IOF(value, shift) ((value) << (shift))
+#define IOF_DATA _IOF(0, 0)
+#define IOF_CONSTANT _IOF(1, 0)
+#define IOF_ARRAY _IOF(0, 1)
+#define IOF_VARIABLE _IOF(1, 1)
+#define IOF_ABSOLUTE _IOF(0, 2)
+#define IOF_RELATIVE _IOF(1, 2)
+/* ... */
+
+/* Collection types. */
+#define COLLECTION_PHYSICAL 0x00
+#define COLLECTION_APPLICATION 0x01
+
+
+/** Creates item prefix.
+ * @param size Item size.
+ * @param type Item type.
+ * @param tag Item tag.
+ */
+#define BUILD_ITEM_PREFIX(size, type, tag) \
+	((size) | ((type) << 2) | ((tag) << 4))
+
+/** Create no-data item.
+ * @param type Item type.
+ * @param tag Item tag.
+ */
+#define ITEM_CREATE0(type, tag) \
+	BUILD_ITEM_PREFIX(0, type, tag)
+
+/** Create item with 1-byte data.
+ * @param type Item type.
+ * @param tag Item tag.
+ * @param data Item data (single byte).
+ */
+#define ITEM_CREATE1(type, tag, data) \
+	BUILD_ITEM_PREFIX(1, type, tag), data
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/main.c
===================================================================
--- uspace/app/vuhid/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,203 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/**
+ * @file
+ * Virtual USB HID device.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usbvirt/device.h>
+
+#include "virthid.h"
+#include "ifaces.h"
+#include "stdreq.h"
+
+static usbvirt_control_request_handler_t endpoint_zero_handlers[] = {
+	{
+		.req_direction = USB_DIRECTION_IN,
+		.req_type = USB_REQUEST_TYPE_STANDARD,
+		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "Get_Descriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		.req_direction = USB_DIRECTION_OUT,
+		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
+		.req_type = USB_REQUEST_TYPE_CLASS,
+		.request = USB_HIDREQ_SET_PROTOCOL,
+		.name = "Set_Protocol",
+		.callback = req_set_protocol
+	},
+	{
+		.req_direction = USB_DIRECTION_OUT,
+		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
+		.req_type = USB_REQUEST_TYPE_CLASS,
+		.request = USB_HIDREQ_SET_REPORT,
+		.name = "Set_Report",
+		.callback = req_set_report
+	},
+	{
+		.callback = NULL
+	}
+};
+
+/** Keyboard callbacks.
+ * We abuse the fact that static variables are zero-filled.
+ */
+static usbvirt_device_ops_t hid_ops = {
+	.control = endpoint_zero_handlers,
+};
+
+/** Standard configuration descriptor. */
+static usb_standard_configuration_descriptor_t std_configuration_descriptor = {
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	/* Will be patched at runtime. */
+	.total_length = sizeof(usb_standard_configuration_descriptor_t),
+	.interface_count = 0,
+	.configuration_number = 1,
+	.str_configuration = 0,
+	.attributes = 128, /* denotes bus-powered device */
+	.max_power = 50
+};
+
+/** Standard device descriptor. */
+static usb_standard_device_descriptor_t std_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_USE_INTERFACE,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+/** HID configuration. */
+usbvirt_device_configuration_t configuration = {
+	.descriptor = &std_configuration_descriptor,
+	.extra = NULL,
+	.extra_count = 0
+};
+
+/** HID standard descriptors. */
+usbvirt_descriptors_t descriptors = {
+	.device = &std_device_descriptor,
+	.configuration = &configuration,
+	.configuration_count = 1,
+};
+
+static vuhid_data_t vuhid_data = {
+	.in_endpoints_mapping = { NULL },
+	.in_endpoint_first_free = 1,
+	.out_endpoints_mapping = { NULL },
+	.out_endpoint_first_free = 1,
+
+	.iface_count = 0,
+	.iface_died_count = 0
+	// mutex and CV must be initialized elsewhere
+};
+
+
+/** Keyboard device.
+ * Rest of the items will be initialized later.
+ */
+static usbvirt_device_t hid_dev = {
+	.ops = &hid_ops,
+	.descriptors = &descriptors,
+	.name = "HID",
+	.device_data = &vuhid_data
+};
+
+
+int main(int argc, char * argv[])
+{
+	int rc;
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG2, "vusbhid");
+
+	fibril_mutex_initialize(&vuhid_data.iface_count_mutex);
+	fibril_condvar_initialize(&vuhid_data.iface_count_cv);
+
+	/* Determine which interfaces to initialize. */
+	int i;
+	for (i = 1; i < argc; i++) {
+		rc = add_interface_by_id(available_hid_interfaces, argv[i],
+		    &hid_dev);
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to add device `%s': %s.\n",
+			    argv[i], str_error(rc));
+		} else {
+			printf("Added device `%s'.\n", argv[i]);
+		}
+	}
+
+	for (i = 0; i < (int) hid_dev.descriptors->configuration->extra_count; i++) {
+		usb_log_debug("Found extra descriptor: %s.\n",
+		    usb_debug_str_buffer(
+		        hid_dev.descriptors->configuration->extra[i].data,
+		        hid_dev.descriptors->configuration->extra[i].length,
+		        0));
+	}
+
+	rc = usbvirt_device_plug(&hid_dev, "/virt/usbhc/hc");
+	if (rc != EOK) {
+		printf("Unable to start communication with VHCD: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	printf("Connected to VHCD...\n");
+
+	wait_for_interfaces_death(&hid_dev);
+	
+	printf("Terminating...\n");
+	
+	usbvirt_device_unplug(&hid_dev);
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/vuhid/report.h
===================================================================
--- uspace/app/vuhid/report.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/report.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010 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 usbvirtkbd
+ * @{
+ */
+/** @file
+ * @brief HID Report Descriptor.
+ */
+#ifndef VUK_REPORT_H_
+#define VUK_REPORT_H_
+
+#include "items.h"
+
+/** Use standard Usage Page. */
+#define STD_USAGE_PAGE(page) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_USAGE_PAGE, page)
+
+/** Usage with one byte usage ID. */
+#define USAGE1(usage_id) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE, usage_id)
+
+/** Start a collection. */
+#define START_COLLECTION(collection) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_COLLECTION, collection)
+
+/** End a collection. */
+#define END_COLLECTION() \
+	ITEM_CREATE0(ITEM_MAIN, TAG_END_COLLECTION)
+
+
+#define USAGE_MINIMUM1(value) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE_MINIMUM, value)
+	
+#define USAGE_MAXIMUM1(value) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE_MAXIMUM, value)
+	
+#define LOGICAL_MINIMUM1(value) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_LOGICAL_MINIMUM, value)
+
+#define LOGICAL_MAXIMUM1(value) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_LOGICAL_MAXIMUM, value)
+
+#define REPORT_SIZE1(size) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_REPORT_SIZE, size)
+
+#define REPORT_COUNT1(count) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_REPORT_COUNT, count)
+	
+#define INPUT(modifiers) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_INPUT, modifiers)
+
+#define OUTPUT(modifiers) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_OUTPUT, modifiers)
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/stdreq.c
===================================================================
--- uspace/app/vuhid/stdreq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/stdreq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,119 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/**
+ * @file
+ *
+ */
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/descriptor.h>
+#include "stdreq.h"
+#include "virthid.h"
+
+#define VUHID_DATA(vuhid, device) \
+	vuhid_data_t *vuhid = device->device_data
+
+int req_get_descriptor(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	VUHID_DATA(vuhid, device);
+
+	if (setup_packet->value_high == USB_DESCTYPE_HID_REPORT) {
+		vuhid_interface_t *iface
+		    = vuhid->interface_mapping[setup_packet->index];
+		if (iface == NULL) {
+			return EFORWARD;
+		}
+		if (iface->report_descriptor != NULL) {
+			usbvirt_control_reply_helper(setup_packet,
+			    data, act_size,
+			    iface->report_descriptor,
+			    iface->report_descriptor_size);
+			return EOK;
+		} else {
+			return ENOENT;
+		}
+	}
+	
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+int req_set_protocol(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	VUHID_DATA(vuhid, device);
+
+	size_t iface_index = setup_packet->index;
+	int protocol = setup_packet->value;
+
+	// FIXME - check ranges
+	vuhid_interface_t *iface = vuhid->interface_mapping[iface_index];
+	if (iface == NULL) {
+		return ENOENT;
+	}
+	iface->set_protocol = protocol;
+
+	return EOK;
+}
+
+int req_set_report(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	VUHID_DATA(vuhid, device);
+
+	size_t iface_index = setup_packet->index;
+
+	// FIXME - check ranges
+	vuhid_interface_t *iface = vuhid->interface_mapping[iface_index];
+	if (iface == NULL) {
+		return ENOENT;
+	}
+
+	size_t data_length = setup_packet->length;
+	if (iface->on_data_out == NULL) {
+		return ENOTSUP;
+	}
+
+	/* SET_REPORT is translated to data out */
+	int rc = iface->on_data_out(iface, data, data_length);
+
+	return rc;
+}
+
+
+
+/** @}
+ */
Index: uspace/app/vuhid/stdreq.h
===================================================================
--- uspace/app/vuhid/stdreq.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/stdreq.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,55 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/** @file
+ * Device request handlers.
+ */
+#ifndef VUHID_STDREQ_H_
+#define VUHID_STDREQ_H_
+
+#include <usbvirt/device.h>
+
+int req_get_descriptor(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
+int req_set_protocol(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
+int req_set_report(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/virthid.h
===================================================================
--- uspace/app/vuhid/virthid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/app/vuhid/virthid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,99 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/** @file
+ *
+ */
+#ifndef VUHID_VIRTHID_H_
+#define VUHID_VIRTHID_H_
+
+#include <usb/usb.h>
+#include <usbvirt/device.h>
+#include <fibril_synch.h>
+
+#define VUHID_ENDPOINT_MAX USB11_ENDPOINT_MAX
+#define VUHID_INTERFACE_MAX 8
+
+typedef struct vuhid_interface vuhid_interface_t;
+
+typedef struct {
+	vuhid_interface_t *in_endpoints_mapping[VUHID_ENDPOINT_MAX];
+	size_t in_endpoint_first_free;
+	vuhid_interface_t *out_endpoints_mapping[VUHID_ENDPOINT_MAX];
+	size_t out_endpoint_first_free;
+	vuhid_interface_t *interface_mapping[VUHID_INTERFACE_MAX];
+
+	fibril_mutex_t iface_count_mutex;
+	fibril_condvar_t iface_count_cv;
+	size_t iface_count;
+	size_t iface_died_count;
+} vuhid_data_t;
+
+struct vuhid_interface {
+	const char *name;
+	const char *id;
+	int usb_subclass;
+	int usb_protocol;
+
+	uint8_t *report_descriptor;
+	size_t report_descriptor_size;
+
+	size_t in_data_size;
+	size_t out_data_size;
+
+	int (*on_data_in)(vuhid_interface_t *, void *, size_t, size_t *);
+	int (*on_data_out)(vuhid_interface_t *, void *, size_t);
+	void (*live)(vuhid_interface_t *);
+
+	int set_protocol;
+
+	void *interface_data;
+
+	vuhid_data_t *vuhid_data;
+};
+
+typedef struct {
+	uint8_t length;
+	uint8_t type;
+	uint16_t hid_spec_release;
+	uint8_t country_code;
+	uint8_t descriptor_count;
+	uint8_t descriptor1_type;
+	uint16_t descriptor1_length;
+} __attribute__ ((packed)) hid_descriptor_t;
+
+int add_interface_by_id(vuhid_interface_t **, const char *, usbvirt_device_t *);
+void wait_for_interfaces_death(usbvirt_device_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/doc/doxygroups.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -165,2 +165,163 @@
 	 * @ingroup emul
 	 */
+
+/**
+ * @defgroup usb USB
+ * @ingroup uspace
+ * @brief USB support for HelenOS.
+ */
+	/**
+	 * @defgroup libusb Base USB library
+	 * @ingroup usb
+	 * @brief Common definitions for any driver or application
+	 * dealing with USB.
+	 */
+
+	/**
+	 * @defgroup libusbdev USB library for device drivers
+	 * @ingroup usb
+	 * @brief Library for writing drivers of endpoint devices (functions).
+	 */
+
+	/**
+	 * @defgroup libusbhost USB library for host controller drivers
+	 * @ingroup usb
+	 * @brief Library for writing host controller drivers.
+	 */
+
+	/**
+	 * @defgroup libusbhid USB library for HID devices
+	 * @ingroup usb
+	 * @brief Library for writing USB HID drivers.
+	 */
+
+	/**
+	 * @defgroup usbvirt USB virtualization
+	 * @ingroup usb
+	 * @brief Support for virtual USB devices.
+	 */
+
+		/**
+		 * @defgroup libusbvirt USB virtualization library
+		 * @ingroup usbvirt
+		 * @brief Library for creating virtual USB devices.
+		 */
+
+		/**
+		 * @defgroup drvusbvhc Virtual USB host controller
+		 * @ingroup usbvirt
+		 * @brief Driver simulating work of USB host controller.
+		 */
+
+		/**
+		 * @defgroup usbvirthub Virtual USB hub
+		 * @ingroup usbvirt
+		 * @brief Extra virtual USB hub for virtual host controller.
+		 * @details
+		 * Some of the sources are shared with virtual host controller,
+		 * see @ref drvusbvhc for the rest of the files.
+		 */
+
+		/**
+		 * @defgroup usbvirtkbd Virtual USB keybaord
+		 * @ingroup usbvirt
+		 * @brief Virtual USB keyboard for virtual host controller.
+		 */
+
+	/**
+	 * @defgroup usbinfo USB info application
+	 * @ingroup usb
+	 * @brief Application for querying USB devices.
+	 * @details
+	 * The intended usage of this application is to query new USB devices
+	 * for their descriptors etc. to simplify driver writing.
+	 */
+
+	/**
+	 * @defgroup lsusb HelenOS version of lsusb command
+	 * @ingroup usb
+	 * @brief Application for listing USB host controllers.
+	 * @details
+	 * List all found host controllers.
+	 */
+
+	/**
+	 * @defgroup drvusbmid USB multi interface device driver
+	 * @ingroup usb
+	 * @brief USB multi interface device driver
+	 * @details
+	 * This driver serves as a mini hub (or bus) driver for devices
+	 * that have the class defined at interface level (those devices
+	 * usually have several interfaces).
+	 *
+	 * The term multi interface device driver (MID) was borrowed
+	 * Solaris operating system.
+	 */
+
+	/**
+	 * @defgroup drvusbhub USB hub driver
+	 * @ingroup usb
+	 * @brief USB hub driver.
+	 */
+
+	/**
+	 * @defgroup drvusbhid USB HID driver
+	 * @ingroup usb
+	 * @brief USB driver for HID devices.
+	 */
+
+	/**
+	 * @defgroup drvusbmouse USB mouse driver
+	 * @ingroup usb
+	 * @brief USB driver for mouse with boot protocol.
+	 */
+
+	/**
+	 * @defgroup drvusbmast USB mass storage driver
+	 * @ingroup usb
+	 * @brief USB driver for mass storage devices (bulk-only protocol).
+	 * This driver is a only a stub and is currently used only for
+	 * testing that bulk transfers work.
+	 */
+
+	/**
+	 * @defgroup drvusbuhci UHCI driver
+	 * @ingroup usb
+	 * @brief Drivers for USB UHCI host controller and root hub.
+	 */
+
+		/**
+		 * @defgroup drvusbuhcirh UHCI root hub driver
+		 * @ingroup drvusbuhci
+		 * @brief Driver for UHCI complaint root hub.
+		 */
+
+		/**
+		 * @defgroup drvusbuhcihc UHCI host controller driver
+		 * @ingroup drvusbuhci
+		 * @brief Driver for UHCI complaint USB host controller.
+		 */
+
+	/**
+	 * @defgroup drvusbohci OHCI driver
+	 * @ingroup usb
+	 * @brief Driver for OHCI host controller.
+	 */
+
+	/**
+	 * @defgroup drvusbehci EHCI driver
+	 * @ingroup usb
+	 * @brief Driver for EHCI host controller.
+	 */
+
+	/**
+	 * @defgroup drvusbfallback USB fallback driver
+	 * @ingroup usb
+	 * @brief Fallback driver for any USB device.
+	 * @details
+	 * The purpose of this driver is to simplify querying of unknown
+	 * devices from within HelenOS (without a driver, no node at all
+	 * may appear under /dev/devices).
+	 */
+
+
Index: uspace/doc/main_usb.h
===================================================================
--- uspace/doc/main_usb.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/doc/main_usb.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,26 @@
+/**
+ @mainpage USB support for HelenOS
+
+This is reference manual for USB subsystem for HelenOS.
+
+HelenOS is a microkernel operating system where most of the functionality
+is provided by userspace tasks rather than system calls.
+This includes file system service, networking and also device drivers.
+
+USB is a standard for communication between host computers and computer
+peripherals.
+The advantage of USB over other kinds of connection between a computer
+and a peripheral is its flexibility.
+USB supports plugging and unplugging of devices without need to turn
+off any of the components.
+The data flow model is designed to accommodate together peripherals
+with different transfer characteristics.
+
+Adding support for USB devices to HelenOS shall improve the usability
+of the system in general even if the support concerns only USB 1.1 and
+the only peripheral drivers are for keyboards and mice.
+
+This reference documentation can be found also on-line at homepage
+of HelenOS USB project at http://helenos-usb.sourceforge.net/
+
+*/
Index: uspace/drv/ehci_hcd/Makefile
===================================================================
--- uspace/drv/ehci_hcd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,47 @@
+#
+# 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 = \
+	$(LIBUSBHOST_PREFIX)/libusbhost.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBHOST_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = ehci_hcd
+
+SOURCES = \
+	hc_iface.c \
+	main.c \
+	pci.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/ehci_hcd/ehci.h
===================================================================
--- uspace/drv/ehci_hcd/ehci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/ehci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -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
+ * Common EHCI definitions.
+ */
+#ifndef DRV_EHCI_EHCI_H
+#define DRV_EHCI_EHCI_H
+
+#include <usbhc_iface.h>
+
+#define NAME "ehci_hcd"
+
+extern usbhc_iface_t ehci_hc_iface;
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/ehci_hcd/ehci_hcd.ma
===================================================================
--- uspace/drv/ehci_hcd/ehci_hcd.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/ehci_hcd.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,39 @@
+10 pci/ven=1002&dev=4345
+10 pci/ven=1002&dev=4386
+10 pci/ven=1002&dev=4396
+10 pci/ven=1002&dev=4373
+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/hc_iface.c
===================================================================
--- uspace/drv/ehci_hcd/hc_iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/hc_iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,326 @@
+/*
+ * 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
+ * USB-HC interface implementation.
+ */
+#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 "ehci.h"
+
+#define UNSUPPORTED(methodname) \
+	usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
+	    methodname, __FILE__, __LINE__)
+
+/** Found free USB address.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] speed Speed of the device that will get this address.
+ * @param[out] address Non-null pointer where to store the free address.
+ * @return Error code.
+ */
+static int request_address(ddf_fun_t *fun, usb_speed_t speed,
+    usb_address_t *address)
+{
+	UNSUPPORTED("request_address");
+
+	return ENOTSUP;
+}
+
+/** Bind USB address with device devman handle.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] handle Devman handle of the device.
+ * @return Error code.
+ */
+static int bind_address(ddf_fun_t *fun,
+    usb_address_t address, devman_handle_t handle)
+{
+	UNSUPPORTED("bind_address");
+
+	return ENOTSUP;
+}
+
+/** Find device handle by USB address.
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address in question.
+ * @param[out] handle Where to store device handle if found.
+ * @return Error code.
+ */
+static int find_by_address(ddf_fun_t *fun, usb_address_t address,
+    devman_handle_t *handle)
+{
+	UNSUPPORTED("find_by_address");
+
+	return ENOTSUP;
+}
+
+/** Release previously requested address.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address to be released.
+ * @return Error code.
+ */
+static int release_address(ddf_fun_t *fun, usb_address_t address)
+{
+	UNSUPPORTED("release_address");
+
+	return ENOTSUP;
+}
+
+/** Register endpoint for bandwidth reservation.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] speed Endpoint speed (invalid means to use device one).
+ * @param[in] endpoint Endpoint number.
+ * @param[in] transfer_type USB transfer type.
+ * @param[in] direction Endpoint data direction.
+ * @param[in] max_packet_size Max packet size of the endpoint.
+ * @param[in] interval Polling interval.
+ * @return Error code.
+ */
+static int register_endpoint(ddf_fun_t *fun,
+    usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
+    usb_transfer_type_t transfer_type, usb_direction_t direction,
+    size_t max_packet_size, unsigned int interval)
+{
+	UNSUPPORTED("register_endpoint");
+
+	return ENOTSUP;
+}
+
+/** Unregister endpoint (free some bandwidth reservation).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] endpoint Endpoint number.
+ * @param[in] direction Endpoint data direction.
+ * @return Error code.
+ */
+static int unregister_endpoint(ddf_fun_t *fun, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	UNSUPPORTED("unregister_endpoint");
+
+	return ENOTSUP;
+}
+
+/** Schedule interrupt out transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
+ *	by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	UNSUPPORTED("interrupt_out");
+
+	return ENOTSUP;
+}
+
+/** Schedule interrupt in transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	UNSUPPORTED("interrupt_in");
+
+	return ENOTSUP;
+}
+
+/** Schedule bulk out transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
+ *	by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int bulk_out(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	UNSUPPORTED("bulk_out");
+
+	return ENOTSUP;
+}
+
+/** Schedule bulk in transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int bulk_in(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	UNSUPPORTED("bulk_in");
+
+	return ENOTSUP;
+}
+
+/** Schedule control write transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
+ *	and deallocated by the caller).
+ * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
+ * @param[in] data_buffer Data buffer (in USB endianess, allocated and
+ *	deallocated by the caller).
+ * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int control_write(ddf_fun_t *fun, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data_buffer, size_t data_buffer_size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	UNSUPPORTED("control_write");
+
+	return ENOTSUP;
+}
+
+/** Schedule control read transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
+ *	and deallocated by the caller).
+ * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
+ * @param[in] data_buffer Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int control_read(ddf_fun_t *fun, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data_buffer, size_t data_buffer_size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	UNSUPPORTED("control_read");
+
+	return ENOTSUP;
+}
+
+/** Host controller interface implementation for EHCI. */
+usbhc_iface_t ehci_hc_iface = {
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.find_by_address = find_by_address,
+	.release_address = release_address,
+
+	.register_endpoint = register_endpoint,
+	.unregister_endpoint = unregister_endpoint,
+
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+
+	.bulk_out = bulk_out,
+	.bulk_in = bulk_in,
+
+	.control_write = control_write,
+	.control_read = control_read
+};
+
+/**
+ * @}
+ */
Index: uspace/drv/ehci_hcd/main.c
===================================================================
--- uspace/drv/ehci_hcd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,130 @@
+/*
+ * 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"
+#include "ehci.h"
+
+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
+};
+static ddf_dev_ops_t hc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &ehci_hc_iface,
+};
+
+/*----------------------------------------------------------------------------*/
+/** 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; \
+}
+
+	uintptr_t reg_base = 0;
+	size_t reg_size = 0;
+	int irq = 0;
+
+	int ret = pci_get_my_registers(device, &reg_base, &reg_size, &irq);
+	CHECK_RET_RETURN(ret,
+	    "Failed to get memory addresses for %" PRIun ": %s.\n",
+	    device->handle, str_error(ret));
+	usb_log_info("Memory mapped regs at 0x%" PRIxn " (size %zu), IRQ %d.\n",
+	    reg_base, reg_size, irq);
+
+	ret = pci_disable_legacy(device, reg_base, reg_size, irq);
+	CHECK_RET_RETURN(ret,
+	    "Failed to disable legacy USB: %s.\n", str_error(ret));
+
+	ddf_fun_t *hc_fun = ddf_fun_create(device, fun_exposed, "ehci_hc");
+	if (hc_fun == NULL) {
+		usb_log_error("Failed to create EHCI function.\n");
+		return ENOMEM;
+	}
+	hc_fun->ops = &hc_ops;
+
+	ret = ddf_fun_bind(hc_fun);
+	CHECK_RET_RETURN(ret,
+	    "Failed to bind EHCI function: %s.\n",
+	    str_error(ret));
+	ret = ddf_fun_add_to_class(hc_fun, USB_HC_DDF_CLASS_NAME);
+	CHECK_RET_RETURN(ret,
+	    "Failed to add EHCI to HC class: %s.\n",
+	    str_error(ret));
+
+	usb_log_info("Controlling new EHCI device `%s' (handle %" PRIun ").\n",
+	    device->name, device->handle);
+
+	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_DEFAULT, NAME);
+	return ddf_driver_main(&ehci_driver);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ehci_hcd/pci.c
===================================================================
--- uspace/drv/ehci_hcd/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,391 @@
+/*
+ * 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 <str_error.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 STS_OFFSET 0x4
+#define INT_OFFSET 0x8
+#define CFG_OFFSET 0x40
+
+#define USBCMD_RUN 1
+#define USBSTS_HALTED (1 << 12)
+
+#define USBLEGSUP_OFFSET 0
+#define USBLEGSUP_BIOS_CONTROL (1 << 16)
+#define USBLEGSUP_OS_CONTROL (1 << 24)
+#define USBLEGCTLSTS_OFFSET 4
+
+#define DEFAULT_WAIT 1000
+#define WAIT_STEP 10
+
+#define PCI_READ(size) \
+do { \
+	async_sess_t *parent_sess = \
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle, \
+	    IPC_FLAG_BLOCKING); \
+	if (!parent_sess) \
+		return ENOMEM; \
+	\
+	sysarg_t add = (sysarg_t) address; \
+	sysarg_t val; \
+	\
+	async_exch_t *exch = async_exchange_begin(parent_sess); \
+	\
+	const int ret = \
+	    async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE), \
+	        IPC_M_CONFIG_SPACE_READ_##size, add, &val); \
+	\
+	async_exchange_end(exch); \
+	async_hangup(parent_sess); \
+	\
+	assert(value); \
+	\
+	*value = val; \
+	return ret; \
+} while (0)
+
+static int pci_read32(const ddf_dev_t *dev, int address, uint32_t *value)
+{
+	PCI_READ(32);
+}
+
+static int pci_read16(const ddf_dev_t *dev, int address, uint16_t *value)
+{
+	PCI_READ(16);
+}
+
+static int pci_read8(const ddf_dev_t *dev, int address, uint8_t *value)
+{
+	PCI_READ(8);
+}
+
+#define PCI_WRITE(size) \
+do { \
+	async_sess_t *parent_sess = \
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle, \
+	    IPC_FLAG_BLOCKING); \
+	if (!parent_sess) \
+		return ENOMEM; \
+	\
+	sysarg_t add = (sysarg_t) address; \
+	sysarg_t val = value; \
+	\
+	async_exch_t *exch = async_exchange_begin(parent_sess); \
+	\
+	const int ret = \
+	    async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE), \
+	        IPC_M_CONFIG_SPACE_WRITE_##size, add, val); \
+	\
+	async_exchange_end(exch); \
+	async_hangup(parent_sess); \
+	\
+	return ret; \
+} while(0)
+
+static int pci_write32(const ddf_dev_t *dev, int address, uint32_t value)
+{
+	PCI_WRITE(32);
+}
+
+static int pci_write16(const ddf_dev_t *dev, int address, uint16_t value)
+{
+	PCI_WRITE(16);
+}
+
+static int pci_write8(const ddf_dev_t *dev, int address, uint8_t value)
+{
+	PCI_WRITE(8);
+}
+
+/** 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(const ddf_dev_t *dev,
+    uintptr_t *mem_reg_address, size_t *mem_reg_size, int *irq_no)
+{
+	assert(dev != NULL);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	hw_resource_list_t hw_resources;
+	int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (rc != EOK) {
+		async_hangup(parent_sess);
+		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: %" PRIxn" %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_sess);
+	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(const ddf_dev_t *device)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	const bool enabled = hw_res_enable_interrupt(parent_sess);
+	async_hangup(parent_sess);
+	
+	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(
+    const ddf_dev_t *device, uintptr_t reg_base, size_t reg_size, int irq)
+{
+	assert(device);
+	(void) pci_read16;
+	(void) pci_read8;
+	(void) pci_write16;
+
+#define CHECK_RET_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		return ret; \
+	} else (void)0
+
+	/* Map EHCI registers */
+	void *regs = NULL;
+	int ret = pio_enable((void*)reg_base, reg_size, &regs);
+	CHECK_RET_RETURN(ret, "Failed to map registers %p: %s.\n",
+	    (void *) reg_base, str_error(ret));
+
+	const uint32_t hcc_params =
+	    *(uint32_t*)(regs + HCC_PARAMS_OFFSET);
+	usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
+
+	/* Read value of EHCI Extended Capabilities Pointer
+	 * position of EEC registers (points to PCI config space) */
+	const uint32_t eecp =
+	    (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
+	usb_log_debug("Value of EECP: %x.\n", eecp);
+
+	/* Read the first EEC. i.e. Legacy Support register */
+	uint32_t usblegsup;
+	ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
+	CHECK_RET_RETURN(ret, "Failed to read USBLEGSUP: %s.\n", str_error(ret));
+	usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
+
+	/* Request control from firmware/BIOS, by writing 1 to highest byte.
+	 * (OS Control semaphore)*/
+	usb_log_debug("Requesting OS control.\n");
+	ret = pci_write8(device, eecp + USBLEGSUP_OFFSET + 3, 1);
+	CHECK_RET_RETURN(ret, "Failed to request OS EHCI control: %s.\n",
+	    str_error(ret));
+
+	size_t wait = 0;
+	/* Wait for BIOS to release control. */
+	ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
+	while ((wait < DEFAULT_WAIT) && (usblegsup & USBLEGSUP_BIOS_CONTROL)) {
+		async_usleep(WAIT_STEP);
+		ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
+		wait += WAIT_STEP;
+	}
+
+
+	if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
+		usb_log_info("BIOS released control after %zu usec.\n", wait);
+	} else {
+		/* BIOS failed to hand over control, this should not happen. */
+		usb_log_warning( "BIOS failed to release control after "
+		    "%zu usecs, force it.\n", wait);
+		ret = pci_write32(device, eecp + USBLEGSUP_OFFSET,
+		    USBLEGSUP_OS_CONTROL);
+		CHECK_RET_RETURN(ret, "Failed to force OS control: %s.\n",
+		    str_error(ret));
+		/* Check capability type here, A value of 01h
+		 * identifies the capability as Legacy Support.
+		 * This extended capability requires one
+		 * additional 32-bit register for control/status information,
+		 * and this register is located at offset EECP+04h
+		 * */
+		if ((usblegsup & 0xff) == 1) {
+			/* Read the second EEC
+			 * Legacy Support and Control register */
+			uint32_t usblegctlsts;
+			ret = pci_read32(
+			    device, eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
+			CHECK_RET_RETURN(ret,
+			    "Failed to get USBLEGCTLSTS: %s.\n", str_error(ret));
+			usb_log_debug("USBLEGCTLSTS: %" PRIx32 ".\n",
+			    usblegctlsts);
+			/* Zero SMI enables in legacy control register.
+			 * It should prevent pre-OS code from interfering. */
+			ret = pci_write32(device, eecp + USBLEGCTLSTS_OFFSET,
+			    0xe0000000); /* three upper bits are WC */
+			CHECK_RET_RETURN(ret,
+			    "Failed(%d) zero USBLEGCTLSTS.\n", ret);
+			udelay(10);
+			ret = pci_read32(
+			    device, eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
+			CHECK_RET_RETURN(ret,
+			    "Failed to get USBLEGCTLSTS 2: %s.\n",
+			    str_error(ret));
+			usb_log_debug("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n",
+			    usblegctlsts);
+		}
+	}
+
+
+	/* Read again Legacy Support register */
+	ret = pci_read32(device, eecp + USBLEGSUP_OFFSET, &usblegsup);
+	CHECK_RET_RETURN(ret, "Failed to read USBLEGSUP: %s.\n", str_error(ret));
+	usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
+
+	/*
+	 * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT
+	 */
+
+	/* Get size of capability registers in memory space. */
+	const unsigned operation_offset = *(uint8_t*)regs;
+	usb_log_debug("USBCMD offset: %d.\n", operation_offset);
+
+	/* Zero USBCMD register. */
+	volatile uint32_t *usbcmd =
+	    (uint32_t*)((uint8_t*)regs + operation_offset + CMD_OFFSET);
+	volatile uint32_t *usbsts =
+	    (uint32_t*)((uint8_t*)regs + operation_offset + STS_OFFSET);
+	volatile uint32_t *usbconf =
+	    (uint32_t*)((uint8_t*)regs + operation_offset + CFG_OFFSET);
+	volatile uint32_t *usbint =
+	    (uint32_t*)((uint8_t*)regs + operation_offset + INT_OFFSET);
+	usb_log_debug("USBCMD value: %x.\n", *usbcmd);
+	if (*usbcmd & USBCMD_RUN) {
+		*usbsts = 0x3f; /* ack all interrupts */
+		*usbint = 0; /* disable all interrutps */
+		*usbconf = 0; /* relase control of RH ports */
+
+		*usbcmd = 0;
+		/* Wait until hc is halted */
+		while ((*usbsts & USBSTS_HALTED) == 0);
+		usb_log_info("EHCI turned off.\n");
+	} else {
+		usb_log_info("EHCI was not running.\n");
+	}
+	usb_log_debug("Registers: \n"
+	    "\t USBCMD: %x(0x00080000 = at least 1ms between interrupts)\n"
+	    "\t USBSTS: %x(0x00001000 = HC halted)\n"
+	    "\t USBINT: %x(0x0 = no interrupts).\n"
+	    "\t CONFIG: %x(0x0 = ports controlled by companion hc).\n",
+	    *usbcmd, *usbsts, *usbint, *usbconf);
+
+	return ret;
+#undef CHECK_RET_RETURN
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/ehci_hcd/pci.h
===================================================================
--- uspace/drv/ehci_hcd/pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ehci_hcd/pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -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(const ddf_dev_t *, uintptr_t *, size_t *, int *);
+int pci_enable_interrupts(const ddf_dev_t *);
+int pci_disable_legacy(const ddf_dev_t *, uintptr_t, size_t, int);
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/ns8250/ns8250.c
===================================================================
--- uspace/drv/ns8250/ns8250.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/drv/ns8250/ns8250.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -263,7 +263,7 @@
 static void ns8250_dev_cleanup(ns8250_t *ns)
 {
-	if (ns->dev->parent_phone > 0) {
-		async_hangup(ns->dev->parent_phone);
-		ns->dev->parent_phone = 0;
+	if (ns->dev->parent_sess) {
+		async_hangup(ns->dev->parent_sess);
+		ns->dev->parent_sess = NULL;
 	}
 }
@@ -337,15 +337,15 @@
 	
 	/* Connect to the parent's driver. */
-	ns->dev->parent_phone = devman_parent_device_connect(ns->dev->handle,
-	    IPC_FLAG_BLOCKING);
-	if (ns->dev->parent_phone < 0) {
+	ns->dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    ns->dev->handle, IPC_FLAG_BLOCKING);
+	if (!ns->dev->parent_sess) {
 		ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
 		    "device %s.", ns->dev->name);
-		ret = ns->dev->parent_phone;
+		ret = ENOENT;
 		goto failed;
 	}
 	
 	/* Get hw resources. */
-	ret = hw_res_get_resource_list(ns->dev->parent_phone, &hw_resources);
+	ret = hw_res_get_resource_list(ns->dev->parent_sess, &hw_resources);
 	if (ret != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
Index: uspace/drv/ohci/Makefile
===================================================================
--- uspace/drv/ohci/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,58 @@
+#
+# 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 = \
+	$(LIBUSBHOST_PREFIX)/libusbhost.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBUSBHOST_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = ohci
+
+SOURCES = \
+	batch.c \
+	endpoint_list.c \
+	hc.c \
+	hcd_endpoint.c \
+	iface.c \
+	main.c \
+	ohci.c \
+	pci.c \
+	root_hub.c \
+	hw_struct/endpoint_descriptor.c \
+	hw_struct/transfer_descriptor.c
+
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/ohci/batch.c
===================================================================
--- uspace/drv/ohci/batch.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/batch.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver USB transaction structure
+ */
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+
+#include "batch.h"
+#include "hcd_endpoint.h"
+#include "utils/malloc32.h"
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+/** OHCI specific data required for USB transfer */
+typedef struct ohci_transfer_batch {
+	/** Endpoint descriptor of the target endpoint. */
+	ed_t *ed;
+	/** List of TDs needed for the transfer */
+	td_t **tds;
+	/** Number of TDs used by the transfer */
+	size_t td_count;
+	/** Dummy TD to be left at the ED and used by the next transfer */
+	size_t leave_td;
+	/** Data buffer, must be accessible byb the OHCI hw. */
+	void *device_buffer;
+} ohci_transfer_batch_t;
+/*----------------------------------------------------------------------------*/
+static void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir);
+static void batch_data(usb_transfer_batch_t *instance);
+/*----------------------------------------------------------------------------*/
+/** Safely destructs ohci_transfer_batch_t structure
+ *
+ * @param[in] ohci_batch Instance to destroy.
+ */
+static void ohci_transfer_batch_dispose(void *ohci_batch)
+{
+	ohci_transfer_batch_t *instance = ohci_batch;
+	if (!instance)
+		return;
+	free32(instance->device_buffer);
+	unsigned i = 0;
+	if (instance->tds) {
+		for (; i< instance->td_count; ++i) {
+			if (i != instance->leave_td)
+				free32(instance->tds[i]);
+		}
+		free(instance->tds);
+	}
+	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Allocate memory initialize internal structures
+ *
+ * @param[in] fun DDF function to pass to callback.
+ * @param[in] ep Communication target
+ * @param[in] buffer Data source/destination.
+ * @param[in] buffer_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 transfer completion
+ * @param[in] func_out function to call on outbound transfer completion
+ * @param[in] arg additional parameter to func_in or func_out
+ * @return Valid pointer if all structures were successfully created,
+ * NULL otherwise.
+ *
+ * Allocates and initializes structures needed by the OHCI hw for the transfer.
+ */
+usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
+    char *buffer, size_t buffer_size,
+    const 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)
+{
+#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
+        if (ptr == NULL) { \
+                usb_log_error(message); \
+                if (instance) { \
+                        usb_transfer_batch_dispose(instance); \
+                } \
+                return NULL; \
+        } else (void)0
+
+	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
+	CHECK_NULL_DISPOSE_RETURN(instance,
+	    "Failed to allocate batch instance.\n");
+	usb_transfer_batch_init(instance, ep, buffer, NULL, buffer_size,
+	    NULL, setup_size, func_in, func_out, arg, fun, NULL,
+	    ohci_transfer_batch_dispose);
+
+	const hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
+	assert(hcd_ep);
+
+	ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1);
+	CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
+	instance->private_data = data;
+
+	data->td_count =
+	    ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER);
+	/* Control transfer need Setup and Status stage */
+	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
+		data->td_count += 2;
+	}
+
+	/* We need an extra place for TD that is currently assigned to hcd_ep*/
+	data->tds = calloc(sizeof(td_t*), data->td_count + 1);
+	CHECK_NULL_DISPOSE_RETURN(data->tds,
+	    "Failed to allocate transfer descriptors.\n");
+
+	/* Add TD left over by the previous transfer */
+	data->tds[0] = hcd_ep->td;
+	data->leave_td = 0;
+	unsigned i = 1;
+	for (; i <= data->td_count; ++i) {
+		data->tds[i] = malloc32(sizeof(td_t));
+		CHECK_NULL_DISPOSE_RETURN(data->tds[i],
+		    "Failed to allocate TD %d.\n", i );
+	}
+
+	data->ed = hcd_ep->ed;
+
+	/* NOTE: OHCI is capable of handling buffer that crosses page boundaries
+	 * it is, however, not capable of handling buffer that occupies more
+	 * than two pages (the first page is computed using start pointer, the
+	 * other using the end pointer) */
+        if (setup_size + buffer_size > 0) {
+		data->device_buffer = malloc32(setup_size + buffer_size);
+                CHECK_NULL_DISPOSE_RETURN(data->device_buffer,
+                    "Failed to allocate device accessible buffer.\n");
+		instance->setup_buffer = data->device_buffer;
+		instance->data_buffer = data->device_buffer + setup_size;
+                memcpy(instance->setup_buffer, setup_buffer, setup_size);
+        }
+
+	return instance;
+}
+/*----------------------------------------------------------------------------*/
+/** Check batch TDs' status.
+ *
+ * @param[in] instance Batch structure to use.
+ * @return False, if there is an active TD, true otherwise.
+ *
+ * Walk all TDs (usually there is just one). Stop with false if there is an
+ * active TD. Stop with true if an error is found. Return true if the walk
+ * completes with the last TD.
+ */
+bool batch_is_complete(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Batch(%p) checking %zu td(s) for completion.\n",
+	    instance, data->td_count);
+	usb_log_debug("ED: %x:%x:%x:%x.\n",
+	    data->ed->status, data->ed->td_head, data->ed->td_tail,
+	    data->ed->next);
+	size_t i = 0;
+	instance->transfered_size = instance->buffer_size;
+	for (; i < data->td_count; ++i) {
+		assert(data->tds[i] != NULL);
+		usb_log_debug("TD %zu: %x:%x:%x:%x.\n", i,
+		    data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next,
+		    data->tds[i]->be);
+		if (!td_is_finished(data->tds[i])) {
+			return false;
+		}
+		instance->error = td_error(data->tds[i]);
+		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%zu):%x.\n",
+			    instance, i, data->tds[i]->status);
+			/* Make sure TD queue is empty (one TD),
+			 * ED should be marked as halted */
+			data->ed->td_tail =
+			    (data->ed->td_head & ED_TDTAIL_PTR_MASK);
+			++i;
+			break;
+		}
+	}
+	data->leave_td = i;
+	assert(data->leave_td <= data->td_count);
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(instance->ep);
+	assert(hcd_ep);
+	hcd_ep->td = data->tds[i];
+	assert(i > 0);
+	for (--i;i < data->td_count; ++i)
+		instance->transfered_size -= td_remain_size(data->tds[i]);
+
+	/* Clear possible ED HALT */
+	data->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
+	const uint32_t pa = addr_to_phys(hcd_ep->td);
+	assert(pa == (data->ed->td_head & ED_TDHEAD_PTR_MASK));
+	assert(pa == (data->ed->td_tail & ED_TDTAIL_PTR_MASK));
+
+	return true;
+}
+/*----------------------------------------------------------------------------*/
+/** Starts execution of the TD list
+ *
+ * @param[in] instance Batch structure to use
+ */
+void batch_commit(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	ed_set_end_td(data->ed, data->tds[data->td_count]);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control write transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control transfer using direction OUT(data stage) and
+ * IN(status stage).
+ */
+void batch_control_write(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN);
+	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control read transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control transfer using direction IN(data stage) and
+ * OUT(status stage).
+ */
+void batch_control_read(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT);
+	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_interrupt_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_interrupt_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_bulk_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer.
+ */
+void batch_bulk_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	batch_data(instance);
+	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic control transfer
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data_dir Direction to use for data stage.
+ * @param[in] status_dir Direction to use for status stage.
+ *
+ * Setup stage with toggle 0 and direction BOTH(SETUP_PID)
+ * Data stage with alternating toggle and direction supplied by parameter.
+ * Status stage with toggle 1 and direction supplied by parameter.
+ */
+void batch_control(usb_transfer_batch_t *instance,
+    usb_direction_t data_dir, usb_direction_t status_dir)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+	int toggle = 0;
+	/* setup stage */
+	td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,
+		instance->setup_size, toggle);
+	td_set_next(data->tds[0], data->tds[1]);
+	usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0]->status,
+	    data->tds[0]->cbp, data->tds[0]->next, data->tds[0]->be);
+
+	/* data stage */
+	size_t td_current = 1;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
+		    OHCI_TD_MAX_TRANSFER : remain_size;
+		toggle = 1 - toggle;
+
+		td_init(data->tds[td_current], data_dir, buffer,
+		    transfer_size, toggle);
+		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current]->status, data->tds[td_current]->cbp,
+		    data->tds[td_current]->next, data->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count - 1);
+		++td_current;
+	}
+
+	/* status stage */
+	assert(td_current == data->td_count - 1);
+	td_init(data->tds[td_current], status_dir, NULL, 0, 1);
+	td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+	usb_log_debug("Created STATUS TD: %x:%x:%x:%x.\n",
+	    data->tds[td_current]->status, data->tds[td_current]->cbp,
+	    data->tds[td_current]->next, data->tds[td_current]->be);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic data transfer
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Direction is supplied by the associated ep and toggle is maintained by the
+ * OHCI hw in ED.
+ */
+void batch_data(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+
+	size_t td_current = 0;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
+		    ? OHCI_TD_MAX_TRANSFER : remain_size;
+
+		td_init(data->tds[td_current], instance->ep->direction,
+		    buffer, transfer_size, -1);
+		td_set_next(data->tds[td_current], data->tds[td_current + 1]);
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current]->status, data->tds[td_current]->cbp,
+		    data->tds[td_current]->next, data->tds[td_current]->be);
+
+		buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count);
+		++td_current;
+	}
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/batch.h
===================================================================
--- uspace/drv/ohci/batch.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/batch.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver USB transaction structure
+ */
+#ifndef DRV_OHCI_BATCH_H
+#define DRV_OHCI_BATCH_H
+
+#include <usbhc_iface.h>
+#include <usb/usb.h>
+#include <usb/host/device_keeper.h>
+#include <usb/host/endpoint.h>
+#include <usb/host/batch.h>
+
+usb_transfer_batch_t * batch_get(
+    ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size,
+    const 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);
+
+bool batch_is_complete(usb_transfer_batch_t *instance);
+
+void batch_commit(usb_transfer_batch_t *instance);
+
+void batch_control_write(usb_transfer_batch_t *instance);
+
+void batch_control_read(usb_transfer_batch_t *instance);
+
+void batch_interrupt_in(usb_transfer_batch_t *instance);
+
+void batch_interrupt_out(usb_transfer_batch_t *instance);
+
+void batch_bulk_in(usb_transfer_batch_t *instance);
+
+void batch_bulk_out(usb_transfer_batch_t *instance);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/endpoint_list.c
===================================================================
--- uspace/drv/ohci/endpoint_list.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/endpoint_list.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver transfer list implementation
+ */
+#include <errno.h>
+#include <usb/debug.h>
+#include <arch/barrier.h>
+
+#include "endpoint_list.h"
+
+/** 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 ed_t structure.
+ */
+int endpoint_list_init(endpoint_list_t *instance, const char *name)
+{
+	assert(instance);
+	instance->name = name;
+	instance->list_head = malloc32(sizeof(ed_t));
+	if (!instance->list_head) {
+		usb_log_error("Failed to allocate list head.\n");
+		return ENOMEM;
+	}
+	instance->list_head_pa = addr_to_phys(instance->list_head);
+	usb_log_debug2("Transfer list %s setup with ED: %p(0x%0" PRIx32 ")).\n",
+	    name, instance->list_head, instance->list_head_pa);
+
+	ed_init(instance->list_head, NULL);
+	list_initialize(&instance->endpoint_list);
+	fibril_mutex_initialize(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Set the next list in transfer list chain.
+ *
+ * @param[in] instance List to lead.
+ * @param[in] next List to append.
+ *
+ * Does not check whether this replaces an existing list.
+ */
+void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next)
+{
+	assert(instance);
+	assert(next);
+	ed_append_ed(instance->list_head, next->list_head);
+}
+/*----------------------------------------------------------------------------*/
+/** Add endpoint to the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] endpoint Endpoint to add.
+ *
+ * The endpoint is added to the end of the list and queue.
+ */
+void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep)
+{
+	assert(instance);
+	assert(hcd_ep);
+	usb_log_debug2("Queue %s: Adding endpoint(%p).\n",
+	    instance->name, hcd_ep);
+
+	fibril_mutex_lock(&instance->guard);
+
+	ed_t *last_ed = NULL;
+	/* Add to the hardware queue. */
+	if (list_empty(&instance->endpoint_list)) {
+		/* There are no active EDs */
+		last_ed = instance->list_head;
+	} else {
+		/* There are active EDs, get the last one */
+		hcd_endpoint_t *last = list_get_instance(
+		    instance->endpoint_list.prev, hcd_endpoint_t, link);
+		assert(last);
+		last_ed = last->ed;
+	}
+	/* Keep link */
+	hcd_ep->ed->next = last_ed->next;
+	/* Make sure ED is written to the memory */
+	write_barrier();
+
+	/* Add ed to the hw queue */
+	ed_append_ed(last_ed, hcd_ep->ed);
+	/* Make sure ED is updated */
+	write_barrier();
+
+	/* Add to the sw list */
+	list_append(&hcd_ep->link, &instance->endpoint_list);
+
+	hcd_endpoint_t *first = list_get_instance(
+	    instance->endpoint_list.next, hcd_endpoint_t, link);
+	usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).\n",
+		hcd_ep, instance->name, first, first->ed);
+	if (last_ed == instance->list_head) {
+		usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x.\n",
+		    instance->name, last_ed, instance->list_head_pa,
+		    last_ed->status, last_ed->td_tail, last_ed->td_head,
+		    last_ed->next);
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Remove endpoint from the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] endpoint Endpoint to remove.
+ */
+void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep)
+{
+	assert(instance);
+	assert(instance->list_head);
+	assert(hcd_ep);
+	assert(hcd_ep->ed);
+
+	fibril_mutex_lock(&instance->guard);
+
+	usb_log_debug2(
+	    "Queue %s: removing endpoint(%p).\n", instance->name, hcd_ep);
+
+	const char *qpos = NULL;
+	ed_t *prev_ed;
+	/* Remove from the hardware queue */
+	if (instance->endpoint_list.next == &hcd_ep->link) {
+		/* I'm the first one here */
+		prev_ed = instance->list_head;
+		qpos = "FIRST";
+	} else {
+		hcd_endpoint_t *prev =
+		    list_get_instance(hcd_ep->link.prev, hcd_endpoint_t, link);
+		prev_ed = prev->ed;
+		qpos = "NOT FIRST";
+	}
+	assert((prev_ed->next & ED_NEXT_PTR_MASK) == addr_to_phys(hcd_ep->ed));
+	prev_ed->next = hcd_ep->ed->next;
+	/* Make sure ED is updated */
+	write_barrier();
+
+	usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.\n",
+	    hcd_ep, qpos, instance->name, hcd_ep->ed->next);
+
+	/* Remove from the endpoint list */
+	list_remove(&hcd_ep->link);
+	fibril_mutex_unlock(&instance->guard);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/endpoint_list.h
===================================================================
--- uspace/drv/ohci/endpoint_list.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/endpoint_list.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver transfer list structure
+ */
+#ifndef DRV_OHCI_ENDPOINT_LIST_H
+#define DRV_OHCI_ENDPOINT_LIST_H
+
+#include <fibril_synch.h>
+
+#include "hcd_endpoint.h"
+#include "hw_struct/endpoint_descriptor.h"
+#include "utils/malloc32.h"
+
+/** Structure maintains both OHCI queue and software list of active endpoints.*/
+typedef struct endpoint_list {
+	/** Guard against add/remove races */
+	fibril_mutex_t guard;
+	/** OHCI hw structure at the beginning of the queue */
+	ed_t *list_head;
+	/** Physical address of the first(dummy) ED */
+	uint32_t list_head_pa;
+	/** Assigned name, provides nicer debug output */
+	const char *name;
+	/** Sw list of all active EDs */
+	link_t endpoint_list;
+} endpoint_list_t;
+
+/** Dispose transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ *
+ * Frees memory of the internal ed_t structure.
+ */
+static inline void endpoint_list_fini(endpoint_list_t *instance)
+{
+	assert(instance);
+	free32(instance->list_head);
+}
+
+int endpoint_list_init(endpoint_list_t *instance, const char *name);
+void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next);
+void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep);
+void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,624 @@
+/*
+ * 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 drvusbohcihc
+ * @{
+ */
+/** @file
+ * @brief OHCI 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 "hc.h"
+#include "hcd_endpoint.h"
+
+#define OHCI_USED_INTERRUPTS \
+    (I_SO | I_WDH | I_UE | I_RHSC)
+static int interrupt_emulator(hc_t *instance);
+static void hc_gain_control(hc_t *instance);
+static int hc_init_transfer_lists(hc_t *instance);
+static int hc_init_memory(hc_t *instance);
+/*----------------------------------------------------------------------------*/
+/** Announce OHCI root hub to the DDF
+ *
+ * @param[in] instance OHCI driver intance
+ * @param[in] hub_fun DDF fuction representing OHCI root hub
+ * @return Error code
+ */
+int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
+{
+	assert(instance);
+	assert(hub_fun);
+
+	const usb_address_t hub_address =
+	    device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
+	if (hub_address <= 0) {
+		usb_log_error("Failed(%d) to get OHCI root hub address.\n",
+		    hub_address);
+		return hub_address;
+	}
+	instance->rh.address = hub_address;
+	usb_device_keeper_bind(
+	    &instance->manager, hub_address, hub_fun->handle);
+
+#define CHECK_RET_RELEASE(ret, message...) \
+if (ret != EOK) { \
+	usb_log_error(message); \
+	hc_remove_endpoint(instance, hub_address, 0, USB_DIRECTION_BOTH); \
+	usb_device_keeper_release(&instance->manager, hub_address); \
+	return ret; \
+} else (void)0
+
+	int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
+	    USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
+	CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
+
+	char *match_str = NULL;
+	/* DDF needs heap allocated string */
+	ret = asprintf(&match_str, "usb&class=hub");
+	ret = ret > 0 ? 0 : ret;
+	CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
+
+	ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
+	CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
+
+	ret = ddf_fun_bind(hub_fun);
+	CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
+
+	return EOK;
+#undef CHECK_RET_RELEASE
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize OHCI hc driver structure
+ *
+ * @param[in] instance Memory place for the structure.
+ * @param[in] regs Address of the memory mapped I/O registers.
+ * @param[in] reg_size Size of the memory mapped area.
+ * @param[in] interrupts True if w interrupts should be used
+ * @return Error code
+ */
+int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts)
+{
+	assert(instance);
+	int ret = EOK;
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	usb_log_error(message); \
+	return ret; \
+} else (void)0
+
+	ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
+	CHECK_RET_RETURN(ret,
+	    "Failed(%d) to gain access to device registers: %s.\n",
+	    ret, str_error(ret));
+
+	list_initialize(&instance->pending_batches);
+	usb_device_keeper_init(&instance->manager);
+	ret = usb_endpoint_manager_init(&instance->ep_manager,
+	    BANDWIDTH_AVAILABLE_USB11);
+	CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
+	    str_error(ret));
+
+	ret = hc_init_memory(instance);
+	CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures: %s.\n",
+	    str_error(ret));
+#undef CHECK_RET_RETURN
+
+	fibril_mutex_initialize(&instance->guard);
+	hc_gain_control(instance);
+
+	rh_init(&instance->rh, instance->registers);
+
+	if (!interrupts) {
+		instance->interrupt_emulator =
+		    fibril_create((int(*)(void*))interrupt_emulator, instance);
+		fibril_add_ready(instance->interrupt_emulator);
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Create end register endpoint structures
+ *
+ * @param[in] instance OHCI driver structure.
+ * @param[in] address USB address of the device.
+ * @param[in] endpoint USB endpoint number.
+ * @param[in] speed Communication speeed of the device.
+ * @param[in] type Endpoint's transfer type.
+ * @param[in] direction Endpoint's direction.
+ * @param[in] mps Maximum packet size the endpoint accepts.
+ * @param[in] size Maximum allowed buffer size.
+ * @param[in] interval Time between transfers(interrupt transfers only).
+ * @return Error code
+ */
+int hc_add_endpoint(
+    hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
+    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
+    size_t mps, size_t size, unsigned interval)
+{
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+	int ret =
+	    endpoint_init(ep, address, endpoint, direction, type, speed, mps);
+	if (ret != EOK) {
+		free(ep);
+		return ret;
+	}
+
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
+	if (hcd_ep == NULL) {
+		endpoint_destroy(ep);
+		return ENOMEM;
+	}
+
+	ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
+	if (ret != EOK) {
+		hcd_endpoint_clear(ep);
+		endpoint_destroy(ep);
+		return ret;
+	}
+
+	/* Enqueue hcd_ep */
+	switch (ep->transfer_type) {
+	case USB_TRANSFER_CONTROL:
+		instance->registers->control &= ~C_CLE;
+		endpoint_list_add_ep(
+		    &instance->lists[ep->transfer_type], hcd_ep);
+		instance->registers->control_current = 0;
+		instance->registers->control |= C_CLE;
+		break;
+	case USB_TRANSFER_BULK:
+		instance->registers->control &= ~C_BLE;
+		endpoint_list_add_ep(
+		    &instance->lists[ep->transfer_type], hcd_ep);
+		instance->registers->control |= C_BLE;
+		break;
+	case USB_TRANSFER_ISOCHRONOUS:
+	case USB_TRANSFER_INTERRUPT:
+		instance->registers->control &= (~C_PLE & ~C_IE);
+		endpoint_list_add_ep(
+		    &instance->lists[ep->transfer_type], hcd_ep);
+		instance->registers->control |= C_PLE | C_IE;
+		break;
+	default:
+		break;
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Dequeue and delete endpoint structures
+ *
+ * @param[in] instance OHCI hc driver structure.
+ * @param[in] address USB address of the device.
+ * @param[in] endpoint USB endpoint number.
+ * @param[in] direction Direction of the endpoint.
+ * @return Error code
+ */
+int hc_remove_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
+	    address, endpoint, direction, NULL);
+	if (ep == NULL) {
+		usb_log_error("Endpoint unregister failed: No such EP.\n");
+		fibril_mutex_unlock(&instance->guard);
+		return ENOENT;
+	}
+
+	hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
+	if (hcd_ep) {
+		/* Dequeue hcd_ep */
+		switch (ep->transfer_type) {
+		case USB_TRANSFER_CONTROL:
+			instance->registers->control &= ~C_CLE;
+			endpoint_list_remove_ep(
+			    &instance->lists[ep->transfer_type], hcd_ep);
+			instance->registers->control_current = 0;
+			instance->registers->control |= C_CLE;
+			break;
+		case USB_TRANSFER_BULK:
+			instance->registers->control &= ~C_BLE;
+			endpoint_list_remove_ep(
+			    &instance->lists[ep->transfer_type], hcd_ep);
+			instance->registers->control |= C_BLE;
+			break;
+		case USB_TRANSFER_ISOCHRONOUS:
+		case USB_TRANSFER_INTERRUPT:
+			instance->registers->control &= (~C_PLE & ~C_IE);
+			endpoint_list_remove_ep(
+			    &instance->lists[ep->transfer_type], hcd_ep);
+			instance->registers->control |= C_PLE | C_IE;
+			break;
+		default:
+			break;
+		}
+		hcd_endpoint_clear(ep);
+	} else {
+		usb_log_warning("Endpoint without hcd equivalent structure.\n");
+	}
+	int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
+	    address, endpoint, direction);
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Get access to endpoint structures
+ *
+ * @param[in] instance OHCI hc driver structure.
+ * @param[in] address USB address of the device.
+ * @param[in] endpoint USB endpoint number.
+ * @param[in] direction Direction of the endpoint.
+ * @param[out] bw Reserved bandwidth.
+ * @return Error code
+ */
+endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
+	    address, endpoint, direction, bw);
+	fibril_mutex_unlock(&instance->guard);
+	return ep;
+}
+/*----------------------------------------------------------------------------*/
+/** Add USB transfer to the schedule.
+ *
+ * @param[in] instance OHCI hc driver structure.
+ * @param[in] batch Batch representing the transfer.
+ * @return Error code.
+ */
+int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
+{
+	assert(instance);
+	assert(batch);
+	assert(batch->ep);
+
+	/* Check for root hub communication */
+	if (batch->ep->address == instance->rh.address) {
+		return rh_request(&instance->rh, batch);
+	}
+
+	fibril_mutex_lock(&instance->guard);
+	list_append(&batch->link, &instance->pending_batches);
+	batch_commit(batch);
+
+	/* Control and bulk schedules need a kick to start working */
+	switch (batch->ep->transfer_type)
+	{
+	case USB_TRANSFER_CONTROL:
+		instance->registers->command_status |= CS_CLF;
+		break;
+	case USB_TRANSFER_BULK:
+		instance->registers->command_status |= CS_BLF;
+		break;
+	default:
+		break;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Interrupt handling routine
+ *
+ * @param[in] instance OHCI hc driver structure.
+ * @param[in] status Value of the status register at the time of interrupt.
+ */
+void hc_interrupt(hc_t *instance, uint32_t status)
+{
+	assert(instance);
+	if ((status & ~I_SF) == 0) /* ignore sof status */
+		return;
+	usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
+	if (status & I_RHSC)
+		rh_interrupt(&instance->rh);
+
+	if (status & I_WDH) {
+		fibril_mutex_lock(&instance->guard);
+		usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca,
+		    instance->registers->hcca,
+		    (void *) addr_to_phys(instance->hcca));
+		usb_log_debug2("Periodic current: %#" PRIx32 ".\n",
+		    instance->registers->periodic_current);
+
+		link_t *current = instance->pending_batches.next;
+		while (current != &instance->pending_batches) {
+			link_t *next = current->next;
+			usb_transfer_batch_t *batch =
+			    usb_transfer_batch_from_link(current);
+
+			if (batch_is_complete(batch)) {
+				list_remove(current);
+				usb_transfer_batch_finish(batch);
+			}
+			current = next;
+		}
+		fibril_mutex_unlock(&instance->guard);
+	}
+
+	if (status & I_UE) {
+		hc_start_hw(instance);
+	}
+
+}
+/*----------------------------------------------------------------------------*/
+/** Check status register regularly
+ *
+ * @param[in] instance OHCI hc driver structure.
+ * @return Error code
+ */
+int interrupt_emulator(hc_t *instance)
+{
+	assert(instance);
+	usb_log_info("Started interrupt emulator.\n");
+	while (1) {
+		const uint32_t status = instance->registers->interrupt_status;
+		instance->registers->interrupt_status = status;
+		hc_interrupt(instance, status);
+		async_usleep(10000);
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Turn off any (BIOS)driver that might be in control of the device.
+ *
+ * @param[in] instance OHCI hc driver structure.
+ */
+void hc_gain_control(hc_t *instance)
+{
+	assert(instance);
+	usb_log_debug("Requesting OHCI control.\n");
+	/* Turn off legacy emulation */
+	volatile uint32_t *ohci_emulation_reg =
+	    (uint32_t*)((char*)instance->registers + 0x100);
+	usb_log_debug("OHCI legacy register %p: %x.\n",
+	    ohci_emulation_reg, *ohci_emulation_reg);
+	/* Do not change A20 state */
+	*ohci_emulation_reg &= 0x100;
+	usb_log_debug("OHCI legacy register %p: %x.\n",
+	    ohci_emulation_reg, *ohci_emulation_reg);
+
+	/* Interrupt routing enabled => smm driver is active */
+	if (instance->registers->control & C_IR) {
+		usb_log_debug("SMM driver: request ownership change.\n");
+		instance->registers->command_status |= CS_OCR;
+		while (instance->registers->control & C_IR) {
+			async_usleep(1000);
+		}
+		usb_log_info("SMM driver: Ownership taken.\n");
+		instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
+		async_usleep(50000);
+		return;
+	}
+
+	const unsigned hc_status =
+	    (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
+	/* Interrupt routing disabled && status != USB_RESET => BIOS active */
+	if (hc_status != C_HCFS_RESET) {
+		usb_log_debug("BIOS driver found.\n");
+		if (hc_status == C_HCFS_OPERATIONAL) {
+			usb_log_info("BIOS driver: HC operational.\n");
+			return;
+		}
+		/* HC is suspended assert resume for 20ms */
+		instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
+		async_usleep(20000);
+		usb_log_info("BIOS driver: HC resumed.\n");
+		return;
+	}
+
+	/* HC is in reset (hw startup) => no other driver
+	 * maintain reset for at least the time specified in USB spec (50 ms)*/
+	usb_log_info("HC found in reset.\n");
+	async_usleep(50000);
+}
+/*----------------------------------------------------------------------------*/
+/** OHCI hw initialization routine.
+ *
+ * @param[in] instance OHCI hc driver structure.
+ */
+void hc_start_hw(hc_t *instance)
+{
+	/* OHCI guide page 42 */
+	assert(instance);
+	usb_log_debug2("Started hc initialization routine.\n");
+
+	/* Save contents of fm_interval register */
+	const uint32_t fm_interval = instance->registers->fm_interval;
+	usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
+
+	/* Reset hc */
+	usb_log_debug2("HC reset.\n");
+	size_t time = 0;
+	instance->registers->command_status = CS_HCR;
+	while (instance->registers->command_status & CS_HCR) {
+		async_usleep(10);
+		time += 10;
+	}
+	usb_log_debug2("HC reset complete in %zu us.\n", time);
+
+	/* Restore fm_interval */
+	instance->registers->fm_interval = fm_interval;
+	assert((instance->registers->command_status & CS_HCR) == 0);
+
+	/* hc is now in suspend state */
+	usb_log_debug2("HC should be in suspend state(%x).\n",
+	    instance->registers->control);
+
+	/* Use HCCA */
+	instance->registers->hcca = addr_to_phys(instance->hcca);
+
+	/* Use queues */
+	instance->registers->bulk_head =
+	    instance->lists[USB_TRANSFER_BULK].list_head_pa;
+	usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
+	    instance->lists[USB_TRANSFER_BULK].list_head,
+	    instance->lists[USB_TRANSFER_BULK].list_head_pa);
+
+	instance->registers->control_head =
+	    instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
+	usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
+	    instance->lists[USB_TRANSFER_CONTROL].list_head,
+	    instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
+
+	/* Enable queues */
+	instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
+	usb_log_debug2("All queues enabled(%x).\n",
+	    instance->registers->control);
+
+	/* Enable interrupts */
+	instance->registers->interrupt_enable = OHCI_USED_INTERRUPTS;
+	usb_log_debug2("Enabled interrupts: %x.\n",
+	    instance->registers->interrupt_enable);
+	instance->registers->interrupt_enable = I_MI;
+
+	/* Set periodic start to 90% */
+	uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
+	instance->registers->periodic_start = (frame_length / 10) * 9;
+	usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
+	    instance->registers->periodic_start,
+	    instance->registers->periodic_start, frame_length);
+
+	instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
+	usb_log_info("OHCI HC up and running(%x).\n",
+	    instance->registers->control);
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize schedule queues
+ *
+ * @param[in] instance OHCI hc driver structure
+ * @return Error code
+ */
+int hc_init_transfer_lists(hc_t *instance)
+{
+	assert(instance);
+#define SETUP_ENDPOINT_LIST(type) \
+do { \
+	const char *name = usb_str_transfer_type(type); \
+	int ret = endpoint_list_init(&instance->lists[type], name); \
+	if (ret != EOK) { \
+		usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
+		    ret, name); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \
+		endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \
+		return ret; \
+	} \
+} while (0)
+
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS);
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT);
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL);
+	SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK);
+#undef SETUP_ENDPOINT_LIST
+	endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT],
+	    &instance->lists[USB_TRANSFER_ISOCHRONOUS]);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize memory structures used by the OHCI hcd.
+ *
+ * @param[in] instance OHCI hc driver structure.
+ * @return Error code.
+ */
+int hc_init_memory(hc_t *instance)
+{
+	assert(instance);
+
+	bzero(&instance->rh, sizeof(instance->rh));
+	/* Init queues */
+	const int ret = hc_init_transfer_lists(instance);
+	if (ret != EOK) {
+		return ret;
+	}
+
+	/*Init HCCA */
+	instance->hcca = malloc32(sizeof(hcca_t));
+	if (instance->hcca == NULL)
+		return ENOMEM;
+	bzero(instance->hcca, sizeof(hcca_t));
+	usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
+
+	unsigned i = 0;
+	for (; i < 32; ++i) {
+		instance->hcca->int_ep[i] =
+		    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
+	}
+	usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
+	    instance->lists[USB_TRANSFER_INTERRUPT].list_head,
+	    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
+
+	/* Init interrupt code */
+	instance->interrupt_code.cmds = instance->interrupt_commands;
+	instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
+	{
+		/* Read status register */
+		instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
+		instance->interrupt_commands[0].dstarg = 1;
+		instance->interrupt_commands[0].addr =
+		    (void*)&instance->registers->interrupt_status;
+
+		/* Test whether we are the interrupt cause */
+		instance->interrupt_commands[1].cmd = CMD_BTEST;
+		instance->interrupt_commands[1].value =
+		    OHCI_USED_INTERRUPTS;
+		instance->interrupt_commands[1].srcarg = 1;
+		instance->interrupt_commands[1].dstarg = 2;
+
+		/* Predicate cleaning and accepting */
+		instance->interrupt_commands[2].cmd = CMD_PREDICATE;
+		instance->interrupt_commands[2].value = 2;
+		instance->interrupt_commands[2].srcarg = 2;
+
+		/* Write-clean status register */
+		instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
+		instance->interrupt_commands[3].srcarg = 1;
+		instance->interrupt_commands[3].addr =
+		    (void*)&instance->registers->interrupt_status;
+
+		/* Accept interrupt */
+		instance->interrupt_commands[4].cmd = CMD_ACCEPT;
+	}
+
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hc.h
===================================================================
--- uspace/drv/ohci/hc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI host controller driver structure
+ */
+#ifndef DRV_OHCI_HC_H
+#define DRV_OHCI_HC_H
+
+#include <fibril.h>
+#include <fibril_synch.h>
+#include <adt/list.h>
+#include <ddi.h>
+
+#include <usb/usb.h>
+#include <usb/host/device_keeper.h>
+#include <usb/host/usb_endpoint_manager.h>
+#include <usbhc_iface.h>
+
+#include "batch.h"
+#include "ohci_regs.h"
+#include "root_hub.h"
+#include "endpoint_list.h"
+#include "hw_struct/hcca.h"
+
+#define OHCI_NEEDED_IRQ_COMMANDS 5
+
+/** Main OHCI drier structure */
+typedef struct hc {
+	/** USB bus driver, devices and addresses */
+	usb_device_keeper_t manager;
+	/** USB bus driver, endpoints */
+	usb_endpoint_manager_t ep_manager;
+
+	/** Memory mapped I/O registers area */
+	ohci_regs_t *registers;
+	/** Host controller communication area structure */
+	hcca_t *hcca;
+
+	/** Transfer schedules */
+	endpoint_list_t lists[4];
+	/** List of active transfers */
+	link_t pending_batches;
+
+	/** Fibril for periodic checks if interrupts can't be used */
+	fid_t interrupt_emulator;
+
+	/** Guards schedule and endpoint manipulation */
+	fibril_mutex_t guard;
+
+	/** Code to be executed in kernel interrupt handler */
+	irq_code_t interrupt_code;
+
+	/** Commands that form interrupt code */
+	irq_cmd_t interrupt_commands[OHCI_NEEDED_IRQ_COMMANDS];
+
+	/** USB hub emulation structure */
+	rh_t rh;
+} hc_t;
+
+int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun);
+int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts);
+void hc_start_hw(hc_t *instance);
+
+/** Safely dispose host controller internal structures
+ *
+ * @param[in] instance Host controller structure to use.
+ */
+static inline void hc_fini(hc_t *instance)
+	{ /* TODO: implement*/ };
+
+int hc_add_endpoint(hc_t *instance, usb_address_t address, usb_endpoint_t ep,
+    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
+    size_t max_packet_size, size_t size, unsigned interval);
+int hc_remove_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction);
+endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw);
+
+int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
+void hc_interrupt(hc_t *instance, uint32_t status);
+
+/** Get and cast pointer to the driver data
+ *
+ * @param[in] fun DDF function pointer
+ * @return cast pointer to driver_data
+ */
+static inline hc_t * fun_to_hc(ddf_fun_t *fun)
+	{ return fun->driver_data; }
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hcd_endpoint.c
===================================================================
--- uspace/drv/ohci/hcd_endpoint.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hcd_endpoint.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include "utils/malloc32.h"
+#include "hcd_endpoint.h"
+
+/** Callback to set toggle on ED.
+ *
+ * @param[in] hcd_ep hcd endpoint structure
+ * @param[in] toggle new value of toggle bit
+ */
+static void hcd_ep_toggle_set(void *hcd_ep, int toggle)
+{
+	hcd_endpoint_t *instance = hcd_ep;
+	assert(instance);
+	assert(instance->ed);
+	ed_toggle_set(instance->ed, toggle);
+}
+/*----------------------------------------------------------------------------*/
+/** Callback to get value of toggle bit.
+ *
+ * @param[in] hcd_ep hcd endpoint structure
+ * @return Current value of toggle bit.
+ */
+static int hcd_ep_toggle_get(void *hcd_ep)
+{
+	hcd_endpoint_t *instance = hcd_ep;
+	assert(instance);
+	assert(instance->ed);
+	return ed_toggle_get(instance->ed);
+}
+/*----------------------------------------------------------------------------*/
+/** Creates new hcd endpoint representation.
+ *
+ * @param[in] ep USBD endpoint structure
+ * @return pointer to a new hcd endpoint structure, NULL on failure.
+ */
+hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep)
+{
+	assert(ep);
+	hcd_endpoint_t *hcd_ep = malloc(sizeof(hcd_endpoint_t));
+	if (hcd_ep == NULL)
+		return NULL;
+
+	hcd_ep->ed = malloc32(sizeof(ed_t));
+	if (hcd_ep->ed == NULL) {
+		free(hcd_ep);
+		return NULL;
+	}
+
+	hcd_ep->td = malloc32(sizeof(td_t));
+	if (hcd_ep->td == NULL) {
+		free32(hcd_ep->ed);
+		free(hcd_ep);
+		return NULL;
+	}
+
+	ed_init(hcd_ep->ed, ep);
+	ed_set_td(hcd_ep->ed, hcd_ep->td);
+	endpoint_set_hc_data(ep, hcd_ep, hcd_ep_toggle_get, hcd_ep_toggle_set);
+
+	return hcd_ep;
+}
+/*----------------------------------------------------------------------------*/
+/** Disposes assigned hcd endpoint structure
+ *
+ * @param[in] ep USBD endpoint structure
+ */
+void hcd_endpoint_clear(endpoint_t *ep)
+{
+	assert(ep);
+	hcd_endpoint_t *hcd_ep = ep->hc_data.data;
+	assert(hcd_ep);
+	free32(hcd_ep->ed);
+	free32(hcd_ep->td);
+	free(hcd_ep);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hcd_endpoint.h
===================================================================
--- uspace/drv/ohci/hcd_endpoint.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hcd_endpoint.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HCD_ENDPOINT_H
+#define DRV_OHCI_HCD_ENDPOINT_H
+
+#include <assert.h>
+#include <adt/list.h>
+#include <usb/host/endpoint.h>
+
+#include "hw_struct/endpoint_descriptor.h"
+#include "hw_struct/transfer_descriptor.h"
+
+/** Connector structure linking ED to to prepared TD. */
+typedef struct hcd_endpoint {
+	/** OHCI endpoint descriptor */
+	ed_t *ed;
+	/** Currently enqueued transfer descriptor */
+	td_t *td;
+	/** Linked list used by driver software */
+	link_t link;
+} hcd_endpoint_t;
+
+hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep);
+void hcd_endpoint_clear(endpoint_t *ep);
+
+/** Get and convert assigned hcd_endpoint_t structure
+ * @param[in] ep USBD endpoint structure.
+ * @return Pointer to assigned hcd endpoint structure
+ */
+static inline hcd_endpoint_t * hcd_endpoint_get(endpoint_t *ep)
+{
+	assert(ep);
+	return ep->hc_data.data;
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/completion_codes.h
===================================================================
--- uspace/drv/ohci/hw_struct/completion_codes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/completion_codes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HW_STRUCT_COMPLETION_CODES_H
+#define DRV_OHCI_HW_STRUCT_COMPLETION_CODES_H
+
+#include <errno.h>
+
+#define CC_NOERROR (0x0)
+#define CC_CRC (0x1)
+#define CC_BITSTUFF (0x2)
+#define CC_TOGGLE (0x3)
+#define CC_STALL (0x4)
+#define CC_NORESPONSE (0x5)
+#define CC_PIDFAIL (0x6)
+#define CC_PIDUNEXPECTED (0x7)
+#define CC_DATAOVERRRUN (0x8)
+#define CC_DATAUNDERRRUN (0x9)
+#define CC_BUFFEROVERRRUN (0xc)
+#define CC_BUFFERUNDERRUN (0xd)
+#define CC_NOACCESS1 (0xe)
+#define CC_NOACCESS2 (0xf)
+
+inline static int cc_to_rc(int cc)
+{
+	switch (cc) {
+	case CC_NOERROR:
+		return EOK;
+
+	case CC_CRC:
+		return EBADCHECKSUM;
+
+	case CC_PIDUNEXPECTED:
+	case CC_PIDFAIL:
+	case CC_BITSTUFF:
+		return EIO;
+
+	case CC_TOGGLE:
+	case CC_STALL:
+		return ESTALL;
+
+	case CC_NORESPONSE:
+		return ETIMEOUT;
+
+	case CC_DATAOVERRRUN:
+	case CC_DATAUNDERRRUN:
+	case CC_BUFFEROVERRRUN:
+	case CC_BUFFERUNDERRUN:
+		return EOVERFLOW;
+
+	case CC_NOACCESS1:
+	case CC_NOACCESS2:
+	default:
+		return ENOTSUP;
+	}
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/endpoint_descriptor.c
===================================================================
--- uspace/drv/ohci/hw_struct/endpoint_descriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/endpoint_descriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include "endpoint_descriptor.h"
+
+static unsigned direc[3] =
+    { ED_STATUS_D_IN, ED_STATUS_D_OUT, ED_STATUS_D_TRANSFER };
+
+void ed_init(ed_t *instance, endpoint_t *ep)
+{
+	assert(instance);
+	bzero(instance, sizeof(ed_t));
+	if (ep == NULL) {
+		instance->status = ED_STATUS_K_FLAG;
+		return;
+	}
+	assert(ep);
+	instance->status = 0
+	    | ((ep->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
+	    | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)
+	    | ((direc[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
+	    | ((ep->max_packet_size & ED_STATUS_MPS_MASK)
+	        << ED_STATUS_MPS_SHIFT);
+
+
+	if (ep->speed == USB_SPEED_LOW)
+		instance->status |= ED_STATUS_S_FLAG;
+	if (ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)
+		instance->status |= ED_STATUS_F_FLAG;
+
+	if (ep->toggle)
+		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/endpoint_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/endpoint_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/endpoint_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HW_STRUCT_ENDPOINT_DESCRIPTOR_H
+#define DRV_OHCI_HW_STRUCT_ENDPOINT_DESCRIPTOR_H
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <usb/host/endpoint.h>
+
+#include "../utils/malloc32.h"
+#include "transfer_descriptor.h"
+
+#include "completion_codes.h"
+
+typedef struct ed {
+	volatile uint32_t status;
+#define ED_STATUS_FA_MASK (0x7f)   /* USB device address   */
+#define ED_STATUS_FA_SHIFT (0)
+#define ED_STATUS_EN_MASK (0xf)    /* USB endpoint address */
+#define ED_STATUS_EN_SHIFT (7)
+#define ED_STATUS_D_MASK (0x3)     /* direction */
+#define ED_STATUS_D_SHIFT (11)
+#define ED_STATUS_D_OUT (0x1)
+#define ED_STATUS_D_IN (0x2)
+#define ED_STATUS_D_TRANSFER (0x3)
+
+#define ED_STATUS_S_FLAG (1 << 13) /* speed flag: 1 = low */
+#define ED_STATUS_K_FLAG (1 << 14) /* skip flag (no not execute this ED) */
+#define ED_STATUS_F_FLAG (1 << 15) /* format: 1 = isochronous*/
+#define ED_STATUS_MPS_MASK (0x3ff) /* max_packet_size*/
+#define ED_STATUS_MPS_SHIFT (16)
+
+	volatile uint32_t td_tail;
+#define ED_TDTAIL_PTR_MASK (0xfffffff0)
+#define ED_TDTAIL_PTR_SHIFT (0)
+
+	volatile uint32_t td_head;
+#define ED_TDHEAD_PTR_MASK (0xfffffff0)
+#define ED_TDHEAD_PTR_SHIFT (0)
+#define ED_TDHEAD_ZERO_MASK (0x3)
+#define ED_TDHEAD_ZERO_SHIFT (2)
+#define ED_TDHEAD_TOGGLE_CARRY (0x2)
+#define ED_TDHEAD_HALTED_FLAG (0x1)
+
+	volatile uint32_t next;
+#define ED_NEXT_PTR_MASK (0xfffffff0)
+#define ED_NEXT_PTR_SHIFT (0)
+} __attribute__((packed)) ed_t;
+
+void ed_init(ed_t *instance, endpoint_t *ep);
+
+static inline void ed_set_td(ed_t *instance, td_t *td)
+{
+	assert(instance);
+	uintptr_t pa = addr_to_phys(td);
+	instance->td_head =
+	    ((pa & ED_TDHEAD_PTR_MASK)
+	    | (instance->td_head & ~ED_TDHEAD_PTR_MASK));
+	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
+}
+
+static inline void ed_set_end_td(ed_t *instance, td_t *td)
+{
+	assert(instance);
+	uintptr_t pa = addr_to_phys(td);
+	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
+}
+
+static inline void ed_append_ed(ed_t *instance, ed_t *next)
+{
+	assert(instance);
+	assert(next);
+	uint32_t pa = addr_to_phys(next);
+	assert((pa & ED_NEXT_PTR_MASK) << ED_NEXT_PTR_SHIFT == pa);
+	instance->next = pa;
+}
+
+static inline int ed_toggle_get(ed_t *instance)
+{
+	assert(instance);
+	return (instance->td_head & ED_TDHEAD_TOGGLE_CARRY) ? 1 : 0;
+}
+
+static inline void ed_toggle_set(ed_t *instance, int toggle)
+{
+	assert(instance);
+	assert(toggle == 0 || toggle == 1);
+	if (toggle == 1) {
+		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
+	} else {
+		/* clear halted flag when reseting toggle */
+		instance->td_head &= ~ED_TDHEAD_TOGGLE_CARRY;
+		instance->td_head &= ~ED_TDHEAD_HALTED_FLAG;
+	}
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/hw_struct/hcca.h
===================================================================
--- uspace/drv/ohci/hw_struct/hcca.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/hcca.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HW_STRUCT_HCCA_H
+#define DRV_OHCI_HW_STRUCT_HCCA_H
+
+#include <stdint.h>
+
+/** Host controller communication area.
+ * Shared memory used for communication between the controller and the driver.
+ */
+typedef struct hcca {
+	uint32_t int_ep[32];
+	uint16_t frame_number;
+	uint16_t pad1;
+	uint32_t done_head;
+	uint32_t reserved[29];
+} __attribute__((packed, aligned)) hcca_t;
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/ohci/hw_struct/iso_transfer_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/iso_transfer_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/iso_transfer_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HW_STRUCT_ISO_TRANSFER_DESCRIPTOR_H
+#define DRV_OHCI_HW_STRUCT_ISO_TRANSFER_DESCRIPTOR_H
+
+#include <stdint.h>
+
+#include "completion_codes.h"
+
+typedef struct itd {
+	volatile uint32_t status;
+#define ITD_STATUS_SF_MASK (0xffff) /* starting frame */
+#define ITD_STATUS_SF_SHIFT (0)
+#define ITD_STATUS_DI_MASK (0x7) /* delay int, wait DI frames before int */
+#define ITD_STATUS_DI_SHIFT (21)
+#define ITD_STATUS_DI_NO_INTERRUPT (0x7)
+#define ITD_STATUS_FC_MASK (0x7) /* frame count */
+#define ITD_STATUS_FC_SHIFT (24)
+#define ITD_STATUS_CC_MASK (0xf) /* condition code */
+#define ITD_STATUS_CC_SHIFT (28)
+
+	volatile uint32_t page;   /* page number of the first byte in buffer */
+#define ITD_PAGE_BP0_MASK (0xfffff000)
+#define ITD_PAGE_BP0_SHIFT (0)
+
+	volatile uint32_t next;
+#define ITD_NEXT_PTR_MASK (0xfffffff0)
+#define ITD_NEXT_PTR_SHIFT (0)
+
+	volatile uint32_t be; /* buffer end, address of the last byte */
+
+	volatile uint16_t offset[8];
+#define ITD_OFFSET_SIZE_MASK (0x3ff)
+#define ITD_OFFSET_SIZE_SHIFT (0)
+#define ITD_OFFSET_CC_MASK (0xf)
+#define ITD_OFFSET_CC_SHIFT (12)
+
+} __attribute__((packed)) itd_t;
+#endif
+/**
+ * @}
+ */
+
+
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include <usb/usb.h>
+#include "transfer_descriptor.h"
+
+static unsigned dp[3] =
+    { TD_STATUS_DP_IN, TD_STATUS_DP_OUT, TD_STATUS_DP_SETUP };
+static unsigned togg[2] = { TD_STATUS_T_0, TD_STATUS_T_1 };
+
+void td_init(
+    td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle)
+{
+	assert(instance);
+	bzero(instance, sizeof(td_t));
+	instance->status = 0
+	    | ((dp[dir] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
+	    | ((CC_NOACCESS2 & TD_STATUS_CC_MASK) << TD_STATUS_CC_SHIFT);
+	if (toggle == 0 || toggle == 1) {
+		instance->status |= togg[toggle] << TD_STATUS_T_SHIFT;
+	}
+	if (dir == USB_DIRECTION_IN) {
+		instance->status |= TD_STATUS_ROUND_FLAG;
+	}
+	if (buffer != NULL) {
+		assert(size != 0);
+		instance->cbp = addr_to_phys(buffer);
+		instance->be = addr_to_phys(buffer + size - 1);
+	}
+}
+/**
+ * @}
+ */
+
Index: uspace/drv/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/hw_struct/transfer_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H
+#define DRV_OHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H
+
+#include <bool.h>
+#include <stdint.h>
+#include "../utils/malloc32.h"
+
+#include "completion_codes.h"
+
+/* OHCI TDs can handle up to 8KB buffers, however, it can use max 2 pages.
+ * Using 4KB buffers guarantees the page count condition.
+ * (OHCI assumes 4KB pages) */
+#define OHCI_TD_MAX_TRANSFER (4 * 1024)
+
+typedef struct td {
+	volatile uint32_t status;
+#define TD_STATUS_ROUND_FLAG (1 << 18)
+#define TD_STATUS_DP_MASK (0x3) /* direction/PID */
+#define TD_STATUS_DP_SHIFT (19)
+#define TD_STATUS_DP_SETUP (0x0)
+#define TD_STATUS_DP_OUT (0x1)
+#define TD_STATUS_DP_IN (0x2)
+#define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */
+#define TD_STATUS_DI_SHIFT (21)
+#define TD_STATUS_DI_NO_INTERRUPT (0x7)
+#define TD_STATUS_T_MASK (0x3)  /* data toggle 1x = use ED toggle carry */
+#define TD_STATUS_T_SHIFT (24)
+#define TD_STATUS_T_0 (0x2)
+#define TD_STATUS_T_1 (0x3)
+#define TD_STATUS_T_ED (0)
+#define TD_STATUS_EC_MASK (0x3) /* error count */
+#define TD_STATUS_EC_SHIFT (26)
+#define TD_STATUS_CC_MASK (0xf) /* condition code */
+#define TD_STATUS_CC_SHIFT (28)
+
+	volatile uint32_t cbp; /* current buffer ptr, data to be transfered */
+	volatile uint32_t next;
+#define TD_NEXT_PTR_MASK (0xfffffff0)
+#define TD_NEXT_PTR_SHIFT (0)
+
+	volatile uint32_t be; /* buffer end, address of the last byte */
+} __attribute__((packed)) td_t;
+
+void td_init(
+    td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle);
+
+inline static void td_set_next(td_t *instance, td_t *next)
+{
+	assert(instance);
+	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
+}
+
+inline static bool td_is_finished(td_t *instance)
+{
+	assert(instance);
+	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	/* something went wrong, error code is set */
+	if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2) {
+		return true;
+	}
+	/* everything done */
+	if (cc == CC_NOERROR && instance->cbp == 0) {
+		return true;
+	}
+	return false;
+}
+
+static inline int td_error(td_t *instance)
+{
+	assert(instance);
+	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	return cc_to_rc(cc);
+}
+
+static inline size_t td_remain_size(td_t *instance)
+{
+	assert(instance);
+	if (instance->cbp == 0)
+		return 0;
+	return instance->be - instance->cbp + 1;
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/iface.c
===================================================================
--- uspace/drv/ohci/iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky, Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver hc interface implementation
+ */
+#include <ddf/driver.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+#include <usb/host/endpoint.h>
+
+#include "iface.h"
+#include "hc.h"
+
+static inline int setup_batch(
+    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
+    void *data, size_t size, void * setup_data, size_t setup_size,
+    usbhc_iface_transfer_in_callback_t in,
+    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
+    hc_t **hc, usb_transfer_batch_t **batch)
+{
+	assert(hc);
+	assert(batch);
+	assert(fun);
+	*hc = fun_to_hc(fun);
+	assert(*hc);
+
+	size_t res_bw;
+	endpoint_t *ep = hc_get_endpoint(*hc,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    target.address, target.endpoint, name, bw, res_bw);
+		return ENOSPC;
+	}
+
+	*batch = batch_get(
+	    fun, ep, data, size, setup_data, setup_size, in, out, arg);
+	if (!*batch)
+		return ENOMEM;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	assert(address);
+
+	usb_log_debug("Address request with speed %d.\n", speed);
+	*address = device_keeper_get_free_address(&hc->manager, speed);
+	usb_log_debug("Address request with result: %d.\n", *address);
+	if (*address <= 0)
+		return *address;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
+	usb_device_keeper_bind(&hc->manager, address, handle);
+	return EOK;
+}
+
+
+/** Find device handle by address interface function.
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address in question.
+ * @param[out] handle Where to store device handle if found.
+ * @return Error code.
+ */
+static int find_by_address(ddf_fun_t *fun, usb_address_t address,
+    devman_handle_t *handle)
+{
+	assert(fun);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	bool found =
+	    usb_device_keeper_find_by_address(&hc->manager, address, handle);
+	return found ? EOK : ENOENT;
+}
+
+/*----------------------------------------------------------------------------*/
+/** 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);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	usb_log_debug("Address release %d.\n", address);
+	usb_device_keeper_release(&hc->manager, address);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Register endpoint for bandwidth reservation.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] ep_speed Endpoint speed (invalid means to use device one).
+ * @param[in] endpoint Endpoint number.
+ * @param[in] transfer_type USB transfer type.
+ * @param[in] direction Endpoint data direction.
+ * @param[in] max_packet_size Max packet size of the endpoint.
+ * @param[in] interval Polling interval.
+ * @return Error code.
+ */
+static int register_endpoint(ddf_fun_t *fun,
+    usb_address_t address, usb_speed_t ep_speed, usb_endpoint_t endpoint,
+    usb_transfer_type_t transfer_type, usb_direction_t direction,
+    size_t max_packet_size, unsigned int interval)
+{
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+
+	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
+	if (speed >= USB_SPEED_MAX) {
+		speed = ep_speed;
+	}
+	const size_t size = max_packet_size;
+
+	usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
+	    address, endpoint, usb_str_transfer_type(transfer_type),
+	    usb_str_speed(speed), direction, size, max_packet_size, interval);
+
+	return hc_add_endpoint(hc, address, endpoint, speed, transfer_type,
+	    direction, max_packet_size, size, interval);
+}
+/*----------------------------------------------------------------------------*/
+static int unregister_endpoint(
+    ddf_fun_t *fun, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	usb_log_debug("Unregister endpoint %d:%d %d.\n",
+	    address, endpoint, direction);
+	return hc_remove_endpoint(hc, address, endpoint, direction);
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule interrupt out transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
+ *	by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int interrupt_out(
+    ddf_fun_t *fun, usb_target_t target, void *data,
+    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	batch_interrupt_out(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule interrupt in transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int interrupt_in(
+    ddf_fun_t *fun, usb_target_t target, void *data,
+    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	batch_interrupt_in(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule bulk out transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
+ *	by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int bulk_out(
+    ddf_fun_t *fun, usb_target_t target, void *data,
+    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	batch_bulk_out(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule bulk in transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int bulk_in(
+    ddf_fun_t *fun, usb_target_t target, void *data,
+    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	batch_bulk_in(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule control write transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
+ *	and deallocated by the caller).
+ * @param[in] setup_size Size of @p setup_packet buffer in bytes.
+ * @param[in] data_buffer Data buffer (in USB endianess, allocated and
+ *	deallocated by the caller).
+ * @param[in] size Size of @p data_buffer buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int control_write(
+    ddf_fun_t *fun, usb_target_t target,
+    void *setup_data, size_t setup_size, void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
+	batch_control_write(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Schedule control read transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
+ *	and deallocated by the caller).
+ * @param[in] setup_size Size of @p setup_packet buffer in bytes.
+ * @param[in] data_buffer Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of @p data_buffer buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int control_read(
+    ddf_fun_t *fun, usb_target_t target,
+    void *setup_data, size_t setup_size, void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, callback, NULL, arg, "Control READ",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	batch_control_read(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+usbhc_iface_t hc_iface = {
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.find_by_address = find_by_address,
+	.release_address = release_address,
+
+	.register_endpoint = register_endpoint,
+	.unregister_endpoint = unregister_endpoint,
+
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+
+	.bulk_out = bulk_out,
+	.bulk_in = bulk_in,
+
+	.control_write = control_write,
+	.control_read = control_read,
+};
+/**
+ * @}
+ */
Index: uspace/drv/ohci/iface.h
===================================================================
--- uspace/drv/ohci/iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * 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 drvusbohci
+ * @{
+ */
+/** @file
+ * Common OHCI definitions.
+ */
+#ifndef DRV_OHCI_IFACE_H
+#define DRV_OHCI_IFACE_H
+
+#include <usbhc_iface.h>
+
+extern usbhc_iface_t hc_iface;
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/ohci/main.c
===================================================================
--- uspace/drv/ohci/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,90 @@
+/*
+ * 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 drvusbohci
+ * @{
+ */
+/** @file
+ * Main routines of OHCI driver.
+ */
+#include <ddf/driver.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/debug.h>
+
+#include "ohci.h"
+
+#define NAME "ohci"
+
+/** Initializes a new ddf driver instance of OHCI hcd.
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int ohci_add_device(ddf_dev_t *device)
+{
+	usb_log_debug("ohci_add_device() called\n");
+	assert(device);
+
+	int ret = device_setup_ohci(device);
+	if (ret != EOK) {
+		usb_log_error("Failed to initialize OHCI driver: %s.\n",
+		    str_error(ret));
+		return ret;
+	}
+	usb_log_info("Controlling new OHCI device '%s'.\n", device->name);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static driver_ops_t ohci_driver_ops = {
+	.add_device = ohci_add_device,
+};
+/*----------------------------------------------------------------------------*/
+static driver_t ohci_driver = {
+	.name = NAME,
+	.driver_ops = &ohci_driver_ops
+};
+/*----------------------------------------------------------------------------*/
+/** 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_DEFAULT, NAME);
+	return ddf_driver_main(&ohci_driver);
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/ohci.c
===================================================================
--- uspace/drv/ohci/ohci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/ohci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/interrupt.h>
+#include <usb_iface.h>
+#include <usb/usb.h>
+#include <usb/ddfiface.h>
+#include <usb/debug.h>
+
+#include "ohci.h"
+#include "iface.h"
+#include "pci.h"
+#include "hc.h"
+#include "root_hub.h"
+
+typedef struct ohci {
+	ddf_fun_t *hc_fun;
+	ddf_fun_t *rh_fun;
+
+	hc_t hc;
+	rh_t rh;
+} ohci_t;
+
+static inline ohci_t * dev_to_ohci(ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(dev->driver_data);
+	return dev->driver_data;
+}
+
+/** 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)
+{
+	hc_t *hc = &dev_to_ohci(dev)->hc;
+	assert(hc);
+	const uint16_t status = IPC_GET_ARG1(*call);
+	hc_interrupt(hc, status);
+}
+/*----------------------------------------------------------------------------*/
+/** Get address of the device identified by handle.
+ *
+ * @param[in] dev DDF instance of the device to use.
+ * @param[in] iid (Unused).
+ * @param[in] call Pointer to the call that represents interrupt.
+ */
+static int usb_iface_get_address(
+    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
+{
+	assert(fun);
+	usb_device_keeper_t *manager = &dev_to_ohci(fun->dev)->hc.manager;
+
+	usb_address_t addr = usb_device_keeper_find(manager, handle);
+	if (addr < 0) {
+		return addr;
+	}
+
+	if (address != NULL) {
+		*address = addr;
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Gets handle of the respective hc (this device, hc function).
+ *
+ * @param[in] root_hub_fun Root hub function seeking hc handle.
+ * @param[out] handle Place to write the handle.
+ * @return Error code.
+ */
+static int usb_iface_get_hc_handle(
+    ddf_fun_t *fun, devman_handle_t *handle)
+{
+	assert(fun);
+	ddf_fun_t *hc_fun = dev_to_ohci(fun->dev)->hc_fun;
+	assert(hc_fun);
+
+	if (handle != NULL)
+		*handle = hc_fun->handle;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Root hub USB interface */
+static usb_iface_t usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle,
+	.get_address = usb_iface_get_address
+};
+/*----------------------------------------------------------------------------*/
+/** Standard USB HC options (HC interface) */
+static ddf_dev_ops_t hc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */
+};
+/*----------------------------------------------------------------------------*/
+/** Standard USB RH options (RH interface) */
+static ddf_dev_ops_t rh_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface,
+};
+/*----------------------------------------------------------------------------*/
+/** Initialize hc and rh ddf structures and their respective drivers.
+ *
+ * @param[in] device DDF instance of the device to use.
+ * @param[in] instance OHCI structure to use.
+ *
+ * This function does all the preparatory work for hc and rh drivers:
+ *  - gets device hw resources
+ *  - disables OHCI legacy support
+ *  - asks for interrupt
+ *  - registers interrupt handler
+ */
+int device_setup_ohci(ddf_dev_t *device)
+{
+	ohci_t *instance = malloc(sizeof(ohci_t));
+	if (instance == NULL) {
+		usb_log_error("Failed to allocate OHCI driver.\n");
+		return ENOMEM;
+	}
+
+#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
+if (ret != EOK) { \
+	if (instance->hc_fun) { \
+		instance->hc_fun->ops = NULL; \
+		instance->hc_fun->driver_data = NULL; \
+		ddf_fun_destroy(instance->hc_fun); \
+	} \
+	if (instance->rh_fun) { \
+		instance->rh_fun->ops = NULL; \
+		instance->rh_fun->driver_data = NULL; \
+		ddf_fun_destroy(instance->rh_fun); \
+	} \
+	free(instance); \
+	usb_log_error(message); \
+	return ret; \
+} else (void)0
+
+	instance->rh_fun = NULL;
+	instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc");
+	int ret = instance->hc_fun ? EOK : ENOMEM;
+	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI HC function.\n");
+	instance->hc_fun->ops = &hc_ops;
+	instance->hc_fun->driver_data = &instance->hc;
+
+	instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci_rh");
+	ret = instance->rh_fun ? EOK : ENOMEM;
+	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI RH function.\n");
+	instance->rh_fun->ops = &rh_ops;
+
+	uintptr_t reg_base = 0;
+	size_t reg_size = 0;
+	int irq = 0;
+
+	ret = pci_get_my_registers(device, &reg_base, &reg_size, &irq);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to get memory addresses for %" PRIun ": %s.\n",
+	    device->handle, str_error(ret));
+	usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
+	    (void *) reg_base, reg_size, irq);
+
+	bool interrupts = false;
+#ifdef CONFIG_USBHC_NO_INTERRUPTS
+	usb_log_warning("Interrupts disabled in OS config, "
+	    "falling back to polling.\n");
+#else
+	ret = pci_enable_interrupts(device);
+	if (ret != EOK) {
+		usb_log_warning("Failed to enable interrupts: %s.\n",
+		    str_error(ret));
+		usb_log_info("HW interrupts not available, "
+		    "falling back to polling.\n");
+	} else {
+		usb_log_debug("Hw interrupts enabled.\n");
+		interrupts = true;
+	}
+#endif
+
+	ret = hc_init(&instance->hc, reg_base, reg_size, interrupts);
+	CHECK_RET_DEST_FREE_RETURN(ret, "Failed(%d) to init ohci_hcd.\n", ret);
+
+#define CHECK_RET_FINI_RETURN(ret, message...) \
+if (ret != EOK) { \
+	hc_fini(&instance->hc); \
+	CHECK_RET_DEST_FREE_RETURN(ret, message); \
+} else (void)0
+
+	/* 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);
+
+	ret = ddf_fun_bind(instance->hc_fun);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to bind OHCI device function: %s.\n",
+	    ret, str_error(ret));
+
+	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed to add OHCI to HC class: %s.\n", str_error(ret));
+
+	device->driver_data = instance;
+
+	hc_start_hw(&instance->hc);
+	hc_register_hub(&instance->hc, instance->rh_fun);
+	return EOK;
+
+#undef CHECK_RET_DEST_FUN_RETURN
+#undef CHECK_RET_FINI_RETURN
+}
+/**
+ * @}
+ */
Index: uspace/drv/ohci/ohci.h
===================================================================
--- uspace/drv/ohci/ohci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/ohci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver main structure for both host controller and root-hub.
+ */
+#ifndef DRV_OHCI_OHCI_H
+#define DRV_OHCI_OHCI_H
+#include <ddi.h>
+#include <ddf/driver.h>
+
+int device_setup_ohci(ddf_dev_t *device);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/ohci.ma
===================================================================
--- uspace/drv/ohci/ohci.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/ohci.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,11 @@
+10 pci/ven=106b&dev=003f
+10 pci/ven=10de&dev=0aa5
+
+10 pci/ven=1002&dev=4374
+10 pci/ven=1002&dev=4375
+
+10 pci/ven=1002&dev=4387
+10 pci/ven=1002&dev=4388
+10 pci/ven=1002&dev=4389
+10 pci/ven=1002&dev=438a
+10 pci/ven=1002&dev=438b
Index: uspace/drv/ohci/ohci_regs.h
===================================================================
--- uspace/drv/ohci/ohci_regs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/ohci_regs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,219 @@
+/*
+ * 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 drvusbohcihc
+ * @{
+ */
+/** @file
+ * @brief OHCI host controller register structure
+ */
+#ifndef DRV_OHCI_OHCI_REGS_H
+#define DRV_OHCI_OHCI_REGS_H
+#include <stdint.h>
+
+/** OHCI memory mapped registers structure */
+typedef struct ohci_regs {
+	const volatile uint32_t revision;
+	volatile uint32_t control;
+#define C_CSBR_MASK (0x3) /* Control-bulk service ratio */
+#define C_CSBR_1_1  (0x0)
+#define C_CSBR_1_2  (0x1)
+#define C_CSBR_1_3  (0x2)
+#define C_CSBR_1_4  (0x3)
+#define C_CSBR_SHIFT (0)
+
+#define C_PLE (1 << 2)   /* Periodic list enable */
+#define C_IE  (1 << 3)   /* Isochronous enable */
+#define C_CLE (1 << 4)   /* Control list enable */
+#define C_BLE (1 << 5)   /* Bulk list enable */
+
+#define C_HCFS_MASK        (0x3) /* Host controller functional state */
+#define C_HCFS_RESET       (0x0)
+#define C_HCFS_RESUME      (0x1)
+#define C_HCFS_OPERATIONAL (0x2)
+#define C_HCFS_SUSPEND     (0x3)
+#define C_HCFS_SHIFT       (6)
+
+#define C_IR  (1 << 8)   /* Interrupt routing, make sure it's 0 */
+#define C_RWC (1 << 9)   /* Remote wakeup connected, host specific */
+#define C_RWE (1 << 10)  /* Remote wakeup enable */
+
+	volatile uint32_t command_status;
+#define CS_HCR (1 << 0)   /* Host controller reset */
+#define CS_CLF (1 << 1)   /* Control list filled */
+#define CS_BLF (1 << 2)   /* Bulk list filled */
+#define CS_OCR (1 << 3)   /* Ownership change request */
+#define CS_SOC_MASK (0x3) /* Scheduling overrun count */
+#define CS_SOC_SHIFT (16)
+
+	/** Interupt enable/disable/status,
+	 * reads give the same value,
+	 * writing causes enable/disable,
+	 * status is write-clean (writing 1 clears the bit*/
+	volatile uint32_t interrupt_status;
+	volatile uint32_t interrupt_enable;
+	volatile uint32_t interrupt_disable;
+#define I_SO   (1 << 0)   /* Scheduling overrun */
+#define I_WDH  (1 << 1)   /* Done head write-back */
+#define I_SF   (1 << 2)   /* Start of frame */
+#define I_RD   (1 << 3)   /* Resume detect */
+#define I_UE   (1 << 4)   /* Unrecoverable error */
+#define I_FNO  (1 << 5)   /* Frame number overflow */
+#define I_RHSC (1 << 6)   /* Root hub status change */
+#define I_OC   (1 << 30)  /* Ownership change */
+#define I_MI   (1 << 31)  /* Master interrupt (all/any interrupts) */
+
+	/** HCCA pointer (see hw_struct hcca.h) */
+	volatile uint32_t hcca;
+#define HCCA_PTR_MASK 0xffffff00 /* HCCA is 256B aligned */
+
+	/** Currently executed periodic endpoint */
+	const volatile uint32_t periodic_current;
+
+	/** The first control endpoint */
+	volatile uint32_t control_head;
+
+	/** Currently executed control endpoint */
+	volatile uint32_t control_current;
+
+	/** The first bulk endpoint */
+	volatile uint32_t bulk_head;
+
+	/** Currently executed bulk endpoint */
+	volatile uint32_t bulk_current;
+
+	/** Done TD list, this value is periodically written to HCCA */
+	const volatile uint32_t done_head;
+
+	/** Frame time and max packet size for all transfers */
+	volatile uint32_t fm_interval;
+#define FMI_FI_MASK (0x3fff) /* Frame interval in bit times (should be 11999)*/
+#define FMI_FI_SHIFT (0)
+#define FMI_FSMPS_MASK (0x7fff) /* Full speed max packet size */
+#define FMI_FSMPS_SHIFT (16)
+#define FMI_TOGGLE_FLAG (1 << 31)
+
+	/** Bit times remaining in current frame */
+	const volatile uint32_t fm_remaining;
+#define FMR_FR_MASK FMI_FI_MASK
+#define FMR_FR_SHIFT FMI_FI_SHIFT
+#define FMR_TOGGLE_FLAG FMI_TOGGLE_FLAG
+
+	/** Frame number */
+	const volatile uint32_t fm_number;
+#define FMN_NUMBER_MASK (0xffff)
+
+	/** Remaining bit time in frame to start periodic transfers */
+	volatile uint32_t periodic_start;
+#define PS_PS_MASK (0x3fff) /* bit time when periodic get priority (0x3e67) */
+
+	/** Threshold for starting LS transaction */
+	volatile uint32_t ls_threshold;
+#define LST_LST_MASK (0x7fff)
+
+	/** The first root hub control register */
+	volatile uint32_t rh_desc_a;
+#define RHDA_NDS_MASK (0xff) /* Number of downstream ports, max 15 */
+#define RHDA_NDS_SHIFT (0)
+#define RHDA_PSM_FLAG  (1 << 8)  /* Power switching mode: 0-global, 1-per port*/
+#define RHDA_NPS_FLAG  (1 << 9)  /* No power switch: 1-power on, 0-use PSM*/
+#define RHDA_DT_FLAG   (1 << 10) /* 1-Compound device, must be 0 */
+#define RHDA_OCPM_FLAG (1 << 11) /* Over-current mode: 0-global, 1-per port */
+#define RHDA_NOCP      (1 << 12) /* OC control: 0-use OCPM, 1-OC off */
+#define RHDA_POTPGT_MASK (0xff)  /* Power on to power good time */
+#define RHDA_POTPGT_SHIFT (24)
+
+	/** The other root hub control register */
+	volatile uint32_t rh_desc_b;
+#define RHDB_DR_MASK (0xffff) /* Device removable mask */
+#define RHDB_DR_SHIFT (0)
+#define RHDB_PCC_MASK (0xffff) /* Power control mask */
+#define RHDB_PCC_SHIFT (16)
+
+/* Port device removable status */
+#define RHDB_DR_FLAG(port) (((1 << port) & RHDB_DR_MASK) << RHDB_DR_SHIFT)
+/* Port power control status: 1-per port power control, 0-global power switch */
+#define RHDB_PPC_FLAG(port) (((1 << port) & RHDB_DR_MASK) << RHDB_DR_SHIFT)
+
+	/** Root hub status register */
+	volatile uint32_t rh_status;
+#define RHS_LPS_FLAG  (1 <<  0)/* read: 0,
+                                * write: 0-no effect,
+                                *        1-turn off port power for ports
+                                *        specified in PPCM(RHDB), or all ports,
+                                *        if power is set globally */
+#define RHS_CLEAR_PORT_POWER RHS_LPS_FLAG /* synonym for the above */
+#define RHS_OCI_FLAG  (1 <<  1)/* Over-current indicator, if per-port: 0 */
+#define RHS_DRWE_FLAG (1 << 15)/* read: 0-connect status change does not wake HC
+                                *       1-connect status change wakes HC
+                                * write: 1-set DRWE, 0-no effect */
+#define RHS_SET_DRWE RHS_DRWE_FLAG
+#define RHS_LPSC_FLAG (1 << 16)/* read: 0,
+                                * write: 0-no effect
+                                *        1-turn on port power for ports
+                                *        specified in PPCM(RHDB), or all ports,
+                                *        if power is set globally */
+#define RHS_SET_PORT_POWER RHS_LPSC_FLAG /* synonym for the above */
+#define RHS_OCIC_FLAG (1 << 17)/* Over-current indicator change   */
+#define RHS_CLEAR_DRWE (1 << 31)
+
+	/** Root hub per port status */
+	volatile uint32_t rh_port_status[];
+#define RHPS_CCS_FLAG (1 << 0) /* r: current connect status,
+                                * w: 1-clear port enable, 0-nothing */
+#define RHPS_CLEAR_PORT_ENABLE RHPS_CCS_FLAG
+#define RHPS_PES_FLAG (1 << 1) /* r: port enable status
+                                * w: 1-set port enable, 0-nothing */
+#define RHPS_SET_PORT_ENABLE RHPS_PES_FLAG
+#define RHPS_PSS_FLAG (1 << 2) /* r: port suspend status
+                                * w: 1-set port suspend, 0-nothing */
+#define RHPS_SET_PORT_SUSPEND RHPS_PSS_FLAG
+#define RHPS_POCI_FLAG (1 << 3) /* r: port over-current (if reports are per-port
+                                 * w: 1-clear port suspend (start resume
+                                 *      if suspened)
+                                 *    0-nothing */
+#define RHPS_CLEAR_PORT_SUSPEND RHPS_POCI_FLAG
+#define RHPS_PRS_FLAG (1 << 4) /* r: port reset status
+                                * w: 1-set port reset, 0-nothing */
+#define RHPS_SET_PORT_RESET RHPS_PRS_FLAG
+#define RHPS_PPS_FLAG (1 << 8) /* r: port power status
+                                * w: 1-set port power, 0-nothing */
+#define RHPS_SET_PORT_POWER RHPS_PPS_FLAG
+#define RHPS_LSDA_FLAG (1 << 9) /* r: low speed device attached
+                                 * w: 1-clear port power, 0-nothing */
+#define RHPS_CLEAR_PORT_POWER RHPS_LSDA_FLAG
+#define RHPS_CSC_FLAG  (1 << 16) /* connect status change Write-Clean */
+#define RHPS_PESC_FLAG (1 << 17) /* port enable status change WC */
+#define RHPS_PSSC_FLAG (1 << 18) /* port suspend status change WC */
+#define RHPS_OCIC_FLAG (1 << 19) /* port over-current change WC */
+#define RHPS_PRSC_FLAG (1 << 20) /* port reset status change WC */
+#define RHPS_CHANGE_WC_MASK 0x1f0000
+} __attribute__((packed)) ohci_regs_t;
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/pci.c
===================================================================
--- uspace/drv/ohci/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @addtogroup drvusbohci
+ * @{
+ */
+/**
+ * @file
+ * PCI related functions needed by the OHCI 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"
+
+/** 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);
+	assert(mem_reg_address);
+	assert(mem_reg_size);
+	assert(irq_no);
+
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	hw_resource_list_t hw_resources;
+	int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (rc != EOK) {
+		async_hangup(parent_sess);
+		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: %p %zu.\n",
+				    (void *) 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_sess);
+	return rc;
+}
+
+/** 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)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	bool enabled = hw_res_enable_interrupt(parent_sess);
+	async_hangup(parent_sess);
+	
+	return enabled ? EOK : EIO;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/ohci/pci.h
===================================================================
--- uspace/drv/ohci/pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,47 @@
+/*
+ * 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 drvusbohci
+ * @{
+ */
+/** @file
+ * PCI related functions needed by OHCI driver.
+ */
+#ifndef DRV_OHCI_PCI_H
+#define DRV_OHCI_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/ohci/root_hub.c
===================================================================
--- uspace/drv/ohci/root_hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/root_hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,944 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#include <assert.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/debug.h>
+
+#include "root_hub.h"
+#include <usb/classes/classes.h>
+#include <usb/dev/driver.h>
+#include "ohci_regs.h"
+
+#include <usb/dev/request.h>
+#include <usb/classes/hub.h>
+
+/**
+ * standart device descriptor for ohci root hub
+ */
+static const usb_standard_device_descriptor_t ohci_rh_device_descriptor = {
+	.configuration_count = 1,
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.device_class = USB_CLASS_HUB,
+	.device_protocol = 0,
+	.device_subclass = 0,
+	.device_version = 0,
+	.length = sizeof (usb_standard_device_descriptor_t),
+	.max_packet_size = 8,
+	.vendor_id = 0x16db,
+	.product_id = 0x0001,
+	.str_serial_number = 0,
+	.usb_spec_version = 0x110,
+};
+
+/**
+ * standart configuration descriptor with filled common values
+ * for ohci root hubs
+ */
+static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor = {
+	.attributes = 1 << 7,
+	.configuration_number = 1,
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	.interface_count = 1,
+	.length = sizeof (usb_standard_configuration_descriptor_t),
+	.max_power = 100,
+	.str_configuration = 0,
+};
+
+/**
+ * standart ohci root hub interface descriptor
+ */
+static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor = {
+	.alternate_setting = 0,
+	.descriptor_type = USB_DESCTYPE_INTERFACE,
+	.endpoint_count = 1,
+	.interface_class = USB_CLASS_HUB,
+	.interface_number = 1,
+	.interface_protocol = 0,
+	.interface_subclass = 0,
+	.length = sizeof (usb_standard_interface_descriptor_t),
+	.str_interface = 0,
+};
+
+/**
+ * standart ohci root hub endpoint descriptor
+ */
+static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor = {
+	.attributes = USB_TRANSFER_INTERRUPT,
+	.descriptor_type = USB_DESCTYPE_ENDPOINT,
+	.endpoint_address = 1 + (1 << 7),
+	.length = sizeof (usb_standard_endpoint_descriptor_t),
+	.max_packet_size = 8,
+	.poll_interval = 255,
+};
+
+/**
+ * bitmask of hub features that are valid to be cleared
+ */
+static const uint32_t hub_clear_feature_valid_mask =
+    RHS_OCIC_FLAG |
+    RHS_CLEAR_PORT_POWER;
+
+/**
+ * bitmask of hub features that are cleared by writing 1 (and not 0)
+ */
+static const uint32_t hub_clear_feature_by_writing_one_mask =
+    RHS_CLEAR_PORT_POWER;
+
+/**
+ * bitmask of hub features that are valid to be set
+ */
+static const uint32_t hub_set_feature_valid_mask =
+    RHS_LPSC_FLAG |
+    RHS_OCIC_FLAG;
+
+/**
+ * bitmask of hub features that are set by writing 1 and cleared by writing 0
+ */
+static const uint32_t hub_set_feature_direct_mask =
+    RHS_SET_PORT_POWER;
+
+/**
+ * bitmask of port features that are valid to be set
+ */
+static const uint32_t port_set_feature_valid_mask =
+    RHPS_SET_PORT_ENABLE |
+    RHPS_SET_PORT_SUSPEND |
+    RHPS_SET_PORT_RESET |
+    RHPS_SET_PORT_POWER;
+
+/**
+ * bitmask of port features that can be cleared
+ */
+static const uint32_t port_clear_feature_valid_mask =
+    RHPS_CCS_FLAG |
+    RHPS_SET_PORT_SUSPEND |
+    RHPS_POCI_FLAG |
+    RHPS_SET_PORT_POWER |
+    RHPS_CSC_FLAG |
+    RHPS_PESC_FLAG |
+    RHPS_PSSC_FLAG |
+    RHPS_OCIC_FLAG |
+    RHPS_PRSC_FLAG;
+
+//note that USB_HUB_FEATURE_PORT_POWER bit is translated into
+//USB_HUB_FEATURE_PORT_LOW_SPEED for port set feature request
+
+/**
+ * bitmask with port status changes
+ */
+static const uint32_t port_status_change_mask = RHPS_CHANGE_WC_MASK;
+
+static int create_serialized_hub_descriptor(rh_t *instance);
+
+static int rh_init_descriptors(rh_t *instance);
+
+static int process_get_port_status_request(rh_t *instance, uint16_t port,
+    usb_transfer_batch_t * request);
+
+static int process_get_hub_status_request(rh_t *instance,
+    usb_transfer_batch_t * request);
+
+static int process_get_status_request(rh_t *instance,
+    usb_transfer_batch_t * request);
+
+static void create_interrupt_mask_in_instance(rh_t *instance);
+
+static int process_get_descriptor_request(rh_t *instance,
+    usb_transfer_batch_t *request);
+
+static int process_get_configuration_request(rh_t *instance,
+    usb_transfer_batch_t *request);
+
+static int process_hub_feature_set_request(rh_t *instance, uint16_t feature);
+
+static int process_hub_feature_clear_request(rh_t *instance,
+    uint16_t feature);
+
+static int process_port_feature_set_request(rh_t *instance,
+    uint16_t feature, uint16_t port);
+
+static int process_port_feature_clear_request(rh_t *instance,
+    uint16_t feature, uint16_t port);
+
+static int process_address_set_request(rh_t *instance,
+    uint16_t address);
+
+static int process_request_with_output(rh_t *instance,
+    usb_transfer_batch_t *request);
+
+static int process_request_with_input(rh_t *instance,
+    usb_transfer_batch_t *request);
+
+static int process_request_without_data(rh_t *instance,
+    usb_transfer_batch_t *request);
+
+static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
+
+static int process_interrupt_mask_in_instance(rh_t *instance, usb_transfer_batch_t * request);
+
+static bool is_zeros(void * buffer, size_t size);
+
+/** Root hub initialization
+ * @return Error code.
+ */
+int rh_init(rh_t *instance, ohci_regs_t *regs) {
+	assert(instance);
+	instance->registers = regs;
+	instance->port_count =
+	    (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;
+	int opResult = rh_init_descriptors(instance);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	// set port power mode to no-power-switching
+	instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
+	instance->unfinished_interrupt_transfer = NULL;
+	instance->interrupt_mask_size = (instance->port_count + 8) / 8;
+	instance->interrupt_buffer = malloc(instance->interrupt_mask_size);
+	if (!instance->interrupt_buffer)
+		return ENOMEM;
+
+	usb_log_info("OHCI root hub with %zu ports initialized.\n",
+	    instance->port_count);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process root hub request
+ *
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+int rh_request(rh_t *instance, usb_transfer_batch_t *request) {
+	assert(instance);
+	assert(request);
+	int opResult;
+	if (request->ep->transfer_type == USB_TRANSFER_CONTROL) {
+		usb_log_info("Root hub got CONTROL packet\n");
+		opResult = process_ctrl_request(instance, request);
+		usb_transfer_batch_finish_error(request, opResult);
+	} else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) {
+		usb_log_info("Root hub got INTERRUPT packet\n");
+		create_interrupt_mask_in_instance(instance);
+		if (is_zeros(instance->interrupt_buffer,
+		    instance->interrupt_mask_size)) {
+			usb_log_debug("No changes..\n");
+			instance->unfinished_interrupt_transfer = request;
+			//will be finished later
+		} else {
+			usb_log_debug("Processing changes..\n");
+			process_interrupt_mask_in_instance(instance, request);
+		}
+		opResult = EOK;
+	} else {
+
+		opResult = EINVAL;
+		usb_transfer_batch_finish_error(request, opResult);
+	}
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process interrupt on a hub
+ *
+ * If there is no pending interrupt transfer, nothing happens.
+ * @param instance
+ */
+void rh_interrupt(rh_t *instance) {
+	if (!instance->unfinished_interrupt_transfer) {
+		return;
+	}
+	usb_log_debug("Finalizing interrupt transfer\n");
+	create_interrupt_mask_in_instance(instance);
+	process_interrupt_mask_in_instance(instance,
+	    instance->unfinished_interrupt_transfer);
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Create hub descriptor used in hub-driver <-> hub communication
+ *
+ * This means creating byt array from data in root hub registers. For more
+ * info see usb hub specification.
+ *
+ * @param instance root hub instance
+ * @return error code
+ */
+static int create_serialized_hub_descriptor(rh_t *instance) {
+	size_t size = 7 +
+	    ((instance->port_count + 7) / 8) * 2;
+	size_t var_size = (instance->port_count + 7) / 8;
+	uint8_t * result = (uint8_t*) malloc(size);
+	if (!result) return ENOMEM;
+
+	bzero(result, size);
+	//size
+	result[0] = size;
+	//descriptor type
+	result[1] = USB_DESCTYPE_HUB;
+	result[2] = instance->port_count;
+	uint32_t hub_desc_reg = instance->registers->rh_desc_a;
+	result[3] =
+	    ((hub_desc_reg >> 8) % 2) +
+	    (((hub_desc_reg >> 9) % 2) << 1) +
+	    (((hub_desc_reg >> 10) % 2) << 2) +
+	    (((hub_desc_reg >> 11) % 2) << 3) +
+	    (((hub_desc_reg >> 12) % 2) << 4);
+	result[4] = 0;
+	result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
+	result[6] = 50;
+
+	size_t port;
+	for (port = 1; port <= instance->port_count; ++port) {
+		uint8_t is_non_removable =
+		    instance->registers->rh_desc_b >> port % 2;
+		result[7 + port / 8] +=
+		    is_non_removable << (port % 8);
+	}
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		result[7 + var_size + i] = 255;
+	}
+	instance->hub_descriptor = result;
+	instance->descriptor_size = size;
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/** initialize hub descriptors
+ *
+ * Initialized are device and full configuration descriptor. These need to
+ * be initialized only once per hub.
+ * @instance root hub instance
+ * @return error code
+ */
+static int rh_init_descriptors(rh_t *instance) {
+	memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
+	    sizeof (ohci_rh_device_descriptor)
+	    );
+	usb_standard_configuration_descriptor_t descriptor;
+	memcpy(&descriptor, &ohci_rh_conf_descriptor,
+	    sizeof (ohci_rh_conf_descriptor));
+
+	int opResult = create_serialized_hub_descriptor(instance);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	descriptor.total_length =
+	    sizeof (usb_standard_configuration_descriptor_t) +
+	    sizeof (usb_standard_endpoint_descriptor_t) +
+	    sizeof (usb_standard_interface_descriptor_t) +
+	    instance->descriptor_size;
+
+	uint8_t * full_config_descriptor =
+	    (uint8_t*) malloc(descriptor.total_length);
+	if (!full_config_descriptor) {
+		return ENOMEM;
+	}
+	memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor),
+	    &ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor) +
+	    sizeof (ohci_rh_iface_descriptor),
+	    &ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor));
+	memcpy(full_config_descriptor + sizeof (descriptor) +
+	    sizeof (ohci_rh_iface_descriptor) +
+	    sizeof (ohci_rh_ep_descriptor),
+	    instance->hub_descriptor, instance->descriptor_size);
+
+	instance->descriptors.configuration = full_config_descriptor;
+	instance->descriptors.configuration_size = descriptor.total_length;
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * create answer to port status_request
+ *
+ * Copy content of corresponding port status register to answer buffer. The
+ * format of the port status register and port status data is the same (
+ * see OHCI root hub and USB hub documentation).
+ *
+ * @param instance root hub instance
+ * @param port port number, counted from 1
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_get_port_status_request(rh_t *instance, uint16_t port,
+    usb_transfer_batch_t * request) {
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	request->transfered_size = 4;
+	uint32_t data = instance->registers->rh_port_status[port - 1];
+	memcpy(request->data_buffer, &data, 4);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * create answer to port status_request
+ *
+ * This copies flags in hub status register into the buffer. The format of the
+ * status register and status message is the same, according to USB hub
+ * specification and OHCI root hub specification.
+ *
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_get_hub_status_request(rh_t *instance,
+    usb_transfer_batch_t * request) {
+	request->transfered_size = 4;
+	//bits, 0,1,16,17
+	uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17);
+	uint32_t data = mask & instance->registers->rh_status;
+	memcpy(request->data_buffer, &data, 4);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * create answer to status request
+ *
+ * This might be either hub status or port status request. If neither,
+ * ENOTSUP is returned.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_get_status_request(rh_t *instance,
+    usb_transfer_batch_t * request) {
+	size_t buffer_size = request->buffer_size;
+	usb_device_request_setup_packet_t * request_packet =
+	    (usb_device_request_setup_packet_t*)
+	    request->setup_buffer;
+
+	usb_hub_bm_request_type_t request_type = request_packet->request_type;
+	if (buffer_size < 4) {
+		usb_log_warning("Requested more data than buffer size\n");
+		return EINVAL;
+	}
+
+	if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
+		return process_get_hub_status_request(instance, request);
+	if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
+		return process_get_port_status_request(instance,
+	    request_packet->index,
+	    request);
+
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * create answer to status interrupt consisting of change bitmap
+ *
+ * Result contains bitmap where bit 0 indicates change on hub and
+ * bit i indicates change on i`th port (i>0). For more info see
+ * Hub and Port status bitmap specification in USB specification
+ * (chapter 11.13.4).
+ * Uses instance`s interrupt buffer to store the interrupt information.
+ * @param instance root hub instance
+ */
+static void create_interrupt_mask_in_instance(rh_t * instance) {
+	uint8_t * bitmap = (uint8_t*) (instance->interrupt_buffer);
+	uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
+	    | (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
+	bzero(bitmap, instance->interrupt_mask_size);
+	if ((instance->registers->rh_status & mask) != 0) {
+		bitmap[0] = 1;
+	}
+	size_t port;
+	mask = port_status_change_mask;
+	for (port = 1; port <= instance->port_count; ++port) {
+		if ((mask & instance->registers->rh_port_status[port - 1]) != 0) {
+
+			bitmap[(port) / 8] += 1 << (port % 8);
+		}
+	}
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * create answer to a descriptor request
+ *
+ * This might be a request for standard (configuration, device, endpoint or
+ * interface) or device specific (hub) descriptor.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_get_descriptor_request(rh_t *instance,
+    usb_transfer_batch_t *request) {
+	usb_device_request_setup_packet_t * setup_request =
+	    (usb_device_request_setup_packet_t*) request->setup_buffer;
+	size_t size;
+	const void * result_descriptor = NULL;
+	const uint16_t setup_request_value = setup_request->value_high;
+	//(setup_request->value_low << 8);
+	switch (setup_request_value) {
+		case USB_DESCTYPE_HUB:
+		{
+			usb_log_debug("USB_DESCTYPE_HUB\n");
+			result_descriptor = instance->hub_descriptor;
+			size = instance->descriptor_size;
+			break;
+		}
+		case USB_DESCTYPE_DEVICE:
+		{
+			usb_log_debug("USB_DESCTYPE_DEVICE\n");
+			result_descriptor = &ohci_rh_device_descriptor;
+			size = sizeof (ohci_rh_device_descriptor);
+			break;
+		}
+		case USB_DESCTYPE_CONFIGURATION:
+		{
+			usb_log_debug("USB_DESCTYPE_CONFIGURATION\n");
+			result_descriptor = instance->descriptors.configuration;
+			size = instance->descriptors.configuration_size;
+			break;
+		}
+		case USB_DESCTYPE_INTERFACE:
+		{
+			usb_log_debug("USB_DESCTYPE_INTERFACE\n");
+			result_descriptor = &ohci_rh_iface_descriptor;
+			size = sizeof (ohci_rh_iface_descriptor);
+			break;
+		}
+		case USB_DESCTYPE_ENDPOINT:
+		{
+			usb_log_debug("USB_DESCTYPE_ENDPOINT\n");
+			result_descriptor = &ohci_rh_ep_descriptor;
+			size = sizeof (ohci_rh_ep_descriptor);
+			break;
+		}
+		default:
+		{
+			usb_log_debug("USB_DESCTYPE_EINVAL %d \n",
+			    setup_request->value);
+			usb_log_debug("\ttype %d\n\trequest %d\n\tvalue "
+			    "%d\n\tindex %d\n\tlen %d\n ",
+			    setup_request->request_type,
+			    setup_request->request,
+			    setup_request_value,
+			    setup_request->index,
+			    setup_request->length
+			    );
+			return EINVAL;
+		}
+	}
+	if (request->buffer_size < size) {
+		size = request->buffer_size;
+	}
+	request->transfered_size = size;
+	memcpy(request->data_buffer, result_descriptor, size);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * answer to get configuration request
+ *
+ * Root hub works independently on the configuration.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_get_configuration_request(rh_t *instance,
+    usb_transfer_batch_t *request) {
+	//set and get configuration requests do not have any meaning, only dummy
+	//values are returned
+	if (request->buffer_size != 1)
+		return EINVAL;
+	request->data_buffer[0] = 1;
+	request->transfered_size = 1;
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process feature-enabling request on hub
+ *
+ * @param instance root hub instance
+ * @param feature feature selector
+ * @return error code
+ */
+static int process_hub_feature_set_request(rh_t *instance,
+    uint16_t feature) {
+	if (!((1 << feature) & hub_set_feature_valid_mask))
+		return EINVAL;
+	if (feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER)
+		feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16;
+	instance->registers->rh_status =
+	    (instance->registers->rh_status | (1 << feature))
+	    & (~hub_clear_feature_by_writing_one_mask);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process feature-disabling request on hub
+ *
+ * @param instance root hub instance
+ * @param feature feature selector
+ * @return error code
+ */
+static int process_hub_feature_clear_request(rh_t *instance,
+    uint16_t feature) {
+	if (!((1 << feature) & hub_clear_feature_valid_mask))
+		return EINVAL;
+	//is the feature cleared directly?
+	if ((1 << feature) & hub_set_feature_direct_mask) {
+		instance->registers->rh_status =
+		    (instance->registers->rh_status & (~(1 << feature)))
+		    & (~hub_clear_feature_by_writing_one_mask);
+	} else {//the feature is cleared by writing '1'
+
+		instance->registers->rh_status =
+		    (instance->registers->rh_status
+		    & (~hub_clear_feature_by_writing_one_mask))
+		    | (1 << feature);
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process feature-enabling request on hub
+ *
+ * @param instance root hub instance
+ * @param feature feature selector
+ * @param port port number, counted from 1
+ * @param enable enable or disable the specified feature
+ * @return error code
+ */
+static int process_port_feature_set_request(rh_t *instance,
+    uint16_t feature, uint16_t port) {
+	if (!((1 << feature) & port_set_feature_valid_mask))
+		return EINVAL;
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	instance->registers->rh_port_status[port - 1] =
+	    (instance->registers->rh_port_status[port - 1] | (1 << feature))
+	    & (~port_clear_feature_valid_mask);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process feature-disabling request on hub
+ *
+ * @param instance root hub instance
+ * @param feature feature selector
+ * @param port port number, counted from 1
+ * @param enable enable or disable the specified feature
+ * @return error code
+ */
+static int process_port_feature_clear_request(rh_t *instance,
+    uint16_t feature, uint16_t port) {
+	if (!((1 << feature) & port_clear_feature_valid_mask))
+		return EINVAL;
+	if (port < 1 || port > instance->port_count)
+		return EINVAL;
+	if (feature == USB_HUB_FEATURE_PORT_POWER)
+		feature = USB_HUB_FEATURE_PORT_LOW_SPEED;
+	if (feature == USB_HUB_FEATURE_PORT_SUSPEND)
+		feature = USB_HUB_FEATURE_PORT_OVER_CURRENT;
+	instance->registers->rh_port_status[port - 1] =
+	    (instance->registers->rh_port_status[port - 1]
+	    & (~port_clear_feature_valid_mask))
+	    | (1 << feature);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * register address to this device
+ *
+ * @param instance root hub instance
+ * @param address new address
+ * @return error code
+ */
+static int process_address_set_request(rh_t *instance,
+    uint16_t address) {
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process one of requests that requere output data
+ *
+ * Request can be one of USB_DEVREQ_GET_STATUS, USB_DEVREQ_GET_DESCRIPTOR or
+ * USB_DEVREQ_GET_CONFIGURATION.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_request_with_output(rh_t *instance,
+    usb_transfer_batch_t *request) {
+	usb_device_request_setup_packet_t * setup_request =
+	    (usb_device_request_setup_packet_t*) request->setup_buffer;
+	if (setup_request->request == USB_DEVREQ_GET_STATUS) {
+		usb_log_debug("USB_DEVREQ_GET_STATUS\n");
+		return process_get_status_request(instance, request);
+	}
+	if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) {
+		usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
+		return process_get_descriptor_request(instance, request);
+	}
+	if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) {
+		usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
+
+		return process_get_configuration_request(instance, request);
+	}
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process one of requests that carry input data
+ *
+ * Request can be one of USB_DEVREQ_SET_DESCRIPTOR or
+ * USB_DEVREQ_SET_CONFIGURATION.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_request_with_input(rh_t *instance,
+    usb_transfer_batch_t *request) {
+	usb_device_request_setup_packet_t * setup_request =
+	    (usb_device_request_setup_packet_t*) request->setup_buffer;
+	request->transfered_size = 0;
+	if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) {
+		return ENOTSUP;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) {
+		//set and get configuration requests do not have any meaning,
+		//only dummy values are returned
+
+		return EOK;
+	}
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process one of requests that do not request nor carry additional data
+ *
+ * Request can be one of USB_DEVREQ_CLEAR_FEATURE, USB_DEVREQ_SET_FEATURE or
+ * USB_DEVREQ_SET_ADDRESS.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_request_without_data(rh_t *instance,
+    usb_transfer_batch_t *request) {
+	usb_device_request_setup_packet_t * setup_request =
+	    (usb_device_request_setup_packet_t*) request->setup_buffer;
+	request->transfered_size = 0;
+	if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) {
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
+			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
+			return process_hub_feature_clear_request(instance,
+			    setup_request->value);
+		}
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
+			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
+			return process_port_feature_clear_request(instance,
+			    setup_request->value,
+			    setup_request->index);
+		}
+		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
+		    setup_request->request_type);
+		return EINVAL;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_FEATURE) {
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
+			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
+			return process_hub_feature_set_request(instance,
+			    setup_request->value);
+		}
+		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
+			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
+			return process_port_feature_set_request(instance,
+			    setup_request->value,
+			    setup_request->index);
+		}
+		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
+		    setup_request->request_type);
+		return EINVAL;
+	}
+	if (setup_request->request == USB_DEVREQ_SET_ADDRESS) {
+		usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
+		return process_address_set_request(instance,
+		    setup_request->value);
+	}
+	usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",
+	    setup_request->request_type);
+
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process hub control request
+ *
+ * If needed, writes answer into the request structure.
+ * Request can be one of
+ * USB_DEVREQ_GET_STATUS,
+ * USB_DEVREQ_GET_DESCRIPTOR,
+ * USB_DEVREQ_GET_CONFIGURATION,
+ * USB_DEVREQ_CLEAR_FEATURE,
+ * USB_DEVREQ_SET_FEATURE,
+ * USB_DEVREQ_SET_ADDRESS,
+ * USB_DEVREQ_SET_DESCRIPTOR or
+ * USB_DEVREQ_SET_CONFIGURATION.
+ *
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) {
+	if (!request->setup_buffer) {
+		usb_log_error("root hub received empty transaction?");
+		return EINVAL;
+	}
+	int opResult;
+	if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) {
+		usb_log_error("Setup packet too small\n");
+		return EINVAL;
+	}
+	usb_log_info("CTRL packet: %s.\n",
+	    usb_debug_str_buffer(
+	    (const uint8_t *) request->setup_buffer, 8, 8));
+	usb_device_request_setup_packet_t * setup_request =
+	    (usb_device_request_setup_packet_t*)
+	    request->setup_buffer;
+	switch (setup_request->request) {
+		case USB_DEVREQ_GET_STATUS:
+		case USB_DEVREQ_GET_DESCRIPTOR:
+		case USB_DEVREQ_GET_CONFIGURATION:
+			usb_log_debug("Processing request with output\n");
+			opResult = process_request_with_output(
+			    instance, request);
+			break;
+		case USB_DEVREQ_CLEAR_FEATURE:
+		case USB_DEVREQ_SET_FEATURE:
+		case USB_DEVREQ_SET_ADDRESS:
+			usb_log_debug("Processing request without "
+			    "additional data\n");
+			opResult = process_request_without_data(
+			    instance, request);
+			break;
+		case USB_DEVREQ_SET_DESCRIPTOR:
+		case USB_DEVREQ_SET_CONFIGURATION:
+			usb_log_debug("Processing request with "
+			    "input\n");
+			opResult = process_request_with_input(
+			    instance, request);
+
+			break;
+		default:
+			usb_log_warning("Received unsuported request: "
+			    "%d\n",
+			    setup_request->request
+			    );
+			opResult = ENOTSUP;
+	}
+	return opResult;
+}
+/*----------------------------------------------------------------------------*/
+
+/**
+ * process hanging interrupt request
+ *
+ * If an interrupt transfer has been received and there was no change,
+ * the driver stores the transfer information and waits for change to occcur.
+ * This routine is called when that happens and it finalizes the interrupt
+ * transfer.
+ *
+ * @param instance hub instance
+ * @param request batch request to be processed
+ *
+ * @return
+ */
+static int process_interrupt_mask_in_instance(rh_t *instance,
+    usb_transfer_batch_t * request) {
+	memcpy(request->data_buffer, instance->interrupt_buffer,
+	    instance->interrupt_mask_size);
+	request->transfered_size = instance->interrupt_mask_size;
+	instance->unfinished_interrupt_transfer = NULL;
+	usb_transfer_batch_finish_error(request, EOK);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * return whether the buffer is full of zeros
+ *
+ * Convenience function.
+ * @param buffer
+ * @param size
+ * @return
+ */
+static bool is_zeros(void *buffer, size_t size) {
+	if (!buffer) return true;
+	if (!size) return true;
+	size_t i;
+	for (i = 0; i < size; ++i) {
+		if (((char*) buffer)[i])
+			return false;
+	}
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/ohci/root_hub.h
===================================================================
--- uspace/drv/ohci/root_hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/root_hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_ROOT_HUB_H
+#define DRV_OHCI_ROOT_HUB_H
+
+#include <usb/usb.h>
+#include <usb/dev/driver.h>
+
+#include "ohci_regs.h"
+#include "batch.h"
+
+/**
+ * ohci root hub representation
+ */
+typedef struct rh {
+	/** pointer to ohci driver registers */
+	ohci_regs_t *registers;
+	/** usb address of the root hub */
+	usb_address_t address;
+	/** hub port count */
+	size_t port_count;
+	/** hubs descriptors */
+	usb_device_descriptors_t descriptors;
+	/** interrupt transfer waiting for an actual interrupt to occur */
+	usb_transfer_batch_t * unfinished_interrupt_transfer;
+	/** pre-allocated interrupt mask
+	 *
+	 * This is allocated when initializing instance, so that memory
+	 * allocation is not needed when processing request. Buffer is used for
+	 * interrupt bitmask.
+	 */
+	uint8_t * interrupt_buffer;
+	/** size of interrupt buffer */
+	size_t interrupt_mask_size;
+	/** instance`s descriptor*/
+	uint8_t * hub_descriptor;
+	/** size of hub descriptor */
+	size_t descriptor_size;
+
+
+} rh_t;
+
+int rh_init(rh_t *instance, ohci_regs_t *regs);
+
+int rh_request(rh_t *instance, usb_transfer_batch_t *request);
+
+void rh_interrupt(rh_t *instance);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/ohci/utils/malloc32.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/ohci/utils/malloc32.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,75 @@
+/*
+ * 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 drvusbohci
+ * @{
+ */
+/** @file
+ * @brief OHCI driver
+ */
+#ifndef DRV_OHCI_UTILS_MALLOC32_H
+#define DRV_OHCI_UTILS_MALLOC32_H
+
+#include <assert.h>
+#include <malloc.h>
+#include <errno.h>
+#include <mem.h>
+#include <as.h>
+
+/** 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)
+{
+	uintptr_t result;
+	int ret = as_get_physical_mapping(addr, &result);
+
+	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 aligned and big enough memory place, NULL on failure.
+ */
+static inline void * malloc32(size_t size)
+	{ return memalign(size, size); }
+/*----------------------------------------------------------------------------*/
+/** Physical mallocator simulator
+ *
+ * @param[in] addr Address of the place allocated by malloc32
+ */
+static inline void free32(void *addr)
+	{ if (addr) free(addr); }
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/pciintel/pci.c
===================================================================
--- uspace/drv/pciintel/pci.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/drv/pciintel/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -52,8 +52,13 @@
 #include <ipc/devman.h>
 #include <ipc/dev_iface.h>
+#include <ipc/irc.h>
+#include <ns.h>
+#include <ipc/services.h>
+#include <sysinfo.h>
 #include <ops/hw_res.h>
 #include <device/hw_res.h>
 #include <ddi.h>
 #include <libarch/ddi.h>
+#include <pci_dev_iface.h>
 
 #include "pci.h"
@@ -84,7 +89,96 @@
 static bool pciintel_enable_interrupt(ddf_fun_t *fnode)
 {
-	/* TODO */
-	
-	return false;
+	/* This is an old ugly way, copied from ne2000 driver */
+	assert(fnode);
+	pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data;
+	
+	sysarg_t apic;
+	sysarg_t i8259;
+	
+	async_sess_t *irc_sess = NULL;
+	
+	if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
+	    || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
+		irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_IRC, 0, 0);
+	}
+	
+	if (!irc_sess)
+		return false;
+	
+	size_t i = 0;
+	hw_resource_list_t *res = &dev_data->hw_resources;
+	for (; i < res->count; i++) {
+		if (res->resources[i].type == INTERRUPT) {
+			const int irq = res->resources[i].res.interrupt.irq;
+			
+			async_exch_t *exch = async_exchange_begin(irc_sess);
+			const int rc =
+			    async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
+			async_exchange_end(exch);
+			
+			if (rc != EOK) {
+				async_hangup(irc_sess);
+				return false;
+			}
+		}
+	}
+	
+	async_hangup(irc_sess);
+	return true;
+}
+
+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)
+		return EINVAL;
+	pci_conf_write_16(PCI_FUN(fun), address, data);
+	return EOK;
+}
+
+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;
 }
 
@@ -94,5 +188,17 @@
 };
 
-static ddf_dev_ops_t pci_fun_ops;
+static pci_dev_iface_t pci_dev_ops = {
+	.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 = &pci_config_space_write_32
+};
+
+static ddf_dev_ops_t pci_fun_ops = {
+	.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops,
+	.interfaces[PCI_DEV_IFACE] = &pci_dev_ops
+};
 
 static int pci_add_device(ddf_dev_t *);
@@ -288,9 +394,14 @@
 	/* Get the value of the BAR. */
 	val = pci_conf_read_32(fun, addr);
+
+#define IO_MASK  (~0x3)
+#define MEM_MASK (~0xf)
 	
 	io = (bool) (val & 1);
 	if (io) {
 		addrw64 = false;
+		mask = IO_MASK;
 	} else {
+		mask = MEM_MASK;
 		switch ((val >> 1) & 3) {
 		case 0:
@@ -308,5 +419,5 @@
 	/* Get the address mask. */
 	pci_conf_write_32(fun, addr, 0xffffffff);
-	mask = pci_conf_read_32(fun, addr);
+	mask &= pci_conf_read_32(fun, addr);
 	
 	/* Restore the original value. */
@@ -469,5 +580,5 @@
 	
 	ddf_msg(LVL_DEBUG, "pci_add_device");
-	dnode->parent_phone = -1;
+	dnode->parent_sess = NULL;
 	
 	bus = pci_bus_new();
@@ -480,10 +591,10 @@
 	dnode->driver_data = bus;
 	
-	dnode->parent_phone = devman_parent_device_connect(dnode->handle,
-	    IPC_FLAG_BLOCKING);
-	if (dnode->parent_phone < 0) {
+	dnode->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    dnode->handle, IPC_FLAG_BLOCKING);
+	if (!dnode->parent_sess) {
 		ddf_msg(LVL_ERROR, "pci_add_device failed to connect to the "
-		    "parent's driver.");
-		rc = dnode->parent_phone;
+		    "parent driver.");
+		rc = ENOENT;
 		goto fail;
 	}
@@ -491,5 +602,5 @@
 	hw_resource_list_t hw_resources;
 	
-	rc = hw_res_get_resource_list(dnode->parent_phone, &hw_resources);
+	rc = hw_res_get_resource_list(dnode->parent_sess, &hw_resources);
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "pci_add_device failed to get hw resources "
@@ -544,11 +655,14 @@
 	if (bus != NULL)
 		pci_bus_delete(bus);
-	if (dnode->parent_phone >= 0)
-		async_hangup(dnode->parent_phone);
+	
+	if (dnode->parent_sess)
+		async_hangup(dnode->parent_sess);
+	
 	if (got_res)
 		hw_res_clean_resource_list(&hw_resources);
+	
 	if (ctl != NULL)
 		ddf_fun_destroy(ctl);
-
+	
 	return rc;
 }
@@ -558,4 +672,5 @@
 	ddf_log_init(NAME, LVL_ERROR);
 	pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
+	pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
 }
 
@@ -629,5 +744,6 @@
 size_t pci_bar_mask_to_size(uint32_t mask)
 {
-	return ((mask & 0xfffffff0) ^ 0xffffffff) + 1;
+	size_t size = mask & ~(mask - 1);
+	return size;
 }
 
Index: uspace/drv/rootvirt/devices.def
===================================================================
--- uspace/drv/rootvirt/devices.def	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/drv/rootvirt/devices.def	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -21,3 +21,14 @@
 	.match_id = "virtual&test1"
 },
+{
+	.name = "test3",
+	.match_id = "virtual&test3"
+},
 #endif
+#ifdef CONFIG_RUN_VIRTUAL_USB_HC
+/* Virtual USB host controller. */
+{
+	.name = "usbhc",
+	.match_id = "usb&hc=vhc"
+},
+#endif
Index: uspace/drv/test3/Makefile
===================================================================
--- uspace/drv/test3/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/test3/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = test3
+
+SOURCES = \
+	test3.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/test3/test3.c
===================================================================
--- uspace/drv/test3/test3.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/test3/test3.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/driver.h>
+#include <ddf/log.h>
+
+#define NAME "test3"
+
+static int test3_add_device(ddf_dev_t *dev);
+
+static driver_ops_t driver_ops = {
+	.add_device = &test3_add_device
+};
+
+static driver_t test3_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+static int register_fun_and_add_to_class(ddf_dev_t *parent,
+     const char *base_name, size_t index, const char *class_name)
+{
+	ddf_fun_t *fun = NULL;
+	int rc;
+	char *fun_name = NULL;
+	
+	rc = asprintf(&fun_name, "%s%zu", base_name, index);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed to format string: %s", str_error(rc));
+		goto leave;
+	}
+	
+	fun = ddf_fun_create(parent, fun_exposed, fun_name);
+	if (fun == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating function %s", fun_name);
+		rc = ENOMEM;
+		goto leave;
+	}
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding function %s: %s", fun_name,
+		    str_error(rc));
+		goto leave;
+	}
+	
+	ddf_fun_add_to_class(fun, class_name);
+
+	ddf_msg(LVL_NOTE, "Registered exposed function `%s'.", fun_name);
+
+leave:	
+	free(fun_name);
+	
+	if ((rc != EOK) && (fun != NULL)) {
+		ddf_fun_destroy(fun);
+	}
+	
+	return rc;
+}
+
+static int test3_add_device(ddf_dev_t *dev)
+{
+	int rc = EOK;
+
+	ddf_msg(LVL_DEBUG, "add_device(name=\"%s\", handle=%d)",
+	    dev->name, (int) dev->handle);
+
+	size_t i;
+	for (i = 0; i < 20; i++) {
+		rc = register_fun_and_add_to_class(dev,
+		    "test3_", i, "test3");
+		if (rc != EOK) {
+			break;
+		}
+	}
+	
+	return rc;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS test3 virtual device driver\n");
+	ddf_log_init(NAME, LVL_ERROR);
+	return ddf_driver_main(&test3_driver);
+}
+
Index: uspace/drv/test3/test3.ma
===================================================================
--- uspace/drv/test3/test3.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/test3/test3.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1 @@
+10 virtual&test3
Index: uspace/drv/uhci_hcd/Makefile
===================================================================
--- uspace/drv/uhci_hcd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2010 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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBHOST_PREFIX)/libusbhost.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBHOST_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = uhci_hcd
+
+SOURCES = \
+	iface.c \
+	main.c \
+	transfer_list.c \
+	uhci.c \
+	hc.c \
+	root_hub.c \
+	hw_struct/transfer_descriptor.c \
+	pci.c \
+	batch.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/uhci_hcd/batch.c
===================================================================
--- uspace/drv/uhci_hcd/batch.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/batch.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,424 @@
+/*
+ * 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 driver USB transfer structure
+ */
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+
+#include "batch.h"
+#include "transfer_list.h"
+#include "hw_struct/transfer_descriptor.h"
+#include "utils/malloc32.h"
+
+#define DEFAULT_ERROR_COUNT 3
+
+/** UHCI specific data required for USB transfer */
+typedef struct uhci_transfer_batch {
+	/** Queue head
+	 * This QH is used to maintain UHCI schedule structure and the element
+	 * pointer points to the first TD of this batch.
+	 */
+	qh_t *qh;
+	/** List of TDs needed for the transfer */
+	td_t *tds;
+	/** Number of TDs used by the transfer */
+	size_t td_count;
+	/** Data buffer, must be accessible by the UHCI hw */
+	void *device_buffer;
+} uhci_transfer_batch_t;
+/*----------------------------------------------------------------------------*/
+static void batch_control(usb_transfer_batch_t *instance,
+    usb_packet_id data_stage, usb_packet_id status_stage);
+static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid);
+/*----------------------------------------------------------------------------*/
+/** Safely destructs uhci_transfer_batch_t structure
+ *
+ * @param[in] uhci_batch Instance to destroy.
+ */
+static void uhci_transfer_batch_dispose(void *uhci_batch)
+{
+	uhci_transfer_batch_t *instance = uhci_batch;
+	assert(instance);
+	free32(instance->device_buffer);
+	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Allocate memory and initialize internal data structure.
+ *
+ * @param[in] fun DDF function to pass to callback.
+ * @param[in] ep Communication target
+ * @param[in] buffer Data source/destination.
+ * @param[in] buffer_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 transfer completion
+ * @param[in] func_out function to call on outbound transfer completion
+ * @param[in] arg additional parameter to func_in or func_out
+ * @return Valid pointer if all structures were successfully created,
+ * NULL otherwise.
+ *
+ * Determines the number of needed transfer descriptors (TDs).
+ * Prepares a transport buffer (that is accessible by the hardware).
+ * Initializes parameters needed for the transfer and callback.
+ */
+usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
+    char *buffer, size_t buffer_size,
+    const 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)
+{
+	assert(ep);
+	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 (uhci_data) { \
+			uhci_transfer_batch_dispose(uhci_data); \
+		} \
+		return NULL; \
+	} else (void)0
+
+	uhci_transfer_batch_t *uhci_data =
+	    malloc(sizeof(uhci_transfer_batch_t));
+	CHECK_NULL_DISPOSE_RETURN(uhci_data,
+	    "Failed to allocate UHCI batch.\n");
+	bzero(uhci_data, sizeof(uhci_transfer_batch_t));
+
+	uhci_data->td_count =
+	    (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
+	if (ep->transfer_type == USB_TRANSFER_CONTROL) {
+		uhci_data->td_count += 2;
+	}
+
+	assert((sizeof(td_t) % 16) == 0);
+	const size_t total_size = (sizeof(td_t) * uhci_data->td_count)
+	    + sizeof(qh_t) + setup_size + buffer_size;
+	uhci_data->device_buffer = malloc32(total_size);
+	CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,
+	    "Failed to allocate UHCI buffer.\n");
+	bzero(uhci_data->device_buffer, total_size);
+
+	uhci_data->tds = uhci_data->device_buffer;
+	uhci_data->qh =
+	    (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));
+
+	qh_init(uhci_data->qh);
+	qh_set_element_td(uhci_data->qh, uhci_data->tds);
+
+	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
+	CHECK_NULL_DISPOSE_RETURN(instance,
+	    "Failed to allocate batch instance.\n");
+	void *setup =
+	    uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)
+	    + sizeof(qh_t);
+	void *data_buffer = setup + setup_size;
+	usb_target_t target =
+	    { .address = ep->address, .endpoint = ep->endpoint };
+	usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size,
+	    setup, setup_size, func_in, func_out, arg, fun,
+	    uhci_data, uhci_transfer_batch_dispose);
+
+	memcpy(instance->setup_buffer, setup_buffer, setup_size);
+	usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
+	    instance, target.address, target.endpoint);
+	return instance;
+}
+/*----------------------------------------------------------------------------*/
+/** 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 TD
+ * is reached.
+ */
+bool batch_is_complete(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	uhci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+
+	usb_log_debug2("Batch(%p) checking %zu transfer(s) for completion.\n",
+	    instance, data->td_count);
+	instance->transfered_size = 0;
+	size_t i = 0;
+	for (;i < data->td_count; ++i) {
+		if (td_is_active(&data->tds[i])) {
+			return false;
+		}
+
+		instance->error = td_status(&data->tds[i]);
+		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%zu):%"
+			    PRIx32 ".\n", instance, i, data->tds[i].status);
+			td_print_status(&data->tds[i]);
+
+			assert(instance->ep != NULL);
+			endpoint_toggle_set(instance->ep,
+			    td_toggle(&data->tds[i]));
+			if (i > 0)
+				goto substract_ret;
+			return true;
+		}
+
+		instance->transfered_size += td_act_size(&data->tds[i]);
+		if (td_is_short(&data->tds[i]))
+			goto substract_ret;
+	}
+substract_ret:
+	instance->transfered_size -= instance->setup_size;
+	return true;
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control write transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control function with pids OUT and IN.
+ */
+void batch_control_write(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	batch_control(instance, USB_PID_OUT, USB_PID_IN);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepares control read transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Uses generic control with pids IN and OUT.
+ */
+void batch_control_read(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	batch_control(instance, USB_PID_IN, USB_PID_OUT);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_IN.
+ */
+void batch_interrupt_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	batch_data(instance, USB_PID_IN);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare interrupt out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_OUT.
+ */
+void batch_interrupt_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	batch_data(instance, USB_PID_OUT);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk in transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_IN.
+ */
+void batch_bulk_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	batch_data(instance, USB_PID_IN);
+	instance->next_step = usb_transfer_batch_call_in_and_dispose;
+	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare bulk out transfer.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ * Data transfer with PID_OUT.
+ */
+void batch_bulk_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	/* We are data out, we are supposed to provide data */
+	memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
+	batch_data(instance, USB_PID_OUT);
+	instance->next_step = usb_transfer_batch_call_out_and_dispose;
+	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic data transfer
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] pid Pid to use for data transactions.
+ *
+ * Transactions with alternating toggle bit and supplied pid value.
+ * The last transfer is marked with IOC flag.
+ */
+void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid)
+{
+	assert(instance);
+	uhci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+
+	const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
+	int toggle = endpoint_toggle_get(instance->ep);
+	assert(toggle == 0 || toggle == 1);
+
+	size_t td = 0;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		const size_t packet_size =
+		    (instance->ep->max_packet_size > remain_size) ?
+		    remain_size : instance->ep->max_packet_size;
+
+		td_t *next_td = (td + 1 < data->td_count)
+		    ? &data->tds[td + 1] : NULL;
+
+
+		usb_target_t target =
+		    { instance->ep->address, instance->ep->endpoint };
+
+		assert(td < data->td_count);
+		td_init(
+		    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, target, pid, buffer, next_td);
+
+		++td;
+		toggle = 1 - toggle;
+		buffer += packet_size;
+		assert(packet_size <= remain_size);
+		remain_size -= packet_size;
+	}
+	td_set_ioc(&data->tds[td - 1]);
+	endpoint_toggle_set(instance->ep, toggle);
+}
+/*----------------------------------------------------------------------------*/
+/** Prepare generic control transfer
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data_stage Pid to use for data tds.
+ * @param[in] status_stage Pid to use for data tds.
+ *
+ * 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 transfer is marked with IOC.
+ */
+void batch_control(usb_transfer_batch_t *instance,
+   usb_packet_id data_stage, usb_packet_id status_stage)
+{
+	assert(instance);
+	uhci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	assert(data->td_count >= 2);
+
+	const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
+	const usb_target_t target =
+	    { instance->ep->address, instance->ep->endpoint };
+
+	/* setup stage */
+	td_init(
+	    data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false,
+	    low_speed, target, USB_PID_SETUP, instance->setup_buffer,
+	    &data->tds[1]);
+
+	/* data stage */
+	size_t td = 1;
+	unsigned toggle = 1;
+	size_t remain_size = instance->buffer_size;
+	char *buffer = instance->data_buffer;
+	while (remain_size > 0) {
+		const size_t packet_size =
+		    (instance->ep->max_packet_size > remain_size) ?
+		    remain_size : instance->ep->max_packet_size;
+
+		td_init(
+		    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
+		    toggle, false, low_speed, target, data_stage,
+		    buffer, &data->tds[td + 1]);
+
+		++td;
+		toggle = 1 - toggle;
+		buffer += packet_size;
+		assert(td < data->td_count);
+		assert(packet_size <= remain_size);
+		remain_size -= packet_size;
+	}
+
+	/* status stage */
+	assert(td == data->td_count - 1);
+
+	td_init(
+	    &data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
+	    target, status_stage, NULL, NULL);
+	td_set_ioc(&data->tds[td]);
+
+	usb_log_debug2("Control last TD status: %x.\n",
+	    data->tds[td].status);
+}
+/*----------------------------------------------------------------------------*/
+/** Provides access to QH data structure.
+ *
+ * @param[in] instance Batch pointer to use.
+ * @return Pointer to the QH used by the batch.
+ */
+qh_t * batch_qh(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	uhci_transfer_batch_t *data = instance->private_data;
+	assert(data);
+	return data->qh;
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/batch.h
===================================================================
--- uspace/drv/uhci_hcd/batch.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/batch.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,65 @@
+/*
+ * 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 driver USB tranfer helper functions
+ */
+#ifndef DRV_UHCI_BATCH_H
+#define DRV_UHCI_BATCH_H
+
+#include <usb/host/batch.h>
+
+#include "hw_struct/queue_head.h"
+
+usb_transfer_batch_t * batch_get(
+    ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size,
+    const 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);
+
+void batch_dispose(usb_transfer_batch_t *instance);
+
+bool batch_is_complete(usb_transfer_batch_t *instance);
+
+void batch_control_write(usb_transfer_batch_t *instance);
+void batch_control_read(usb_transfer_batch_t *instance);
+
+void batch_interrupt_in(usb_transfer_batch_t *instance);
+void batch_interrupt_out(usb_transfer_batch_t *instance);
+
+void batch_bulk_in(usb_transfer_batch_t *instance);
+void batch_bulk_out(usb_transfer_batch_t *instance);
+
+qh_t * batch_qh(usb_transfer_batch_t *instance);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/hc.c
===================================================================
--- uspace/drv/uhci_hcd/hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,474 @@
+/*
+ * 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 "hc.h"
+
+#define UHCI_INTR_ALLOW_INTERRUPTS \
+    (UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET)
+#define UHCI_STATUS_USED_INTERRUPTS \
+    (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
+
+
+static int hc_init_transfer_lists(hc_t *instance);
+static int hc_init_mem_structures(hc_t *instance);
+static void hc_init_hw(hc_t *instance);
+
+static int hc_interrupt_emulator(void *arg);
+static int hc_debug_checker(void *arg);
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI hc driver structure
+ *
+ * @param[in] instance Memory place to initialize.
+ * @param[in] regs Address of I/O control registers.
+ * @param[in] reg_size Size of I/O control registers.
+ * @param[in] interrupts True if hw interrupts should be used.
+ * @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 hc_init(hc_t *instance, void *regs, size_t reg_size, bool interrupts)
+{
+	assert(reg_size >= sizeof(regs_t));
+	int ret;
+
+#define CHECK_RET_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		return ret; \
+	} else (void) 0
+
+	instance->hw_interrupts = interrupts;
+	instance->hw_failures = 0;
+
+	/* allow access to hc control registers */
+	regs_t *io;
+	ret = pio_enable(regs, reg_size, (void **)&io);
+	CHECK_RET_RETURN(ret,
+	    "Failed(%d) to gain access to registers at %p: %s.\n",
+	    ret, io, str_error(ret));
+	instance->registers = io;
+	usb_log_debug("Device registers at %p (%zuB) accessible.\n",
+	    io, reg_size);
+
+	ret = hc_init_mem_structures(instance);
+	CHECK_RET_RETURN(ret,
+	    "Failed(%d) to initialize UHCI memory structures: %s.\n",
+	    ret, str_error(ret));
+
+	hc_init_hw(instance);
+	if (!interrupts) {
+		instance->interrupt_emulator =
+		    fibril_create(hc_interrupt_emulator, instance);
+		fibril_add_ready(instance->interrupt_emulator);
+	}
+	(void)hc_debug_checker;
+
+	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 hc_init_hw(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 frame to exactly 1ms */
+	pio_write_8(&registers->sofmod, 64);
+
+	/* Set frame list 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_ALLOW_INTERRUPTS);
+	}
+
+	const 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 hc_init_mem_structures(hc_t *instance)
+{
+	assert(instance);
+#define CHECK_RET_RETURN(ret, message...) \
+	if (ret != EOK) { \
+		usb_log_error(message); \
+		return ret; \
+	} else (void) 0
+
+	/* Init interrupt code */
+	instance->interrupt_code.cmds = instance->interrupt_commands;
+	{
+		/* Read status register */
+		instance->interrupt_commands[0].cmd = CMD_PIO_READ_16;
+		instance->interrupt_commands[0].dstarg = 1;
+		instance->interrupt_commands[0].addr =
+		    &instance->registers->usbsts;
+
+		/* Test whether we are the interrupt cause */
+		instance->interrupt_commands[1].cmd = CMD_BTEST;
+		instance->interrupt_commands[1].value =
+		    UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS;
+		instance->interrupt_commands[1].srcarg = 1;
+		instance->interrupt_commands[1].dstarg = 2;
+
+		/* Predicate cleaning and accepting */
+		instance->interrupt_commands[2].cmd = CMD_PREDICATE;
+		instance->interrupt_commands[2].value = 2;
+		instance->interrupt_commands[2].srcarg = 2;
+
+		/* Write clean status register */
+		instance->interrupt_commands[3].cmd = CMD_PIO_WRITE_A_16;
+		instance->interrupt_commands[3].srcarg = 1;
+		instance->interrupt_commands[3].addr =
+		    &instance->registers->usbsts;
+
+		/* Accept interrupt */
+		instance->interrupt_commands[4].cmd = CMD_ACCEPT;
+
+		instance->interrupt_code.cmdcount = UHCI_NEEDED_IRQ_COMMANDS;
+	}
+
+	/* Init transfer lists */
+	int ret = hc_init_transfer_lists(instance);
+	CHECK_RET_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->frame_list ? EOK : ENOMEM;
+	CHECK_RET_RETURN(ret, "Failed to get frame list page.\n");
+	usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
+
+	/* Set all frames to point to the first queue head */
+	const uint32_t queue = LINK_POINTER_QH(
+	        addr_to_phys(instance->transfers_interrupt.queue_head));
+
+	unsigned i = 0;
+	for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
+		instance->frame_list[i] = queue;
+	}
+
+	/* Init device keeper */
+	usb_device_keeper_init(&instance->manager);
+	usb_log_debug("Initialized device manager.\n");
+
+	ret = usb_endpoint_manager_init(&instance->ep_manager,
+	    BANDWIDTH_AVAILABLE_USB11);
+	CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
+	    str_error(ret));
+
+	return EOK;
+#undef CHECK_RET_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 hc_init_transfer_lists(hc_t *instance)
+{
+	assert(instance);
+#define SETUP_TRANSFER_LIST(type, name) \
+do { \
+	int ret = transfer_list_init(&instance->transfers_##type, name); \
+	if (ret != EOK) { \
+		usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \
+		    ret, name, str_error(ret)); \
+		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; \
+	} \
+} while (0)
+
+	SETUP_TRANSFER_LIST(bulk_full, "BULK FULL");
+	SETUP_TRANSFER_LIST(control_full, "CONTROL FULL");
+	SETUP_TRANSFER_LIST(control_slow, "CONTROL LOW");
+	SETUP_TRANSFER_LIST(interrupt, "INTERRUPT");
+#undef SETUP_TRANSFER_LIST
+	/* Connect lists into one schedule */
+	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, This feature is not needed (adds no benefit) and is supposedly
+	 * buggy on certain hw, enable at your own risk. */
+#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 hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
+{
+	assert(instance);
+	assert(batch);
+
+	transfer_list_t *list =
+	    instance->transfers[batch->ep->speed][batch->ep->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 hc_interrupt(hc_t *instance, uint16_t status)
+{
+	assert(instance);
+	/* Lower 2 bits are transaction error and transaction complete */
+	if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
+		LIST_INITIALIZE(done);
+		transfer_list_remove_finished(
+		    &instance->transfers_interrupt, &done);
+		transfer_list_remove_finished(
+		    &instance->transfers_control_slow, &done);
+		transfer_list_remove_finished(
+		    &instance->transfers_control_full, &done);
+		transfer_list_remove_finished(
+		    &instance->transfers_bulk_full, &done);
+
+		while (!list_empty(&done)) {
+			link_t *item = done.next;
+			list_remove(item);
+			usb_transfer_batch_t *batch =
+			    list_get_instance(item, usb_transfer_batch_t, link);
+			usb_transfer_batch_finish(batch);
+		}
+	}
+	/* Resume interrupts are not supported */
+	if (status & UHCI_STATUS_RESUME) {
+		usb_log_error("Resume interrupt!\n");
+	}
+
+	/* Bits 4 and 5 indicate hc error */
+	if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
+		usb_log_error("UHCI hardware failure!.\n");
+		++instance->hw_failures;
+		transfer_list_abort_all(&instance->transfers_interrupt);
+		transfer_list_abort_all(&instance->transfers_control_slow);
+		transfer_list_abort_all(&instance->transfers_control_full);
+		transfer_list_abort_all(&instance->transfers_bulk_full);
+
+		if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
+			/* reinitialize hw, this triggers virtual disconnect*/
+			hc_init_hw(instance);
+		} else {
+			usb_log_fatal("Too many UHCI hardware failures!.\n");
+			hc_fini(instance);
+		}
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Polling function, emulates interrupts.
+ *
+ * @param[in] arg UHCI hc structure to use.
+ * @return EOK (should never return)
+ */
+int hc_interrupt_emulator(void* arg)
+{
+	usb_log_debug("Started interrupt emulator.\n");
+	hc_t *instance = arg;
+	assert(instance);
+
+	while (1) {
+		/* Read and clear status register */
+		uint16_t status = pio_read_16(&instance->registers->usbsts);
+		pio_write_16(&instance->registers->usbsts, status);
+		if (status != 0)
+			usb_log_debug2("UHCI status: %x.\n", status);
+// Qemu fails to report stalled communication
+// see https://bugs.launchpad.net/qemu/+bug/757654
+// This is a simple workaround to force queue processing every time
+	//	status |= 1;
+		hc_interrupt(instance, status);
+		async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
+	}
+	return EOK;
+}
+/*---------------------------------------------------------------------------*/
+/** Debug function, checks consistency of memory structures.
+ *
+ * @param[in] arg UHCI structure to use.
+ * @return EOK (should never return)
+ */
+int hc_debug_checker(void *arg)
+{
+	hc_t *instance = 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);
+		}
+
+		const 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",
+			    (void *) frame_list,
+			    (void *) 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",
+			    (void *) expected_pa, frnum, (void *) 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",
+			    (void *) expected_pa, (void *) 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",
+			    (void *) expected_pa, (void *) 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",
+			    (void *) expected_pa, (void *) real_pa);
+		}
+		async_usleep(UHCI_DEBUGER_TIMEOUT);
+	}
+	return EOK;
+#undef QH
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/hc.h
===================================================================
--- uspace/drv/uhci_hcd/hc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/hc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,160 @@
+/*
+ * 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_HC_H
+#define DRV_UHCI_HC_H
+
+#include <fibril.h>
+#include <ddi.h>
+
+#include <usb/host/device_keeper.h>
+#include <usb/host/usb_endpoint_manager.h>
+#include <usb/host/batch.h>
+
+#include "transfer_list.h"
+
+/** UHCI I/O registers layout */
+typedef struct uhci_regs {
+	/** Command register, controls HC behaviour */
+	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)
+
+	/** Status register, 1 means interrupt is asserted (if enabled) */
+	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)
+#define UHCI_STATUS_NM_INTERRUPTS \
+    (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)
+
+	/** Interrupt enabled registers */
+	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)
+
+	/** Register stores frame number used in SOF packet */
+	uint16_t frnum;
+
+	/** Pointer(physical) to the Frame List */
+	uint32_t flbaseadd;
+
+	/** SOF modification to match external timers */
+	uint8_t sofmod;
+} regs_t;
+
+#define UHCI_FRAME_LIST_COUNT 1024
+#define UHCI_INT_EMULATOR_TIMEOUT 10000
+#define UHCI_DEBUGER_TIMEOUT 5000000
+#define UHCI_ALLOWED_HW_FAIL 5
+#define UHCI_NEEDED_IRQ_COMMANDS 5
+
+/** Main UHCI driver structure */
+typedef struct hc {
+	/** USB bus driver, devices and addresses */
+	usb_device_keeper_t manager;
+	/** USB bus driver, endpoints */
+	usb_endpoint_manager_t ep_manager;
+
+	/** Addresses of I/O registers */
+	regs_t *registers;
+
+	/** Frame List contains 1024 link pointers */
+	link_pointer_t *frame_list;
+
+	/** List and queue of interrupt transfers */
+	transfer_list_t transfers_interrupt;
+	/** List and queue of low speed control transfers */
+	transfer_list_t transfers_control_slow;
+	/** List and queue of full speed bulk transfers */
+	transfer_list_t transfers_bulk_full;
+	/** List and queue of full speed control transfers */
+	transfer_list_t transfers_control_full;
+
+	/** Pointer table to the above lists, helps during scheduling */
+	transfer_list_t *transfers[2][4];
+
+	/** Code to be executed in kernel interrupt handler */
+	irq_code_t interrupt_code;
+
+	/** Commands that form interrupt code */
+	irq_cmd_t interrupt_commands[UHCI_NEEDED_IRQ_COMMANDS];
+
+	/** Fibril periodically checking status register*/
+	fid_t interrupt_emulator;
+
+	/** Indicator of hw interrupts availability */
+	bool hw_interrupts;
+
+	/** Number of hw failures detected. */
+	unsigned hw_failures;
+} hc_t;
+
+int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interupts);
+
+int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
+
+void hc_interrupt(hc_t *instance, uint16_t status);
+
+/** Safely dispose host controller internal structures
+ *
+ * @param[in] instance Host controller structure to use.
+ */
+static inline void hc_fini(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 hc_t * fun_to_hc(ddf_fun_t *fun)
+{
+	assert(fun);
+	return fun->driver_data;
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/hw_struct/link_pointer.h
===================================================================
--- uspace/drv/uhci_hcd/hw_struct/link_pointer.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/hw_struct/link_pointer.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,61 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI driver
+ */
+#ifndef DRV_UHCI_HW_STRUCT_LINK_POINTER_H
+#define DRV_UHCI_HW_STRUCT_LINK_POINTER_H
+
+/* UHCI link pointer, used by many data structures */
+typedef uint32_t link_pointer_t;
+
+#define LINK_POINTER_TERMINATE_FLAG (1 << 0)
+#define LINK_POINTER_QUEUE_HEAD_FLAG (1 << 1)
+#define LINK_POINTER_ZERO_BIT_FLAG (1 << 2)
+#define LINK_POINTER_VERTICAL_FLAG (1 << 2)
+#define LINK_POINTER_RESERVED_FLAG (1 << 3)
+
+#define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */
+
+#define LINK_POINTER_QH(address) \
+	((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_QUEUE_HEAD_FLAG)
+
+#define LINK_POINTER_TD(address) \
+	(address & LINK_POINTER_ADDRESS_MASK)
+
+#define LINK_POINTER_TERM \
+	((link_pointer_t)LINK_POINTER_TERMINATE_FLAG)
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/uhci_hcd/hw_struct/queue_head.h
===================================================================
--- uspace/drv/uhci_hcd/hw_struct/queue_head.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/hw_struct/queue_head.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,100 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI driver
+ */
+#ifndef DRV_UHCI_HW_STRUCT_QH_H
+#define DRV_UHCI_HW_STRUCT_QH_H
+#include <assert.h>
+
+#include "link_pointer.h"
+#include "transfer_descriptor.h"
+#include "../utils/malloc32.h"
+
+/** This structure is defined in UHCI design guide p. 31 */
+typedef struct queue_head {
+	/** Pointer to the next entity (another QH or TD */
+	volatile link_pointer_t next;
+	/** Pointer to the contained entities (execution controlled by vertical flag*/
+	volatile link_pointer_t element;
+} __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 = 0 | LINK_POINTER_TERMINATE_FLAG;
+}
+/*----------------------------------------------------------------------------*/
+/** Set queue head next pointer
+ *
+ * @param[in] instance qh_t structure to use.
+ * @param[in] next Address of the next queue.
+ *
+ * Adds proper flag. If the pointer is NULL, sets next to terminal NULL.
+ */
+static inline void qh_set_next_qh(qh_t *instance, qh_t *next)
+{
+	uint32_t pa = addr_to_phys(next);
+	if (pa) {
+		instance->next = LINK_POINTER_QH(pa);
+	} else {
+		instance->next = LINK_POINTER_TERM;
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Set queue head element pointer
+ *
+ * @param[in] instance qh_t structure to use.
+ * @param[in] td Transfer descriptor to set as the first element.
+ *
+ * Adds proper flag. If the pointer is NULL, sets element to terminal NULL.
+ */
+static inline void qh_set_element_td(qh_t *instance, td_t *td)
+{
+	uint32_t pa = addr_to_phys(td);
+	if (pa) {
+		instance->element = LINK_POINTER_TD(pa);
+	} else {
+		instance->element = LINK_POINTER_TERM;
+	}
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/uhci_hcd/hw_struct/transfer_descriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/hw_struct/transfer_descriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,176 @@
+/*
+ * 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 driver
+ */
+#include <errno.h>
+#include <usb/debug.h>
+
+#include "transfer_descriptor.h"
+#include "../utils/malloc32.h"
+
+/** 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));
+
+	const uint32_t next_pa = addr_to_phys(next);
+	assert((next_pa & LINK_POINTER_ADDRESS_MASK) == next_pa);
+
+	instance->next = 0
+	    | LINK_POINTER_VERTICAL_FLAG
+	    | (next_pa ? next_pa : LINK_POINTER_TERMINATE_FLAG);
+
+	instance->status = 0
+	    | ((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;
+
+	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);
+
+	instance->buffer_ptr = addr_to_phys(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));
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
+
+	/* This is hc internal error it should never be reported. */
+	if ((instance->status & TD_STATUS_ERROR_BIT_STUFF) != 0)
+		return EAGAIN;
+
+	/* CRC or timeout error, like device not present or bad data,
+	 * it won't be reported unless err count reached zero */
+	if ((instance->status & TD_STATUS_ERROR_CRC) != 0)
+		return EBADCHECKSUM;
+
+	/* HC does not end transactions on these, it should never be reported */
+	if ((instance->status & TD_STATUS_ERROR_NAK) != 0)
+		return EAGAIN;
+
+	/* Buffer overrun or underrun */
+	if ((instance->status & TD_STATUS_ERROR_BUFFER) != 0)
+		return ERANGE;
+
+	/* Device babble is something serious */
+	if ((instance->status & TD_STATUS_ERROR_BABBLE) != 0)
+		return EIO;
+
+	/* Stall might represent err count reaching zero or stall response from
+	 * the device. If err count reached zero, one of the above is reported*/
+	if ((instance->status & TD_STATUS_ERROR_STALLED) != 0)
+		return ESTALL;
+
+	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(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu.\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," : "",
+	    td_act_size(instance)
+	);
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/uhci_hcd/hw_struct/transfer_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/hw_struct/transfer_descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,166 @@
+/*
+ * 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 driver
+ */
+#ifndef DRV_UHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H
+#define DRV_UHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H
+
+#include <mem.h>
+#include <usb/usb.h>
+
+#include "link_pointer.h"
+
+/** Transfer Descriptor, defined in UHCI design guide p. 26 */
+typedef struct transfer_descriptor {
+	/** Pointer to the next entity (TD or QH) */
+	link_pointer_t next;
+
+	/** Status doubleword */
+	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_LOW_SPEED_FLAG   (1 << 26)
+#define TD_STATUS_ISOCHRONOUS_FLAG (1 << 25)
+#define TD_STATUS_IOC_FLAG         (1 << 24)
+
+#define TD_STATUS_ERROR_ACTIVE    (1 << 23)
+#define TD_STATUS_ERROR_STALLED   (1 << 22)
+#define TD_STATUS_ERROR_BUFFER    (1 << 21)
+#define TD_STATUS_ERROR_BABBLE    (1 << 20)
+#define TD_STATUS_ERROR_NAK       (1 << 19)
+#define TD_STATUS_ERROR_CRC       (1 << 18)
+#define TD_STATUS_ERROR_BIT_STUFF (1 << 17)
+#define TD_STATUS_ERROR_RESERVED  (1 << 16)
+#define TD_STATUS_ERROR_POS 16
+#define TD_STATUS_ERROR_MASK 0xff
+
+#define TD_STATUS_ACTLEN_POS 0
+#define TD_STATUS_ACTLEN_MASK 0x7ff
+
+	/* double word with USB device specific info */
+	volatile uint32_t device;
+#define TD_DEVICE_MAXLEN_POS 21
+#define TD_DEVICE_MAXLEN_MASK 0x7ff
+#define TD_DEVICE_RESERVED_FLAG        (1 << 20)
+#define TD_DEVICE_DATA_TOGGLE_ONE_FLAG (1 << 19)
+#define TD_DEVICE_ENDPOINT_POS 15
+#define TD_DEVICE_ENDPOINT_MASK 0xf
+#define TD_DEVICE_ADDRESS_POS 8
+#define TD_DEVICE_ADDRESS_MASK 0x7f
+#define TD_DEVICE_PID_POS 0
+#define TD_DEVICE_PID_MASK 0xff
+
+	/** Pointer(physical) to the beginning of the transaction's buffer */
+	volatile uint32_t buffer_ptr;
+
+	/* According to UHCI design guide, there is 16 bytes of
+	 * data available here.
+	 * According to linux kernel the hardware does not care,
+	 * it just needs to be aligned. We don't use it anyway.
+	 */
+} __attribute__((packed)) td_t;
+
+
+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 td_status(td_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 received on SPD marked transfer.
+ *
+ * @param[in] instance TD structure to use.
+ * @return True if data 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_SPD_FLAG) && act_size < max_size;
+}
+/*----------------------------------------------------------------------------*/
+/** 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/iface.c
===================================================================
--- uspace/drv/uhci_hcd/iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky, 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 driver hc interface implementation
+ */
+#include <ddf/driver.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+#include <usb/host/endpoint.h>
+
+#include "iface.h"
+#include "batch.h"
+#include "hc.h"
+
+static inline int setup_batch(
+    ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
+    void *data, size_t size, void * setup_data, size_t setup_size,
+    usbhc_iface_transfer_in_callback_t in,
+    usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
+    hc_t **hc, usb_transfer_batch_t **batch)
+{
+	assert(hc);
+	assert(batch);
+	assert(fun);
+	*hc = fun_to_hc(fun);
+	assert(*hc);
+
+	size_t res_bw;
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,
+	    target.address, target.endpoint, direction, &res_bw);
+	if (ep == NULL) {
+		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
+		    target.address, target.endpoint, name);
+		return ENOENT;
+	}
+
+	usb_log_debug("%s %d:%d %zu(%zu).\n",
+	    name, target.address, target.endpoint, size, ep->max_packet_size);
+
+	const size_t bw = bandwidth_count_usb11(
+	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
+	if (res_bw < bw) {
+		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
+		    "but only %zu is reserved.\n",
+		    target.address, target.endpoint, name, bw, res_bw);
+		return ENOSPC;
+	}
+
+	*batch = batch_get(
+	        fun, ep, data, size, setup_data, setup_size, in, out, arg);
+	if (!*batch)
+		return ENOMEM;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	assert(address);
+
+	usb_log_debug("Address request with speed %d.\n", speed);
+	*address = device_keeper_get_free_address(&hc->manager, speed);
+	usb_log_debug("Address request with result: %d.\n", *address);
+	if (*address <= 0)
+		return *address;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
+	usb_device_keeper_bind(&hc->manager, address, handle);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Find device handle by address interface function.
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address in question.
+ * @param[out] handle Where to store device handle if found.
+ * @return Error code.
+ */
+static int find_by_address(ddf_fun_t *fun, usb_address_t address,
+    devman_handle_t *handle)
+{
+	assert(fun);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	const bool found =
+	    usb_device_keeper_find_by_address(&hc->manager, address, handle);
+	return found ? EOK : ENOENT;
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	usb_log_debug("Address release %d.\n", address);
+	usb_device_keeper_release(&hc->manager, address);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static int register_endpoint(
+    ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed,
+    usb_endpoint_t endpoint,
+    usb_transfer_type_t transfer_type, usb_direction_t direction,
+    size_t max_packet_size, unsigned int interval)
+{
+	assert(fun);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	const size_t size = max_packet_size;
+	usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
+	if (speed >= USB_SPEED_MAX) {
+		speed = ep_speed;
+	}
+	usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
+	    address, endpoint, usb_str_transfer_type(transfer_type),
+	    usb_str_speed(speed), direction, size, max_packet_size, interval);
+
+	return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint,
+	    direction, transfer_type, speed, max_packet_size, size);
+}
+/*----------------------------------------------------------------------------*/
+static int unregister_endpoint(
+    ddf_fun_t *fun, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(fun);
+	hc_t *hc = fun_to_hc(fun);
+	assert(hc);
+	usb_log_debug("Unregister endpoint %d:%d %d.\n",
+	    address, endpoint, direction);
+	return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address,
+	    endpoint, direction);
+}
+/*----------------------------------------------------------------------------*/
+/** Interrupt out transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @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, void *data,
+    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	assert(batch);
+	assert(hc);
+	batch_interrupt_out(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Interrupt in transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @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, void *data,
+    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	assert(batch);
+	assert(hc);
+	batch_interrupt_in(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Bulk out transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @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, void *data,
+    size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
+	    NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	assert(batch);
+	assert(hc);
+	batch_bulk_out(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Bulk in transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @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, void *data,
+    size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
+	    NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	assert(batch);
+	assert(hc);
+	batch_bulk_in(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Control write transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @param[in] setup_data Data to send with SETUP transfer.
+ * @param[in] setup_size Size of data to send with SETUP transfer (always 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,
+    void *setup_data, size_t setup_size, void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, NULL, callback, arg, "Control WRITE",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	assert(batch);
+	assert(hc);
+	usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
+	batch_control_write(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Control read transaction interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] target USB device to write to.
+ * @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,
+    void *setup_data, size_t setup_size, void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	usb_transfer_batch_t *batch = NULL;
+	hc_t *hc = NULL;
+	int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
+	    setup_data, setup_size, callback, NULL, arg, "Control READ",
+	    &hc, &batch);
+	if (ret != EOK)
+		return ret;
+	assert(batch);
+	assert(hc);
+	batch_control_read(batch);
+	ret = hc_schedule(hc, batch);
+	if (ret != EOK) {
+		usb_transfer_batch_dispose(batch);
+	}
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+usbhc_iface_t hc_iface = {
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.find_by_address = find_by_address,
+	.release_address = release_address,
+
+	.register_endpoint = register_endpoint,
+	.unregister_endpoint = unregister_endpoint,
+
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+
+	.bulk_out = bulk_out,
+	.bulk_in = bulk_in,
+
+	.control_write = control_write,
+	.control_read = control_read,
+};
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/iface.h
===================================================================
--- uspace/drv/uhci_hcd/iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI driver iface
+ */
+#ifndef DRV_UHCI_IFACE_H
+#define DRV_UHCI_IFACE_H
+
+#include <usbhc_iface.h>
+
+extern usbhc_iface_t hc_iface;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/main.c
===================================================================
--- uspace/drv/uhci_hcd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky, 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 driver initialization
+ */
+#include <ddf/driver.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/ddfiface.h>
+#include <usb/debug.h>
+
+#include "uhci.h"
+
+#define NAME "uhci_hcd"
+
+static int uhci_add_device(ddf_dev_t *device);
+/*----------------------------------------------------------------------------*/
+static driver_ops_t uhci_driver_ops = {
+	.add_device = uhci_add_device,
+};
+/*----------------------------------------------------------------------------*/
+static driver_t uhci_driver = {
+	.name = NAME,
+	.driver_ops = &uhci_driver_ops
+};
+/*----------------------------------------------------------------------------*/
+/** 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)
+{
+	usb_log_debug2("uhci_add_device() called\n");
+	assert(device);
+
+	int ret = device_setup_uhci(device);
+	if (ret != EOK) {
+		usb_log_error("Failed to initialize UHCI driver: %s.\n",
+		    str_error(ret));
+		return ret;
+	}
+	usb_log_info("Controlling new UHCI device '%s'.\n", device->name);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Number 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[])
+{
+	printf(NAME ": HelenOS UHCI driver.\n");
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return ddf_driver_main(&uhci_driver);
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/pci.c
===================================================================
--- uspace/drv/uhci_hcd/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,169 @@
+/*
+ * 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 drvusbuhcihc
+ * @{
+ */
+/**
+ * @file
+ * PCI related functions needed by the UHCI driver.
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <devman.h>
+#include <device/hw_res.h>
+
+#include <usb/debug.h>
+#include <pci_dev_iface.h>
+
+#include "pci.h"
+
+/** Get I/O address of registers and IRQ for given device.
+ *
+ * @param[in] dev Device asking for the addresses.
+ * @param[out] io_reg_address Base address of the I/O range.
+ * @param[out] io_reg_size Size of the I/O range.
+ * @param[out] irq_no IRQ assigned to the device.
+ * @return Error code.
+ */
+int pci_get_my_registers(const ddf_dev_t *dev,
+    uintptr_t *io_reg_address, size_t *io_reg_size, int *irq_no)
+{
+	assert(dev);
+	assert(io_reg_address);
+	assert(io_reg_size);
+	assert(irq_no);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	hw_resource_list_t hw_resources;
+	int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (rc != EOK) {
+		async_hangup(parent_sess);
+		return rc;
+	}
+	
+	uintptr_t io_address = 0;
+	size_t io_size = 0;
+	bool io_found = false;
+	
+	int irq = 0;
+	bool irq_found = false;
+	
+	size_t i;
+	for (i = 0; i < hw_resources.count; i++) {
+		const 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: %" PRIx64" %zu.\n",
+			    res->res.io_range.address, res->res.io_range.size);
+			io_found = true;
+			break;
+		default:
+			break;
+		}
+	}
+	
+	async_hangup(parent_sess);
+	
+	if (!io_found || !irq_found)
+		return ENOENT;
+	
+	*io_reg_address = io_address;
+	*io_reg_size = io_size;
+	*irq_no = irq;
+	
+	return EOK;
+}
+
+/** Call the PCI driver with a request to enable interrupts
+ *
+ * @param[in] device Device asking for interrupts
+ * @return Error code.
+ */
+int pci_enable_interrupts(const ddf_dev_t *device)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	const bool enabled = hw_res_enable_interrupt(parent_sess);
+	async_hangup(parent_sess);
+	
+	return enabled ? EOK : EIO;
+}
+
+/** 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(const ddf_dev_t *device)
+{
+	assert(device);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	/* See UHCI design guide for these values p.45,
+	 * write all WC bits in USB legacy register */
+	const sysarg_t address = 0xc0;
+	const sysarg_t value = 0xaf00;
+	
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	
+	const int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_16, address, value);
+	
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+	
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/pci.h
===================================================================
--- uspace/drv/uhci_hcd/pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 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 drvusbuhcihc
+ * @{
+ */
+/** @file
+ * @brief UHCI driver PCI helper functions
+ */
+#ifndef DRV_UHCI_PCI_H
+#define DRV_UHCI_PCI_H
+
+#include <ddf/driver.h>
+
+int pci_get_my_registers(const ddf_dev_t *, uintptr_t *, size_t *, int *);
+int pci_enable_interrupts(const ddf_dev_t *);
+int pci_disable_legacy(const ddf_dev_t *);
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/drv/uhci_hcd/root_hub.c
===================================================================
--- uspace/drv/uhci_hcd/root_hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/root_hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,85 @@
+/*
+ * 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 "root_hub.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 rh_init(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(%d) to create root hub match string: %s.\n",
+		    ret, str_error(ret));
+		return ret;
+	}
+	assert(match_str);
+
+	ret = ddf_fun_add_match_id(fun, match_str, 100);
+	if (ret != EOK) {
+		free(match_str);
+		usb_log_error("Failed(%d) to add root hub match id: %s\n",
+		    ret, str_error(ret));
+		return ret;
+	}
+
+	/* Initialize resource structure */
+	instance->resource_list.count = 1;
+	instance->resource_list.resources = &instance->io_regs;
+
+	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/root_hub.h
===================================================================
--- uspace/drv/uhci_hcd/root_hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/root_hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,55 @@
+/*
+ * 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_RH_H
+#define DRV_UHCI_RH_H
+
+#include <ddf/driver.h>
+#include <ops/hw_res.h>
+
+/** DDF support structure for uhci_rhd driver, provides I/O resources */
+typedef struct rh {
+	/** List of resources available to the root hub. */
+	hw_resource_list_t resource_list;
+	/** The only resource in the RH resource list */
+	hw_resource_t io_regs;
+} rh_t;
+
+int rh_init(
+    rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/transfer_list.c
===================================================================
--- uspace/drv/uhci_hcd/transfer_list.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/transfer_list.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,241 @@
+/*
+ * 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 driver transfer list implementation
+ */
+#include <errno.h>
+#include <usb/debug.h>
+#include <arch/barrier.h>
+
+
+#include "transfer_list.h"
+#include "batch.h"
+
+static void transfer_list_remove_batch(
+    transfer_list_t *instance, usb_transfer_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->name = name;
+	instance->queue_head = malloc32(sizeof(qh_t));
+	if (!instance->queue_head) {
+		usb_log_error("Failed to allocate queue head.\n");
+		return ENOMEM;
+	}
+	const uint32_t queue_head_pa = addr_to_phys(instance->queue_head);
+	usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ).\n",
+	    name, instance->queue_head, queue_head_pa);
+
+	qh_init(instance->queue_head);
+	list_initialize(&instance->batch_list);
+	fibril_mutex_initialize(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Dispose transfer list structures.
+ *
+ * @param[in] instance Memory place to use.
+ *
+ * Frees memory of the internal qh_t structure.
+ */
+void transfer_list_fini(transfer_list_t *instance)
+{
+	assert(instance);
+	free32(instance->queue_head);
+}
+/** 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)
+{
+	assert(instance);
+	assert(instance->queue_head);
+	assert(next);
+	/* Set queue_head.next to point to the follower */
+	qh_set_next_qh(instance->queue_head, next->queue_head);
+}
+/*----------------------------------------------------------------------------*/
+/** Add transfer batch to the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] batch Transfer batch to submit.
+ *
+ * The batch is added to the end of the list and queue.
+ */
+void transfer_list_add_batch(
+    transfer_list_t *instance, usb_transfer_batch_t *batch)
+{
+	assert(instance);
+	assert(batch);
+	usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
+
+	fibril_mutex_lock(&instance->guard);
+
+	qh_t *last_qh = NULL;
+	/* Add to the hardware queue. */
+	if (list_empty(&instance->batch_list)) {
+		/* There is nothing scheduled */
+		last_qh = instance->queue_head;
+	} else {
+		/* There is something scheduled */
+		usb_transfer_batch_t *last =
+		    usb_transfer_batch_from_link(instance->batch_list.prev);
+		last_qh = batch_qh(last);
+	}
+	const uint32_t pa = addr_to_phys(batch_qh(batch));
+	assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
+
+	/* Make sure all data in the batch are written */
+	write_barrier();
+
+	/* keep link */
+	batch_qh(batch)->next = last_qh->next;
+	qh_set_next_qh(last_qh, batch_qh(batch));
+
+	/* Make sure the pointer is updated */
+	write_barrier();
+
+	/* Add to the driver's list */
+	list_append(&batch->link, &instance->batch_list);
+
+	usb_transfer_batch_t *first = list_get_instance(
+	    instance->batch_list.next, usb_transfer_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);
+}
+/*----------------------------------------------------------------------------*/
+/** Add completed bantches to the provided list.
+ *
+ * @param[in] instance List to use.
+ * @param[in] done list to fill
+ */
+void transfer_list_remove_finished(transfer_list_t *instance, link_t *done)
+{
+	assert(instance);
+	assert(done);
+
+	fibril_mutex_lock(&instance->guard);
+	link_t *current = instance->batch_list.next;
+	while (current != &instance->batch_list) {
+		link_t * const next = current->next;
+		usb_transfer_batch_t *batch =
+		    usb_transfer_batch_from_link(current);
+
+		if (batch_is_complete(batch)) {
+			/* Save for processing */
+			transfer_list_remove_batch(instance, batch);
+			list_append(current, done);
+		}
+		current = next;
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Walk the list and finish all batches with EINTR.
+ *
+ * @param[in] instance List to use.
+ */
+void transfer_list_abort_all(transfer_list_t *instance)
+{
+	fibril_mutex_lock(&instance->guard);
+	while (!list_empty(&instance->batch_list)) {
+		link_t * const current = instance->batch_list.next;
+		usb_transfer_batch_t *batch =
+		    usb_transfer_batch_from_link(current);
+		transfer_list_remove_batch(instance, batch);
+		usb_transfer_batch_finish_error(batch, EINTR);
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Remove a transfer batch from the list and queue.
+ *
+ * @param[in] instance List to use.
+ * @param[in] batch Transfer batch to remove.
+ *
+ * Does not lock the transfer list, caller is responsible for that.
+ */
+void transfer_list_remove_batch(
+    transfer_list_t *instance, usb_transfer_batch_t *batch)
+{
+	assert(instance);
+	assert(instance->queue_head);
+	assert(batch);
+	assert(batch_qh(batch));
+	assert(fibril_mutex_is_locked(&instance->guard));
+
+	usb_log_debug2(
+	    "Queue %s: removing batch(%p).\n", instance->name, batch);
+
+	const char *qpos = NULL;
+	qh_t *prev_qh = NULL;
+	/* Remove from the hardware queue */
+	if (instance->batch_list.next == &batch->link) {
+		/* I'm the first one here */
+		prev_qh = instance->queue_head;
+		qpos = "FIRST";
+	} else {
+		/* The thing before me is a batch too */
+		usb_transfer_batch_t *prev =
+		    usb_transfer_batch_from_link(batch->link.prev);
+		prev_qh = batch_qh(prev);
+		qpos = "NOT FIRST";
+	}
+	assert((prev_qh->next & LINK_POINTER_ADDRESS_MASK)
+	    == addr_to_phys(batch_qh(batch)));
+	prev_qh->next = batch_qh(batch)->next;
+
+	/* Make sure the pointer is updated */
+	write_barrier();
+
+	/* Remove from the batch list */
+	list_remove(&batch->link);
+	usb_log_debug("Batch(%p) removed (%s) from %s, next: %x.\n",
+	    batch, qpos, instance->name, batch_qh(batch)->next);
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/transfer_list.h
===================================================================
--- uspace/drv/uhci_hcd/transfer_list.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/transfer_list.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,66 @@
+/*
+ * 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 driver transfer list structure
+ */
+#ifndef DRV_UHCI_TRANSFER_LIST_H
+#define DRV_UHCI_TRANSFER_LIST_H
+
+#include <fibril_synch.h>
+#include <usb/host/batch.h>
+
+#include "hw_struct/queue_head.h"
+
+/** Structure maintaining both hw queue and software list
+ * of currently executed transfers
+ */
+typedef struct transfer_list {
+	/** Guard against multiple add/remove races */
+	fibril_mutex_t guard;
+	/** UHCI hw structure represeting this queue */
+	qh_t *queue_head;
+	/** Assigned name, for nicer debug output */
+	const char *name;
+	/** List of all batches in this list */
+	link_t batch_list;
+} transfer_list_t;
+
+void transfer_list_fini(transfer_list_t *instance);
+int transfer_list_init(transfer_list_t *instance, const char *name);
+void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);
+void transfer_list_add_batch(
+    transfer_list_t *instance, usb_transfer_batch_t *batch);
+void transfer_list_remove_finished(transfer_list_t *instance, link_t *done);
+void transfer_list_abort_all(transfer_list_t *instance);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/uhci.c
===================================================================
--- uspace/drv/uhci_hcd/uhci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/uhci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,286 @@
+/*
+ * 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 <errno.h>
+#include <str_error.h>
+#include <ddf/interrupt.h>
+#include <usb_iface.h>
+#include <usb/ddfiface.h>
+#include <usb/debug.h>
+
+#include "uhci.h"
+#include "iface.h"
+#include "pci.h"
+
+#include "hc.h"
+#include "root_hub.h"
+
+/** Structure representing both functions of UHCI hc, USB host controller
+ * and USB root hub */
+typedef struct uhci {
+	/** Pointer to DDF represenation of UHCI host controller */
+	ddf_fun_t *hc_fun;
+	/** Pointer to DDF represenation of UHCI root hub */
+	ddf_fun_t *rh_fun;
+
+	/** Internal driver's represenation of UHCI host controller */
+	hc_t hc;
+	/** Internal driver's represenation of UHCI root hub */
+	rh_t rh;
+} uhci_t;
+
+static inline uhci_t * dev_to_uhci(const ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(dev->driver_data);
+	return dev->driver_data;
+}
+/*----------------------------------------------------------------------------*/
+/** IRQ handling callback, forward status from call to diver structure.
+ *
+ * @param[in] dev DDF instance of the device to use.
+ * @param[in] iid (Unused).
+ * @param[in] call Pointer to the call from kernel.
+ */
+static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
+{
+	assert(dev);
+	uhci_t *uhci = dev_to_uhci(dev);
+	hc_t *hc = &uhci->hc;
+	const uint16_t status = IPC_GET_ARG1(*call);
+	assert(hc);
+	hc_interrupt(hc, status);
+}
+/*----------------------------------------------------------------------------*/
+/** Operations supported by the HC driver */
+static ddf_dev_ops_t hc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */
+};
+/*----------------------------------------------------------------------------*/
+/** Get address of the device identified by handle.
+ *
+ * @param[in] fun DDF instance of the function to use.
+ * @param[in] handle DDF handle of the driver seeking its USB address.
+ * @param[out] address Found address.
+ */
+static int usb_iface_get_address(
+    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
+{
+	assert(fun);
+	usb_device_keeper_t *manager = &dev_to_uhci(fun->dev)->hc.manager;
+	usb_address_t addr = usb_device_keeper_find(manager, handle);
+
+	if (addr < 0) {
+		return addr;
+	}
+
+	if (address != NULL) {
+		*address = addr;
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Gets handle of the respective hc.
+ *
+ * @param[in] fun DDF function of uhci device.
+ * @param[out] handle Host cotnroller handle.
+ * @return Error code.
+ */
+static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
+{
+	assert(fun);
+	ddf_fun_t *hc_fun = dev_to_uhci(fun->dev)->hc_fun;
+	assert(hc_fun);
+
+	if (handle != NULL)
+		*handle = hc_fun->handle;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** USB interface implementation used by RH */
+static usb_iface_t usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle,
+	.get_address = usb_iface_get_address
+};
+/*----------------------------------------------------------------------------*/
+/** 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);
+	rh_t *rh = fun->driver_data;
+	assert(rh);
+	return &rh->resource_list;
+}
+/*----------------------------------------------------------------------------*/
+/** Interface to provide the root hub driver with hw info */
+static hw_res_ops_t hw_res_iface = {
+	.get_resource_list = get_resource_list,
+	.enable_interrupt = NULL,
+};
+/*----------------------------------------------------------------------------*/
+/** RH function support for uhci_rhd */
+static ddf_dev_ops_t 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] device DDF instance of the device to use.
+ *
+ * This function does all the preparatory work for hc and rh drivers:
+ *  - gets device's hw resources
+ *  - disables UHCI legacy support (PCI config space)
+ *  - attempts to enable interrupts
+ *  - registers interrupt handler
+ */
+int device_setup_uhci(ddf_dev_t *device)
+{
+	assert(device);
+	uhci_t *instance = malloc(sizeof(uhci_t));
+	if (instance == NULL) {
+		usb_log_error("Failed to allocate OHCI driver.\n");
+		return ENOMEM;
+	}
+
+#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
+if (ret != EOK) { \
+	if (instance->hc_fun) \
+		instance->hc_fun->ops = NULL; \
+		instance->hc_fun->driver_data = NULL; \
+		ddf_fun_destroy(instance->hc_fun); \
+	if (instance->rh_fun) {\
+		instance->rh_fun->ops = NULL; \
+		instance->rh_fun->driver_data = NULL; \
+		ddf_fun_destroy(instance->rh_fun); \
+	} \
+	free(instance); \
+	usb_log_error(message); \
+	return ret; \
+} else (void)0
+
+	instance->rh_fun = NULL;
+	instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci_hc");
+	int ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
+	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI HC function.\n");
+	instance->hc_fun->ops = &hc_ops;
+	instance->hc_fun->driver_data = &instance->hc;
+
+	instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci_rh");
+	ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
+	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI RH function.\n");
+	instance->rh_fun->ops = &rh_ops;
+	instance->rh_fun->driver_data = &instance->rh;
+
+	uintptr_t reg_base = 0;
+	size_t reg_size = 0;
+	int irq = 0;
+
+	ret = pci_get_my_registers(device, &reg_base, &reg_size, &irq);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to get I/O addresses for %" PRIun ": %s.\n",
+	    device->handle, str_error(ret));
+	usb_log_debug("I/O regs at 0x%p (size %zu), IRQ %d.\n",
+	    (void *) reg_base, reg_size, irq);
+
+	ret = pci_disable_legacy(device);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
+
+	bool interrupts = false;
+#ifdef CONFIG_USBHC_NO_INTERRUPTS
+	usb_log_warning("Interrupts disabled in OS config, " \
+	    "falling back to polling.\n");
+#else
+	ret = pci_enable_interrupts(device);
+	if (ret != EOK) {
+		usb_log_warning("Failed to enable interrupts: %s.\n",
+		    str_error(ret));
+		usb_log_info("HW interrupts not available, " \
+		    "falling back to polling.\n");
+	} else {
+		usb_log_debug("Hw interrupts enabled.\n");
+		interrupts = true;
+	}
+#endif
+
+
+	ret = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed(%d) to init uhci_hcd: %s.\n", ret, str_error(ret));
+
+#define CHECK_RET_FINI_RETURN(ret, message...) \
+if (ret != EOK) { \
+	hc_fini(&instance->hc); \
+	CHECK_RET_DEST_FREE_RETURN(ret, message); \
+	return ret; \
+} else (void)0
+
+	/* 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: %s.\n",
+	    ret, str_error(ret));
+
+	ret = ddf_fun_bind(instance->hc_fun);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to bind UHCI device function: %s.\n",
+	    ret, str_error(ret));
+
+	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed to add UHCI to HC class: %s.\n", str_error(ret));
+
+	ret = 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: %s.\n", ret, str_error(ret));
+
+	ret = ddf_fun_bind(instance->rh_fun);
+	CHECK_RET_FINI_RETURN(ret,
+	    "Failed(%d) to register UHCI root hub: %s.\n", ret, str_error(ret));
+
+	device->driver_data = instance;
+	return EOK;
+#undef CHECK_RET_FINI_RETURN
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/uhci.h
===================================================================
--- uspace/drv/uhci_hcd/uhci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/uhci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,43 @@
+/*
+ * 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 main structure for both host controller and root-hub.
+ */
+#ifndef DRV_UHCI_UHCI_H
+#define DRV_UHCI_UHCI_H
+#include <ddf/driver.h>
+
+int device_setup_uhci(ddf_dev_t *device);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_hcd/uhci_hcd.ma
===================================================================
--- uspace/drv/uhci_hcd/uhci_hcd.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/uhci_hcd.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,25 @@
+10 pci/ven=8086&dev=7020
+10 pci/ven=8086&dev=7112
+
+10 pci/ven=8086&dev=27c8
+10 pci/ven=8086&dev=27c9
+10 pci/ven=8086&dev=27ca
+10 pci/ven=8086&dev=27cb
+
+
+10 pci/ven=8086&dev=2830
+10 pci/ven=8086&dev=2831
+10 pci/ven=8086&dev=2832
+10 pci/ven=8086&dev=2834
+10 pci/ven=8086&dev=2835
+
+10 pci/ven=8086&dev=2934
+10 pci/ven=8086&dev=2935
+10 pci/ven=8086&dev=2936
+10 pci/ven=8086&dev=2937
+10 pci/ven=8086&dev=2938
+10 pci/ven=8086&dev=2939
+
+10 pci/ven=8086&dev=24c2
+10 pci/ven=8086&dev=24c4
+10 pci/ven=8086&dev=24c7
Index: uspace/drv/uhci_hcd/utils/malloc32.h
===================================================================
--- uspace/drv/uhci_hcd/utils/malloc32.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_hcd/utils/malloc32.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,114 @@
+/*
+ * 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_UTILS_MALLOC32_H
+#define DRV_UHCI_UTILS_MALLOC32_H
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <mem.h>
+#include <as.h>
+
+#define UHCI_STRCUTURES_ALIGNMENT 16
+#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)
+{
+	if (addr == NULL)
+		return 0;
+
+	uintptr_t result;
+	const int ret = as_get_physical_mapping(addr, &result);
+	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) {
+	/* This works only when the host has less than 4GB of memory as
+	 * physical address needs to fit into 32 bits */
+
+	/* If we need more than one page there is no guarantee that the
+	 * memory will be continuous */
+	if (size > PAGE_SIZE)
+		return NULL;
+	/* Calculate alignment to make sure the block won't cross page
+	 * boundary */
+	size_t alignment = UHCI_STRCUTURES_ALIGNMENT;
+	while (alignment < size)
+		alignment *= 2;
+	return memalign(alignment, size);
+}
+/*----------------------------------------------------------------------------*/
+/** Physical mallocator simulator
+ *
+ * @param[in] addr Address of the place allocated by malloc32
+ */
+static inline void free32(void *addr) {
+	if (!addr)
+		return;
+	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);
+	if (free_address == 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 NULL;
+	return ret;
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_rhd/Makefile
===================================================================
--- uspace/drv/uhci_rhd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = uhci_rhd
+
+SOURCES = \
+	main.c \
+	port.c \
+	root_hub.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/uhci_rhd/main.c
===================================================================
--- uspace/drv/uhci_rhd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,182 @@
+/*
+ * 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 drvusbuhcirh
+ * @{
+ */
+/** @file
+ * @brief UHCI root hub initialization routines
+ */
+
+#include <ddf/driver.h>
+#include <devman.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 "root_hub.h"
+
+#define NAME "uhci_rhd"
+
+static int hc_get_my_registers(const ddf_dev_t *dev,
+    uintptr_t *io_reg_address, size_t *io_reg_size);
+
+static int uhci_rh_add_device(ddf_dev_t *device);
+
+static driver_ops_t uhci_rh_driver_ops = {
+	.add_device = uhci_rh_add_device,
+};
+
+static driver_t uhci_rh_driver = {
+	.name = NAME,
+	.driver_ops = &uhci_rh_driver_ops
+};
+
+/** 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[])
+{
+	printf(NAME ": HelenOS UHCI root hub driver.\n");
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	return ddf_driver_main(&uhci_rh_driver);
+}
+
+/** 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)
+{
+	if (!device)
+		return EINVAL;
+
+	usb_log_debug2("uhci_rh_add_device(handle=%" PRIun ")\n",
+	    device->handle);
+
+	uintptr_t io_regs = 0;
+	size_t io_size = 0;
+	uhci_root_hub_t *rh = NULL;
+	int ret = EOK;
+
+#define CHECK_RET_FREE_RH_RETURN(ret, message...) \
+if (ret != EOK) { \
+	usb_log_error(message); \
+	if (rh) \
+		free(rh); \
+	return ret; \
+} else (void)0
+
+	ret = hc_get_my_registers(device, &io_regs, &io_size);
+	CHECK_RET_FREE_RH_RETURN(ret,
+	    "Failed to get registers from HC: %s.\n", str_error(ret));
+	usb_log_debug("I/O regs at %p (size %zuB).\n",
+	    (void *) io_regs, io_size);
+
+	rh = malloc(sizeof(uhci_root_hub_t));
+	ret = (rh == NULL) ? ENOMEM : EOK;
+	CHECK_RET_FREE_RH_RETURN(ret,
+	    "Failed to allocate rh driver instance.\n");
+
+	ret = uhci_root_hub_init(rh, (void*)io_regs, io_size, device);
+	CHECK_RET_FREE_RH_RETURN(ret,
+	    "Failed(%d) to initialize rh driver instance: %s.\n",
+	    ret, str_error(ret));
+
+	device->driver_data = rh;
+	usb_log_info("Controlling root hub '%s' (%" PRIun ").\n",
+	    device->name, device->handle);
+	return EOK;
+}
+
+/** 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(
+    const ddf_dev_t *dev, uintptr_t *io_reg_address, size_t *io_reg_size)
+{
+	assert(dev);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	hw_resource_list_t hw_resources;
+	const int ret = hw_res_get_resource_list(parent_sess, &hw_resources);
+	if (ret != EOK) {
+		async_hangup(parent_sess);
+		return ret;
+	}
+	
+	uintptr_t io_address = 0;
+	size_t io_size = 0;
+	bool io_found = false;
+	
+	size_t i = 0;
+	for (; i < hw_resources.count; i++) {
+		hw_resource_t *res = &hw_resources.resources[i];
+		if (res->type == IO_RANGE) {
+			io_address = res->res.io_range.address;
+			io_size = res->res.io_range.size;
+			io_found = true;
+		}
+	
+	}
+	async_hangup(parent_sess);
+	
+	if (!io_found)
+		return ENOENT;
+	
+	if (io_reg_address != NULL)
+		*io_reg_address = io_address;
+	
+	if (io_reg_size != NULL)
+		*io_reg_size = io_size;
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/uhci_rhd/port.c
===================================================================
--- uspace/drv/uhci_rhd/port.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/port.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,355 @@
+/*
+ * 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 drvusbuhcirh
+ * @{
+ */
+/** @file
+ * @brief UHCI root hub port routines
+ */
+#include <libarch/ddi.h>  /* pio_read and pio_write */
+#include <fibril_synch.h> /* async_usleep */
+#include <errno.h>
+#include <str_error.h>
+#include <async.h>
+
+#include <usb/usb.h>    /* usb_address_t */
+#include <usb/dev/hub.h>    /* usb_hc_new_device_wrapper */
+#include <usb/debug.h>
+
+#include "port.h"
+
+static int uhci_port_check(void *port);
+static int uhci_port_reset_enable(int portno, void *arg);
+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 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] val New register value.
+ * @return Error code. (Always EOK)
+ */
+static inline void uhci_port_write_status(uhci_port_t *port, port_status_t val)
+{
+	assert(port);
+	pio_write_16(port->address, val);
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize UHCI root hub port instance.
+ *
+ * @param[in] port Memory structure to use.
+ * @param[in] address Address of I/O register.
+ * @param[in] number Port number.
+ * @param[in] usec Polling interval.
+ * @param[in] rh Pointer to ddf instance of 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);
+	char *id_string;
+	asprintf(&id_string, "Port (%p - %u)", port, number);
+	if (id_string == NULL) {
+		return ENOMEM;
+	}
+
+	port->id_string = id_string;
+	port->address = address;
+	port->number = number;
+	port->wait_period_usec = usec;
+	port->attached_device = 0;
+	port->rh = rh;
+
+	int ret =
+	    usb_hc_connection_initialize_from_device(&port->hc_connection, rh);
+	if (ret != EOK) {
+		usb_log_error("%s: failed to initialize connection to HC.",
+		    port->id_string);
+		free(id_string);
+		return ret;
+	}
+
+	port->checker = fibril_create(uhci_port_check, port);
+	if (port->checker == 0) {
+		usb_log_error("%s: failed to create polling fibril.",
+		    port->id_string);
+		free(id_string);
+		return ENOMEM;
+	}
+
+	fibril_add_ready(port->checker);
+	usb_log_debug("%s: Started polling fibril (%" PRIun ").\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)
+{
+	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 *instance = port;
+	assert(instance);
+
+	while (1) {
+		async_usleep(instance->wait_period_usec);
+
+		/* Read register value */
+		const 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);
+
+		/* Remove any old device */
+		if (instance->attached_device) {
+			usb_log_debug2("%s: Removing device.\n",
+			    instance->id_string);
+			uhci_port_remove_device(instance);
+		}
+
+		int ret =
+		    usb_hc_connection_open(&instance->hc_connection);
+		if (ret != EOK) {
+			usb_log_error("%s: Failed to connect to HC.",
+			    instance->id_string);
+			continue;
+		}
+
+		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);
+		}
+
+		ret = usb_hc_connection_close(&instance->hc_connection);
+		if (ret != EOK) {
+			usb_log_error("%s: Failed to disconnect.",
+			    instance->id_string);
+		}
+	}
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Callback for enabling port during adding a new device.
+ *
+ * @param portno Port number (unused).
+ * @param arg Pointer to uhci_port_t of port with the new device.
+ * @return Error code.
+ *
+ * Resets and enables the ub port.
+ */
+int uhci_port_reset_enable(int portno, void *arg)
+{
+	uhci_port_t *port = arg;
+	assert(port);
+
+	usb_log_debug2("%s: new_device_enable_port.\n", port->id_string);
+
+	/*
+	 * Resets from root ports should be nominally 50ms (USB spec 7.1.7.3)
+	 */
+	{
+		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;
+		uhci_port_write_status(port, port_status);
+		async_usleep(50000);
+		port_status = uhci_port_read_status(port);
+		port_status &= ~STATUS_IN_RESET;
+		uhci_port_write_status(port, port_status);
+		while (uhci_port_read_status(port) & STATUS_IN_RESET);
+	}
+	/* PIO delay, should not be longer than 3ms as the device might
+	 * enter suspend state. */
+	udelay(10);
+	/* Enable the port. */
+	uhci_port_set_enabled(port, true);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** 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_debug("%s: Detected new device.\n", port->id_string);
+
+	int ret, count = 0;
+	usb_address_t dev_addr;
+	do {
+		ret = usb_hc_new_device_wrapper(port->rh, &port->hc_connection,
+		    speed, uhci_port_reset_enable, port->number, port,
+		    &dev_addr, &port->attached_device, NULL, NULL, NULL);
+	} while (ret != EOK && ++count < 4);
+
+	if (ret != EOK) {
+		usb_log_error("%s: Failed(%d) to add device: %s.\n",
+		    port->id_string, ret, str_error(ret));
+		uhci_port_set_enabled(port, false);
+		return ret;
+	}
+
+	usb_log_info("New device at port %u, address %d (handle %" PRIun ").\n",
+	    port->number, 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 %" PRIun ".\n",
+	    port->id_string, port->attached_device);
+	port->attached_device = 0;
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+/** 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;
+	} else {
+		port_status &= ~STATUS_ENABLED;
+	}
+
+	/* Write new value. */
+	uhci_port_write_status(port, port_status);
+
+	/* Wait for port to become enabled */
+	do {
+		port_status = uhci_port_read_status(port);
+	} while ((port_status & STATUS_CONNECTED) &&
+	    !(port_status & STATUS_ENABLED));
+
+	usb_log_debug("%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" : " ERR: NO ALWAYS ONE"
+	);
+}
+/**
+ * @}
+ */
Index: uspace/drv/uhci_rhd/port.h
===================================================================
--- uspace/drv/uhci_rhd/port.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/port.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,77 @@
+/*
+ * 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 drvusbuhcirh
+ * @{
+ */
+/** @file
+ * @brief UHCI root hub port routines
+ */
+#ifndef DRV_UHCI_PORT_H
+#define DRV_UHCI_PORT_H
+
+#include <stdint.h>
+#include <fibril.h>
+#include <ddf/driver.h>
+#include <usb/hc.h> /* usb_hc_connection_t */
+
+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)
+
+/** UHCI port structure */
+typedef struct uhci_port {
+	const char *id_string;
+	port_status_t *address;
+	unsigned number;
+	unsigned wait_period_usec;
+	usb_hc_connection_t hc_connection;
+	ddf_dev_t *rh;
+	devman_handle_t attached_device;
+	fid_t checker;
+} uhci_port_t;
+
+int uhci_port_init(
+    uhci_port_t *port, port_status_t *address, unsigned number,
+    unsigned usec, ddf_dev_t *rh);
+
+void uhci_port_fini(uhci_port_t *port);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_rhd/root_hub.c
===================================================================
--- uspace/drv/uhci_rhd/root_hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/root_hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,97 @@
+/*
+ * 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 drvusbuhcirh
+ * @{
+ */
+/** @file
+ * @brief UHCI root hub driver
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <ddi.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)
+{
+	assert(instance);
+	assert(rh);
+
+	/* Allow access to root hub port registers */
+	assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT <= size);
+	port_status_t *regs;
+	int ret = pio_enable(addr, size, (void**)&regs);
+	if (ret < 0) {
+		usb_log_error(
+		    "Failed(%d) to gain access to port registers at %p: %s.\n",
+		    ret, regs, str_error(ret));
+		return ret;
+	}
+
+	/* Initialize root hub ports */
+	unsigned i = 0;
+	for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
+		ret = uhci_port_init(
+		    &instance->ports[i], &regs[i], i, ROOT_HUB_WAIT_USEC, rh);
+		if (ret != EOK) {
+			unsigned j = 0;
+			for (;j < i; ++j)
+				uhci_port_fini(&instance->ports[j]);
+			return ret;
+		}
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Cleanup UHCI root hub instance.
+ *
+ * @param[in] instance Root hub structure to use.
+ */
+void uhci_root_hub_fini(uhci_root_hub_t* instance)
+{
+	assert(instance);
+	unsigned i = 0;
+	for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
+		uhci_port_fini(&instance->ports[i]);
+	}
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * @}
+ */
Index: uspace/drv/uhci_rhd/root_hub.h
===================================================================
--- uspace/drv/uhci_rhd/root_hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/root_hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,57 @@
+/*
+ * 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 drvusbuhcirh
+ * @{
+ */
+/** @file
+ * @brief UHCI driver
+ */
+#ifndef DRV_UHCI_ROOT_HUB_H
+#define DRV_UHCI_ROOT_HUB_H
+
+#include <ddf/driver.h>
+
+#include "port.h"
+
+#define UHCI_ROOT_HUB_PORT_COUNT 2
+#define ROOT_HUB_WAIT_USEC 250000 /* 250 miliseconds */
+
+/** UHCI root hub drvier structure */
+typedef struct root_hub {
+	/** Ports provided by the hub */
+	uhci_port_t ports[UHCI_ROOT_HUB_PORT_COUNT];
+} uhci_root_hub_t;
+
+int uhci_root_hub_init(
+    uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh);
+
+void uhci_root_hub_fini(uhci_root_hub_t *instance);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci_rhd/uhci_rhd.ma
===================================================================
--- uspace/drv/uhci_rhd/uhci_rhd.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/uhci_rhd/uhci_rhd.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1 @@
+10 usb&uhci&root-hub
Index: uspace/drv/usbflbk/Makefile
===================================================================
--- uspace/drv/usbflbk/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbflbk/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = usbflbk
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbflbk/main.c
===================================================================
--- uspace/drv/usbflbk/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbflbk/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,95 @@
+/*
+ * 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 drvusbfallback
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB fallback driver.
+ */
+#include <usb/dev/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#define NAME "usbflbk"
+
+/** Callback when new device is attached and recognized by DDF.
+ *
+ * @param dev Representation of a generic DDF device.
+ * @return Error code.
+ */
+static int usbfallback_add_device(usb_device_t *dev)
+{
+	int rc;
+	const char *fun_name = "ctl";
+
+	ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
+	    fun_name);
+	if (ctl_fun == NULL) {
+		usb_log_error("Failed to create control function.\n");
+		return ENOMEM;
+	}
+	rc = ddf_fun_bind(ctl_fun);
+	if (rc != EOK) {
+		usb_log_error("Failed to bind control function: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	usb_log_info("Pretending to control %s `%s'" \
+	    " (node `%s', handle %" PRIun ").\n",
+	    dev->interface_no < 0 ? "device" : "interface",
+	    dev->ddf_dev->name, fun_name, dev->ddf_dev->handle);
+
+	return EOK;
+}
+
+/** USB fallback driver ops. */
+static usb_driver_ops_t usbfallback_driver_ops = {
+	.add_device = usbfallback_add_device,
+};
+
+/** USB fallback driver. */
+static usb_driver_t usbfallback_driver = {
+	.name = NAME,
+	.ops = &usbfallback_driver_ops,
+	.endpoints = NULL
+};
+
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&usbfallback_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbflbk/usbflbk.ma
===================================================================
--- uspace/drv/usbflbk/usbflbk.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbflbk/usbflbk.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,2 @@
+10 usb&fallback
+10 usb&interface&fallback
Index: uspace/drv/usbhid/Makefile
===================================================================
--- uspace/drv/usbhid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2010-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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBHID_PREFIX)/libusbhid.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I. \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBUSBHID_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = usbhid
+
+STOLEN_LAYOUT_SOURCES = \
+        kbd/layout/us_qwerty.c \
+        kbd/layout/us_dvorak.c \
+        kbd/layout/cz.c
+
+SOURCES = \
+	main.c \
+	usbhid.c \
+	subdrivers.c \
+	kbd/conv.c \
+	kbd/kbddev.c \
+	kbd/kbdrepeat.c \
+	generic/hiddev.c \
+	mouse/mousedev.c \
+	multimedia/multimedia.c \
+	multimedia/keymap.c \
+	$(STOLEN_LAYOUT_SOURCES)
+
+EXTRA_CLEAN = $(STOLEN_LAYOUT_SOURCES)
+
+SRV_KBD = $(USPACE_PREFIX)/srv/hid/kbd
+
+include $(USPACE_PREFIX)/Makefile.common
+
+kbd/layout/%.c: $(SRV_KBD)/layout/%.c
+	ln -sfn ../../$< $@
Index: uspace/drv/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/usbhid/generic/hiddev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/generic/hiddev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,244 @@
+/*
+ * 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 driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+
+#include <usbhid_iface.h>
+
+#include "hiddev.h"
+#include "usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.flags = 0
+};
+
+const char *HID_GENERIC_FUN_NAME = "hid";
+const char *HID_GENERIC_CLASS_NAME = "hid";
+
+/*----------------------------------------------------------------------------*/
+
+static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun);
+
+static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer, 
+    size_t size, size_t *act_size, int *event_nr, unsigned int flags);
+
+static int usb_generic_hid_client_connected(ddf_fun_t *fun);
+
+static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun);
+
+static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc, 
+    size_t size, size_t *actual_size);
+
+/*----------------------------------------------------------------------------*/
+
+static usbhid_iface_t usb_generic_iface = {
+	.get_event = usb_generic_hid_get_event,
+	.get_event_length = usb_generic_hid_get_event_length,
+	.get_report_descriptor_length = usb_generic_get_report_descriptor_length,
+	.get_report_descriptor = usb_generic_get_report_descriptor
+};
+
+static ddf_dev_ops_t usb_generic_hid_ops = {
+	.interfaces[USBHID_DEV_IFACE] = &usb_generic_iface,
+	.open = usb_generic_hid_client_connected
+};
+
+/*----------------------------------------------------------------------------*/
+
+static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun)
+{
+	usb_log_debug2("Generic HID: Get event length (fun: %p, "
+	    "fun->driver_data: %p.\n", fun, fun->driver_data);
+	
+	if (fun == NULL || fun->driver_data == NULL) {
+		return 0;
+	}
+
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	usb_log_debug2("hid_dev: %p, Max input report size (%zu).\n",
+	    hid_dev, hid_dev->max_input_report_size);
+	
+	return hid_dev->max_input_report_size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer, 
+    size_t size, size_t *act_size, int *event_nr, unsigned int flags)
+{
+	usb_log_debug2("Generic HID: Get event.\n");
+	
+	if (fun == NULL || fun->driver_data == NULL || buffer == NULL
+	    || act_size == NULL || event_nr == NULL) {
+		usb_log_debug("No function");
+		return EINVAL;
+	}
+
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	if (hid_dev->input_report_size > size) {
+		usb_log_debug("input_report_size > size (%zu, %zu)\n", 
+		    hid_dev->input_report_size, size);
+		return EINVAL;	// TODO: other error code
+	}
+	
+	/*! @todo This should probably be somehow atomic. */
+	memcpy(buffer, hid_dev->input_report, 
+	    hid_dev->input_report_size);
+	*act_size = hid_dev->input_report_size;
+	*event_nr = usb_hid_report_number(hid_dev);
+	
+	usb_log_debug2("OK\n");
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun)
+{
+	usb_log_debug("Generic HID: Get report descriptor length.\n");
+	
+	if (fun == NULL || fun->driver_data == NULL) {
+		usb_log_debug("No function");
+		return EINVAL;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	usb_log_debug2("hid_dev->report_desc_size = %zu\n", 
+	    hid_dev->report_desc_size);
+	
+	return hid_dev->report_desc_size;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc, 
+    size_t size, size_t *actual_size)
+{
+	usb_log_debug2("Generic HID: Get report descriptor.\n");
+	
+	if (fun == NULL || fun->driver_data == NULL) {
+		usb_log_debug("No function");
+		return EINVAL;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	if (hid_dev->report_desc_size > size) {
+		return EINVAL;
+	}
+	
+	memcpy(desc, hid_dev->report_desc, hid_dev->report_desc_size);
+	*actual_size = hid_dev->report_desc_size;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_generic_hid_client_connected(ddf_fun_t *fun)
+{
+	usb_log_debug("Generic HID: Client connected.\n");
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_generic_hid_create_function(usb_hid_dev_t *hid_dev)
+{	
+	/* Create the function exposed under /dev/devices. */
+	/** @todo Generate numbers for the devices? */
+	usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME);
+	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	    HID_GENERIC_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	fun->ops = &usb_generic_hid_ops;
+	fun->driver_data = hid_dev;
+
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	usb_log_debug("HID function created. Handle: %" PRIun "\n", fun->handle);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	if (hid_dev == NULL) {
+		return EINVAL;
+	}
+	
+	return usb_generic_hid_create_function(hid_dev);
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data, 
+    uint8_t *buffer, size_t buffer_size)
+{
+	usb_log_debug2("usb_hid_polling_callback(%p, %p, %zu)\n",
+	    hid_dev, buffer, buffer_size);
+	usb_debug_str_buffer(buffer, buffer_size, 0);
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/usbhid/generic/hiddev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/generic/hiddev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,59 @@
+/*
+ * 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 driver API.
+ */
+
+#ifndef USB_HID_HIDDDEV_H_
+#define USB_HID_HIDDDEV_H_
+
+#include <usb/dev/driver.h>
+
+struct usb_hid_dev;
+
+usb_endpoint_description_t usb_hid_generic_poll_endpoint_description;
+
+const char *HID_GENERIC_FUN_NAME;
+const char *HID_GENERIC_CLASS_NAME;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_generic_hid_init(struct usb_hid_dev *hid_dev, void **data);
+
+bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev, void *data,
+    uint8_t *buffer, size_t buffer_size);
+
+#endif // USB_HID_HIDDDEV_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd.h
===================================================================
--- uspace/drv/usbhid/kbd.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,5 @@
+/*
+ * Dummy file because of shared layout sources.
+ *
+ * Do not delete.
+ */
Index: uspace/drv/usbhid/kbd/conv.c
===================================================================
--- uspace/drv/usbhid/kbd/conv.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/conv.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,194 @@
+/*
+ * 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 scancode parser.
+ */
+
+#include <io/keycode.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include "conv.h"
+
+/**
+ * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
+ * HelenOS key codes.
+ */
+static int scanmap_simple[255] = {
+
+//	[0x29] = KC_BACKTICK,
+
+//	[0x02] = KC_1,
+//	[0x03] = KC_2,
+	[0x04] = KC_A,
+	[0x05] = KC_B,
+	[0x06] = KC_C,
+	[0x07] = KC_D,
+	[0x08] = KC_E,
+	[0x09] = KC_F,
+	[0x0a] = KC_G,
+	[0x0b] = KC_H,
+	[0x0c] = KC_I,
+	[0x0d] = KC_J,
+	[0x0e] = KC_K,
+	[0x0f] = KC_L,
+	[0x10] = KC_M,
+	[0x11] = KC_N,
+	[0x12] = KC_O,
+	[0x13] = KC_P,
+	[0x14] = KC_Q,
+	[0x15] = KC_R,
+	[0x16] = KC_S,
+	[0x17] = KC_T,
+	[0x18] = KC_U,
+	[0x19] = KC_V,
+	[0x1a] = KC_W,
+	[0x1b] = KC_X,
+	[0x1c] = KC_Y,
+	[0x1d] = KC_Z,
+
+	[0x1e] = KC_1,
+	[0x1f] = KC_2,
+	[0x20] = KC_3,
+	[0x21] = KC_4,
+	[0x22] = KC_5,
+	[0x23] = KC_6,
+	[0x24] = KC_7,
+	[0x25] = KC_8,
+	[0x26] = KC_9,
+	[0x27] = KC_0,
+	
+	[0x28] = KC_ENTER,
+	[0x29] = KC_ESCAPE,
+	[0x2a] = KC_BACKSPACE,
+	[0x2b] = KC_TAB,
+	[0x2c] = KC_SPACE,
+
+	[0x2d] = KC_MINUS,  // same as DASH? (- or _)
+	[0x2e] = KC_EQUALS,
+	[0x2f] = KC_LBRACKET,
+	[0x30] = KC_RBRACKET,
+	[0x31] = KC_BACKSLASH,
+	//[0x32] = KC_,	// TODO: HASH??? maybe same as 0x31 - backslash
+	[0x32] = KC_BACKSLASH,
+	[0x33] = KC_SEMICOLON,
+	[0x34] = KC_QUOTE,  // same as APOSTROPHE? (')
+	[0x35] = KC_BACKTICK,  // same as GRAVE ACCENT?? (`)
+	[0x36] = KC_COMMA,
+	[0x37] = KC_PERIOD,
+	[0x38] = KC_SLASH,
+
+	[0x39] = KC_CAPS_LOCK,
+	
+	[0x3a] = KC_F1,
+	[0x3b] = KC_F2,
+	[0x3c] = KC_F3,
+	[0x3d] = KC_F4,
+	[0x3e] = KC_F5,
+	[0x3f] = KC_F6,
+	[0x40] = KC_F7,
+	[0x41] = KC_F8,
+	[0x42] = KC_F9,
+	[0x43] = KC_F10,
+	[0x44] = KC_F11,
+	[0x45] = KC_F12,
+	
+	[0x46] = KC_PRTSCR,
+	[0x47] = KC_SCROLL_LOCK,
+	[0x48] = KC_PAUSE,
+	[0x49] = KC_INSERT,
+	[0x4a] = KC_HOME,
+	[0x4b] = KC_PAGE_UP,
+	[0x4c] = KC_DELETE,
+	[0x4d] = KC_END,
+	[0x4e] = KC_PAGE_DOWN,
+	[0x4f] = KC_RIGHT,
+	[0x50] = KC_LEFT,
+	[0x51] = KC_DOWN,
+	[0x52] = KC_UP,
+	
+	//[0x64] = // some funny key
+	
+	[0xe0] = KC_LCTRL,
+	[0xe1] = KC_LSHIFT,
+	[0xe2] = KC_LALT,
+	//[0xe3] = KC_L	// TODO: left GUI
+	[0xe4] = KC_RCTRL,
+	[0xe5] = KC_RSHIFT,
+	[0xe6] = KC_RALT,
+	//[0xe7] = KC_R	// TODO: right GUI
+	
+	[0x53] = KC_NUM_LOCK,
+	[0x54] = KC_NSLASH,
+	[0x55] = KC_NTIMES,
+	[0x56] = KC_NMINUS,
+	[0x57] = KC_NPLUS,
+	[0x58] = KC_NENTER,
+	[0x59] = KC_N1,
+	[0x5a] = KC_N2,
+	[0x5b] = KC_N3,
+	[0x5c] = KC_N4,
+	[0x5d] = KC_N5,
+	[0x5e] = KC_N6,
+	[0x5f] = KC_N7,
+	[0x60] = KC_N8,
+	[0x61] = KC_N9,
+	[0x62] = KC_N0,
+	[0x63] = KC_NPERIOD
+	
+};
+
+/**
+ * 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)
+{
+	unsigned int key;
+	int *map = scanmap_simple;
+	size_t map_length = sizeof(scanmap_simple) / sizeof(int);
+
+	if ((scancode < 0) || ((size_t) scancode >= map_length))
+		return -1;
+
+	key = map[scancode];
+	
+	return key;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/conv.h
===================================================================
--- uspace/drv/usbhid/kbd/conv.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/conv.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * 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 scancode parser.
+ */
+
+#ifndef USB_HID_CONV_H_
+#define USB_HID_CONV_H_
+
+unsigned int usbhid_parse_scancode(int scancode);
+
+#endif /* USB_HID_CONV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/kbddev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,973 @@
+/*
+ * 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 device structure and API.
+ */
+
+#include <errno.h>
+#include <str_error.h>
+#include <stdio.h>
+
+#include <io/keycode.h>
+#include <ipc/kbd.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <fibril.h>
+#include <fibril_synch.h>
+
+#include <usb/usb.h>
+#include <usb/dev/dp.h>
+#include <usb/dev/request.h>
+#include <usb/hid/hid.h>
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <usb/hid/hidparser.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/usages/core.h>
+#include <usb/hid/request.h>
+#include <usb/hid/hidreport.h>
+#include <usb/hid/usages/led.h>
+
+#include <usb/dev/driver.h>
+
+#include "kbddev.h"
+
+#include "layout.h"
+#include "conv.h"
+#include "kbdrepeat.h"
+
+#include "../usbhid.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
+/*----------------------------------------------------------------------------*/
+/** Default modifiers when the keyboard is initialized. */
+static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
+
+static const uint8_t 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. */
+usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
+	.flags = 0
+};
+
+const char *HID_KBD_FUN_NAME = "keyboard";
+const char *HID_KBD_CLASS_NAME = "keyboard";
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE = 63
+};
+
+static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[
+    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE] = {
+        0x05, 0x01,  // Usage Page (Generic Desktop),
+        0x09, 0x06,  // Usage (Keyboard),
+        0xA1, 0x01,  // Collection (Application),
+        0x75, 0x01,  //   Report Size (1),
+        0x95, 0x08,  //   Report Count (8),       
+        0x05, 0x07,  //   Usage Page (Key Codes);
+        0x19, 0xE0,  //   Usage Minimum (224),
+        0x29, 0xE7,  //   Usage Maximum (231),
+        0x15, 0x00,  //   Logical Minimum (0),
+        0x25, 0x01,  //   Logical Maximum (1),
+        0x81, 0x02,  //   Input (Data, Variable, Absolute),   ; Modifier byte
+	0x95, 0x01,  //   Report Count (1),
+        0x75, 0x08,  //   Report Size (8),
+        0x81, 0x01,  //   Input (Constant),                   ; Reserved byte
+        0x95, 0x05,  //   Report Count (5),
+        0x75, 0x01,  //   Report Size (1),
+        0x05, 0x08,  //   Usage Page (Page# for LEDs),
+        0x19, 0x01,  //   Usage Minimum (1),
+        0x29, 0x05,  //   Usage Maxmimum (5),
+        0x91, 0x02,  //   Output (Data, Variable, Absolute),  ; LED report
+        0x95, 0x01,  //   Report Count (1),
+        0x75, 0x03,  //   Report Size (3),
+        0x91, 0x01,  //   Output (Constant),              ; LED report padding
+        0x95, 0x06,  //   Report Count (6),
+        0x75, 0x08,  //   Report Size (8),
+        0x15, 0x00,  //   Logical Minimum (0),
+        0x25, 0xff,  //   Logical Maximum (255),
+        0x05, 0x07,  //   Usage Page (Key Codes),
+        0x19, 0x00,  //   Usage Minimum (0),
+        0x29, 0xff,  //   Usage Maximum (255),
+        0x81, 0x00,  //   Input (Data, Array),            ; Key arrays (6 bytes)
+        0xC0           // End Collection
+
+};
+
+/*----------------------------------------------------------------------------*/
+
+typedef enum usb_kbd_flags {
+	USB_KBD_STATUS_UNINITIALIZED = 0,
+	USB_KBD_STATUS_INITIALIZED = 1,
+	USB_KBD_STATUS_TO_DESTROY = -1
+} usb_kbd_flags;
+
+/*----------------------------------------------------------------------------*/
+/* Keyboard layouts                                                           */
+/*----------------------------------------------------------------------------*/
+
+#define NUM_LAYOUTS 3
+
+/** Keyboard layout map. */
+static layout_op_t *layout[NUM_LAYOUTS] = {
+	&us_qwerty_op,
+	&us_dvorak_op,
+	&cz_op
+};
+
+static int active_layout = 0;
+
+/*----------------------------------------------------------------------------*/
+/* IPC method handler                                                         */
+/*----------------------------------------------------------------------------*/
+
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** 
+ * 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.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+	
+	usb_kbd_t *kbd_dev = (usb_kbd_t *)fun->driver_data;
+	if (kbd_dev == NULL) {
+		usb_log_debug("default_connection_handler: "
+		    "Missing parameter.\n");
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (kbd_dev->console_phone != -1) {
+			usb_log_debug("default_connection_handler: "
+			    "console phone already set\n");
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		kbd_dev->console_phone = callback;
+		
+		usb_log_debug("default_connection_handler: OK\n");
+		async_answer_0(icallid, EOK);
+		return;
+	}
+	
+	usb_log_debug("default_connection_handler: Wrong function.\n");
+	async_answer_0(icallid, EINVAL);
+}
+
+/*----------------------------------------------------------------------------*/
+/* 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 usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev) 
+{
+	if (kbd_dev->output_size == 0) {
+		return;
+	}
+
+	/* Reset the LED data. */
+	memset(kbd_dev->led_data, 0, kbd_dev->led_output_size * sizeof(int32_t));
+	usb_log_debug("Creating output report:\n");
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, kbd_dev->led_path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+	    USB_HID_REPORT_TYPE_OUTPUT);
+	
+	while (field != NULL) {		
+		
+		if ((field->usage == USB_HID_LED_NUM_LOCK) 
+		    && (kbd_dev->mods & KM_NUM_LOCK)){
+			field->value = 1;
+		}
+
+		if ((field->usage == USB_HID_LED_CAPS_LOCK) 
+		    && (kbd_dev->mods & KM_CAPS_LOCK)){
+			field->value = 1;
+		}
+
+		if ((field->usage == USB_HID_LED_SCROLL_LOCK) 
+		    && (kbd_dev->mods & KM_SCROLL_LOCK)){
+			field->value = 1;
+		}
+		
+		field = usb_hid_report_get_sibling(hid_dev->report, field,
+		    kbd_dev->led_path,  
+	    	USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+			USB_HID_REPORT_TYPE_OUTPUT);
+	}
+	
+	// TODO: what about the Report ID?
+	int rc = usb_hid_report_output_translate(hid_dev->report, 0,
+	    kbd_dev->output_buffer, kbd_dev->output_size);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error translating LED output to output report"
+		    ".\n");
+		return;
+	}
+	
+	usb_log_debug("Output report buffer: %s\n", 
+	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size, 
+	        0));
+	
+	usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT, 
+	    kbd_dev->output_buffer, kbd_dev->output_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 usb_kbd_push_ev(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, int type, 
+    unsigned int key)
+{
+	kbd_event_t ev;
+	unsigned mod_mask;
+
+	/*
+	 * 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;
+	case KC_RCTRL: mod_mask = KM_RCTRL; break;
+	case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
+	case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
+	case KC_LALT: mod_mask = KM_LALT; break;
+	case KC_RALT: mod_mask = KM_RALT; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KEY_PRESS)
+			kbd_dev->mods = kbd_dev->mods | mod_mask;
+		else
+			kbd_dev->mods = kbd_dev->mods & ~mod_mask;
+	}
+
+	switch (key) {
+	case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
+	case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
+	case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KEY_PRESS) {
+			/*
+			 * Only change lock state on transition from released
+			 * to pressed. This prevents autorepeat from messing
+			 * up the lock state.
+			 */
+			unsigned int locks_old = kbd_dev->lock_keys;
+			
+			kbd_dev->mods = 
+			    kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
+			kbd_dev->lock_keys = kbd_dev->lock_keys | mod_mask;
+
+			/* Update keyboard lock indicator lights. */
+			if (kbd_dev->lock_keys != locks_old 
+			    && hid_dev != NULL) { // ugly hack
+				usb_kbd_set_led(hid_dev, kbd_dev);
+			}
+		} else {
+			kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
+		}
+	}
+
+	if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
+		// do not send anything to the console, this is our business
+		return;
+	}
+	
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F1) {
+		active_layout = 0;
+		layout[active_layout]->reset();
+		return;
+	}
+
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F2) {
+		active_layout = 1;
+		layout[active_layout]->reset();
+		return;
+	}
+
+	if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F3) {
+		active_layout = 2;
+		layout[active_layout]->reset();
+		return;
+	}
+	
+	ev.type = type;
+	ev.key = key;
+	ev.mods = kbd_dev->mods;
+
+	ev.c = layout[active_layout]->parse_ev(&ev);
+
+	usb_log_debug2("Sending key %d to the console\n", ev.key);
+	if (kbd_dev->console_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+	
+	async_obsolete_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key, 
+	    ev.mods, ev.c);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static inline int usb_kbd_is_lock(unsigned int key_code) 
+{
+	return (key_code == KC_NUM_LOCK
+	    || key_code == KC_SCROLL_LOCK
+	    || key_code == KC_CAPS_LOCK);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 (usb_kbd_push_ev()), the auto-repeat fibril is notified about
+ * key presses and releases (see usb_kbd_repeat_start() and 
+ * usb_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 usb_kbd_push_ev(), usb_kbd_repeat_start(), usb_kbd_repeat_stop()
+ */
+static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev, 
+    usb_kbd_t *kbd_dev)
+{
+	unsigned int key;
+	unsigned int i, j;
+	
+	/*
+	 * First of all, check if the kbd have reported phantom state.
+	 *
+	 * As there is no way to distinguish keys from modifiers, we do not have
+	 * a way to check that 'all keys report Error Rollover'. We thus check
+	 * if there is at least one such error and in such case we ignore the
+	 * whole input report.
+	 */
+	i = 0;
+	while (i < kbd_dev->key_count && kbd_dev->keys[i] != ERROR_ROLLOVER) {
+		++i;
+	}
+	if (i != kbd_dev->key_count) {
+		usb_log_debug("Phantom state occured.\n");
+		// phantom state, do nothing
+		return;
+	}
+	
+	/*
+	 * 1) Key releases
+	 */
+	for (j = 0; j < kbd_dev->key_count; ++j) {
+		// try to find the old key in the new key list
+		i = 0;
+		while (i < kbd_dev->key_count
+		    && kbd_dev->keys[i] != kbd_dev->keys_old[j]) {
+			++i;
+		}
+		
+		if (i == kbd_dev->key_count) {
+			// not found, i.e. the key was released
+			key = usbhid_parse_scancode(kbd_dev->keys_old[j]);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_stop(kbd_dev, key);
+			}
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_RELEASE, key);
+			usb_log_debug2("Key released: %d\n", key);
+		} else {
+			// found, nothing happens
+		}
+	}
+	
+	/*
+	 * 1) Key presses
+	 */
+	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->key_count 
+		    && kbd_dev->keys_old[j] != kbd_dev->keys[i]) { 
+			++j;
+		}
+		
+		if (j == kbd_dev->key_count) {
+			// not found, i.e. new key pressed
+			key = usbhid_parse_scancode(kbd_dev->keys[i]);
+			usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
+			    kbd_dev->keys[i]);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_start(kbd_dev, key);
+			}
+			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, key);
+		} else {
+			// found, nothing happens
+		}
+	}
+	
+	memcpy(kbd_dev->keys_old, kbd_dev->keys, kbd_dev->key_count * 4);
+	
+	usb_log_debug2("New stored keys: ");
+	for (i = 0; i < kbd_dev->key_count; ++i) {
+		usb_log_debug2("%d ", kbd_dev->keys_old[i]);
+	}
+	usb_log_debug2("\n");
+}
+
+/*----------------------------------------------------------------------------*/
+/* 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 (usb_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 usb_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report(),
+ *     usb_hid_parse_report().
+ */
+static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev,
+                                 uint8_t *buffer, size_t actual_size)
+{
+	assert(hid_dev->report != NULL);
+	assert(hid_dev != NULL);
+	assert(kbd_dev != NULL);
+
+	usb_log_debug("Calling usb_hid_parse_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
+	
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+
+	uint8_t report_id;
+	int rc = usb_hid_parse_report(hid_dev->report, buffer, actual_size, 
+	    &report_id);
+	
+	if (rc != EOK) {
+		usb_log_warning("Error in usb_hid_parse_report():"
+		    "%s\n", str_error(rc));
+	}
+	
+	usb_hid_report_path_set_report_id (path, report_id);
+	
+	// fill in the currently pressed keys
+	
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, 
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    USB_HID_REPORT_TYPE_INPUT);
+	unsigned i = 0;
+	
+	while (field != NULL) {
+		usb_log_debug2("FIELD (%p) - VALUE(%d) USAGE(%u)\n", 
+		    field, field->value, field->usage);
+		
+		assert(i < kbd_dev->key_count);
+		
+		// save the key usage
+		if (field->value != 0) {
+			kbd_dev->keys[i] = field->usage;
+		}
+		else {
+			kbd_dev->keys[i] = 0;
+		}
+		usb_log_debug2("Saved %u. key usage %d\n", i, kbd_dev->keys[i]);
+		
+		++i;
+		field = usb_hid_report_get_sibling(hid_dev->report, field, path, 
+		    USB_HID_PATH_COMPARE_END 
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+	
+	usb_hid_report_path_free(path);
+	
+	usb_kbd_check_key_changes(hid_dev, kbd_dev);
+}
+
+/*----------------------------------------------------------------------------*/
+/* HID/KBD structure manipulation                                             */
+/*----------------------------------------------------------------------------*/
+
+static void usb_kbd_mark_unusable(usb_kbd_t *kbd_dev)
+{
+	kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Creates a new USB/HID keyboard structure.
+ *
+ * The structure returned by this function is not initialized. Use 
+ * usb_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 usb_kbd_t *usb_kbd_new(void)
+{
+	usb_kbd_t *kbd_dev = 
+	    (usb_kbd_t *)calloc(1, sizeof(usb_kbd_t));
+
+	if (kbd_dev == NULL) {
+		usb_log_fatal("No memory!\n");
+		return NULL;
+	}
+	
+	kbd_dev->console_phone = -1;
+	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
+	
+	return kbd_dev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_kbd_create_function(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
+{
+	assert(hid_dev != NULL);
+	assert(hid_dev->usb_dev != NULL);
+	assert(kbd_dev != NULL);
+	
+	/* Create the function exposed under /dev/devices. */
+	usb_log_debug("Creating DDF function %s...\n", HID_KBD_FUN_NAME);
+	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	    HID_KBD_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/*
+	 * Store the initialized HID device and HID ops
+	 * to the DDF function.
+	 */
+	fun->ops = &kbd_dev->ops;
+	fun->driver_data = kbd_dev;
+
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	usb_log_debug("%s function created. Handle: %" PRIun "\n",
+	    HID_KBD_FUN_NAME, fun->handle);
+	
+	usb_log_debug("Adding DDF function to class %s...\n", 
+	    HID_KBD_CLASS_NAME);
+	rc = ddf_fun_add_to_class(fun, HID_KBD_CLASS_NAME);
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class %s: %s.\n",
+		    HID_KBD_CLASS_NAME, str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/* API functions                                                              */
+/*----------------------------------------------------------------------------*/
+/**
+ * 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().
+ */
+int usb_kbd_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	usb_log_debug("Initializing HID/KBD structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init keyboard structure: no structure"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	/*
+	 * TODO: make more general
+	 */
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	
+	usb_hid_report_path_set_report_id(path, 0);
+	
+	kbd_dev->key_count = usb_hid_report_size(
+	    hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT); 
+	usb_hid_report_path_free(path);
+	
+	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
+	
+	kbd_dev->keys = (int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
+	
+	if (kbd_dev->keys == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	kbd_dev->keys_old = 
+		(int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
+	
+	if (kbd_dev->keys_old == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(kbd_dev->keys);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Output report
+	 */
+	kbd_dev->output_size = 0;
+	kbd_dev->output_buffer = usb_hid_report_output(hid_dev->report, 
+	    &kbd_dev->output_size, 0);
+	if (kbd_dev->output_buffer == NULL) {
+		usb_log_warning("Error creating output report buffer.\n");
+		free(kbd_dev->keys);
+		return ENOMEM;
+	}
+	
+	usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
+	
+	kbd_dev->led_path = usb_hid_report_path();
+	usb_hid_report_path_append_item(
+	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
+	
+	kbd_dev->led_output_size = usb_hid_report_size(hid_dev->report, 
+	    0, USB_HID_REPORT_TYPE_OUTPUT);
+	
+	usb_log_debug("Output report size (in items): %zu\n", 
+	    kbd_dev->led_output_size);
+	
+	kbd_dev->led_data = (int32_t *)calloc(
+	    kbd_dev->led_output_size, sizeof(int32_t));
+	
+	if (kbd_dev->led_data == NULL) {
+		usb_log_warning("Error creating buffer for LED output report."
+		    "\n");
+		free(kbd_dev->keys);
+		usb_hid_report_output_free(kbd_dev->output_buffer);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Modifiers and locks
+	 */	
+	kbd_dev->modifiers = 0;
+	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
+	kbd_dev->lock_keys = 0;
+	
+	/*
+	 * Autorepeat
+	 */	
+	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);
+		usb_hid_report_output_free(kbd_dev->output_buffer);
+		free(kbd_dev);
+		return ENOMEM;
+	}
+	
+	fibril_mutex_initialize(kbd_dev->repeat_mtx);
+	
+	// save the KBD device structure into the HID device structure
+	*data = kbd_dev;
+	
+	// set handler for incoming calls
+	kbd_dev->ops.default_handler = default_connection_handler;
+	
+	/*
+	 * Set LEDs according to initial setup.
+	 * Set Idle rate
+	 */
+	usb_kbd_set_led(hid_dev, kbd_dev);
+	
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, IDLE_RATE);
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_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);
+	
+	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
+	usb_log_debug("HID/KBD device structure initialized.\n");
+	
+	usb_log_debug("Creating KBD function...\n");
+	int rc = usb_kbd_create_function(hid_dev, kbd_dev);
+	if (rc != EOK) {
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data, 
+     uint8_t *buffer, size_t buffer_size)
+{
+	if (hid_dev == NULL || buffer == NULL || data == NULL) {
+		// do not continue polling (???)
+		return false;
+	}
+	
+	usb_kbd_t *kbd_dev = (usb_kbd_t *)data;
+	assert(kbd_dev != NULL);
+	
+	// TODO: add return value from this function
+	usb_kbd_process_data(hid_dev, kbd_dev, buffer, buffer_size);
+	
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Properly destroys the USB/HID keyboard structure.
+ *
+ * @param kbd_dev Pointer to the structure to be destroyed.
+ */
+void usb_kbd_free(usb_kbd_t **kbd_dev)
+{
+	if (kbd_dev == NULL || *kbd_dev == NULL) {
+		return;
+	}
+	
+	// hangup phone to the console
+	async_obsolete_hangup((*kbd_dev)->console_phone);
+	
+	if ((*kbd_dev)->repeat_mtx != NULL) {
+		//assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
+		while (fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)) {}
+		free((*kbd_dev)->repeat_mtx);
+	}
+	
+	// free all buffers
+	if ((*kbd_dev)->keys != NULL) {
+		free((*kbd_dev)->keys);
+	}
+	if ((*kbd_dev)->keys_old != NULL) {
+		free((*kbd_dev)->keys_old);
+	}
+	if ((*kbd_dev)->led_data != NULL) {
+		free((*kbd_dev)->led_data);
+	}
+	if ((*kbd_dev)->led_path != NULL) {
+		usb_hid_report_path_free((*kbd_dev)->led_path);
+	}
+	if ((*kbd_dev)->output_buffer != NULL) {
+		usb_hid_report_output_free((*kbd_dev)->output_buffer);
+	}
+
+	free(*kbd_dev);
+	*kbd_dev = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_kbd_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (hid_dev == NULL) {
+		return;
+	}
+	
+	if (data != NULL) {
+		usb_kbd_t *kbd_dev = (usb_kbd_t *)data;
+		if (usb_kbd_is_initialized(kbd_dev)) {
+			usb_kbd_mark_unusable(kbd_dev);
+		} else {
+			usb_kbd_free(&kbd_dev);
+		}
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	int rc = usb_hid_parse_report_descriptor(hid_dev->report, 
+	    USB_KBD_BOOT_REPORT_DESCRIPTOR, 
+	    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
+	
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/usbhid/kbd/kbddev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/kbddev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,144 @@
+/*
+ * 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 device structure and API.
+ */
+
+#ifndef USB_HID_KBDDEV_H_
+#define USB_HID_KBDDEV_H_
+
+#include <stdint.h>
+
+#include <fibril_synch.h>
+
+#include <usb/hid/hid.h>
+#include <usb/hid/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+
+#include "kbdrepeat.h"
+
+struct usb_hid_dev;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 usb_kbd_t {
+	/** Previously pressed keys (not translated to key codes). */
+	int32_t *keys_old;
+	/** Currently pressed keys (not translated to key codes). */
+	int32_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;
+	
+	/** @todo What is this actually? */
+	ddf_dev_ops_t ops;
+	
+	/** Information for auto-repeat of keys. */
+	usb_kbd_repeat_t repeat;
+	
+	/** Mutex for accessing the information about auto-repeat. */
+	fibril_mutex_t *repeat_mtx;
+	
+	uint8_t *output_buffer;
+	
+	size_t output_size;
+	
+	size_t led_output_size;
+	
+	usb_hid_report_path_t *led_path;
+	
+	int32_t *led_data;
+	
+	/** State of the structure (for checking before use). 
+	 * 
+	 * 0 - not initialized
+	 * 1 - initialized
+	 * -1 - ready for destroying
+	 */
+	int initialized;
+} usb_kbd_t;
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
+
+const char *HID_KBD_FUN_NAME;
+const char *HID_KBD_CLASS_NAME;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_init(struct usb_hid_dev *hid_dev, void **data);
+
+bool usb_kbd_polling_callback(struct usb_hid_dev *hid_dev, void *data, 
+                              uint8_t *buffer, size_t buffer_size);
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev);
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev);
+
+void usb_kbd_free(usb_kbd_t **kbd_dev);
+
+void usb_kbd_push_ev(struct usb_hid_dev *hid_dev, usb_kbd_t *kbd_dev,
+    int type, unsigned int key);
+
+void usb_kbd_deinit(struct usb_hid_dev *hid_dev, void *data);
+
+int usb_kbd_set_boot_protocol(struct usb_hid_dev *hid_dev);
+
+#endif /* USB_HID_KBDDEV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/kbdrepeat.c
===================================================================
--- uspace/drv/usbhid/kbd/kbdrepeat.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/kbdrepeat.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,186 @@
+/*
+ * 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 (
+ * usb_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 usb_kbd_repeat_loop(usb_kbd_t *kbd)
+{
+	unsigned int delay = 0;
+	
+	usb_log_debug("Starting autorepeat loop.\n");
+
+	while (true) {
+		// check if the kbd structure is usable
+		if (!usb_kbd_is_initialized(kbd)) {
+			if (usb_kbd_is_ready_to_destroy(kbd)) {
+				usb_kbd_free(&kbd);
+				assert(kbd == NULL);
+			}
+			return;
+		}
+		
+		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);
+				// ugly hack with the NULL
+				usb_kbd_push_ev(NULL, 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 usb_kbd_repeat_fibril(void *arg)
+{
+	usb_log_debug("Autorepeat fibril spawned.\n");
+	
+	if (arg == NULL) {
+		usb_log_error("No device!\n");
+		return EINVAL;
+	}
+	
+	usb_kbd_t *kbd = (usb_kbd_t *)arg;
+	
+	usb_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 usb_kbd_repeat_start(usb_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 usb_kbd_repeat_stop(usb_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/kbd/kbdrepeat.h
===================================================================
--- uspace/drv/usbhid/kbd/kbdrepeat.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/kbdrepeat.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,68 @@
+/*
+ * 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 USB_HID_KBDREPEAT_H_
+#define USB_HID_KBDREPEAT_H_
+
+struct usb_kbd_t;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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;
+} usb_kbd_repeat_t;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_kbd_repeat_fibril(void *arg);
+
+void usb_kbd_repeat_start(struct usb_kbd_t *kbd, unsigned int key);
+
+void usb_kbd_repeat_stop(struct usb_kbd_t *kbd, unsigned int key);
+
+#endif /* USB_HID_KBDREPEAT_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/kbd/layout.h
===================================================================
--- uspace/drv/usbhid/kbd/layout.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/layout.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1 @@
+../layout.h
Index: uspace/drv/usbhid/kbd/main.c
===================================================================
--- uspace/drv/usbhid/kbd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/kbd/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * 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
+ * Main routines of USB KBD driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/dev/driver.h>
+
+#include "kbddev.h"
+#include "kbdrepeat.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbkbd"
+
+/**
+ * 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 usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ *
+ * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
+ */
+static int usb_kbd_try_add_device(usb_device_t *dev)
+{
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *kbd_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
+	    "keyboard");
+	if (kbd_fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID KBD device...\n");
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		ddf_fun_destroy(kbd_fun);
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	int rc = usb_kbd_init(kbd_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID KBD device.\n");
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID KBD device structure initialized.\n");
+	
+	/*
+	 * Store the initialized keyboard device and keyboard ops
+	 * to the DDF function.
+	 */
+	kbd_fun->driver_data = kbd_dev;
+	kbd_fun->ops = &keyboard_ops;
+
+	rc = ddf_fun_bind(kbd_fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'keyboard': %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   USB_KBD_POLL_EP_NO,
+	   /* Callback when data arrives. */
+	   usb_kbd_polling_callback,
+	   /* How much data to request. */
+	   dev->pipes[USB_KBD_POLL_EP_NO].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_kbd_polling_ended_callback,
+	   /* Custom argument. */
+	   kbd_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_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;
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 usb_kbd_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_kbd_add_device()\n");
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add USB KBD device: endpoint not "
+		    "found.\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_kbd_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add KBD device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("Keyboard `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_kbd_driver_ops = {
+        .add_device = usb_kbd_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_kbd_driver = {
+        .name = NAME,
+        .ops = &usb_kbd_driver_ops,
+        .endpoints = usb_kbd_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB KBD driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return usb_driver_main(&usb_kbd_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/layout.h
===================================================================
--- uspace/drv/usbhid/layout.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/layout.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Lubos Slovak 
+ * (copied from /uspace/srv/hid/kbd/include/layout.h)
+ * 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
+ * Keyboard layout.
+ */
+
+#ifndef USB_HID_LAYOUT_H_
+#define USB_HID_LAYOUT_H_
+
+#include <sys/types.h>
+#include <io/console.h>
+
+typedef struct {
+	void (*reset)(void);
+	wchar_t (*parse_ev)(kbd_event_t *);
+} layout_op_t;
+
+extern layout_op_t us_qwerty_op;
+extern layout_op_t us_dvorak_op;
+extern layout_op_t cz_op;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * 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
+ * Main routines of USB HID driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/dev/driver.h>
+#include <usb/dev/poll.h>
+
+#include "usbhid.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbhid"
+
+/**
+ * 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 usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ */
+static int usb_hid_try_add_device(usb_device_t *dev)
+{
+	assert(dev != NULL);
+	
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID device...\n");
+	
+	usb_hid_dev_t *hid_dev = usb_hid_new();
+	if (hid_dev == NULL) {
+		usb_log_error("Error while creating USB/HID device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	int rc = usb_hid_init(hid_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID device.\n");
+		usb_hid_free(&hid_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID device structure initialized.\n");
+	
+	/*
+	 * 1) subdriver vytvori vlastnu ddf_fun, vlastne ddf_dev_ops, ktore da
+	 *    do nej.
+	 * 2) do tych ops do .interfaces[DEV_IFACE_USBHID (asi)] priradi 
+	 *    vyplnenu strukturu usbhid_iface_t.
+	 * 3) klientska aplikacia - musi si rucne vytvorit telefon
+	 *    (devman_device_connect() - cesta k zariadeniu (/hw/pci0/...) az 
+	 *    k tej fcii.
+	 *    pouzit usb/classes/hid/iface.h - prvy int je telefon
+	 */
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   hid_dev->poll_pipe_index,
+	   /* Callback when data arrives. */
+	   usb_hid_polling_callback,
+	   /* How much data to request. */
+	   dev->pipes[hid_dev->poll_pipe_index].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_hid_polling_ended_callback,
+	   /* Custom argument. */
+	   hid_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 usb_hid_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_hid_add_device()\n");
+	
+	if (dev == NULL) {
+		usb_log_warning("Wrong parameter given for add_device().\n");
+		return EINVAL;
+	}
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported HID device.\n");
+		usb_log_error("Failed to add HID device: endpoints not found."
+		    "\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_hid_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported HID device.\n");
+		usb_log_error("Failed to add HID device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("HID device `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_hid_driver_ops = {
+        .add_device = usb_hid_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_hid_driver = {
+        .name = NAME,
+        .ops = &usb_hid_driver_ops,
+        .endpoints = usb_hid_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB HID driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&usb_hid_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/usbhid/mouse/mousedev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/mouse/mousedev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak, 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB Mouse driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/request.h>
+#include <usb/hid/usages/core.h>
+#include <errno.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <str_error.h>
+#include <ipc/mouse.h>
+#include <io/console.h>
+
+#include <ipc/kbd.h>
+#include <io/keycode.h>
+
+#include "mousedev.h"
+#include "../usbhid.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
+#define NAME "mouse"
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_MOUSE,
+	.flags = 0
+};
+
+const char *HID_MOUSE_FUN_NAME = "mouse";
+const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
+const char *HID_MOUSE_CLASS_NAME = "mouse";
+const char *HID_MOUSE_WHEEL_CLASS_NAME = "keyboard";
+
+/** Default idle rate for mouses. */
+static const uint8_t IDLE_RATE = 0;
+static const size_t USB_MOUSE_BUTTON_COUNT = 3;
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63
+};
+
+static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[
+    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = {
+	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
+	0x09, 0x02,                    // USAGE (Mouse)
+	0xa1, 0x01,                    // COLLECTION (Application)
+	0x09, 0x01,                    //   USAGE (Pointer)
+	0xa1, 0x00,                    //   COLLECTION (Physical)
+	0x95, 0x03,                    //     REPORT_COUNT (3)
+	0x75, 0x01,                    //     REPORT_SIZE (1)
+	0x05, 0x09,                    //     USAGE_PAGE (Button)
+	0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
+	0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
+	0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
+	0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
+	0x81, 0x02,                    //     INPUT (Data,Var,Abs)
+	0x95, 0x01,                    //     REPORT_COUNT (1)
+	0x75, 0x05,                    //     REPORT_SIZE (5)
+	0x81, 0x01,                    //     INPUT (Cnst)
+	0x75, 0x08,                    //     REPORT_SIZE (8)
+	0x95, 0x02,                    //     REPORT_COUNT (2)
+	0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
+	0x09, 0x30,                    //     USAGE (X)
+	0x09, 0x31,                    //     USAGE (Y)
+	0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
+	0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
+	0x81, 0x06,                    //     INPUT (Data,Var,Rel)
+	0xc0,                          //   END_COLLECTION
+	0xc0                           // END_COLLECTION
+};
+
+/*----------------------------------------------------------------------------*/
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+	
+	usb_mouse_t *mouse_dev = (usb_mouse_t *)fun->driver_data;
+	
+	if (mouse_dev == NULL) {
+		usb_log_debug("default_connection_handler: Missing "
+		    "parameters.\n");
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+	
+	usb_log_debug("default_connection_handler: fun->name: %s\n",
+	              fun->name);
+	usb_log_debug("default_connection_handler: mouse_phone: %d, wheel "
+	    "phone: %d\n", mouse_dev->mouse_phone, mouse_dev->wheel_phone);
+	
+	int *phone = (str_cmp(fun->name, HID_MOUSE_FUN_NAME) == 0) 
+		     ? &mouse_dev->mouse_phone : &mouse_dev->wheel_phone;
+	
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (*phone != -1) {
+			usb_log_debug("default_connection_handler: Console "
+			    "phone to mouse already set.\n");
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		*phone = callback;
+		usb_log_debug("Console phone to mouse set ok (%d).\n", *phone);
+		async_answer_0(icallid, EOK);
+		return;
+	}
+
+	usb_log_debug("default_connection_handler: Invalid function.\n");
+	async_answer_0(icallid, EINVAL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static usb_mouse_t *usb_mouse_new(void)
+{
+	usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t));
+	if (mouse == NULL) {
+		return NULL;
+	}
+	mouse->mouse_phone = -1;
+	mouse->wheel_phone = -1;
+	
+	return mouse;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_mouse_free(usb_mouse_t **mouse_dev)
+{
+	assert(mouse_dev != NULL && *mouse_dev != NULL);
+	
+	// hangup phone to the console
+	if ((*mouse_dev)->mouse_phone >= 0) {
+		async_obsolete_hangup((*mouse_dev)->mouse_phone);
+	}
+	
+	if ((*mouse_dev)->wheel_phone >= 0) {
+		async_obsolete_hangup((*mouse_dev)->wheel_phone);
+	}
+	
+	free(*mouse_dev);
+	*mouse_dev = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel)
+{
+	kbd_event_t ev;
+	
+	ev.type = KEY_PRESS;
+	ev.key = (wheel > 0) ? KC_UP : (wheel < 0) ? KC_DOWN : 0;
+	ev.mods = 0;
+	ev.c = 0;
+
+	if (mouse_dev->wheel_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+	
+	int count = (wheel < 0) ? -wheel : wheel;
+	int i;
+	
+	for (i = 0; i < count * 3; ++i) {
+		usb_log_debug2("Sending key %d to the console\n", ev.key);
+		async_obsolete_msg_4(mouse_dev->wheel_phone, KBD_EVENT, ev.type, 
+		    ev.key, ev.mods, ev.c);
+		// send key release right away
+		async_obsolete_msg_4(mouse_dev->wheel_phone, KBD_EVENT, KEY_RELEASE, 
+		    ev.key, ev.mods, ev.c);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev, 
+                                     usb_mouse_t *mouse_dev, uint8_t *buffer,
+                                     size_t buffer_size)
+{
+	assert(mouse_dev != NULL);
+	
+	usb_log_debug2("got buffer: %s.\n",
+	    usb_debug_str_buffer(buffer, buffer_size, 0));
+	
+	if (mouse_dev->mouse_phone < 0) {
+		usb_log_warning(NAME " No console phone.\n");
+		return true;
+	}
+
+	/*
+	 * parse the input report
+	 */
+	
+	usb_log_debug(NAME " Calling usb_hid_parse_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, buffer_size, 0));
+	
+	uint8_t report_id;
+	
+	int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 
+	    &report_id);
+	
+	if (rc != EOK) {
+		usb_log_warning(NAME "Error in usb_hid_parse_report(): %s\n", 
+		    str_error(rc));
+		return true;
+	}
+	
+	/*
+	 * X
+	 */
+	int shift_x = 0;
+	
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP, 
+	    USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
+
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END, 
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	if (field != NULL) {
+		usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value, 
+		    field->usage);
+		shift_x = field->value;
+	}
+
+	usb_hid_report_path_free(path);
+	
+	/*
+	 * Y
+	 */
+	int shift_y = 0;
+	
+	path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP, 
+	    USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
+
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END, 
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	if (field != NULL) {
+		usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value, 
+		    field->usage);
+		shift_y = field->value;
+	}
+
+	usb_hid_report_path_free(path);
+	
+	if ((shift_x != 0) || (shift_y != 0)) {
+		async_obsolete_req_2_0(mouse_dev->mouse_phone,
+		    MEVENT_MOVE, shift_x, shift_y);
+	}
+	
+	/*
+	 * Wheel
+	 */
+	int wheel = 0;
+	
+	path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP, 
+	    USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
+
+	usb_hid_report_path_set_report_id(path, report_id);
+	
+	field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END, 
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	if (field != NULL) {
+		usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value, 
+		    field->usage);
+		wheel = field->value;
+	}
+
+	usb_hid_report_path_free(path);
+	
+	// send arrow up for positive direction and arrow down for negative
+	// direction; three arrows for difference of 1
+	usb_mouse_send_wheel(mouse_dev, wheel);
+	
+	
+	/*
+	 * Buttons
+	 */
+	path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
+	usb_hid_report_path_set_report_id(path, report_id);
+	
+	field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	while (field != NULL) {
+		usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value, 
+		    field->usage);
+		
+		if (mouse_dev->buttons[field->usage - field->usage_minimum] == 0
+		    && field->value != 0) {
+			async_obsolete_req_2_0(mouse_dev->mouse_phone,
+			    MEVENT_BUTTON, field->usage, 1);
+			mouse_dev->buttons[field->usage - field->usage_minimum]
+			    = field->value;
+		} else if (
+		    mouse_dev->buttons[field->usage - field->usage_minimum] != 0
+		    && field->value == 0) {
+		       async_obsolete_req_2_0(mouse_dev->mouse_phone,
+			   MEVENT_BUTTON, field->usage, 0);
+		       mouse_dev->buttons[field->usage - field->usage_minimum]
+			   = field->value;
+	       }
+		
+		field = usb_hid_report_get_sibling(
+		    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+	
+	usb_hid_report_path_free(path);
+
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_mouse_create_function(usb_hid_dev_t *hid_dev, usb_mouse_t *mouse)
+{
+	assert(hid_dev != NULL);
+	assert(mouse != NULL);
+	
+	/* Create the function exposed under /dev/devices. */
+	usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME);
+	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	    HID_MOUSE_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	fun->ops = &mouse->ops;
+	fun->driver_data = mouse;
+
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	usb_log_debug("Adding DDF function to class %s...\n", 
+	    HID_MOUSE_CLASS_NAME);
+	rc = ddf_fun_add_to_class(fun, HID_MOUSE_CLASS_NAME);
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class %s: %s.\n",
+		    HID_MOUSE_CLASS_NAME, str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	/*
+	 * Special function for acting as keyboard (wheel)
+	 */
+	usb_log_debug("Creating DDF function %s...\n", 
+	              HID_MOUSE_WHEEL_FUN_NAME);
+	fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	    HID_MOUSE_WHEEL_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/*
+	 * Store the initialized HID device and HID ops
+	 * to the DDF function.
+	 */
+	fun->ops = &mouse->ops;
+	fun->driver_data = mouse;
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	usb_log_debug("Adding DDF function to class %s...\n", 
+	    HID_MOUSE_WHEEL_CLASS_NAME);
+	rc = ddf_fun_add_to_class(fun, HID_MOUSE_WHEEL_CLASS_NAME);
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class %s: %s.\n",
+		    HID_MOUSE_WHEEL_CLASS_NAME, str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	usb_log_debug("Initializing HID/Mouse structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init keyboard structure: no structure"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	usb_mouse_t *mouse_dev = usb_mouse_new();
+	if (mouse_dev == NULL) {
+		usb_log_error("Error while creating USB/HID Mouse device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	mouse_dev->buttons = (int32_t *)calloc(USB_MOUSE_BUTTON_COUNT, 
+	    sizeof(int32_t));
+	
+	if (mouse_dev->buttons == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(mouse_dev);
+		return ENOMEM;
+	}
+	
+	// save the Mouse device structure into the HID device structure
+	*data = mouse_dev;
+	
+	// set handler for incoming calls
+	mouse_dev->ops.default_handler = default_connection_handler;
+	
+	// TODO: how to know if the device supports the request???
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, IDLE_RATE);
+	
+	int rc = usb_mouse_create_function(hid_dev, mouse_dev);
+	if (rc != EOK) {
+		usb_mouse_free(&mouse_dev);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data, 
+     uint8_t *buffer, size_t buffer_size)
+{
+	usb_log_debug("usb_mouse_polling_callback()\n");
+	usb_debug_str_buffer(buffer, buffer_size, 0);
+	
+	if (hid_dev == NULL || data == NULL) {
+		usb_log_error("Missing argument to the mouse polling callback."
+		    "\n");
+		return false;
+	}
+	
+	usb_mouse_t *mouse_dev = (usb_mouse_t *)data;
+		
+	return usb_mouse_process_report(hid_dev, mouse_dev, buffer, 
+	                                buffer_size);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (data != NULL) {
+		usb_mouse_free((usb_mouse_t **)&data);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	int rc = usb_hid_parse_report_descriptor(hid_dev->report, 
+	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR, 
+	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
+	
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/usbhid/mouse/mousedev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/mouse/mousedev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,80 @@
+/*
+ * 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 Mouse driver API.
+ */
+
+#ifndef USB_HID_MOUSEDEV_H_
+#define USB_HID_MOUSEDEV_H_
+
+#include <usb/dev/driver.h>
+
+struct usb_hid_dev;
+
+/*----------------------------------------------------------------------------*/
+
+/** Container for USB mouse device. */
+typedef struct {
+	/** IPC phone to console (consumer). */
+	int mouse_phone;
+	int wheel_phone;
+	
+	int32_t *buttons;
+	
+	ddf_dev_ops_t ops;
+} usb_mouse_t;
+
+/*----------------------------------------------------------------------------*/
+
+usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
+
+const char *HID_MOUSE_FUN_NAME;
+const char *HID_MOUSE_CLASS_NAME;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_mouse_init(struct usb_hid_dev *hid_dev, void **data);
+
+bool usb_mouse_polling_callback(struct usb_hid_dev *hid_dev, void *data, 
+    uint8_t *buffer, size_t buffer_size);
+
+void usb_mouse_deinit(struct usb_hid_dev *hid_dev, void *data);
+
+int usb_mouse_set_boot_protocol(struct usb_hid_dev *hid_dev);
+
+/*----------------------------------------------------------------------------*/
+
+#endif // USB_HID_MOUSEDEV_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/multimedia/keymap.c
===================================================================
--- uspace/drv/usbhid/multimedia/keymap.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/multimedia/keymap.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,94 @@
+/*
+ * 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
+ * UUSB multimedia key to keycode mapping.
+ */
+
+#include <io/keycode.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include "keymap.h"
+
+/**
+ * Mapping between USB HID multimedia usages (from HID Usage Tables) and 
+ * corresponding HelenOS key codes.
+ *
+ * Currently only Usages used by Logitech UltraX keyboard are present. All other
+ * should result in 0.
+ */
+static int usb_hid_keymap_consumer[0x29c] = {
+	[0xb5] = 0,       /* Scan Next Track */
+	[0xb6] = 0,       /* Scan Previous Track */
+	[0xb7] = 0,       /* Stop */
+	[0xb8] = 0,       /* Eject */
+	[0xcd] = 0/*KC_F2*/,   /* Play/Pause */
+	[0xe2] = 0/*KC_F3*/,   /* Mute */
+	[0xe9] = 0/*KC_F5*/,   /* Volume Increment */
+	[0xea] = 0/*KC_F4*/,   /* Volume Decrement */
+	[0x183] = 0/*KC_F1*/,      /* AL Consumer Control Configuration */
+	[0x18a] = 0,      /* AL Email Reader */
+	[0x192] = 0,      /* AL Calculator */
+	[0x221] = 0,      /* AC Search */
+	[0x223] = 0/*KC_F6*/,      /* AC Home */
+	[0x224] = 0,      /* AC Back */
+	[0x225] = 0,      /* AC Forward */
+	[0x226] = 0,      /* AC Stop */
+	[0x227] = 0,  /* AC Refresh */
+	[0x22a] = 0   /* AC Bookmarks */
+};
+
+/**
+ * Translates USB HID Usages from the Consumer Page into HelenOS keycodes.
+ *
+ * @param usage USB HID Consumer Page Usage number.
+ * 
+ * @retval HelenOS key code corresponding to the given USB Consumer Page Usage.
+ */
+unsigned int usb_multimedia_map_usage(int usage)
+{
+	unsigned int key;
+	int *map = usb_hid_keymap_consumer;
+	size_t map_length = sizeof(usb_hid_keymap_consumer) / sizeof(int);
+
+	if ((usage < 0) || ((size_t)usage >= map_length))
+		return -1;
+
+	/*! @todo What if the usage is not in the table? */
+	key = map[usage];
+	
+	return key;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/multimedia/keymap.h
===================================================================
--- uspace/drv/usbhid/multimedia/keymap.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/multimedia/keymap.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * 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 multimedia key to keycode mapping.
+ */
+
+#ifndef USB_HID_MULTIMEDIA_KEYMAP_H_
+#define USB_HID_MULTIMEDIA_KEYMAP_H_
+
+unsigned int usb_multimedia_map_usage(int usage);
+
+#endif /* USB_HID_MULTIMEDIA_KEYMAP_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/usbhid/multimedia/multimedia.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/multimedia/multimedia.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak, 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB Keyboard multimedia keys subdriver.
+ */
+
+
+#include "multimedia.h"
+#include "../usbhid.h"
+#include "keymap.h"
+
+#include <usb/hid/hidparser.h>
+#include <usb/debug.h>
+#include <usb/hid/usages/core.h>
+#include <usb/hid/usages/consumer.h>
+
+#include <errno.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <str_error.h>
+
+#include <ipc/kbd.h>
+#include <io/console.h>
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
+#define NAME "multimedia-keys"
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Logitech UltraX device type.
+ */
+typedef struct usb_multimedia_t {
+	/** Previously pressed keys (not translated to key codes). */
+	//int32_t *keys_old;
+	/** Currently pressed keys (not translated to key codes). */
+	//int32_t *keys;
+	/** Count of stored keys (i.e. number of keys in the report). */
+	//size_t key_count;	
+	/** IPC phone to the console device (for sending key events). */
+	int console_phone;
+} usb_multimedia_t;
+
+
+/*----------------------------------------------------------------------------*/
+/** 
+ * 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.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	usb_log_debug(NAME " default_connection_handler()\n");
+	
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+	
+	usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data;
+	//usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	
+	if (multim_dev == NULL) {
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (multim_dev->console_phone != -1) {
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		multim_dev->console_phone = callback;
+		usb_log_debug(NAME " Saved phone to console: %d\n", callback);
+		async_answer_0(icallid, EOK);
+		return;
+	}
+	
+	async_answer_0(icallid, EINVAL);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static ddf_dev_ops_t multimedia_ops = {
+	.default_handler = default_connection_handler
+};
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 hid_dev 
+ * @param lgtch_dev 
+ * @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.
+ */
+static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev, 
+    usb_multimedia_t *multim_dev, int type, unsigned int key)
+{
+	assert(hid_dev != NULL);
+	assert(multim_dev != NULL);
+	
+	kbd_event_t ev;
+	
+	ev.type = type;
+	ev.key = key;
+	ev.mods = 0;
+	ev.c = 0;
+
+	usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
+	if (multim_dev->console_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+	
+	async_obsolete_msg_4(multim_dev->console_phone, KBD_EVENT, ev.type, ev.key, 
+	    ev.mods, ev.c);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static void usb_multimedia_free(usb_multimedia_t **multim_dev)
+{
+	if (multim_dev == NULL || *multim_dev == NULL) {
+		return;
+	}
+	
+	// hangup phone to the console
+	async_obsolete_hangup((*multim_dev)->console_phone);
+
+	free(*multim_dev);
+	*multim_dev = NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev, 
+    usb_multimedia_t *multim_dev)
+{
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	    NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	fun->ops = &multimedia_ops;
+	fun->driver_data = multim_dev;   // TODO: maybe change to hid_dev->data
+	
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	usb_log_debug("%s function created (jandle: %" PRIun ").\n",
+	    NAME, fun->handle);
+	
+	rc = ddf_fun_add_to_class(fun, "keyboard");
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'keyboard': %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
+{
+	if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
+		return EINVAL; /*! @todo Other return code? */
+	}
+	
+	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
+	
+	usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
+	    sizeof(usb_multimedia_t));
+	if (multim_dev == NULL) {
+		return ENOMEM;
+	}
+	
+	multim_dev->console_phone = -1;
+	
+	/*! @todo Autorepeat */
+	
+	// save the KBD device structure into the HID device structure
+	*data = multim_dev;
+	
+	usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
+	
+	int rc = usb_multimedia_create_function(hid_dev, multim_dev);
+	if (rc != EOK) {
+		usb_multimedia_free(&multim_dev);
+		return rc;
+	}
+	
+	usb_log_debug(NAME " HID/multimedia structure initialized.\n");
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
+{
+	if (hid_dev == NULL) {
+		return;
+	}
+	
+	if (data != NULL) {
+		usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
+		usb_multimedia_free(&multim_dev);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data, 
+    uint8_t *buffer, size_t buffer_size)
+{
+	// TODO: checks
+	if (hid_dev == NULL || data == NULL || buffer == NULL) {
+		return false;
+	}
+	
+	usb_log_debug(NAME " usb_lgtch_polling_callback(%p, %p, %zu)\n",
+	    hid_dev, buffer, buffer_size);
+	
+	usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
+
+	usb_log_debug(NAME " Calling usb_hid_parse_report() with "
+	    "buffer %s\n", usb_debug_str_buffer(buffer, buffer_size, 0));
+	
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
+
+	uint8_t report_id;
+	
+	int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 
+	    &report_id);
+	
+	if (rc != EOK) {
+		usb_log_warning(NAME "Error in usb_hid_parse_report(): %s\n", 
+		    str_error(rc));
+		return true;
+	}
+	
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END 
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	/*! @todo Is this iterating OK if done multiple times? 
+	 *  @todo The parsing is not OK
+	 */
+	while (field != NULL) {
+		if(field->value != 0) {
+			usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", 
+			    field->value, field->usage);
+			unsigned int key = 
+			    usb_multimedia_map_usage(field->usage);
+			const char *key_str = 
+			    usbhid_multimedia_usage_to_str(field->usage);
+			usb_log_info("Pressed key: %s\n", key_str);
+			usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS, 
+			                       key);
+		}
+		
+		field = usb_hid_report_get_sibling(
+		    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    USB_HID_REPORT_TYPE_INPUT);
+	}	
+
+	usb_hid_report_path_free(path);
+	
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/multimedia/multimedia.h
===================================================================
--- uspace/drv/usbhid/multimedia/multimedia.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/multimedia/multimedia.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,58 @@
+/*
+ * 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 Keyboard multimedia keys subdriver.
+ */
+
+#ifndef USB_HID_MULTIMEDIA_H_
+#define USB_HID_MULTIMEDIA_H_
+
+#include <usb/dev/driver.h>
+
+struct usb_hid_dev;
+
+/*----------------------------------------------------------------------------*/
+
+int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data);
+
+void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data);
+
+bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data,
+    uint8_t *buffer, size_t buffer_size);
+
+/*----------------------------------------------------------------------------*/
+
+#endif // USB_HID_MULTIMEDIA_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/subdrivers.c
===================================================================
--- uspace/drv/usbhid/subdrivers.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/subdrivers.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,106 @@
+/*
+ * 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 subdriver mappings.
+ */
+
+#include "subdrivers.h"
+#include <usb/hid/usages/core.h>
+#include <usb/hid/hidpath.h>
+
+#include "multimedia/multimedia.h"
+#include "mouse/mousedev.h"
+#include "generic/hiddev.h"
+
+static usb_hid_subdriver_usage_t path_kbd[] = {
+	{USB_HIDUT_PAGE_GENERIC_DESKTOP, 
+	 USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD}, 
+	{0, 0}
+};
+
+static usb_hid_subdriver_usage_t path_mouse[] = {
+	{USB_HIDUT_PAGE_GENERIC_DESKTOP, USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE},
+	{0, 0}
+};
+
+static usb_hid_subdriver_usage_t multim_key_path[] = {
+	{USB_HIDUT_PAGE_CONSUMER, USB_HIDUT_USAGE_CONSUMER_CONSUMER_CONTROL},
+	{0, 0}
+};
+
+const usb_hid_subdriver_mapping_t usb_hid_subdrivers[] = {
+	{
+		path_kbd,
+		0,
+		USB_HID_PATH_COMPARE_BEGIN,
+		-1,
+		-1,
+		{
+			.init = usb_kbd_init,
+			.deinit = usb_kbd_deinit,
+			.poll = usb_kbd_polling_callback,
+			.poll_end = NULL
+		},
+		
+	},
+	{
+		multim_key_path,
+		1,
+		USB_HID_PATH_COMPARE_BEGIN,
+		-1,
+		-1,
+		{
+			.init = usb_multimedia_init,
+			.deinit = usb_multimedia_deinit,
+			.poll = usb_multimedia_polling_callback,
+			.poll_end = NULL
+		}
+	},
+	{
+		path_mouse,
+		0,
+		USB_HID_PATH_COMPARE_BEGIN,
+		-1,
+		-1,
+		{
+			.init = usb_mouse_init,
+			.deinit = usb_mouse_deinit,
+			.poll = usb_mouse_polling_callback,
+			.poll_end = NULL
+		}
+	},
+	{NULL, -1, 0, -1, -1, {NULL, NULL, NULL, NULL, NULL}}
+};
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/subdrivers.h
===================================================================
--- uspace/drv/usbhid/subdrivers.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/subdrivers.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,73 @@
+/*
+ * 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 subdriver mappings.
+ */
+
+#ifndef USB_HID_SUBDRIVERS_H_
+#define USB_HID_SUBDRIVERS_H_
+
+#include "usbhid.h"
+#include "kbd/kbddev.h"
+
+/*----------------------------------------------------------------------------*/
+
+typedef struct usb_hid_subdriver_usage {
+	int usage_page;
+	int usage;
+} usb_hid_subdriver_usage_t;
+
+/*----------------------------------------------------------------------------*/
+
+/* TODO: This mapping must contain some other information to get the proper
+ *       interface.
+ */
+typedef struct usb_hid_subdriver_mapping {
+	const usb_hid_subdriver_usage_t *usage_path;
+	int report_id;
+	int compare;
+	int vendor_id;
+	int product_id;
+	usb_hid_subdriver_t subdriver;
+} usb_hid_subdriver_mapping_t;
+
+/*----------------------------------------------------------------------------*/
+
+extern const usb_hid_subdriver_mapping_t usb_hid_subdrivers[];
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* USB_HID_SUBDRIVERS_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.c
===================================================================
--- uspace/drv/usbhid/usbhid.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/usbhid.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,678 @@
+/*
+ * 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 driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/hidparser.h>
+#include <usb/hid/hidreport.h>
+#include <usb/hid/request.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include "usbhid.h"
+
+#include "kbd/kbddev.h"
+#include "generic/hiddev.h"
+#include "mouse/mousedev.h"
+#include "subdrivers.h"
+
+/*----------------------------------------------------------------------------*/
+
+/* Array of endpoints expected on the device, NULL terminated. */
+usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
+	&usb_hid_kbd_poll_endpoint_description,
+	&usb_hid_mouse_poll_endpoint_description,
+	&usb_hid_generic_poll_endpoint_description,
+	NULL
+};
+
+static const int USB_HID_MAX_SUBDRIVERS = 10;
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	assert(hid_dev->subdriver_count >= 0);
+	
+	// set the init callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].init = usb_kbd_init;
+	
+	// set the polling callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
+	    usb_kbd_polling_callback;
+	
+	// set the polling ended callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
+	
+	// set the deinit callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = usb_kbd_deinit;
+	
+	// set subdriver count
+	++hid_dev->subdriver_count;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	assert(hid_dev->subdriver_count >= 0);
+	
+	// set the init callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].init = usb_mouse_init;
+	
+	// set the polling callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
+	    usb_mouse_polling_callback;
+	
+	// set the polling ended callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
+	
+	// set the deinit callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = usb_mouse_deinit;
+	
+	// set subdriver count
+	++hid_dev->subdriver_count;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	assert(hid_dev->subdriver_count >= 0);
+	
+	// set the init callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].init =
+	    usb_generic_hid_init;
+	
+	// set the polling callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
+	    usb_generic_hid_polling_callback;
+	
+	// set the polling ended callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
+	
+	// set the deinit callback
+	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = NULL;
+	
+	// set subdriver count
+	++hid_dev->subdriver_count;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev, 
+    const usb_hid_subdriver_mapping_t *mapping)
+{
+	assert(hid_dev != NULL);
+	assert(hid_dev->usb_dev != NULL);
+	
+	return (hid_dev->usb_dev->descriptors.device.vendor_id 
+	    == mapping->vendor_id
+	    && hid_dev->usb_dev->descriptors.device.product_id 
+	    == mapping->product_id);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev, 
+    const usb_hid_subdriver_mapping_t *mapping)
+{
+	assert(hid_dev != NULL);
+	assert(mapping != NULL);
+	
+	usb_hid_report_path_t *usage_path = usb_hid_report_path();
+	if (usage_path == NULL) {
+		usb_log_debug("Failed to create usage path.\n");
+		return false;
+	}
+	int i = 0;
+	while (mapping->usage_path[i].usage != 0 
+	    || mapping->usage_path[i].usage_page != 0) {
+		if (usb_hid_report_path_append_item(usage_path, 
+		    mapping->usage_path[i].usage_page, 
+		    mapping->usage_path[i].usage) != EOK) {
+			usb_log_debug("Failed to append to usage path.\n");
+			usb_hid_report_path_free(usage_path);
+			return false;
+		}
+		++i;
+	}
+	
+	assert(hid_dev->report != NULL);
+	
+	usb_log_debug("Compare flags: %d\n", mapping->compare);
+	
+	bool matches = false;
+	uint8_t report_id = mapping->report_id;
+
+	do {
+		usb_log_debug("Trying report id %u\n", report_id);
+		
+		if (report_id != 0) {
+			usb_hid_report_path_set_report_id(usage_path,
+				report_id);
+		}
+
+		usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+		    hid_dev->report,
+		    NULL, usage_path, mapping->compare, 
+		    USB_HID_REPORT_TYPE_INPUT);
+		
+		usb_log_debug("Field: %p\n", field);
+
+		if (field != NULL) {
+			matches = true;
+			break;
+		}
+		
+		report_id = usb_hid_get_next_report_id(
+		    hid_dev->report, report_id,
+		    USB_HID_REPORT_TYPE_INPUT);
+	} while (!matches && report_id != 0);
+	
+	usb_hid_report_path_free(usage_path);
+	
+	return matches;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev, 
+    const usb_hid_subdriver_t **subdrivers, int count)
+{
+	int i;
+	
+	if (count <= 0) {
+		hid_dev->subdriver_count = 0;
+		hid_dev->subdrivers = NULL;
+		return EOK;
+	}
+	
+	// add one generic HID subdriver per device
+	
+	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc((count + 1) * 
+	    sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	
+	for (i = 0; i < count; ++i) {
+		hid_dev->subdrivers[i].init = subdrivers[i]->init;
+		hid_dev->subdrivers[i].deinit = subdrivers[i]->deinit;
+		hid_dev->subdrivers[i].poll = subdrivers[i]->poll;
+		hid_dev->subdrivers[i].poll_end = subdrivers[i]->poll_end;
+	}
+	
+	hid_dev->subdrivers[count].init = usb_generic_hid_init;
+	hid_dev->subdrivers[count].poll = usb_generic_hid_polling_callback;
+	hid_dev->subdrivers[count].deinit = NULL;
+	hid_dev->subdrivers[count].poll_end = NULL;
+	
+	hid_dev->subdriver_count = count + 1;
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+	
+	const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
+	
+	int i = 0, count = 0;
+	const usb_hid_subdriver_mapping_t *mapping = &usb_hid_subdrivers[i];
+
+	bool ids_matched;
+	bool matched;
+	
+	while (count < USB_HID_MAX_SUBDRIVERS &&
+	    (mapping->usage_path != NULL
+	    || mapping->vendor_id >= 0 || mapping->product_id >= 0)) {
+		// check the vendor & product ID
+		if (mapping->vendor_id >= 0 && mapping->product_id < 0) {
+			usb_log_warning("Missing Product ID for Vendor ID %d\n",
+			    mapping->vendor_id);
+			return EINVAL;
+		}
+		if (mapping->product_id >= 0 && mapping->vendor_id < 0) {
+			usb_log_warning("Missing Vendor ID for Product ID %d\n",
+			    mapping->product_id);
+			return EINVAL;
+		}
+		
+		ids_matched = false;
+		matched = false;
+		
+		if (mapping->vendor_id >= 0) {
+			assert(mapping->product_id >= 0);
+			usb_log_debug("Comparing device against vendor ID %u"
+			    " and product ID %u.\n", mapping->vendor_id,
+			    mapping->product_id);
+			if (usb_hid_ids_match(hid_dev, mapping)) {
+				usb_log_debug("IDs matched.\n");
+				ids_matched = true;
+			}
+		}
+		
+		if (mapping->usage_path != NULL) {
+			usb_log_debug("Comparing device against usage path.\n");
+			if (usb_hid_path_matches(hid_dev, mapping)) {
+				// does not matter if IDs were matched
+				matched = true;
+			}
+		} else {
+			// matched only if IDs were matched and there is no path
+			matched = ids_matched;
+		}
+		
+		if (matched) {
+			usb_log_debug("Subdriver matched.\n");
+			subdrivers[count++] = &mapping->subdriver;
+		}
+		
+		mapping = &usb_hid_subdrivers[++i];
+	}
+	
+	// we have all subdrivers determined, save them into the hid device
+	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	assert(hid_dev != NULL && dev != NULL);
+	
+	int rc = EOK;
+	
+	if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
+		usb_log_debug("Found keyboard endpoint.\n");
+		// save the pipe index
+		hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
+	} else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
+		usb_log_debug("Found mouse endpoint.\n");
+		// save the pipe index
+		hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
+	} else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
+		usb_log_debug("Found generic HID endpoint.\n");
+		// save the pipe index
+		hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
+	} else {
+		usb_log_error("None of supported endpoints found - probably"
+		    " not a supported device.\n");
+		rc = ENOTSUP;
+	}
+	
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int usb_hid_init_report(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL && hid_dev->report != NULL);
+	
+	uint8_t report_id = 0;
+	size_t size;
+	
+	size_t max_size = 0;
+	
+	do {
+		usb_log_debug("Getting size of the report.\n");
+		size = usb_hid_report_byte_size(hid_dev->report, report_id, 
+		    USB_HID_REPORT_TYPE_INPUT);
+		usb_log_debug("Report ID: %u, size: %zu\n", report_id, size);
+		max_size = (size > max_size) ? size : max_size;
+		usb_log_debug("Getting next report ID\n");
+		report_id = usb_hid_get_next_report_id(hid_dev->report, 
+		    report_id, USB_HID_REPORT_TYPE_INPUT);
+	} while (report_id != 0);
+	
+	usb_log_debug("Max size of input report: %zu\n", max_size);
+	
+	hid_dev->max_input_report_size = max_size;
+	assert(hid_dev->input_report == NULL);
+	
+	hid_dev->input_report = malloc(max_size);
+	if (hid_dev->input_report == NULL) {
+		return ENOMEM;
+	}
+	memset(hid_dev->input_report, 0, max_size);
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+usb_hid_dev_t *usb_hid_new(void)
+{
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
+	    sizeof(usb_hid_dev_t));
+	
+	if (hid_dev == NULL) {
+		usb_log_fatal("No memory!\n");
+		return NULL;
+	}
+	
+	hid_dev->report = (usb_hid_report_t *)(malloc(sizeof(
+	    usb_hid_report_t)));
+	if (hid_dev->report == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(hid_dev);
+		return NULL;
+	}
+	
+	hid_dev->poll_pipe_index = -1;
+	
+	return hid_dev;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	int rc, i;
+	
+	usb_log_debug("Initializing HID structure...\n");
+	
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init HID structure: no structure given"
+		    ".\n");
+		return EINVAL;
+	}
+	
+	if (dev == NULL) {
+		usb_log_error("Failed to init HID structure: no USB device"
+		    " given.\n");
+		return EINVAL;
+	}
+	
+	/* The USB device should already be initialized, save it in structure */
+	hid_dev->usb_dev = dev;
+	
+	rc = usb_hid_check_pipes(hid_dev, dev);
+	if (rc != EOK) {
+		return rc;
+	}
+		
+	/* Get the report descriptor and parse it. */
+	rc = usb_hid_process_report_descriptor(hid_dev->usb_dev, 
+	    hid_dev->report, &hid_dev->report_desc, &hid_dev->report_desc_size);
+	
+	bool fallback = false;
+	
+	if (rc == EOK) {
+		// try to find subdrivers that may want to handle this device
+		rc = usb_hid_find_subdrivers(hid_dev);
+		if (rc != EOK || hid_dev->subdriver_count == 0) {
+			// try to fall back to the boot protocol if available
+			usb_log_info("No subdrivers found to handle this"
+			    " device.\n");
+			fallback = true;
+			assert(hid_dev->subdrivers == NULL);
+			assert(hid_dev->subdriver_count == 0);
+		}
+	} else {
+		usb_log_error("Failed to parse Report descriptor.\n");
+		// try to fall back to the boot protocol if available
+		fallback = true;
+	}
+	
+	if (fallback) {
+		// fall back to boot protocol
+		switch (hid_dev->poll_pipe_index) {
+		case USB_HID_KBD_POLL_EP_NO:
+			usb_log_info("Falling back to kbd boot protocol.\n");
+			rc = usb_kbd_set_boot_protocol(hid_dev);
+			if (rc == EOK) {
+				rc = usb_hid_set_boot_kbd_subdriver(hid_dev);
+			}
+			break;
+		case USB_HID_MOUSE_POLL_EP_NO:
+			usb_log_info("Falling back to mouse boot protocol.\n");
+			rc = usb_mouse_set_boot_protocol(hid_dev);
+			if (rc == EOK) {
+				rc = usb_hid_set_boot_mouse_subdriver(hid_dev);
+			}
+			break;
+		default:
+			assert(hid_dev->poll_pipe_index 
+			    == USB_HID_GENERIC_POLL_EP_NO);
+			
+			usb_log_info("Falling back to generic HID driver.\n");
+			rc = usb_hid_set_generic_hid_subdriver(hid_dev);
+		}
+	}
+	
+	if (rc != EOK) {
+		usb_log_error("No subdriver for handling this device could be"
+		    " initialized: %s.\n", str_error(rc));
+		usb_log_debug("Subdriver count: %d\n", 
+		    hid_dev->subdriver_count);
+		
+	} else {
+		bool ok = false;
+		
+		usb_log_debug("Subdriver count: %d\n", 
+		    hid_dev->subdriver_count);
+		
+		for (i = 0; i < hid_dev->subdriver_count; ++i) {
+			if (hid_dev->subdrivers[i].init != NULL) {
+				usb_log_debug("Initializing subdriver %d.\n",i);
+				rc = hid_dev->subdrivers[i].init(hid_dev,
+				    &hid_dev->subdrivers[i].data);
+				if (rc != EOK) {
+					usb_log_warning("Failed to initialize"
+					    " HID subdriver structure.\n");
+				} else {
+					// at least one subdriver initialized
+					ok = true;
+				}
+			} else {
+				ok = true;
+			}
+		}
+		
+		rc = (ok) ? EOK : -1;	// what error to report
+	}
+	
+	
+	if (rc == EOK) {
+		// save max input report size and allocate space for the report
+		rc = usb_hid_init_report(hid_dev);
+		if (rc != EOK) {
+			usb_log_error("Failed to initialize input report buffer"
+			    ".\n");
+		}
+	}
+	
+	
+	return rc;
+}
+
+/*----------------------------------------------------------------------------*/
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
+    size_t buffer_size, void *arg)
+{
+	int i;
+	
+	if (dev == NULL || arg == NULL || buffer == NULL) {
+		usb_log_error("Missing arguments to polling callback.\n");
+		return false;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	assert(hid_dev->input_report != NULL);
+	usb_log_debug("Max input report size: %zu, buffer size: %zu\n",
+	    hid_dev->max_input_report_size, buffer_size);
+
+	if (hid_dev->max_input_report_size >= buffer_size) {
+		/*! @todo This should probably be atomic. */
+		memcpy(hid_dev->input_report, buffer, buffer_size);
+		hid_dev->input_report_size = buffer_size;
+		usb_hid_new_report(hid_dev);
+	}
+	
+	bool cont = false;
+	
+	// continue if at least one of the subdrivers want to continue
+	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll != NULL
+		    && hid_dev->subdrivers[i].poll(hid_dev, 
+		        hid_dev->subdrivers[i].data, buffer, buffer_size)) {
+			cont = true;
+		}
+	}
+	
+	return cont;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
+     void *arg)
+{
+	int i; 
+	
+	if (dev == NULL || arg == NULL) {
+		return;
+	}
+	
+	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
+	
+	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll_end != NULL) {
+			hid_dev->subdrivers[i].poll_end(hid_dev,
+			    hid_dev->subdrivers[i].data, reason);
+		}
+	}
+	
+	usb_hid_free(&hid_dev);
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_new_report(usb_hid_dev_t *hid_dev)
+{
+	++hid_dev->report_nr;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_hid_report_number(usb_hid_dev_t *hid_dev)
+{
+	return hid_dev->report_nr;
+}
+
+/*----------------------------------------------------------------------------*/
+
+void usb_hid_free(usb_hid_dev_t **hid_dev)
+{
+	int i;
+	
+	if (hid_dev == NULL || *hid_dev == NULL) {
+		return;
+	}
+	
+	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
+	    (*hid_dev)->subdrivers, (*hid_dev)->subdriver_count);
+	
+	assert((*hid_dev)->subdrivers != NULL 
+	    || (*hid_dev)->subdriver_count == 0);
+	
+	for (i = 0; i < (*hid_dev)->subdriver_count; ++i) {
+		if ((*hid_dev)->subdrivers[i].deinit != NULL) {
+			(*hid_dev)->subdrivers[i].deinit(*hid_dev,
+			    (*hid_dev)->subdrivers[i].data);
+		}
+	}
+	
+	// free the subdrivers info
+	if ((*hid_dev)->subdrivers != NULL) {
+		free((*hid_dev)->subdrivers);
+	}
+
+	// destroy the parser
+	if ((*hid_dev)->report != NULL) {
+		usb_hid_free_report((*hid_dev)->report);
+	}
+
+	if ((*hid_dev)->report_desc != NULL) {
+		free((*hid_dev)->report_desc);
+	}
+
+	free(*hid_dev);
+	*hid_dev = NULL;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.h
===================================================================
--- uspace/drv/usbhid/usbhid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/usbhid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,137 @@
+/*
+ * 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 driver API.
+ */
+
+#ifndef USB_HID_USBHID_H_
+#define USB_HID_USBHID_H_
+
+#include <stdint.h>
+
+#include <usb/hid/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+#include <usb/hid/hid.h>
+#include <bool.h>
+
+struct usb_hid_dev;
+
+typedef int (*usb_hid_driver_init_t)(struct usb_hid_dev *, void **data);
+typedef void (*usb_hid_driver_deinit_t)(struct usb_hid_dev *, void *data);
+typedef bool (*usb_hid_driver_poll)(struct usb_hid_dev *, void *data, uint8_t *,
+                                    size_t);
+typedef int (*usb_hid_driver_poll_ended)(struct usb_hid_dev *, void *data, 
+                                         bool reason);
+
+typedef struct usb_hid_subdriver {	
+	/** Function to be called when initializing HID device. */
+	usb_hid_driver_init_t init;
+	/** Function to be called when destroying the HID device structure. */
+	usb_hid_driver_deinit_t deinit;
+	/** Function to be called when data arrives from the device. */
+	usb_hid_driver_poll poll;
+	/** Function to be called when polling ends. */
+	usb_hid_driver_poll_ended poll_end;
+	/** Arbitrary data needed by the subdriver. */
+	void *data;
+} usb_hid_subdriver_t;
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Structure for holding general HID device data.
+ */
+typedef struct usb_hid_dev {
+	/** Structure holding generic USB device information. */
+	usb_device_t *usb_dev;
+	
+	/** Index of the polling pipe in usb_hid_endpoints array. */
+	int poll_pipe_index;
+	
+	/** Subdrivers. */
+	usb_hid_subdriver_t *subdrivers;
+	
+	/** Number of subdrivers. */
+	int subdriver_count;
+	
+	/** Report descriptor. */
+	uint8_t *report_desc;
+
+	/** Report descriptor size. */
+	size_t report_desc_size;
+	
+	/** HID Report parser. */
+	usb_hid_report_t *report;
+	
+	uint8_t *input_report;
+	
+	size_t input_report_size;
+	size_t max_input_report_size;
+	
+	int report_nr;
+} usb_hid_dev_t;
+
+/*----------------------------------------------------------------------------*/
+
+enum {
+	USB_HID_KBD_POLL_EP_NO = 0,
+	USB_HID_MOUSE_POLL_EP_NO = 1,
+	USB_HID_GENERIC_POLL_EP_NO = 2,
+	USB_HID_POLL_EP_COUNT = 3
+};
+
+usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1];
+
+/*----------------------------------------------------------------------------*/
+
+usb_hid_dev_t *usb_hid_new(void);
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
+    size_t buffer_size, void *arg);
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
+     void *arg);
+
+void usb_hid_new_report(usb_hid_dev_t *hid_dev);
+
+int usb_hid_report_number(usb_hid_dev_t *hid_dev);
+
+void usb_hid_free(usb_hid_dev_t **hid_dev);
+
+#endif /* USB_HID_USBHID_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhid/usbhid.ma
===================================================================
--- uspace/drv/usbhid/usbhid.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhid/usbhid.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,3 @@
+100 usb&interface&class=HID&subclass=0x01&protocol=0x01
+1000 usb&interface&class=HID&subclass=0x01&protocol=0x02
+100 usb&interface&class=HID
Index: uspace/drv/usbhub/Makefile
===================================================================
--- uspace/drv/usbhub/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2010 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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = usbhub
+
+SOURCES = \
+	main.c \
+	utils.c \
+	usbhub.c \
+	ports.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbhub/main.c
===================================================================
--- uspace/drv/usbhub/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010 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 drvusbhub
+ * @{
+ */
+
+#include <ddf/driver.h>
+#include <errno.h>
+#include <async.h>
+#include <stdio.h>
+
+#include <usb/dev/driver.h>
+#include <usb/classes/classes.h>
+
+#include "usbhub.h"
+#include "usbhub_private.h"
+
+/** Hub status-change endpoint description.
+ *
+ * For more information see section 11.15.1 of USB 1.1 specification.
+ */
+static usb_endpoint_description_t hub_status_change_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.flags = 0
+};
+
+/**
+ * usb hub driver operations
+ *
+ * The most important one is add_device, which is set to usb_hub_add_device.
+ */
+static usb_driver_ops_t usb_hub_driver_ops = {
+	.add_device = usb_hub_add_device
+};
+
+/**
+ * hub endpoints, excluding control endpoint
+ */
+static usb_endpoint_description_t *usb_hub_endpoints[] = {
+	&hub_status_change_endpoint_description,
+	NULL
+};
+
+/**
+ * static usb hub driver information
+ */
+static usb_driver_t usb_hub_driver = {
+	.name = NAME,
+	.ops = &usb_hub_driver_ops,
+	.endpoints = usb_hub_endpoints
+};
+
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB hub driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&usb_hub_driver);
+}
+
+/**
+ * @}
+ */
+
Index: uspace/drv/usbhub/port_status.h
===================================================================
--- uspace/drv/usbhub/port_status.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/port_status.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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 drvusbhub
+ * @{
+ */
+
+#ifndef HUB_PORT_STATUS_H
+#define	HUB_PORT_STATUS_H
+
+#include <bool.h>
+#include <sys/types.h>
+#include <usb/dev/request.h>
+#include "usbhub_private.h"
+
+/**
+ * structure holding port status and changes flags.
+ * should not be accessed directly, use supplied getter/setter methods.
+ *
+ * For more information refer to table 11-15 in
+ * "Universal Serial Bus Specification Revision 1.1"
+ *
+ */
+typedef uint32_t usb_port_status_t;
+
+/**
+ * structure holding hub status and changes flags.
+ * should not be accessed directly, use supplied getter/setter methods.
+ *
+ * For more information refer to table 11.16.2.5 in
+ * "Universal Serial Bus Specification Revision 1.1"
+ *
+ */
+typedef uint32_t usb_hub_status_t;
+
+/**
+ * set values in request to be it a port status request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_port_status_request(
+    usb_device_request_setup_packet_t *request, uint16_t port) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS;
+	request->request = USB_HUB_REQUEST_GET_STATUS;
+	request->value = 0;
+	request->length = 4;
+}
+
+/**
+ * set values in request to be it a port status request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_hub_status_request(
+    usb_device_request_setup_packet_t *request) {
+	request->index = 0;
+	request->request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS;
+	request->request = USB_HUB_REQUEST_GET_STATUS;
+	request->value = 0;
+	request->length = 4;
+}
+
+/**
+ * create request for usb hub port status
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_port_status_request(uint16_t port) {
+	usb_device_request_setup_packet_t *result =
+	    malloc(sizeof (usb_device_request_setup_packet_t));
+	usb_hub_set_port_status_request(result, port);
+	return result;
+}
+
+/**
+ * set the device request to be a port feature enable request
+ * @param request
+ * @param port
+ * @param feature_selector
+ */
+static inline void usb_hub_set_enable_port_feature_request(
+    usb_device_request_setup_packet_t *request, uint16_t port,
+    uint16_t feature_selector) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = feature_selector;
+	request->length = 0;
+}
+
+/**
+ * set the device request to be a port feature clear request
+ * @param request
+ * @param port
+ * @param feature_selector
+ */
+static inline void usb_hub_set_disable_port_feature_request(
+    usb_device_request_setup_packet_t *request, uint16_t port,
+    uint16_t feature_selector
+    ) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_CLEAR_FEATURE;
+	request->value = feature_selector;
+	request->length = 0;
+}
+
+/**
+ * set the device request to be a port enable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_enable_port_request(
+    usb_device_request_setup_packet_t *request, uint16_t port
+    ) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_C_PORT_ENABLE;
+	request->length = 0;
+}
+
+/**
+ * enable specified port
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_enable_port_request(uint16_t port) {
+	usb_device_request_setup_packet_t *result =
+	    malloc(sizeof (usb_device_request_setup_packet_t));
+	usb_hub_set_enable_port_request(result, port);
+	return result;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_disable_port_request(
+    usb_device_request_setup_packet_t *request, uint16_t port
+    ) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_C_PORT_SUSPEND;
+	request->length = 0;
+}
+
+/**
+ * disable specified port
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_disable_port_request(uint16_t port) {
+	usb_device_request_setup_packet_t *result =
+	    malloc(sizeof (usb_device_request_setup_packet_t));
+	usb_hub_set_disable_port_request(result, port);
+	return result;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_reset_port_request(
+    usb_device_request_setup_packet_t *request, uint16_t port
+    ) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_PORT_RESET;
+	request->length = 0;
+}
+
+/**
+ * disable specified port
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_reset_port_request(uint16_t port) {
+	usb_device_request_setup_packet_t *result =
+	    malloc(sizeof (usb_device_request_setup_packet_t));
+	usb_hub_set_reset_port_request(result, port);
+	return result;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_power_port_request(
+    usb_device_request_setup_packet_t *request, uint16_t port
+    ) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_PORT_POWER;
+	request->length = 0;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_unset_power_port_request(
+    usb_device_request_setup_packet_t *request, uint16_t port
+    ) {
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_CLEAR_FEATURE;
+	request->value = USB_HUB_FEATURE_PORT_POWER;
+	request->length = 0;
+}
+
+/**
+ * get i`th bit of port status
+ * 
+ * @param status
+ * @param idx
+ * @return
+ */
+static inline bool usb_port_is_status(usb_port_status_t status, int idx) {
+	return (status & (1 << idx)) != 0;
+}
+
+/**
+ * set i`th bit of port status
+ * 
+ * @param status
+ * @param idx
+ * @param value
+ */
+static inline void usb_port_status_set_bit(
+    usb_port_status_t * status, int idx, bool value) {
+	(*status) = value ?
+	    ((*status) | (1 << (idx))) :
+	    ((*status)&(~(1 << (idx))));
+}
+
+/**
+ * get i`th bit of hub status
+ * 
+ * @param status
+ * @param idx
+ * @return
+ */
+static inline bool usb_hub_is_status(usb_hub_status_t status, int idx) {
+	return (status & (1 << idx)) != 0;
+}
+
+/**
+ * set i`th bit of hub status
+ * 
+ * @param status
+ * @param idx
+ * @param value
+ */
+static inline void usb_hub_status_set_bit(
+    usb_hub_status_t *status, int idx, bool value) {
+	(*status) = value ?
+	    ((*status) | (1 << (idx))) :
+	    ((*status)&(~(1 << (idx))));
+}
+
+/**
+ * low speed device on the port indicator
+ * 
+ * @param status
+ * @return true if low speed device is attached
+ */
+static inline bool usb_port_low_speed(usb_port_status_t status) {
+	return usb_port_is_status(status, 9);
+}
+
+/**
+ * set low speed device connected bit in port status
+ * 
+ * @param status
+ * @param low_speed value of the bit
+ */
+static inline void usb_port_set_low_speed(usb_port_status_t *status, bool low_speed) {
+	usb_port_status_set_bit(status, 9, low_speed);
+}
+
+//high speed device attached
+
+/**
+ * high speed device on the port indicator
+ *
+ * @param status
+ * @return true if high speed device is on port
+ */
+static inline bool usb_port_high_speed(usb_port_status_t status) {
+	return usb_port_is_status(status, 10);
+}
+
+/**
+ * set high speed device bit in port status
+ *
+ * @param status
+ * @param high_speed value of the bit
+ */
+static inline void usb_port_set_high_speed(usb_port_status_t *status, bool high_speed) {
+	usb_port_status_set_bit(status, 10, high_speed);
+}
+
+/**
+ * speed getter for port status
+ *
+ * @param status
+ * @return speed of usb device (for more see usb specification)
+ */
+static inline usb_speed_t usb_port_speed(usb_port_status_t status) {
+	if (usb_port_low_speed(status))
+		return USB_SPEED_LOW;
+	if (usb_port_high_speed(status))
+		return USB_SPEED_HIGH;
+	return USB_SPEED_FULL;
+}
+
+
+
+#endif	/* HUB_PORT_STATUS_H */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/ports.c
===================================================================
--- uspace/drv/usbhub/ports.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/ports.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,465 @@
+/*
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * Hub ports functions.
+ */
+
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <inttypes.h>
+#include <fibril_synch.h>
+
+#include <usb/debug.h>
+
+#include "ports.h"
+#include "usbhub.h"
+#include "usbhub_private.h"
+#include "port_status.h"
+
+/** Information for fibril for device discovery. */
+struct add_device_phase1 {
+	usb_hub_info_t *hub;
+	size_t port;
+	usb_speed_t speed;
+};
+
+/**
+ * count of port status changes that are not explicitly handled by
+ * any function here and must be cleared by hand
+ */
+static const unsigned int non_handled_changes_count = 2;
+
+/**
+ * port status changes that are not explicitly handled by
+ * any function here and must be cleared by hand
+ */
+static const int non_handled_changes[] = {
+	USB_HUB_FEATURE_C_PORT_ENABLE,
+	USB_HUB_FEATURE_C_PORT_SUSPEND
+};
+
+static void usb_hub_removed_device(
+    usb_hub_info_t *hub, uint16_t port);
+
+static void usb_hub_port_reset_completed(usb_hub_info_t *hub,
+    uint16_t port, uint32_t status);
+
+static void usb_hub_port_over_current(usb_hub_info_t *hub,
+    uint16_t port, uint32_t status);
+
+static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
+    usb_port_status_t *status);
+
+static int enable_port_callback(int port_no, void *arg);
+
+static int add_device_phase1_worker_fibril(void *arg);
+
+static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
+    usb_speed_t speed);
+
+/**
+ * Process interrupts on given hub port
+ *
+ * Accepts connection, over current and port reset change.
+ * @param hub hub representation
+ * @param port port number, starting from 1
+ */
+void usb_hub_process_port_interrupt(usb_hub_info_t *hub,
+    uint16_t port) {
+	usb_log_debug("Interrupt at port %zu\n", (size_t) port);
+	//determine type of change
+	//usb_pipe_t *pipe = hub->control_pipe;
+
+	int opResult;
+
+	usb_port_status_t status;
+	opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status);
+	if (opResult != EOK) {
+		usb_log_error("Failed to get port %zu status: %s.\n",
+		    (size_t) port, str_error(opResult));
+		return;
+	}
+	//connection change
+	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_CONNECTION)) {
+		bool device_connected = usb_port_is_status(status,
+		    USB_HUB_FEATURE_PORT_CONNECTION);
+		usb_log_debug("Connection change on port %zu: %s.\n",
+		    (size_t) port,
+		    device_connected ? "device attached" : "device removed");
+
+		if (device_connected) {
+			opResult = create_add_device_fibril(hub, port,
+			    usb_port_speed(status));
+			if (opResult != EOK) {
+				usb_log_error(
+				    "Cannot handle change on port %zu: %s.\n",
+				    (size_t) port, str_error(opResult));
+			}
+		} else {
+			usb_hub_removed_device(hub, port);
+		}
+	}
+	//over current
+	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) {
+		//check if it was not auto-resolved
+		usb_log_debug("Overcurrent change on port\n");
+		usb_hub_port_over_current(hub, port, status);
+	}
+	//port reset
+	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_RESET)) {
+		usb_hub_port_reset_completed(hub, port, status);
+	}
+	usb_log_debug("Status x%x : %d\n ", status, status);
+
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_C_PORT_CONNECTION, false);
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_C_PORT_RESET, false);
+	usb_port_status_set_bit(
+	    &status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT, false);
+
+	//clearing not yet handled changes	
+	unsigned int feature_idx;
+	for (feature_idx = 0;
+	    feature_idx < non_handled_changes_count;
+	    ++feature_idx) {
+		unsigned int bit_idx = non_handled_changes[feature_idx];
+		if (status & (1 << bit_idx)) {
+			usb_log_info(
+			    "There was not yet handled change on port %d: %d"
+			    ";clearing it\n",
+			    port, bit_idx);
+			int opResult = usb_hub_clear_port_feature(
+			    hub->control_pipe,
+			    port, bit_idx);
+			if (opResult != EOK) {
+				usb_log_warning(
+				    "Could not clear port flag %d: %s\n",
+				    bit_idx, str_error(opResult)
+				    );
+			}
+			usb_port_status_set_bit(
+			    &status, bit_idx, false);
+		}
+	}
+	if (status >> 16) {
+		usb_log_info("There is still some unhandled change %X\n",
+		    status);
+	}
+}
+
+/**
+ * routine called when a device on port has been removed
+ *
+ * If the device on port had default address, it releases default address.
+ * Otherwise does not do anything, because DDF does not allow to remove device
+ * from it`s device tree.
+ * @param hub hub representation
+ * @param port port number, starting from 1
+ */
+static void usb_hub_removed_device(
+    usb_hub_info_t *hub, uint16_t port) {
+
+	int opResult = usb_hub_clear_port_feature(hub->control_pipe,
+	    port, USB_HUB_FEATURE_C_PORT_CONNECTION);
+	if (opResult != EOK) {
+		usb_log_warning("Could not clear port-change-connection flag\n");
+	}
+	/** \TODO remove device from device manager - not yet implemented in
+	 * devide manager
+	 */
+
+	//close address
+
+	usb_hub_port_t *the_port = hub->ports + port;
+
+	fibril_mutex_lock(&hub->port_mutex);
+
+	if (the_port->attached_device.address >= 0) {
+		usb_log_warning("Device unplug on `%s' (port %zu): " \
+		    "not implemented.\n", hub->usb_device->ddf_dev->name,
+		    (size_t) port);
+		the_port->attached_device.address = -1;
+		the_port->attached_device.handle = 0;
+	} else {
+		usb_log_warning("Device removed before being registered.\n");
+
+		/*
+		 * Device was removed before port reset completed.
+		 * We will announce a failed port reset to unblock the
+		 * port reset callback from new device wrapper.
+		 */
+		fibril_mutex_lock(&the_port->reset_mutex);
+		the_port->reset_completed = true;
+		the_port->reset_okay = false;
+		fibril_condvar_broadcast(&the_port->reset_cv);
+		fibril_mutex_unlock(&the_port->reset_mutex);
+	}
+
+	fibril_mutex_unlock(&hub->port_mutex);
+}
+
+/**
+ * Process port reset change
+ *
+ * After this change port should be enabled, unless some problem occured.
+ * This functions triggers second phase of enabling new device.
+ * @param hub
+ * @param port
+ * @param status
+ */
+static void usb_hub_port_reset_completed(usb_hub_info_t *hub,
+    uint16_t port, uint32_t status) {
+	usb_log_debug("Port %zu reset complete.\n", (size_t) port);
+	if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) {
+		/* Finalize device adding. */
+		usb_hub_port_t *the_port = hub->ports + port;
+		fibril_mutex_lock(&the_port->reset_mutex);
+		the_port->reset_completed = true;
+		the_port->reset_okay = true;
+		fibril_condvar_broadcast(&the_port->reset_cv);
+		fibril_mutex_unlock(&the_port->reset_mutex);
+	} else {
+		usb_log_warning(
+		    "Port %zu reset complete but port not enabled.\n",
+		    (size_t) port);
+	}
+	/* Clear the port reset change. */
+	int rc = usb_hub_clear_port_feature(hub->control_pipe,
+	    port, USB_HUB_FEATURE_C_PORT_RESET);
+	if (rc != EOK) {
+		usb_log_error("Failed to clear port %d reset feature: %s.\n",
+		    port, str_error(rc));
+	}
+}
+
+/**
+ * Process over current condition on port.
+ *
+ * Turn off the power on the port.
+ *
+ * @param hub hub representation
+ * @param port port number, starting from 1
+ */
+static void usb_hub_port_over_current(usb_hub_info_t *hub,
+    uint16_t port, uint32_t status) {
+	int opResult;
+	if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)) {
+		opResult = usb_hub_clear_port_feature(hub->control_pipe,
+		    port, USB_HUB_FEATURE_PORT_POWER);
+		if (opResult != EOK) {
+			usb_log_error("Cannot power off port %d; %s\n",
+			    port, str_error(opResult));
+		}
+	} else {
+		opResult = usb_hub_set_port_feature(hub->control_pipe,
+		    port, USB_HUB_FEATURE_PORT_POWER);
+		if (opResult != EOK) {
+			usb_log_error("Cannot power on port %d; %s\n",
+			    port, str_error(opResult));
+		}
+	}
+}
+
+/** Retrieve port status.
+ *
+ * @param[in] ctrl_pipe Control pipe to use.
+ * @param[in] port Port number (starting at 1).
+ * @param[out] status Where to store the port status.
+ * @return Error code.
+ */
+static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
+    usb_port_status_t *status) {
+	size_t recv_size;
+	usb_device_request_setup_packet_t request;
+	usb_port_status_t status_tmp;
+
+	usb_hub_set_port_status_request(&request, port);
+	int rc = usb_pipe_control_read(ctrl_pipe,
+	    &request, sizeof (usb_device_request_setup_packet_t),
+	    &status_tmp, sizeof (status_tmp), &recv_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (recv_size != sizeof (status_tmp)) {
+		return ELIMIT;
+	}
+
+	if (status != NULL) {
+		*status = status_tmp;
+	}
+
+	return EOK;
+}
+
+/** Callback for enabling a specific port.
+ *
+ * We wait on a CV until port is reseted.
+ * That is announced via change on interrupt pipe.
+ *
+ * @param port_no Port number (starting at 1).
+ * @param arg Custom argument, points to @c usb_hub_info_t.
+ * @return Error code.
+ */
+static int enable_port_callback(int port_no, void *arg) {
+	usb_hub_info_t *hub = arg;
+	int rc;
+	usb_device_request_setup_packet_t request;
+	usb_hub_port_t *my_port = hub->ports + port_no;
+
+	usb_hub_set_reset_port_request(&request, port_no);
+	rc = usb_pipe_control_write(hub->control_pipe,
+	    &request, sizeof (request), NULL, 0);
+	if (rc != EOK) {
+		usb_log_warning("Port reset failed: %s.\n", str_error(rc));
+		return rc;
+	}
+
+	/*
+	 * Wait until reset completes.
+	 */
+	fibril_mutex_lock(&my_port->reset_mutex);
+	while (!my_port->reset_completed) {
+		fibril_condvar_wait(&my_port->reset_cv, &my_port->reset_mutex);
+	}
+	fibril_mutex_unlock(&my_port->reset_mutex);
+
+	if (my_port->reset_okay) {
+		return EOK;
+	} else {
+		return ESTALL;
+	}
+}
+
+/** Fibril for adding a new device.
+ *
+ * Separate fibril is needed because the port reset completion is announced
+ * via interrupt pipe and thus we cannot block here.
+ *
+ * @param arg Pointer to struct add_device_phase1.
+ * @return 0 Always.
+ */
+static int add_device_phase1_worker_fibril(void *arg) {
+	struct add_device_phase1 *data
+	    = (struct add_device_phase1 *) arg;
+
+	usb_address_t new_address;
+	devman_handle_t child_handle;
+
+	int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
+	    &data->hub->connection, data->speed,
+	    enable_port_callback, (int) data->port, data->hub,
+	    &new_address, &child_handle,
+	    NULL, NULL, NULL);
+
+	if (rc != EOK) {
+		usb_log_error("Failed registering device on port %zu: %s.\n",
+		    data->port, str_error(rc));
+		goto leave;
+	}
+
+	fibril_mutex_lock(&data->hub->port_mutex);
+	data->hub->ports[data->port].attached_device.handle = child_handle;
+	data->hub->ports[data->port].attached_device.address = new_address;
+	fibril_mutex_unlock(&data->hub->port_mutex);
+
+	usb_log_info("Detected new device on `%s' (port %zu), "
+	    "address %d (handle %" PRIun ").\n",
+	    data->hub->usb_device->ddf_dev->name, data->port,
+	    new_address, child_handle);
+
+leave:
+	free(arg);
+
+	fibril_mutex_lock(&data->hub->pending_ops_mutex);
+	assert(data->hub->pending_ops_count > 0);
+	data->hub->pending_ops_count--;
+	fibril_condvar_signal(&data->hub->pending_ops_cv);
+	fibril_mutex_unlock(&data->hub->pending_ops_mutex);
+
+
+	return EOK;
+}
+
+/** Start device adding when connection change is detected.
+ *
+ * This fires a new fibril to complete the device addition.
+ *
+ * @param hub Hub where the change occured.
+ * @param port Port index (starting at 1).
+ * @param speed Speed of the device.
+ * @return Error code.
+ */
+static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
+    usb_speed_t speed) {
+	struct add_device_phase1 *data
+	    = malloc(sizeof (struct add_device_phase1));
+	if (data == NULL) {
+		return ENOMEM;
+	}
+	data->hub = hub;
+	data->port = port;
+	data->speed = speed;
+
+	usb_hub_port_t *the_port = hub->ports + port;
+
+	fibril_mutex_lock(&the_port->reset_mutex);
+	the_port->reset_completed = false;
+	fibril_mutex_unlock(&the_port->reset_mutex);
+
+	int rc = usb_hub_clear_port_feature(hub->control_pipe, port,
+	    USB_HUB_FEATURE_C_PORT_CONNECTION);
+	if (rc != EOK) {
+		free(data);
+		usb_log_warning("Failed to clear port change flag: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
+	if (fibril == 0) {
+		free(data);
+		return ENOMEM;
+	}
+	fibril_mutex_lock(&hub->pending_ops_mutex);
+	hub->pending_ops_count++;
+	fibril_mutex_unlock(&hub->pending_ops_mutex);
+	fibril_add_ready(fibril);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/ports.h
===================================================================
--- uspace/drv/usbhub/ports.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/ports.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,80 @@
+/*
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * Hub ports related functions.
+ */
+#ifndef DRV_USBHUB_PORTS_H
+#define DRV_USBHUB_PORTS_H
+
+#include <usb/dev/driver.h>
+#include <usb/dev/hub.h>
+
+typedef struct usb_hub_info_t usb_hub_info_t;
+
+/** Information about single port on a hub. */
+typedef struct {
+	/** Mutex needed by CV for checking port reset. */
+	fibril_mutex_t reset_mutex;
+	/** CV for waiting to port reset completion. */
+	fibril_condvar_t reset_cv;
+	/** Whether port reset is completed.
+	 * Guarded by @c reset_mutex.
+	 */
+	bool reset_completed;
+	/** Whether to announce the port reset as successful. */
+	bool reset_okay;
+
+	/** Information about attached device. */
+	usb_hc_attached_device_t attached_device;
+} usb_hub_port_t;
+
+/** Initialize hub port information.
+ *
+ * @param port Port to be initialized.
+ */
+static inline void usb_hub_port_init(usb_hub_port_t *port) {
+	port->attached_device.address = -1;
+	port->attached_device.handle = 0;
+	fibril_mutex_initialize(&port->reset_mutex);
+	fibril_condvar_initialize(&port->reset_cv);
+}
+
+
+void usb_hub_process_port_interrupt(usb_hub_info_t *hub,
+	uint16_t port);
+
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/usbhub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * @brief usb hub main functionality
+ */
+
+#include <ddf/driver.h>
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <inttypes.h>
+
+#include <usb_iface.h>
+#include <usb/ddfiface.h>
+#include <usb/descriptor.h>
+#include <usb/dev/recognise.h>
+#include <usb/dev/request.h>
+#include <usb/classes/hub.h>
+#include <usb/dev/poll.h>
+#include <stdio.h>
+
+#include "usbhub.h"
+#include "usbhub_private.h"
+#include "port_status.h"
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/classes/classes.h>
+
+
+static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev);
+
+static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info);
+
+static int usb_hub_set_configuration(usb_hub_info_t *hub_info);
+
+static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info);
+
+static int usb_process_hub_over_current(usb_hub_info_t *hub_info,
+    usb_hub_status_t status);
+
+static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info,
+    usb_hub_status_t status);
+
+static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info);
+
+static void usb_hub_polling_terminated_callback(usb_device_t *device,
+    bool was_error, void *data);
+
+
+//*********************************************
+//
+//  hub driver code, initialization
+//
+//*********************************************
+
+/**
+ * Initialize hub device driver fibril
+ *
+ * Creates hub representation and fibril that periodically checks hub`s status.
+ * Hub representation is passed to the fibril.
+ * @param usb_dev generic usb device information
+ * @return error code
+ */
+int usb_hub_add_device(usb_device_t *usb_dev) {
+	if (!usb_dev) return EINVAL;
+	usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
+	//create hc connection
+	usb_log_debug("Initializing USB wire abstraction.\n");
+	int opResult = usb_hc_connection_initialize_from_device(
+	    &hub_info->connection,
+	    hub_info->usb_device->ddf_dev);
+	if (opResult != EOK) {
+		usb_log_error("Could not initialize connection to device, "
+		    " %s\n",
+		    str_error(opResult));
+		free(hub_info);
+		return opResult;
+	}
+
+	//set hub configuration
+	opResult = usb_hub_set_configuration(hub_info);
+	if (opResult != EOK) {
+		usb_log_error("Could not set hub configuration, %s\n",
+		    str_error(opResult));
+		free(hub_info);
+		return opResult;
+	}
+	//get port count and create attached_devs
+	opResult = usb_hub_process_hub_specific_info(hub_info);
+	if (opResult != EOK) {
+		usb_log_error("Could process hub specific info, %s\n",
+		    str_error(opResult));
+		free(hub_info);
+		return opResult;
+	}
+
+	usb_log_debug("Creating 'hub' function in DDF.\n");
+	ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
+	    fun_exposed, "hub");
+	assert(hub_fun != NULL);
+	hub_fun->ops = NULL;
+
+	opResult = ddf_fun_bind(hub_fun);
+	assert(opResult == EOK);
+	opResult = ddf_fun_add_to_class(hub_fun, "hub");
+	assert(opResult == EOK);
+
+	opResult = usb_hub_start_hub_fibril(hub_info);
+	if (opResult != EOK)
+		free(hub_info);
+	return opResult;
+}
+
+/** Callback for polling hub for changes.
+ *
+ * @param dev Device where the change occured.
+ * @param change_bitmap Bitmap of changed ports.
+ * @param change_bitmap_size Size of the bitmap in bytes.
+ * @param arg Custom argument, points to @c usb_hub_info_t.
+ * @return Whether to continue polling.
+ */
+bool hub_port_changes_callback(usb_device_t *dev,
+    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) {
+	usb_log_debug("hub_port_changes_callback\n");
+	usb_hub_info_t *hub = (usb_hub_info_t *) arg;
+
+	/* FIXME: check that we received enough bytes. */
+	if (change_bitmap_size == 0) {
+		goto leave;
+	}
+
+	bool change;
+	change = ((uint8_t*) change_bitmap)[0] & 1;
+	if (change) {
+		usb_hub_process_global_interrupt(hub);
+	}
+
+	size_t port;
+	for (port = 1; port < hub->port_count + 1; port++) {
+		bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
+		if (change) {
+			usb_hub_process_port_interrupt(hub, port);
+		}
+	}
+leave:
+	/* FIXME: proper interval. */
+	async_usleep(1000 * 250);
+
+	return true;
+}
+
+
+//*********************************************
+//
+//  support functions
+//
+//*********************************************
+
+/**
+ * create usb_hub_info_t structure
+ *
+ * Does only basic copying of known information into new structure.
+ * @param usb_dev usb device structure
+ * @return basic usb_hub_info_t structure
+ */
+static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev) {
+	usb_hub_info_t * result = malloc(sizeof (usb_hub_info_t));
+	if (!result) return NULL;
+	result->usb_device = usb_dev;
+	result->status_change_pipe = usb_dev->pipes[0].pipe;
+	result->control_pipe = &usb_dev->ctrl_pipe;
+	result->is_default_address_used = false;
+
+	result->ports = NULL;
+	result->port_count = (size_t) - 1;
+	fibril_mutex_initialize(&result->port_mutex);
+
+	fibril_mutex_initialize(&result->pending_ops_mutex);
+	fibril_condvar_initialize(&result->pending_ops_cv);
+	result->pending_ops_count = 0;
+	return result;
+}
+
+/**
+ * Load hub-specific information into hub_info structure and process if needed
+ *
+ * Particularly read port count and initialize structure holding port
+ * information. If there are non-removable devices, start initializing them.
+ * This function is hub-specific and should be run only after the hub is
+ * configured using usb_hub_set_configuration function.
+ * @param hub_info hub representation
+ * @return error code
+ */
+static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) {
+	// get hub descriptor
+	usb_log_debug("Creating serialized descriptor\n");
+	uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];
+	usb_hub_descriptor_t * descriptor;
+	int opResult;
+
+	size_t received_size;
+	opResult = usb_request_get_descriptor(hub_info->control_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
+	    USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
+
+	if (opResult != EOK) {
+		usb_log_error("Failed when receiving hub descriptor, "
+		    "%s\n",
+		    str_error(opResult));
+		free(serialized_descriptor);
+		return opResult;
+	}
+	usb_log_debug2("Deserializing descriptor\n");
+	descriptor = usb_create_deserialized_hub_desriptor(
+	    serialized_descriptor);
+	if (descriptor == NULL) {
+		usb_log_warning("could not deserialize descriptor \n");
+		return ENOMEM;
+	}
+	usb_log_debug("setting port count to %d\n", descriptor->ports_count);
+	hub_info->port_count = descriptor->ports_count;
+	bool is_power_switched =
+	    ((descriptor->hub_characteristics & 1) == 0);
+	bool has_individual_port_powering =
+	    ((descriptor->hub_characteristics & 1) != 0);
+	hub_info->ports = malloc(
+	    sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
+	if (!hub_info->ports) {
+		return ENOMEM;
+	}
+	size_t port;
+	for (port = 0; port < hub_info->port_count + 1; ++port) {
+		usb_hub_port_init(&hub_info->ports[port]);
+	}
+	if (is_power_switched) {
+		usb_log_debug("Hub power switched\n");
+
+		if (!has_individual_port_powering) {
+			//this setting actually makes no difference
+			usb_log_debug("Hub has global powering\n");
+		}
+
+		for (port = 1; port <= hub_info->port_count; ++port) {
+			usb_log_debug("Powering port %zu.\n", port);
+			opResult = usb_hub_set_port_feature(hub_info->control_pipe,
+			    port, USB_HUB_FEATURE_PORT_POWER);
+			if (opResult != EOK) {
+				usb_log_error("Cannot power on port %zu: %s.\n",
+				    port, str_error(opResult));
+			}
+		}
+
+	} else {
+		usb_log_debug("Power not switched, not going to be powered\n");
+	}
+	usb_log_debug2("Freeing data\n");
+	free(descriptor);
+	return EOK;
+}
+
+/**
+ * Set configuration of hub
+ *
+ * Check whether there is at least one configuration and sets the first one.
+ * This function should be run prior to running any hub-specific action.
+ * @param hub_info hub representation
+ * @return error code
+ */
+static int usb_hub_set_configuration(usb_hub_info_t *hub_info) {
+	//device descriptor
+	usb_standard_device_descriptor_t *std_descriptor
+	    = &hub_info->usb_device->descriptors.device;
+	usb_log_debug("Hub has %d configurations\n",
+	    std_descriptor->configuration_count);
+	if (std_descriptor->configuration_count < 1) {
+		usb_log_error("There are no configurations available\n");
+		return EINVAL;
+	}
+
+	usb_standard_configuration_descriptor_t *config_descriptor
+	    = (usb_standard_configuration_descriptor_t *)
+	    hub_info->usb_device->descriptors.configuration;
+
+	/* Set configuration. */
+	int opResult = usb_request_set_configuration(
+	    &hub_info->usb_device->ctrl_pipe,
+	    config_descriptor->configuration_number);
+
+	if (opResult != EOK) {
+		usb_log_error("Failed to set hub configuration: %s.\n",
+		    str_error(opResult));
+		return opResult;
+	}
+	usb_log_debug("\tUsed configuration %d\n",
+	    config_descriptor->configuration_number);
+
+	return EOK;
+}
+
+/**
+ * create and start fibril with hub control loop
+ *
+ * Before the fibril is started, the control pipe and host controller
+ * connection of the hub is open.
+ *
+ * @param hub_info hub representing structure
+ * @return error code
+ */
+static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info) {
+	int rc;
+
+	rc = usb_device_auto_poll(hub_info->usb_device, 0,
+	    hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
+	    usb_hub_polling_terminated_callback, hub_info);
+	if (rc != EOK) {
+		usb_log_error("Failed to create polling fibril: %s.\n",
+		    str_error(rc));
+		free(hub_info);
+		return rc;
+	}
+
+	usb_log_info("Controlling hub `%s' (%zu ports).\n",
+	    hub_info->usb_device->ddf_dev->name, hub_info->port_count);
+	return EOK;
+}
+
+//*********************************************
+//
+//  change handling functions
+//
+//*********************************************
+
+/**
+ * process hub over current change
+ *
+ * This means either to power off the hub or power it on.
+ * @param hub_info hub instance
+ * @param status hub status bitmask
+ * @return error code
+ */
+static int usb_process_hub_over_current(usb_hub_info_t *hub_info,
+    usb_hub_status_t status) {
+	int opResult;
+	if (usb_hub_is_status(status, USB_HUB_FEATURE_HUB_OVER_CURRENT)) {
+		//poweroff all ports
+		unsigned int port;
+		for (port = 1; port <= hub_info->port_count; ++port) {
+			opResult = usb_hub_clear_port_feature(
+			    hub_info->control_pipe, port,
+			    USB_HUB_FEATURE_PORT_POWER);
+			if (opResult != EOK) {
+				usb_log_warning(
+				    "Cannot power off port %d;  %s\n",
+				    port, str_error(opResult));
+			}
+		}
+	} else {
+		//power all ports
+		unsigned int port;
+		for (port = 1; port <= hub_info->port_count; ++port) {
+			opResult = usb_hub_set_port_feature(
+			    hub_info->control_pipe, port,
+			    USB_HUB_FEATURE_PORT_POWER);
+			if (opResult != EOK) {
+				usb_log_warning(
+				    "Cannot power off port %d;  %s\n",
+				    port, str_error(opResult));
+			}
+		}
+	}
+	return opResult;
+}
+
+/**
+ * process hub local power change
+ *
+ * This change is ignored.
+ * @param hub_info hub instance
+ * @param status hub status bitmask
+ * @return error code
+ */
+static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info,
+    usb_hub_status_t status) {
+	int opResult = EOK;
+	opResult = usb_hub_clear_feature(hub_info->control_pipe,
+	    USB_HUB_FEATURE_C_HUB_LOCAL_POWER);
+	if (opResult != EOK) {
+		usb_log_error("Cannnot clear hub power change flag: "
+		    "%s\n",
+		    str_error(opResult));
+	}
+	return opResult;
+}
+
+/**
+ * process hub interrupts
+ *
+ * The change can be either in the over-current condition or
+ * local-power change.
+ * @param hub_info hub instance
+ */
+static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info) {
+	usb_log_debug("Global interrupt on a hub\n");
+	usb_pipe_t *pipe = hub_info->control_pipe;
+	int opResult;
+
+	usb_port_status_t status;
+	size_t rcvd_size;
+	usb_device_request_setup_packet_t request;
+	//int opResult;
+	usb_hub_set_hub_status_request(&request);
+	//endpoint 0
+
+	opResult = usb_pipe_control_read(
+	    pipe,
+	    &request, sizeof (usb_device_request_setup_packet_t),
+	    &status, 4, &rcvd_size
+	    );
+	if (opResult != EOK) {
+		usb_log_error("Could not get hub status: %s\n",
+		    str_error(opResult));
+		return;
+	}
+	if (rcvd_size != sizeof (usb_port_status_t)) {
+		usb_log_error("Received status has incorrect size\n");
+		return;
+	}
+	//port reset
+	if (
+	    usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) {
+		usb_process_hub_over_current(hub_info, status);
+	}
+	if (
+	    usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) {
+		usb_process_hub_local_power_change(hub_info, status);
+	}
+}
+
+/**
+ * callback called from hub polling fibril when the fibril terminates
+ *
+ * Should perform a cleanup - deletes hub_info.
+ * @param device usb device afected
+ * @param was_error indicates that the fibril is stoped due to an error
+ * @param data pointer to usb_hub_info_t structure
+ */
+static void usb_hub_polling_terminated_callback(usb_device_t *device,
+    bool was_error, void *data) {
+	usb_hub_info_t * hub = data;
+	assert(hub);
+
+	fibril_mutex_lock(&hub->pending_ops_mutex);
+
+	/* The device is dead. However there might be some pending operations
+	 * that we need to wait for.
+	 * One of them is device adding in progress.
+	 * The respective fibril is probably waiting for status change
+	 * in port reset (port enable) callback.
+	 * Such change would never come (otherwise we would not be here).
+	 * Thus, we would flush all pending port resets.
+	 */
+	if (hub->pending_ops_count > 0) {
+		fibril_mutex_lock(&hub->port_mutex);
+		size_t port;
+		for (port = 0; port < hub->port_count; port++) {
+			usb_hub_port_t *the_port = hub->ports + port;
+			fibril_mutex_lock(&the_port->reset_mutex);
+			the_port->reset_completed = true;
+			the_port->reset_okay = false;
+			fibril_condvar_broadcast(&the_port->reset_cv);
+			fibril_mutex_unlock(&the_port->reset_mutex);
+		}
+		fibril_mutex_unlock(&hub->port_mutex);
+	}
+	/* And now wait for them. */
+	while (hub->pending_ops_count > 0) {
+		fibril_condvar_wait(&hub->pending_ops_cv,
+		    &hub->pending_ops_mutex);
+	}
+	fibril_mutex_unlock(&hub->pending_ops_mutex);
+
+	usb_device_destroy(hub->usb_device);
+
+	free(hub->ports);
+	free(hub);
+}
+
+
+
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/usbhub.h
===================================================================
--- uspace/drv/usbhub/usbhub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/usbhub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010 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 drvusbhub
+ * @{
+ */
+/** @file
+ * @brief Hub driver.
+ */
+#ifndef DRV_USBHUB_USBHUB_H
+#define DRV_USBHUB_USBHUB_H
+
+#include <ipc/devman.h>
+#include <ddf/driver.h>
+
+#include <usb/dev/hub.h>
+#include <usb/classes/hub.h>
+
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+
+#include <fibril_synch.h>
+
+#define NAME "usbhub"
+
+#include "ports.h"
+
+/** Information about attached hub. */
+struct usb_hub_info_t {
+	/** Number of ports. */
+	size_t port_count;
+
+	/** attached device handles, for each port one */
+	usb_hub_port_t *ports;
+
+	fibril_mutex_t port_mutex;
+
+	/** connection to hcd */
+	usb_hc_connection_t connection;
+
+	/** default address is used indicator
+	 *
+	 * If default address is requested by this device, it cannot
+	 * be requested by the same hub again, otherwise a deadlock will occur.
+	 */
+	bool is_default_address_used;
+
+	/** convenience pointer to status change pipe
+	 *
+	 * Status change pipe is initialized in usb_device structure. This is
+	 * pointer into this structure, so that it does not have to be
+	 * searched again and again for the 'right pipe'.
+	 */
+	usb_pipe_t * status_change_pipe;
+
+	/** convenience pointer to control pipe
+	 *
+	 * Control pipe is initialized in usb_device structure. This is
+	 * pointer into this structure, so that it does not have to be
+	 * searched again and again for the 'right pipe'.
+	 */
+	usb_pipe_t * control_pipe;
+
+	/** generic usb device data*/
+	usb_device_t * usb_device;
+
+	/** Number of pending operations on the mutex to prevent shooting
+	 * ourselves in the foot.
+	 * When the hub is disconnected but we are in the middle of some
+	 * operation, we cannot destroy this structure right away because
+	 * the pending operation might use it.
+	 */
+	size_t pending_ops_count;
+	/** Guard for pending_ops_count. */
+	fibril_mutex_t pending_ops_mutex;
+	/** Condition variable for pending_ops_count. */
+	fibril_condvar_t pending_ops_cv;
+
+};
+
+int usb_hub_add_device(usb_device_t *usb_dev);
+
+bool hub_port_changes_callback(usb_device_t *dev,
+    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/usbhub.ma
===================================================================
--- uspace/drv/usbhub/usbhub.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/usbhub.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,2 @@
+10 usb&hub
+10 usb&class=hub
Index: uspace/drv/usbhub/usbhub_private.h
===================================================================
--- uspace/drv/usbhub/usbhub_private.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/usbhub_private.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * @brief Hub driver private definitions
+ */
+
+#ifndef USBHUB_PRIVATE_H
+#define	USBHUB_PRIVATE_H
+
+#include "usbhub.h"
+
+#include <adt/list.h>
+#include <bool.h>
+#include <ddf/driver.h>
+#include <fibril_synch.h>
+
+#include <usb/classes/hub.h>
+#include <usb/usb.h>
+#include <usb/debug.h>
+#include <usb/dev/request.h>
+
+//************
+//
+// convenience define for malloc
+//
+//************
+
+
+usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device);
+
+/**
+ * Set the device request to be a get hub descriptor request.
+ * @warning the size is allways set to USB_HUB_MAX_DESCRIPTOR_SIZE
+ * @param request
+ * @param addr
+ */
+static inline void usb_hub_set_descriptor_request(
+    usb_device_request_setup_packet_t * request
+    ) {
+	request->index = 0;
+	request->request_type = USB_HUB_REQ_TYPE_GET_DESCRIPTOR;
+	request->request = USB_HUB_REQUEST_GET_DESCRIPTOR;
+	request->value_high = USB_DESCTYPE_HUB;
+	request->value_low = 0;
+	request->length = USB_HUB_MAX_DESCRIPTOR_SIZE;
+}
+
+/**
+ * Clear feature on hub port.
+ *
+ * @param hc Host controller telephone
+ * @param address Hub address
+ * @param port_index Port
+ * @param feature Feature selector
+ * @return Operation result
+ */
+static inline int usb_hub_clear_port_feature(usb_pipe_t *pipe,
+    int port_index,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
+		.request = USB_DEVREQ_CLEAR_FEATURE,
+		.length = 0,
+		.index = port_index
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof (clear_request), NULL, 0);
+}
+
+/**
+ * Clear feature on hub port.
+ *
+ * @param hc Host controller telephone
+ * @param address Hub address
+ * @param port_index Port
+ * @param feature Feature selector
+ * @return Operation result
+ */
+static inline int usb_hub_set_port_feature(usb_pipe_t *pipe,
+    int port_index,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
+		.request = USB_DEVREQ_SET_FEATURE,
+		.length = 0,
+		.index = port_index
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof (clear_request), NULL, 0);
+}
+
+/**
+ * Clear feature on hub port.
+ *
+ * @param pipe pipe to hub control endpoint
+ * @param feature Feature selector
+ * @return Operation result
+ */
+static inline int usb_hub_clear_feature(usb_pipe_t *pipe,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
+		.request = USB_DEVREQ_CLEAR_FEATURE,
+		.length = 0,
+		.index = 0
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof (clear_request), NULL, 0);
+}
+
+/**
+ * Clear feature on hub port.
+ *
+ * @param pipe pipe to hub control endpoint
+ * @param feature Feature selector
+ * @return Operation result
+ */
+static inline int usb_hub_set_feature(usb_pipe_t *pipe,
+    usb_hub_class_feature_t feature) {
+
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
+		.request = USB_DEVREQ_SET_FEATURE,
+		.length = 0,
+		.index = 0
+	};
+	clear_request.value = feature;
+	return usb_pipe_control_write(pipe, &clear_request,
+	    sizeof (clear_request), NULL, 0);
+}
+
+
+void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t * descriptor);
+
+void usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor,
+    void * serialized_descriptor);
+
+usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
+    void * serialized_descriptor);
+
+void usb_deserialize_hub_desriptor(void * serialized_descriptor,
+    usb_hub_descriptor_t * descriptor);
+
+
+#endif	/* USBHUB_PRIVATE_H */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbhub/utils.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * @brief various utilities
+ */
+#include <ddf/driver.h>
+#include <bool.h>
+#include <errno.h>
+
+#include <usbhc_iface.h>
+#include <usb/descriptor.h>
+#include <usb/classes/hub.h>
+
+#include "usbhub.h"
+#include "usbhub_private.h"
+#include "port_status.h"
+
+
+size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
+
+//*********************************************
+//
+//  various utils
+//
+//*********************************************
+
+//hub descriptor utils
+
+/**
+ * create uint8_t array with serialized descriptor
+ *
+ * @param descriptor
+ * @return newly created serializd descriptor pointer
+ */
+void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t *descriptor) {
+	//base size
+	size_t size = 7;
+	//variable size according to port count
+	size_t var_size = (descriptor->ports_count + 7) / 8;
+	size += 2 * var_size;
+	uint8_t * result = malloc(size);
+	//size
+	if (result)
+		usb_serialize_hub_descriptor(descriptor, result);
+	return result;
+}
+
+/**
+ * serialize descriptor into given buffer
+ *
+ * The buffer size is not checked.
+ * @param descriptor
+ * @param serialized_descriptor
+ */
+void usb_serialize_hub_descriptor(usb_hub_descriptor_t *descriptor,
+    void * serialized_descriptor) {
+	//base size
+	uint8_t * sdescriptor = serialized_descriptor;
+	size_t size = 7;
+	//variable size according to port count
+	size_t var_size = (descriptor->ports_count + 7) / 8;
+	size += 2 * var_size;
+	//size
+	sdescriptor[0] = size;
+	//descriptor type
+	sdescriptor[1] = USB_DESCTYPE_HUB;
+	sdescriptor[2] = descriptor->ports_count;
+	/// @fixme handling of endianness??
+	sdescriptor[3] = descriptor->hub_characteristics / 256;
+	sdescriptor[4] = descriptor->hub_characteristics % 256;
+	sdescriptor[5] = descriptor->pwr_on_2_good_time;
+	sdescriptor[6] = descriptor->current_requirement;
+
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		sdescriptor[7 + i] = descriptor->devices_removable[i];
+	}
+	for (i = 0; i < var_size; ++i) {
+		sdescriptor[7 + var_size + i] = 255;
+	}
+}
+
+/**
+ * create deserialized desriptor structure out of serialized descriptor
+ *
+ * The serialized descriptor must be proper usb hub descriptor,
+ * otherwise an eerror might occur.
+ *
+ * @param sdescriptor serialized descriptor
+ * @return newly created deserialized descriptor pointer
+ */
+usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
+    void *serialized_descriptor) {
+	uint8_t * sdescriptor = serialized_descriptor;
+
+	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
+		usb_log_warning("trying to deserialize wrong descriptor %x\n",
+		    sdescriptor[1]);
+		return NULL;
+	}
+
+	usb_hub_descriptor_t * result = malloc(sizeof (usb_hub_descriptor_t));
+	if (result)
+		usb_deserialize_hub_desriptor(serialized_descriptor, result);
+	return result;
+}
+
+/**
+ * deserialize descriptor into given pointer
+ * 
+ * @param serialized_descriptor
+ * @param descriptor
+ * @return
+ */
+void usb_deserialize_hub_desriptor(
+    void * serialized_descriptor, usb_hub_descriptor_t *descriptor) {
+	uint8_t * sdescriptor = serialized_descriptor;
+	descriptor->ports_count = sdescriptor[2];
+	/// @fixme handling of endianness??
+	descriptor->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
+	descriptor->pwr_on_2_good_time = sdescriptor[5];
+	descriptor->current_requirement = sdescriptor[6];
+	size_t var_size = (descriptor->ports_count + 7) / 8;
+	//descriptor->devices_removable = (uint8_t*) malloc(var_size);
+
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		descriptor->devices_removable[i] = sdescriptor[7 + i];
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/Makefile
===================================================================
--- uspace/drv/usbmast/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = usbmast
+
+SOURCES = \
+	inquiry.c \
+	main.c \
+	mast.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmast/cmds.h
===================================================================
--- uspace/drv/usbmast/cmds.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/cmds.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,85 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef USB_USBMAST_CMDS_H_
+#define USB_USBMAST_CMDS_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint32_t dCBWSignature;
+	uint32_t dCBWTag;
+	uint32_t dCBWDataTransferLength;
+	uint8_t bmCBWFlags;
+	uint8_t bCBWLUN;
+	uint8_t bCBWBLength;
+	uint8_t CBWCB[16];
+} __attribute__((packed)) usb_massstor_cbw_t;
+
+typedef struct {
+	uint32_t dCSWSignature;
+	uint32_t dCSWTag;
+	uint32_t dCSWDataResidue;
+	uint8_t dCSWStatus;
+} __attribute__((packed)) usb_massstor_csw_t;
+
+static inline void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
+    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
+    uint8_t lun, uint8_t cmd_len, uint8_t *cmd)
+{
+	cbw->dCBWSignature = uint32_host2usb(0x43425355);
+	cbw->dCBWTag = tag;
+	cbw->dCBWDataTransferLength = transfer_length;
+
+	cbw->bmCBWFlags = 0;
+	if (dir == USB_DIRECTION_IN) {
+		cbw->bmCBWFlags |= (1 << 7);
+	}
+
+	/* Only lowest 4 bits. */
+	cbw->bCBWLUN = lun & 0x0F;
+
+	/* Only lowest 5 bits. */
+	cbw->bCBWBLength = cmd_len & 0x1F;
+
+	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/inquiry.c
===================================================================
--- uspace/drv/usbmast/inquiry.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/inquiry.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,193 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB mass storage driver.
+ */
+#include <usb/dev/driver.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/massstor.h>
+#include <errno.h>
+#include <str_error.h>
+#include <str.h>
+#include <ctype.h>
+#include "cmds.h"
+#include "scsi.h"
+#include "mast.h"
+
+#define BITS_GET_MASK(type, bitcount) (((type)(1 << (bitcount)))-1)
+#define BITS_GET_MID_MASK(type, bitcount, offset) \
+	((type)( BITS_GET_MASK(type, (bitcount) + (offset)) - BITS_GET_MASK(type, bitcount) ))
+#define BITS_GET(type, number, bitcount, offset) \
+	((type)( (number) & (BITS_GET_MID_MASK(type, bitcount, offset)) ) >> (offset))
+
+#define INQUIRY_RESPONSE_LENGTH 36
+
+#define STR_UNKNOWN "<unknown>"
+
+/** String constants for SCSI peripheral device types. */
+static const char *str_peripheral_device_types[] = {
+	"direct-access device",
+	"sequential-access device",
+	"printer device",
+	"processor device",
+	"write-once device",
+	"CDROM device",
+	"scanner device",
+	"optical memory device",
+	"medium changer",
+	"communications device",
+	"graphic arts pre-press device",
+	"graphic arts pre-press device",
+	"storage array controller device",
+	"enclosure services device",
+	"simplified direct-access device",
+	"optical card reader/writer device",
+	"bridging expander",
+	"object-based storage device",
+	"automation driver interface",
+	STR_UNKNOWN, // 0x13
+	STR_UNKNOWN, // 0x14
+	STR_UNKNOWN, // 0x15
+	STR_UNKNOWN, // 0x16
+	STR_UNKNOWN, // 0x17
+	STR_UNKNOWN, // 0x18
+	STR_UNKNOWN, // 0x19
+	STR_UNKNOWN, // 0x1A
+	STR_UNKNOWN, // 0x1B
+	STR_UNKNOWN, // 0x1C
+	STR_UNKNOWN, // 0x1D
+	"well-known logical unit",
+	"uknown or no device state"
+};
+#define str_peripheral_device_types_count \
+	(sizeof(str_peripheral_device_types)/sizeof(str_peripheral_device_types[0]))
+
+/** Get string representation for SCSI peripheral device type.
+ *
+ * See for example here for a list
+ * http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type.
+ *
+ * @param type SCSI peripheral device type code.
+ * @return String representation.
+ */
+const char *usb_str_masstor_scsi_peripheral_device_type(int type)
+{
+	if ((type < 0)
+	    || ((size_t)type >= str_peripheral_device_types_count)) {
+		return STR_UNKNOWN;
+	}
+	return str_peripheral_device_types[type];
+}
+
+/** Trim trailing spaces from a string (rewrite with string terminator).
+ *
+ * @param name String to be trimmed (in-out parameter).
+ */
+static void trim_trailing_spaces(char *name)
+{
+	size_t len = str_length(name);
+	while ((len > 0) && isspace((int) name[len - 1])) {
+		name[len - 1] = 0;
+		len--;
+	}
+}
+
+/** Perform SCSI INQUIRY command on USB mass storage device.
+ *
+ * @param dev USB device.
+ * @param bulk_in_idx Index (in dev->pipes) of bulk in pipe.
+ * @param bulk_out_idx Index of bulk out pipe.
+ * @param inquiry_result Where to store parsed inquiry result.
+ * @return Error code.
+ */
+int usb_massstor_inquiry(usb_device_t *dev,
+    size_t bulk_in_idx, size_t bulk_out_idx,
+    usb_massstor_inquiry_result_t *inquiry_result)
+{
+	scsi_cmd_inquiry_t inquiry = {
+		.op_code = 0x12,
+		.lun_evpd = 0,
+		.page_code = 0,
+		.alloc_length = host2uint16_t_be(INQUIRY_RESPONSE_LENGTH),
+		.ctrl = 0
+	};
+	size_t response_len;
+	uint8_t response[INQUIRY_RESPONSE_LENGTH];
+
+	int rc;
+
+	rc = usb_massstor_data_in(dev, bulk_in_idx, bulk_out_idx,
+	    0xDEADBEEF, 0, (uint8_t *) &inquiry, sizeof(inquiry),
+	    response, INQUIRY_RESPONSE_LENGTH, &response_len);
+
+	if (rc != EOK) {
+		usb_log_error("Failed to probe device %s using %s: %s.\n",
+		   dev->ddf_dev->name, "SCSI:INQUIRY", str_error(rc));
+		return rc;
+	}
+
+	if (response_len < 8) {
+		usb_log_error("The SCSI response is too short.\n");
+		return ERANGE;
+	}
+
+	/*
+	 * This is an ugly part of the code. We will parse the returned
+	 * data by hand and try to get as many useful data as possible.
+	 */
+	bzero(inquiry_result, sizeof(*inquiry_result));
+
+	/* This shall be returned by all devices. */
+	inquiry_result->peripheral_device_type
+	    = BITS_GET(uint8_t, response[0], 5, 0);
+	inquiry_result->removable = BITS_GET(uint8_t, response[1], 1, 7);
+
+	if (response_len < 32) {
+		return EOK;
+	}
+
+	str_ncpy(inquiry_result->vendor_id, 9,
+	    (const char *) &response[8], 8);
+	trim_trailing_spaces(inquiry_result->vendor_id);
+
+	str_ncpy(inquiry_result->product_and_revision, 12,
+	    (const char *) &response[16], 11);
+	trim_trailing_spaces(inquiry_result->product_and_revision);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/main.c
===================================================================
--- uspace/drv/usbmast/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,151 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB mass storage driver.
+ */
+#include <usb/dev/driver.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/massstor.h>
+#include <errno.h>
+#include <str_error.h>
+#include "cmds.h"
+#include "scsi.h"
+#include "mast.h"
+
+#define NAME "usbmast"
+
+#define BULK_IN_EP 0
+#define BULK_OUT_EP 1
+
+#define GET_BULK_IN(dev) ((dev)->pipes[BULK_IN_EP].pipe)
+#define GET_BULK_OUT(dev) ((dev)->pipes[BULK_OUT_EP].pipe)
+
+static usb_endpoint_description_t bulk_in_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+static usb_endpoint_description_t bulk_out_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_OUT,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+
+usb_endpoint_description_t *mast_endpoints[] = {
+	&bulk_in_ep,
+	&bulk_out_ep,
+	NULL
+};
+
+/** Callback when new device is attached and recognized as a mass storage.
+ *
+ * @param dev Representation of a the USB device.
+ * @return Error code.
+ */
+static int usbmast_add_device(usb_device_t *dev)
+{
+	int rc;
+	const char *fun_name = "ctl";
+
+	ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
+	    fun_name);
+	if (ctl_fun == NULL) {
+		usb_log_error("Failed to create control function.\n");
+		return ENOMEM;
+	}
+	rc = ddf_fun_bind(ctl_fun);
+	if (rc != EOK) {
+		usb_log_error("Failed to bind control function: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	usb_log_info("Pretending to control mass storage `%s'.\n",
+	    dev->ddf_dev->name);
+	usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_IN_EP].pipe->endpoint_no,
+	    (size_t) dev->pipes[BULK_IN_EP].descriptor->max_packet_size);
+	usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_OUT_EP].pipe->endpoint_no,
+	    (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
+
+	size_t lun_count = usb_masstor_get_lun_count(dev);
+
+	usb_massstor_inquiry_result_t inquiry;
+	rc = usb_massstor_inquiry(dev, BULK_IN_EP, BULK_OUT_EP, &inquiry);
+	if (rc != EOK) {
+		usb_log_warning("Failed to inquiry device `%s': %s.\n",
+		    dev->ddf_dev->name, str_error(rc));
+		return EOK;
+	}
+
+	usb_log_info("Mass storage `%s': " \
+	    "`%s' by `%s' is %s (%s), %zu LUN(s).\n",
+	    dev->ddf_dev->name,
+	    inquiry.product_and_revision, inquiry.vendor_id,
+	    usb_str_masstor_scsi_peripheral_device_type(inquiry.peripheral_device_type),
+	    inquiry.removable ? "removable" : "non-removable",
+	    lun_count);
+
+	return EOK;
+}
+
+/** USB mass storage driver ops. */
+static usb_driver_ops_t usbmast_driver_ops = {
+	.add_device = usbmast_add_device,
+};
+
+/** USB mass storage driver. */
+static usb_driver_t usbmast_driver = {
+	.name = NAME,
+	.ops = &usbmast_driver_ops,
+	.endpoints = mast_endpoints
+};
+
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&usbmast_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/mast.c
===================================================================
--- uspace/drv/usbmast/mast.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/mast.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,222 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Generic functions for USB mass storage (implementation).
+ */
+#include "mast.h"
+#include "cmds.h"
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <usb/dev/request.h>
+
+bool usb_mast_verbose = true;
+
+#define MASTLOG(format, ...) \
+	do { \
+		if (usb_mast_verbose) { \
+			usb_log_debug("USB cl08: " format, ##__VA_ARGS__); \
+		} \
+	} while (false)
+
+/** Request data from mass storage device.
+ *
+ * @param bulk_in_pipe Bulk in pipe to the device.
+ * @param bulk_out_pipe Bulk out pipe to the device.
+ * @param tag Command block wrapper tag (automatically compared with answer).
+ * @param lun LUN index.
+ * @param cmd SCSI command buffer (in SCSI endianness).
+ * @param cmd_size Length of SCSI command @p cmd in bytes.
+ * @param in_buffer Buffer where to store the answer (CSW is not returned).
+ * @param in_buffer_size Size of the buffer (size of the request to the device).
+ * @param received_size Number of actually received bytes.
+ * @return Error code.
+ */
+int usb_massstor_data_in(usb_device_t *dev,
+    size_t bulk_in_pipe_index, size_t bulk_out_pipe_index,
+    uint32_t tag, uint8_t lun, void *cmd, size_t cmd_size,
+    void *in_buffer, size_t in_buffer_size, size_t *received_size)
+{
+	int rc;
+	size_t act_size;
+	usb_pipe_t *bulk_in_pipe = dev->pipes[bulk_in_pipe_index].pipe;
+	usb_pipe_t *bulk_out_pipe = dev->pipes[bulk_out_pipe_index].pipe;
+
+	/* Prepare CBW - command block wrapper */
+	usb_massstor_cbw_t cbw;
+	usb_massstor_cbw_prepare(&cbw, tag, in_buffer_size,
+	    USB_DIRECTION_IN, lun, cmd_size, cmd);
+
+	/* First, send the CBW. */
+	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
+	MASTLOG("CBW '%s' sent: %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Try to retrieve the data from the device. */
+	act_size = 0;
+	rc = usb_pipe_read(bulk_in_pipe, in_buffer, in_buffer_size, &act_size);
+	MASTLOG("Received %zuB (%s): %s.\n", act_size,
+	    usb_debug_str_buffer((uint8_t *) in_buffer, act_size, 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Read CSW. */
+	usb_massstor_csw_t csw;
+	size_t csw_size;
+	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
+	MASTLOG("CSW '%s' received (%zuB): %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+	if (csw_size != sizeof(csw)) {
+		return ERANGE;
+	}
+
+	if (csw.dCSWTag != tag) {
+		return EBADCHECKSUM;
+	}
+
+	/*
+	 * Determine the actual return value from the CSW.
+	 */
+	if (csw.dCSWStatus != 0) {
+		// FIXME: better error code
+		// FIXME: distinguish 0x01 and 0x02
+		return EXDEV;
+	}
+
+	size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
+	if (residue > in_buffer_size) {
+		return ERANGE;
+	}
+	if (act_size != in_buffer_size - residue) {
+		return ERANGE;
+	}
+	if (received_size != NULL) {
+		*received_size = in_buffer_size - residue;
+	}
+
+	return EOK;
+}
+
+/** Perform bulk-only mass storage reset.
+ *
+ * @param dev Device to be reseted.
+ * @return Error code.
+ */
+int usb_massstor_reset(usb_device_t *dev)
+{
+	return usb_control_request_set(&dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFF, 0, dev->interface_no, NULL, 0);
+}
+
+/** Perform complete reset recovery of bulk-only mass storage.
+ *
+ * Notice that no error is reported because if this fails, the error
+ * would reappear on next transaction somehow.
+ *
+ * @param dev Device to be reseted.
+ * @param bulk_in_idx Index of bulk in pipe.
+ * @param bulk_out_idx Index of bulk out pipe.
+ */
+void usb_massstor_reset_recovery(usb_device_t *dev,
+    size_t bulk_in_idx, size_t bulk_out_idx)
+{
+	/* We would ignore errors here because if this fails
+	 * we are doomed anyway and any following transaction would fail.
+	 */
+	usb_massstor_reset(dev);
+	usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[bulk_in_idx].pipe);
+	usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[bulk_out_idx].pipe);
+}
+
+/** Get max LUN of a mass storage device.
+ *
+ * @see usb_masstor_get_lun_count
+ *
+ * @warning Error from this command does not necessarily indicate malfunction
+ * of the device. Device does not need to support this request.
+ * You shall rather use usb_masstor_get_lun_count.
+ *
+ * @param dev Mass storage device.
+ * @return Error code of maximum LUN (index, not count).
+ */
+int usb_massstor_get_max_lun(usb_device_t *dev)
+{
+	uint8_t max_lun;
+	size_t data_recv_len;
+	int rc = usb_control_request_get(&dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFE, 0, dev->interface_no, &max_lun, 1, &data_recv_len);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (data_recv_len != 1) {
+		return EEMPTY;
+	}
+	return (int) max_lun;
+}
+
+/** Get number of LUNs supported by mass storage device.
+ *
+ * @warning This function hides any error during the request
+ * (typically that shall not be a problem).
+ *
+ * @param dev Mass storage device.
+ * @return Number of LUNs.
+ */
+size_t usb_masstor_get_lun_count(usb_device_t *dev)
+{
+	int max_lun = usb_massstor_get_max_lun(dev);
+	if (max_lun < 0) {
+		max_lun = 1;
+	} else {
+		max_lun++;
+	}
+
+	return (size_t) max_lun;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/mast.h
===================================================================
--- uspace/drv/usbmast/mast.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/mast.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,73 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * Generic functions for USB mass storage.
+ */
+
+#ifndef USB_USBMAST_MAST_H_
+#define USB_USBMAST_MAST_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+
+/** Result of SCSI INQUIRY command.
+ * This is already parsed structure, not the original buffer returned by
+ * the device.
+ */
+typedef struct {
+	/** SCSI peripheral device type. */
+	int peripheral_device_type;
+	/** Whether the device is removable. */
+	bool removable;
+	/** Vendor ID string. */
+	char vendor_id[9];
+	/** Product ID and product revision string. */
+	char product_and_revision[12];
+} usb_massstor_inquiry_result_t;
+
+int usb_massstor_data_in(usb_device_t *dev, size_t, size_t,
+    uint32_t, uint8_t, void *, size_t, void *, size_t, size_t *);
+int usb_massstor_reset(usb_device_t *);
+void usb_massstor_reset_recovery(usb_device_t *, size_t, size_t);
+int usb_massstor_get_max_lun(usb_device_t *);
+size_t usb_masstor_get_lun_count(usb_device_t *);
+int usb_massstor_inquiry(usb_device_t *, size_t, size_t,
+    usb_massstor_inquiry_result_t *);
+const char *usb_str_masstor_scsi_peripheral_device_type(int);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/scsi.h
===================================================================
--- uspace/drv/usbmast/scsi.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/scsi.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,54 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * SCSI related structures.
+ */
+
+#ifndef USB_USBMAST_SCSI_H_
+#define USB_USBMAST_SCSI_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint8_t op_code;
+	uint8_t lun_evpd;
+	uint8_t page_code;
+	uint16_t alloc_length;
+	uint8_t ctrl;
+} __attribute__((packed)) scsi_cmd_inquiry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmast/usbmast.ma
===================================================================
--- uspace/drv/usbmast/usbmast.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmast/usbmast.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1 @@
+50 usb&interface&class=mass-storage&subclass=0x06&protocol=0x50
Index: uspace/drv/usbmid/Makefile
===================================================================
--- uspace/drv/usbmid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+	
+BINARY = usbmid
+
+SOURCES = \
+	dump.c \
+	explore.c \
+	main.c \
+	usbmid.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmid/dump.c
===================================================================
--- uspace/drv/usbmid/dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,120 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Dumping and debugging functions.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/dp.h>
+#include <usb/classes/classes.h>
+#include "usbmid.h"
+
+/** Dump found descriptor.
+ *
+ * @param data Descriptor data.
+ * @param depth Nesting depth.
+ */
+static void dump_tree_descriptor(uint8_t *data, size_t depth)
+{
+	if (data == NULL) {
+		return;
+	}
+	int type = (int) *(data + 1);
+	if (type == USB_DESCTYPE_INTERFACE) {
+		usb_standard_interface_descriptor_t *descriptor
+		    = (usb_standard_interface_descriptor_t *) data;
+		usb_log_info("Found interface: %s (0x%02x/0x%02x/0x%02x).\n",
+		    usb_str_class(descriptor->interface_class),
+		    (int) descriptor->interface_class,
+		    (int) descriptor->interface_subclass,
+		    (int) descriptor->interface_protocol);
+	}
+}
+
+/** Dump tree of descriptors.
+ *
+ * @param parser Descriptor parser.
+ * @param data Descriptor parser data.
+ * @param root Pointer to current root.
+ * @param depth Nesting depth.
+ */
+static void dump_tree_internal(usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
+    uint8_t *root, size_t depth)
+{
+	if (root == NULL) {
+		return;
+	}
+	dump_tree_descriptor(root, depth);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		dump_tree_internal(parser, data, child, depth + 1);
+		child = usb_dp_get_sibling_descriptor(parser, data, root, child);
+	} while (child != NULL);
+}
+
+/** Dump descriptor tree.
+ *
+ * @param parser Descriptor parser.
+ * @param data Descriptor parser data.
+ */
+static void dump_tree(usb_dp_parser_t *parser, usb_dp_parser_data_t *data)
+{
+	uint8_t *ptr = data->data;
+	dump_tree_internal(parser, data, ptr, 0);
+}
+
+/** Dump given descriptors.
+ *
+ * @param descriptors Descriptors buffer (typically full config descriptor).
+ * @param length Size of @p descriptors buffer in bytes.
+ */
+void usbmid_dump_descriptors(uint8_t *descriptors, size_t length)
+{
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = length,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+
+	dump_tree(&parser, &data);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/explore.c
===================================================================
--- uspace/drv/usbmid/explore.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/explore.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,211 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Exploration of available interfaces in the USB device.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <usb/classes/classes.h>
+#include <usb/dev/request.h>
+#include <usb/dev/dp.h>
+#include <usb/ddfiface.h>
+#include "usbmid.h"
+
+/** Operations of the device itself. */
+static ddf_dev_ops_t mid_device_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
+};
+
+/** Tell whether given interface is already in the list.
+ *
+ * @param list List of usbmid_interface_t members to be searched.
+ * @param interface_no Interface number caller is looking for.
+ * @return Interface @p interface_no is already present in the list.
+ */
+static bool interface_in_list(link_t *list, int interface_no)
+{
+	link_t *l;
+	for (l = list->next; l != list; l = l->next) {
+		usbmid_interface_t *iface
+		    = list_get_instance(l, usbmid_interface_t, link);
+		if (iface->interface_no == interface_no) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/** Create list of interfaces from configuration descriptor.
+ *
+ * @param config_descriptor Configuration descriptor.
+ * @param config_descriptor_size Size of configuration descriptor in bytes.
+ * @param list List where to add the interfaces.
+ */
+static void create_interfaces(uint8_t *config_descriptor,
+    size_t config_descriptor_size, link_t *list)
+{
+	usb_dp_parser_data_t data = {
+		.data = config_descriptor,
+		.size = config_descriptor_size,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+
+	uint8_t *interface_ptr = usb_dp_get_nested_descriptor(&parser, &data,
+	    data.data);
+	if (interface_ptr == NULL) {
+		return;
+	}
+
+	do {
+		if (interface_ptr[1] != USB_DESCTYPE_INTERFACE) {
+			goto next_descriptor;
+		}
+
+		usb_standard_interface_descriptor_t *interface
+		    = (usb_standard_interface_descriptor_t *) interface_ptr;
+
+		/* Skip alternate interfaces. */
+		if (!interface_in_list(list, interface->interface_number)) {
+			usbmid_interface_t *iface
+			    = malloc(sizeof(usbmid_interface_t));
+			if (iface == NULL) {
+				break;
+			}
+			link_initialize(&iface->link);
+			iface->fun = NULL;
+			iface->interface_no = interface->interface_number;
+			iface->interface = interface;
+
+			list_append(&iface->link, list);
+		}
+
+		/* TODO: add the alternatives and create match ids from them
+		 * as well.
+		 */
+
+next_descriptor:
+		interface_ptr = usb_dp_get_sibling_descriptor(&parser, &data,
+		    data.data, interface_ptr);
+
+	} while (interface_ptr != NULL);
+
+}
+
+/** Explore MID device.
+ *
+ * We expect that @p dev is initialized and session on control pipe is
+ * started.
+ *
+ * @param dev Device to be explored.
+ * @return Whether to accept this device from devman.
+ */
+bool usbmid_explore_device(usb_device_t *dev)
+{
+	int rc;
+
+	int dev_class = dev->descriptors.device.device_class;
+	if (dev_class != USB_CLASS_USE_INTERFACE) {
+		usb_log_warning(
+		    "Device class: %d (%s), but expected class 0.\n",
+		    dev_class, usb_str_class(dev_class));
+		usb_log_error("Not multi interface device, refusing.\n");
+		return false;
+	}
+
+	/* Short cuts to save on typing ;-). */
+	uint8_t *config_descriptor_raw = dev->descriptors.configuration;
+	size_t config_descriptor_size = dev->descriptors.configuration_size;
+	usb_standard_configuration_descriptor_t *config_descriptor =
+	    (usb_standard_configuration_descriptor_t *) config_descriptor_raw;
+
+	/* Select the first configuration */
+	rc = usb_request_set_configuration(&dev->ctrl_pipe,
+	    config_descriptor->configuration_number);
+	if (rc != EOK) {
+		usb_log_error("Failed to set device configuration: %s.\n",
+		    str_error(rc));
+		return false;
+	}
+
+	/* Create control function */
+	ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "ctl");
+	if (ctl_fun == NULL) {
+		usb_log_error("Failed to create control function.\n");
+		return false;
+	}
+
+	ctl_fun->ops = &mid_device_ops;
+
+	rc = ddf_fun_bind(ctl_fun);
+	if (rc != EOK) {
+		usb_log_error("Failed to bind control function: %s.\n",
+		    str_error(rc));
+		return false;
+	}
+
+	/* Create interface children. */
+	link_t interface_list;
+	list_initialize(&interface_list);
+	create_interfaces(config_descriptor_raw, config_descriptor_size,
+	    &interface_list);
+
+	link_t *link;
+	for (link = interface_list.next; link != &interface_list;
+	    link = link->next) {
+		usbmid_interface_t *iface = list_get_instance(link,
+		    usbmid_interface_t, link);
+
+		usb_log_info("Creating child for interface %d (%s).\n",
+		    (int) iface->interface_no,
+		    usb_str_class(iface->interface->interface_class));
+
+		rc = usbmid_spawn_interface_child(dev, iface,
+		    &dev->descriptors.device, iface->interface);
+		if (rc != EOK) {
+			usb_log_error("Failed to create interface child: %s.\n",
+			    str_error(rc));
+		}
+	}
+
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/main.c
===================================================================
--- uspace/drv/usbmid/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,91 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB multi interface device driver.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/dev/request.h>
+#include <usb/descriptor.h>
+#include <usb/dev/pipes.h>
+
+#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(usb_device_t *dev)
+{
+	usb_log_info("Taking care of new MID `%s'.\n", dev->ddf_dev->name);
+
+	usb_pipe_start_long_transfer(&dev->ctrl_pipe);
+
+	bool accept = usbmid_explore_device(dev);
+
+	usb_pipe_end_long_transfer(&dev->ctrl_pipe);
+
+	if (!accept) {
+		return ENOTSUP;
+	}
+
+	return EOK;
+}
+
+/** USB MID driver ops. */
+static usb_driver_ops_t mid_driver_ops = {
+	.add_device = usbmid_add_device,
+};
+
+/** USB MID driver. */
+static usb_driver_t mid_driver = {
+	.name = NAME,
+	.ops = &mid_driver_ops,
+	.endpoints = NULL
+};
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": USB multi interface device driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	return usb_driver_main(&mid_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/usbmid.c
===================================================================
--- uspace/drv/usbmid/usbmid.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/usbmid.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,152 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Helper functions.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <usb_iface.h>
+#include <usb/ddfiface.h>
+#include <usb/dev/pipes.h>
+#include <usb/classes/classes.h>
+#include <usb/dev/recognise.h>
+#include "usbmid.h"
+
+/** Callback for DDF USB interface. */
+static int usb_iface_get_address_impl(ddf_fun_t *fun, devman_handle_t handle,
+    usb_address_t *address)
+{
+	return usb_iface_get_address_hub_impl(fun, handle, address);
+}
+
+/** Callback for DDF USB interface. */
+static int usb_iface_get_interface_impl(ddf_fun_t *fun, devman_handle_t handle,
+    int *iface_no)
+{
+	assert(fun);
+
+	usbmid_interface_t *iface = fun->driver_data;
+	assert(iface);
+
+	if (iface_no != NULL) {
+		*iface_no = iface->interface_no;
+	}
+
+	return EOK;
+}
+
+/** 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,
+	.get_address = usb_iface_get_address_impl,
+	.get_interface = usb_iface_get_interface_impl
+};
+
+/** Operations for children - interface functions. */
+static ddf_dev_ops_t child_device_ops = {
+	.interfaces[USB_DEV_IFACE] = &child_usb_iface
+};
+
+
+/** Spawn new child device from one interface.
+ *
+ * @param parent Parent MID device.
+ * @param iface Interface information.
+ * @param device_descriptor Device descriptor.
+ * @param interface_descriptor Interface descriptor.
+ * @return Error code.
+ */
+int usbmid_spawn_interface_child(usb_device_t *parent,
+    usbmid_interface_t *iface,
+    const usb_standard_device_descriptor_t *device_descriptor,
+    const usb_standard_interface_descriptor_t *interface_descriptor)
+{
+	ddf_fun_t *child = NULL;
+	char *child_name = NULL;
+	int rc;
+
+	/*
+	 * Name is class name followed by interface number.
+	 * The interface number shall provide uniqueness while the
+	 * class name something humanly understandable.
+	 */
+	rc = asprintf(&child_name, "%s%d",
+	    usb_str_class(interface_descriptor->interface_class),
+	    (int) interface_descriptor->interface_number);
+	if (rc < 0) {
+		goto error_leave;
+	}
+
+	/* Create the device. */
+	child = ddf_fun_create(parent->ddf_dev, fun_inner, child_name);
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+
+	iface->fun = child;
+
+	child->driver_data = iface;
+	child->ops = &child_device_ops;
+
+	rc = usb_device_create_match_ids_from_interface(device_descriptor,
+	    interface_descriptor,
+	    &child->match_ids);
+	if (rc != EOK) {
+		goto error_leave;
+	}
+
+	rc = ddf_fun_bind(child);
+	if (rc != EOK) {
+		goto error_leave;
+	}
+
+	return EOK;
+
+error_leave:
+	if (child != NULL) {
+		child->name = NULL;
+		/* This takes care of match_id deallocation as well. */
+		ddf_fun_destroy(child);
+	}
+	if (child_name != NULL) {
+		free(child_name);
+	}
+
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/usbmid.h
===================================================================
--- uspace/drv/usbmid/usbmid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/usbmid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,69 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/** @file
+ * Common definitions.
+ */
+
+#ifndef USBMID_H_
+#define USBMID_H_
+
+#include <adt/list.h>
+#include <ddf/driver.h>
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <usb/dev/driver.h>
+
+#define NAME "usbmid"
+
+/** Container for single interface in a MID device. */
+typedef struct {
+	/** Function container. */
+	ddf_fun_t *fun;
+	/** Interface descriptor. */
+	usb_standard_interface_descriptor_t *interface;
+	/** Interface number. */
+	int interface_no;
+	/** List link. */
+	link_t link;
+} usbmid_interface_t;
+
+bool usbmid_explore_device(usb_device_t *);
+int usbmid_spawn_interface_child(usb_device_t *, usbmid_interface_t *,
+    const usb_standard_device_descriptor_t *,
+    const usb_standard_interface_descriptor_t *);
+void usbmid_dump_descriptors(uint8_t *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/usbmid.ma
===================================================================
--- uspace/drv/usbmid/usbmid.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmid/usbmid.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1 @@
+100 usb&mid
Index: uspace/drv/usbmouse/Makefile
===================================================================
--- uspace/drv/usbmouse/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmouse/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,49 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+
+LIBS = \
+	$(LIBUSBHID_PREFIX)/libusbhid.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBUSBHID_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+BINARY = usbmouse
+
+SOURCES = \
+	init.c \
+	main.c \
+	mouse.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmouse/init.c
===================================================================
--- uspace/drv/usbmouse/init.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmouse/init.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,141 @@
+/*
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Initialization routines for USB mouse driver.
+ */
+
+#include "mouse.h"
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usb/dev/request.h>
+#include <usb/hid/request.h>
+#include <errno.h>
+
+/** Mouse polling endpoint description for boot protocol subclass. */
+usb_endpoint_description_t poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_MOUSE,
+	.flags = 0
+};
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun     Device function handling the call.
+ * @param icallid Call ID.
+ * @param icall   Call data.
+ *
+ */
+static void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid,
+    ipc_call_t *icall)
+{
+	usb_mouse_t *mouse = (usb_mouse_t *) fun->driver_data;
+	assert(mouse != NULL);
+	
+	async_sess_t *callback =
+	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+	
+	if (callback) {
+		if (mouse->console_sess == NULL) {
+			mouse->console_sess = callback;
+			async_answer_0(icallid, EOK);
+		} else
+			async_answer_0(icallid, ELIMIT);
+	} else
+		async_answer_0(icallid, EINVAL);
+}
+
+/** Device ops for USB mouse. */
+static ddf_dev_ops_t mouse_ops = {
+	.default_handler = default_connection_handler
+};
+
+/** 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));
+	if (mouse == NULL)
+		return ENOMEM;
+	
+	mouse->dev = dev;
+	mouse->console_sess = NULL;
+	
+	int rc;
+	
+	/* Create DDF function. */
+	mouse->mouse_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "mouse");
+	if (mouse->mouse_fun == NULL) {
+		rc = ENOMEM;
+		goto leave;
+	}
+	
+	mouse->mouse_fun->ops = &mouse_ops;
+	
+	rc = ddf_fun_bind(mouse->mouse_fun);
+	if (rc != EOK)
+		goto leave;
+	
+	/* Add the function to mouse class. */
+	rc = ddf_fun_add_to_class(mouse->mouse_fun, "mouse");
+	if (rc != EOK)
+		goto leave;
+	
+	/* Set the boot protocol. */
+	rc = usbhid_req_set_protocol(&dev->ctrl_pipe, dev->interface_no,
+	    USB_HID_PROTOCOL_BOOT);
+	if (rc != EOK)
+		goto leave;
+	
+	/* Everything allright. */
+	dev->driver_data = mouse;
+	mouse->mouse_fun->driver_data = mouse;
+	
+	return EOK;
+	
+leave:
+	free(mouse);
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/main.c
===================================================================
--- uspace/drv/usbmouse/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmouse/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,105 @@
+/*
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB boot protocol mouse driver.
+ */
+
+#include "mouse.h"
+#include <usb/debug.h>
+#include <usb/dev/poll.h>
+#include <errno.h>
+#include <str_error.h>
+
+#define NAME  "usbmouse"
+
+/** 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);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize device driver: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	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;
+	}
+	
+	usb_log_info("controlling new mouse (handle %" PRIun ").\n",
+	    dev->ddf_dev->handle);
+	
+	return EOK;
+}
+
+/** USB mouse driver ops. */
+static usb_driver_ops_t mouse_driver_ops = {
+	.add_device = usbmouse_add_device,
+};
+
+static usb_endpoint_description_t *endpoints[] = {
+	&poll_endpoint_description,
+	NULL
+};
+
+/** USB mouse driver. */
+static usb_driver_t mouse_driver = {
+	.name = NAME,
+	.ops = &mouse_driver_ops,
+	.endpoints = endpoints
+};
+
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+	return usb_driver_main(&mouse_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/mouse.c
===================================================================
--- uspace/drv/usbmouse/mouse.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmouse/mouse.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,131 @@
+/*
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Actual handling of USB mouse protocol.
+ */
+
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ipc/mouse.h>
+#include <async.h>
+#include "mouse.h"
+
+/** Mouse polling callback.
+ *
+ * @param dev    Device that is being polled.
+ * @param buffer Data buffer.
+ * @param size   Buffer size in bytes.
+ * @param arg    Pointer to usb_mouse_t.
+ *
+ * @return Always true.
+ *
+ */
+bool usb_mouse_polling_callback(usb_device_t *dev, uint8_t *buffer,
+    size_t size, void *arg)
+{
+	usb_mouse_t *mouse = (usb_mouse_t *) arg;
+	
+	usb_log_debug2("got buffer: %s.\n",
+	    usb_debug_str_buffer(buffer, size, 0));
+	
+	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_sess) {
+		if ((shift_x != 0) || (shift_y != 0)) {
+			// FIXME: guessed for QEMU
+			
+			async_exch_t *exch = async_exchange_begin(mouse->console_sess);
+			async_req_2_0(exch, MEVENT_MOVE, -shift_x / 10, -shift_y / 10);
+			async_exchange_end(exch);
+		}
+		if (butt) {
+			// FIXME: proper button clicking
+			
+			async_exch_t *exch = async_exchange_begin(mouse->console_sess);
+			async_req_2_0(exch, MEVENT_BUTTON, 1, 1);
+			async_req_2_0(exch, MEVENT_BUTTON, 1, 0);
+			async_exchange_end(exch);
+		}
+	}
+	
+	usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
+	    str_buttons, shift_x, shift_y, wheel);
+	
+	/* Guess. */
+	async_usleep(1000);
+	
+	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              Pointer 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_sess);
+	mouse->console_sess = NULL;
+	
+	usb_device_destroy(dev);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/mouse.h
===================================================================
--- uspace/drv/usbmouse/mouse.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmouse/mouse.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,74 @@
+/*
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Common definitions for USB mouse driver.
+ */
+
+#ifndef USBMOUSE_MOUSE_H_
+#define USBMOUSE_MOUSE_H_
+
+#include <usb/dev/driver.h>
+#include <usb/dev/pipes.h>
+#include <time.h>
+#include <async.h>
+
+#define POLL_PIPE(dev) \
+	((dev)->pipes[0].pipe)
+
+/** Container for USB mouse device. */
+typedef struct {
+	/** Generic device container. */
+	usb_device_t *dev;
+	
+	/** Function representing the device. */
+	ddf_fun_t *mouse_fun;
+	
+	/** Polling interval in microseconds. */
+	suseconds_t poll_interval_us;
+	
+	/** Callback session to console (consumer). */
+	async_sess_t *console_sess;
+} usb_mouse_t;
+
+extern usb_endpoint_description_t poll_endpoint_description;
+
+extern int usb_mouse_create(usb_device_t *);
+extern bool usb_mouse_polling_callback(usb_device_t *, uint8_t *, size_t,
+    void *);
+extern void usb_mouse_polling_ended_callback(usb_device_t *, bool, void *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/usbmouse.ma
===================================================================
--- uspace/drv/usbmouse/usbmouse.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/usbmouse/usbmouse.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1 @@
+100 usb&interface&class=HID&subclass=0x01&protocol=0x02
Index: uspace/drv/vhc/Makefile
===================================================================
--- uspace/drv/vhc/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2010 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSBHOST_PREFIX)/libusbhost.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += \
+	-I$(LIBUSBVIRT_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBUSBHOST_PREFIX)/include \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+BINARY = vhc
+
+SOURCES = \
+	hub/virthub.c \
+	hub/hub.c \
+	hub/virthubops.c \
+	conndev.c \
+	connhost.c \
+	devconn.c \
+	hub.c \
+	main.c \
+	transfer.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/vhc/conn.h
===================================================================
--- uspace/drv/vhc/conn.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/conn.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Connection handling of incoming calls.
+ */
+#ifndef VHCD_CONN_H_
+#define VHCD_CONN_H_
+
+#include <usb/usb.h>
+#include <usbhc_iface.h>
+#include <usb_iface.h>
+#include "vhcd.h"
+
+extern usbhc_iface_t vhc_iface;
+extern usb_iface_t vhc_usb_iface;
+extern usb_iface_t rh_usb_iface;
+
+void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+void on_client_close(ddf_fun_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/vhc/conndev.c
===================================================================
--- uspace/drv/vhc/conndev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/conndev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,139 @@
+/*
+ * 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * Connection handling of calls from virtual device (implementation).
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <ddf/driver.h>
+#include <usbvirt/ipc.h>
+#include <async.h>
+#include "conn.h"
+
+static fibril_local uintptr_t plugged_device_handle = 0;
+#define PLUGGED_DEVICE_NAME_MAXLEN 256
+static fibril_local char plugged_device_name[PLUGGED_DEVICE_NAME_MAXLEN + 1] = "<unknown>";
+
+/** Receive device name.
+ *
+ * @warning Errors are silently ignored.
+ *
+ * @param sess Session to the virtual device.
+ *
+ */
+static void receive_device_name(async_sess_t *sess)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t opening_request = async_send_0(exch, IPC_M_USBVIRT_GET_NAME, NULL);
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return;
+	}
+	
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, plugged_device_name,
+	     PLUGGED_DEVICE_NAME_MAXLEN, &data_request_call);
+	
+	async_exchange_end(exch);
+	
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return;
+	}
+	
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	if ((data_request_rc != EOK) || (opening_request_rc != EOK))
+		return;
+	
+	size_t len = IPC_GET_ARG2(data_request_call);
+	plugged_device_name[len] = 0;
+}
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid,
+    ipc_call_t *icall)
+{
+	vhc_data_t *vhc = fun->dev->driver_data;
+	
+	async_sess_t *callback =
+	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+	
+	if (callback) {
+		int rc = vhc_virtdev_plug(vhc, callback, &plugged_device_handle);
+		if (rc != EOK) {
+			async_answer_0(icallid, rc);
+			async_hangup(callback);
+			return;
+		}
+		
+		async_answer_0(icallid, EOK);
+		
+		receive_device_name(callback);
+		
+		usb_log_info("New virtual device `%s' (id: %" PRIxn ").\n",
+		    plugged_device_name, plugged_device_handle);
+	} else
+		async_answer_0(icallid, EINVAL);
+}
+
+/** Callback when client disconnects.
+ *
+ * Used to unplug virtual USB device.
+ *
+ * @param fun
+ */
+void on_client_close(ddf_fun_t *fun)
+{
+	vhc_data_t *vhc = fun->dev->driver_data;
+
+	if (plugged_device_handle != 0) {
+		usb_log_info("Virtual device `%s' disconnected (id: %" PRIxn ").\n",
+		    plugged_device_name, plugged_device_handle);
+		vhc_virtdev_unplug(vhc, plugged_device_handle);
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/connhost.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,490 @@
+/*
+ * 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * Host controller interface implementation.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <usb/usb.h>
+#include <usb/ddfiface.h>
+#include <usb/debug.h>
+#include <usbhc_iface.h>
+#include "vhcd.h"
+
+#define GET_VHC_DATA(fun) \
+	((vhc_data_t *)fun->dev->driver_data)
+#define VHC_DATA(vhc, fun) \
+	vhc_data_t *vhc = GET_VHC_DATA(fun); assert(vhc->magic == 0xdeadbeef)
+
+#define UNSUPPORTED(methodname) \
+	usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
+	    methodname, __FILE__, __LINE__)
+
+/** Found free USB address.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] speed Speed of the device that will get this address.
+ * @param[out] address Non-null pointer where to store the free address.
+ * @return Error code.
+ */
+static int request_address(ddf_fun_t *fun, usb_speed_t speed,
+    usb_address_t *address)
+{
+	VHC_DATA(vhc, fun);
+
+	usb_address_t addr = device_keeper_get_free_address(&vhc->dev_keeper,
+	    USB_SPEED_HIGH);
+	if (addr < 0) {
+		return addr;
+	}
+
+	if (address != NULL) {
+		*address = addr;
+	}
+
+	return EOK;
+}
+
+/** Bind USB address with device devman handle.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] handle Devman handle of the device.
+ * @return Error code.
+ */
+static int bind_address(ddf_fun_t *fun,
+    usb_address_t address, devman_handle_t handle)
+{
+	VHC_DATA(vhc, fun);
+	usb_log_debug("Binding handle %" PRIun " to address %d.\n",
+	    handle, address);
+	usb_device_keeper_bind(&vhc->dev_keeper, address, handle);
+
+	return EOK;
+}
+
+/** Find device handle by address interface function.
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address in question.
+ * @param[out] handle Where to store device handle if found.
+ * @return Error code.
+ */
+static int find_by_address(ddf_fun_t *fun, usb_address_t address,
+    devman_handle_t *handle)
+{
+	VHC_DATA(vhc, fun);
+	bool found =
+	    usb_device_keeper_find_by_address(&vhc->dev_keeper, address, handle);
+	return found ? EOK : ENOENT;
+}
+
+/** Release previously requested address.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address to be released.
+ * @return Error code.
+ */
+static int release_address(ddf_fun_t *fun, usb_address_t address)
+{
+	VHC_DATA(vhc, fun);
+	usb_log_debug("Releasing address %d...\n", address);
+	usb_device_keeper_release(&vhc->dev_keeper, address);
+
+	return ENOTSUP;
+}
+
+/** Register endpoint for bandwidth reservation.
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] speed Endpoint speed (invalid means to use device one).
+ * @param[in] endpoint Endpoint number.
+ * @param[in] transfer_type USB transfer type.
+ * @param[in] direction Endpoint data direction.
+ * @param[in] max_packet_size Max packet size of the endpoint.
+ * @param[in] interval Polling interval.
+ * @return Error code.
+ */
+static int register_endpoint(ddf_fun_t *fun,
+    usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
+    usb_transfer_type_t transfer_type, usb_direction_t direction,
+    size_t max_packet_size, unsigned int interval)
+{
+	VHC_DATA(vhc, fun);
+
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL) {
+		return ENOMEM;
+	}
+
+	int rc = endpoint_init(ep, address, endpoint, direction, transfer_type,
+	    USB_SPEED_FULL, 1);
+	if (rc != EOK) {
+		free(ep);
+		return rc;
+	}
+
+	rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
+	if (rc != EOK) {
+		endpoint_destroy(ep);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Unregister endpoint (free some bandwidth reservation).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] address USB address of the device.
+ * @param[in] endpoint Endpoint number.
+ * @param[in] direction Endpoint data direction.
+ * @return Error code.
+ */
+static int unregister_endpoint(ddf_fun_t *fun, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	VHC_DATA(vhc, fun);
+
+	endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
+	    address, endpoint, direction, NULL);
+	if (ep == NULL) {
+		return ENOENT;
+	}
+
+	int rc = usb_endpoint_manager_unregister_ep(&vhc->ep_manager,
+	    address, endpoint, direction);
+
+	return rc;
+}
+
+/** Schedule interrupt out transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
+ *	by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	VHC_DATA(vhc, fun);
+
+	vhc_transfer_t *transfer = vhc_transfer_create(target.address,
+	    target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_INTERRUPT,
+	    fun, arg);
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->data_buffer = data;
+	transfer->data_buffer_size = size;
+	transfer->callback_out = callback;
+
+	int rc = vhc_virtdev_add_transfer(vhc, transfer);
+	if (rc != EOK) {
+		free(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Schedule interrupt in transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	VHC_DATA(vhc, fun);
+
+	vhc_transfer_t *transfer = vhc_transfer_create(target.address,
+	    target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_INTERRUPT,
+	    fun, arg);
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->data_buffer = data;
+	transfer->data_buffer_size = size;
+	transfer->callback_in = callback;
+
+	int rc = vhc_virtdev_add_transfer(vhc, transfer);
+	if (rc != EOK) {
+		free(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Schedule bulk out transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
+ *	by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int bulk_out(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	UNSUPPORTED("bulk_out");
+
+	return ENOTSUP;
+}
+
+/** Schedule bulk in transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] data Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] size Size of the @p data buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int bulk_in(ddf_fun_t *fun, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	UNSUPPORTED("bulk_in");
+
+	return ENOTSUP;
+}
+
+/** Schedule control write transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
+ *	and deallocated by the caller).
+ * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
+ * @param[in] data_buffer Data buffer (in USB endianess, allocated and
+ *	deallocated by the caller).
+ * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int control_write(ddf_fun_t *fun, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data_buffer, size_t data_buffer_size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	VHC_DATA(vhc, fun);
+
+	vhc_transfer_t *transfer = vhc_transfer_create(target.address,
+	    target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_CONTROL,
+	    fun, arg);
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->setup_buffer = setup_packet;
+	transfer->setup_buffer_size = setup_packet_size;
+	transfer->data_buffer = data_buffer;
+	transfer->data_buffer_size = data_buffer_size;
+	transfer->callback_out = callback;
+
+	int rc = vhc_virtdev_add_transfer(vhc, transfer);
+	if (rc != EOK) {
+		free(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Schedule control read transfer.
+ *
+ * The callback is supposed to be called once the transfer (on the wire) is
+ * complete regardless of the outcome.
+ * However, the callback could be called only when this function returns
+ * with success status (i.e. returns EOK).
+ *
+ * @param[in] fun Device function the action was invoked on.
+ * @param[in] target Target pipe (address and endpoint number) specification.
+ * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
+ *	and deallocated by the caller).
+ * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
+ * @param[in] data_buffer Buffer where to store the data (in USB endianess,
+ *	allocated and deallocated by the caller).
+ * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
+ * @param[in] callback Callback to be issued once the transfer is complete.
+ * @param[in] arg Pass-through argument to the callback.
+ * @return Error code.
+ */
+static int control_read(ddf_fun_t *fun, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data_buffer, size_t data_buffer_size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	VHC_DATA(vhc, fun);
+
+	vhc_transfer_t *transfer = vhc_transfer_create(target.address,
+	    target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_CONTROL,
+	    fun, arg);
+	if (transfer == NULL) {
+		return ENOMEM;
+	}
+
+	transfer->setup_buffer = setup_packet;
+	transfer->setup_buffer_size = setup_packet_size;
+	transfer->data_buffer = data_buffer;
+	transfer->data_buffer_size = data_buffer_size;
+	transfer->callback_in = callback;
+
+	int rc = vhc_virtdev_add_transfer(vhc, transfer);
+	if (rc != EOK) {
+		free(transfer);
+		return rc;
+	}
+
+	return EOK;
+}
+
+static int tell_address(ddf_fun_t *fun, devman_handle_t handle,
+    usb_address_t *address)
+{
+	UNSUPPORTED("tell_address");
+
+	return ENOTSUP;
+}
+
+static int usb_iface_get_hc_handle_rh_impl(ddf_fun_t *root_hub_fun,
+    devman_handle_t *handle)
+{
+	VHC_DATA(vhc, root_hub_fun);
+
+	*handle = vhc->hc_fun->handle;
+
+	return EOK;
+}
+
+static int tell_address_rh(ddf_fun_t *root_hub_fun, devman_handle_t handle,
+    usb_address_t *address)
+{
+	VHC_DATA(vhc, root_hub_fun);
+
+	if (handle == 0) {
+		handle = root_hub_fun->handle;
+	}
+
+	usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
+	usb_address_t addr = usb_device_keeper_find(&vhc->dev_keeper, handle);
+	if (addr < 0) {
+		return addr;
+	} else {
+		*address = addr;
+		return EOK;
+	}
+}
+
+usbhc_iface_t vhc_iface = {
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.find_by_address = find_by_address,
+	.release_address = release_address,
+
+	.register_endpoint = register_endpoint,
+	.unregister_endpoint = unregister_endpoint,
+
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+
+	.bulk_in = bulk_in,
+	.bulk_out = bulk_out,
+
+	.control_write = control_write,
+	.control_read = control_read
+};
+
+usb_iface_t vhc_usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle_hc_impl,
+	.get_address = tell_address
+};
+
+usb_iface_t rh_usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle_rh_impl,
+	.get_address = tell_address_rh
+};
+
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/devconn.c
===================================================================
--- uspace/drv/vhc/devconn.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/devconn.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include "vhcd.h"
+#include "hub/virthub.h"
+
+
+static vhc_virtdev_t *vhc_virtdev_create()
+{
+	vhc_virtdev_t *dev = malloc(sizeof(vhc_virtdev_t));
+	if (dev == NULL) {
+		return NULL;
+	}
+	dev->address = 0;
+	dev->dev_sess = NULL;
+	dev->dev_local = NULL;
+	dev->plugged = true;
+	link_initialize(&dev->link);
+	fibril_mutex_initialize(&dev->guard);
+	list_initialize(&dev->transfer_queue);
+
+	return dev;
+}
+
+static int vhc_virtdev_plug_generic(vhc_data_t *vhc,
+    async_sess_t *sess, usbvirt_device_t *virtdev,
+    uintptr_t *handle, bool connect)
+{
+	vhc_virtdev_t *dev = vhc_virtdev_create();
+	if (dev == NULL) {
+		return ENOMEM;
+	}
+
+	dev->dev_sess = sess;
+	dev->dev_local = virtdev;
+
+	fibril_mutex_lock(&vhc->guard);
+	list_append(&dev->link, &vhc->devices);
+	fibril_mutex_unlock(&vhc->guard);
+
+	fid_t fibril = fibril_create(vhc_transfer_queue_processor, dev);
+	if (fibril == 0) {
+		free(dev);
+		return ENOMEM;
+	}
+	fibril_add_ready(fibril);
+
+	if (handle != NULL) {
+		*handle = (uintptr_t) dev;
+	}
+
+	if (connect) {
+		// FIXME: check status
+		(void) virthub_connect_device(vhc->hub, dev);
+	}
+
+	return EOK;
+}
+
+int vhc_virtdev_plug(vhc_data_t *vhc, async_sess_t *sess, uintptr_t *handle)
+{
+	return vhc_virtdev_plug_generic(vhc, sess, NULL, handle, true);
+}
+
+int vhc_virtdev_plug_local(vhc_data_t *vhc, usbvirt_device_t *dev, uintptr_t *handle)
+{
+	return vhc_virtdev_plug_generic(vhc, NULL, dev, handle, true);
+}
+
+int vhc_virtdev_plug_hub(vhc_data_t *vhc, usbvirt_device_t *dev, uintptr_t *handle)
+{
+	return vhc_virtdev_plug_generic(vhc, NULL, dev, handle, false);
+}
+
+void vhc_virtdev_unplug(vhc_data_t *vhc, uintptr_t handle)
+{
+	vhc_virtdev_t *dev = (vhc_virtdev_t *) handle;
+
+	// FIXME: check status
+	(void) virthub_disconnect_device(vhc->hub, dev);
+
+	fibril_mutex_lock(&vhc->guard);
+	fibril_mutex_lock(&dev->guard);
+	dev->plugged = false;
+	list_remove(&dev->link);
+	fibril_mutex_unlock(&dev->guard);
+	fibril_mutex_unlock(&vhc->guard);
+}
Index: uspace/drv/vhc/hub.c
===================================================================
--- uspace/drv/vhc/hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub.
+ */
+
+#include <usb/classes/classes.h>
+#include <usbvirt/device.h>
+#include <errno.h>
+#include <async.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <usb/dev/hub.h>
+#include <usb/dev/recognise.h>
+
+#include "hub.h"
+#include "vhcd.h"
+#include "conn.h"
+
+usbvirt_device_t virtual_hub_device = {
+	.name = "root hub",
+	.ops = &hub_ops,
+	.address = 0
+};
+
+static ddf_dev_ops_t rh_ops = {
+	.interfaces[USB_DEV_IFACE] = &rh_usb_iface,
+};
+
+static int hub_register_in_devman_fibril(void *arg);
+
+void virtual_hub_device_init(ddf_fun_t *hc_dev)
+{
+	virthub_init(&virtual_hub_device);
+
+	/*
+	 * We need to register the root hub.
+	 * This must be done in separate fibril because the device
+	 * we are connecting to are ourselves and we cannot connect
+	 * before leaving the add_device() function.
+	 */
+	fid_t root_hub_registration
+	    = fibril_create(hub_register_in_devman_fibril, hc_dev);
+	if (root_hub_registration == 0) {
+		usb_log_fatal("Failed to create hub registration fibril.\n");
+		return;
+	}
+
+	fibril_add_ready(root_hub_registration);
+}
+
+static int pretend_port_rest(int unused, void *unused2)
+{
+	return EOK;
+}
+
+/** Register root hub in devman.
+ *
+ * @param arg Host controller device (type <code>device_t *</code>).
+ * @return Error code.
+ */
+int hub_register_in_devman_fibril(void *arg)
+{
+	ddf_fun_t *hc_dev = (ddf_fun_t *) arg;
+
+	/*
+	 * Wait until parent device is properly initialized.
+	 */
+	async_sess_t *sess;
+	do {
+		sess = devman_device_connect(EXCHANGE_SERIALIZE, hc_dev->handle, 0);
+	} while (!sess);
+	async_hangup(sess);
+
+	int rc;
+
+	usb_hc_connection_t hc_conn;
+	rc = usb_hc_connection_initialize(&hc_conn, hc_dev->handle);
+	assert(rc == EOK);
+
+	rc = usb_hc_connection_open(&hc_conn);
+	assert(rc == EOK);
+
+	ddf_fun_t *hub_dev;
+	rc = usb_hc_new_device_wrapper(hc_dev->dev, &hc_conn,
+	    USB_SPEED_FULL,
+	    pretend_port_rest, 0, NULL,
+	    NULL, NULL, &rh_ops, hc_dev, &hub_dev);
+	if (rc != EOK) {
+		usb_log_fatal("Failed to create root hub: %s.\n",
+		    str_error(rc));
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	usb_log_info("Created root hub function (handle %zu).\n",
+	    (size_t) hub_dev->handle);
+
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub.h
===================================================================
--- uspace/drv/vhc/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub.
+ */
+
+#ifndef VHCD_HUB_H_
+#define VHCD_HUB_H_
+
+#include <usbvirt/device.h>
+#include <ddf/driver.h>
+
+#include "hub/hub.h"
+#include "hub/virthub.h"
+
+extern usbvirt_device_t virtual_hub_device;
+
+void virtual_hub_device_init(ddf_fun_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/hub.c
===================================================================
--- uspace/drv/vhc/hub/hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub/hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Representation of an USB hub (implementation).
+ */
+#include <usb/classes/classes.h>
+#include <usbvirt/device.h>
+#include <errno.h>
+#include <str_error.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ddf/driver.h>
+#include <usb/debug.h>
+
+#include "hub.h"
+
+
+/** Produce a byte from bit values.
+ */
+#define MAKE_BYTE(b0, b1, b2, b3, b4, b5, b6, b7) \
+	(( \
+		((b0) << 0) \
+		| ((b1) << 1) \
+		| ((b2) << 2) \
+		| ((b3) << 3) \
+		| ((b4) << 4) \
+		| ((b5) << 5) \
+		| ((b6) << 6) \
+		| ((b7) << 7) \
+	))
+
+/* Static functions. */
+static hub_port_t *get_hub_port(hub_t *, size_t);
+static void set_port_status_change(hub_port_t *, hub_status_change_t);
+static void clear_port_status_change(hub_port_t *, uint16_t);
+static int set_port_state_delayed_fibril(void *);
+static void set_port_state_delayed(hub_t *, size_t, suseconds_t,
+    hub_port_state_t, hub_port_state_t);
+
+/** Convert hub port state to a char. */
+char hub_port_state_to_char(hub_port_state_t state) {
+	switch (state) {
+		case HUB_PORT_STATE_NOT_CONFIGURED:
+			return '-';
+		case HUB_PORT_STATE_POWERED_OFF:
+			return 'O';
+		case HUB_PORT_STATE_DISCONNECTED:
+			return 'X';
+		case HUB_PORT_STATE_DISABLED:
+			return 'D';
+		case HUB_PORT_STATE_RESETTING:
+			return 'R';
+		case HUB_PORT_STATE_ENABLED:
+			return 'E';
+		case HUB_PORT_STATE_SUSPENDED:
+			return 'S';
+		case HUB_PORT_STATE_RESUMING:
+			return 'F';
+		default:
+			return '?';
+	}
+}
+
+/** Initialize single hub port.
+ *
+ * @param port Port to be initialized.
+ * @param index Port index (one based).
+ */
+static void hub_init_port(hub_port_t *port, hub_t *hub, size_t index)
+{
+	port->connected_device = NULL;
+	port->index = index;
+	port->state = HUB_PORT_STATE_NOT_CONFIGURED;
+	port->status_change = 0;
+	port->hub = hub;
+}
+
+/** Initialize the hub.
+ *
+ * @param hub Hub to be initialized.
+ */
+void hub_init(hub_t *hub)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_init_port(&hub->ports[i], hub, i + 1);
+	}
+	hub->custom_data = NULL;
+	hub->signal_changes = true;
+	fibril_mutex_initialize(&hub->guard);
+}
+
+/** Connect a device to the hub.
+ *
+ * @param hub Hub to connect device to.
+ * @param device Device to be connected.
+ * @return Index of port the device was connected to.
+ * @retval -1 No free port available.
+ */
+size_t hub_connect_device(hub_t *hub, void *device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub->ports[i];
+
+		if (port->connected_device != NULL) {
+			continue;
+		}
+
+		port->connected_device = device;
+
+		/*
+		 * TODO:
+		 * If the hub was configured, we can normally
+		 * announce the plug-in.
+		 * Otherwise, we will wait until hub is configured
+		 * and announce changes in single burst.
+		 */
+		//if (port->state == HUB_PORT_STATE_DISCONNECTED) {
+			port->state = HUB_PORT_STATE_DISABLED;
+			set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+		//}
+
+		return i;
+	}
+
+	return (size_t) -1;
+}
+
+/** Disconnects a device from a hub.
+ *
+ * @param hub Hub the device was connected to.
+ * @param device Device to be disconnected.
+ * @return Error code.
+ */
+int hub_disconnect_device(hub_t *hub, void *device)
+{
+	size_t index = hub_find_device(hub, device);
+	if (index == (size_t) -1) {
+		return ENOENT;
+	}
+
+	hub_port_t *port = &hub->ports[index];
+
+	port->connected_device = NULL;
+	port->state = HUB_PORT_STATE_DISCONNECTED;
+	set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+
+	return EOK;
+}
+
+/** Find port device is connected to.
+ *
+ * @param hub Hub in question.
+ * @param device Device in question.
+ * @return Port index (zero based).
+ * @retval -1 Device is not connected.
+ */
+size_t hub_find_device(hub_t *hub, void *device)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub->ports[i];
+
+		if (port->connected_device == device) {
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+/** Acquire exclusive access to the hub.
+ *
+ * @param hub Hub in question.
+ */
+void hub_acquire(hub_t *hub)
+{
+	fibril_mutex_lock(&hub->guard);
+}
+
+/** Give up exclusive access to the hub.
+ *
+ * @param hub Hub in question.
+ */
+void hub_release(hub_t *hub)
+{
+	fibril_mutex_unlock(&hub->guard);
+}
+
+/** Change port state.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @param state New port state.
+ */
+void hub_set_port_state(hub_t *hub, size_t port_index, hub_port_state_t state)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return;
+	}
+
+	usb_log_debug("Setting port %zu to state %d.\n", port_index, state);
+
+	switch (state) {
+		case HUB_PORT_STATE_POWERED_OFF:
+			clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+			clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
+			clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
+			break;
+		case HUB_PORT_STATE_RESUMING:
+			port->state = state;
+			set_port_state_delayed(hub, port_index,
+			    10, state, HUB_PORT_STATE_ENABLED);
+			break;
+		case HUB_PORT_STATE_RESETTING:
+			port->state = state;
+			set_port_state_delayed(hub, port_index,
+			    10, state, HUB_PORT_STATE_ENABLED);
+			break;
+		case HUB_PORT_STATE_ENABLED:
+			if (port->state == HUB_PORT_STATE_RESETTING) {
+				set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
+			}
+			break;
+		default:
+			break;
+	}
+
+	port->state = state;
+}
+
+/** Change state of all ports.
+ *
+ * @param hub Hub in question.
+ * @param state New state for all ports.
+ */
+void hub_set_port_state_all(hub_t *hub, hub_port_state_t state)
+{
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_set_port_state(hub, i, state);
+	}
+}
+
+/** Get port state.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @return Port state.
+ */
+hub_port_state_t hub_get_port_state(hub_t *hub, size_t port_index)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return HUB_PORT_STATE_UNKNOWN;
+	}
+
+	return port->state;
+}
+
+/** Clear port status change bit.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @param change Change to be cleared.
+ */
+void hub_clear_port_status_change(hub_t *hub, size_t port_index,
+    hub_status_change_t change)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return;
+	}
+
+	clear_port_status_change(port, change);
+}
+
+/** Get port status change bits.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @return Port status change bitmap in standard format.
+ */
+uint16_t hub_get_port_status_change(hub_t *hub, size_t port_index)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return 0;
+	}
+
+	return port->status_change;
+}
+
+/** Get port status bits.
+ *
+ * @param hub Hub the port belongs to.
+ * @param port_index Port index (zero based).
+ * @return Port status bitmap in standard format.
+ */
+uint32_t hub_get_port_status(hub_t *hub, size_t port_index)
+{
+	hub_port_t *port = get_hub_port(hub, port_index);
+	if (port == NULL) {
+		return 0;
+	}
+
+	uint32_t status;
+	status = MAKE_BYTE(
+	    /* Current connect status. */
+	    port->connected_device == NULL ? 0 : 1,
+	    /* Port enabled/disabled. */
+	    port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
+	    /* Suspend. */
+	    (port->state == HUB_PORT_STATE_SUSPENDED)
+		|| (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
+	    /* Over-current. */
+	    0,
+	    /* Reset. */
+	    port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
+	    /* Reserved. */
+	    0, 0, 0)
+
+	    | (MAKE_BYTE(
+	    /* Port power. */
+	    port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
+	    /* Full-speed device. */
+	    0,
+	    /* Reserved. */
+	    0, 0, 0, 0, 0, 0
+	    )) << 8;
+
+	status |= (port->status_change << 16);
+
+	return status;
+}
+
+/** Create hub status change bitmap.
+ *
+ * @warning This function assumes that the whole bitmap fits into 8 bits.
+ *
+ * @param hub Hub in question.
+ * @return Hub status change bitmap.
+ */
+uint8_t hub_get_status_change_bitmap(hub_t *hub)
+{
+	uint8_t change_map = 0;
+
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub->ports[i];
+
+		if (port->status_change != 0) {
+			change_map |= (1 << port->index);
+		}
+	}
+
+	return change_map;
+}
+
+
+/*
+ *
+ * STATIC (HELPER) FUNCTIONS
+ *
+ */
+
+/** Find a port in a hub.
+ *
+ * @param hub Hub in question.
+ * @param port Port index (zero based).
+ * @return Port structure.
+ * @retval NULL Invalid port index.
+ */
+static hub_port_t *get_hub_port(hub_t *hub, size_t port)
+{
+	if (port >= HUB_PORT_COUNT) {
+		return NULL;
+	}
+
+	return &hub->ports[port];
+}
+
+/** Adds a port status change to a port.
+ *
+ * @param port The port with status change.
+ * @param change Change to be added to the status.
+ */
+static void set_port_status_change(hub_port_t *port,
+    hub_status_change_t change)
+{
+	assert(port != NULL);
+	uint16_t old_value = port->status_change;
+	port->status_change |= change;
+	usb_log_debug("Changing status change on %zu: %04x => %04x\n",
+	    port->index,
+	    (unsigned int) old_value, (unsigned int) port->status_change);
+	port->hub->signal_changes = true;
+}
+
+/** Clears a port status change on a port.
+ *
+ * @param port The port with status change.
+ * @param change Change to be removed from the status.
+ */
+static void clear_port_status_change(hub_port_t *port,
+    uint16_t change)
+{
+	assert(port != NULL);
+	port->status_change &= (~change);
+	port->hub->signal_changes = true;
+}
+
+/** Structure for automatic (delayed) port state change. */
+struct delay_port_state_change {
+	/** Delay in microseconds. */
+	suseconds_t delay;
+	/** Old state of the port. */
+	hub_port_state_t old_state;
+	/** New state of the port. */
+	hub_port_state_t new_state;
+	/** Port index (zero based). */
+	size_t port;
+	/** Hub. */
+	hub_t *hub;
+};
+
+/** Fibril responsible for delayed port state change.
+ *
+ * @param arg Pointer to delay_port_state_change.
+ * @return Always EOK.
+ */
+static int set_port_state_delayed_fibril(void *arg)
+{
+	struct delay_port_state_change *change
+	    = (struct delay_port_state_change *) arg;
+
+	async_usleep(change->delay);
+
+	hub_acquire(change->hub);
+
+	hub_port_t *port = get_hub_port(change->hub, change->port);
+	assert(port != NULL);
+
+	if (port->state == change->old_state) {
+		hub_set_port_state(change->hub, change->port,
+		    change->new_state);
+	}
+
+	hub_release(change->hub);
+
+	free(change);
+
+	return EOK;
+}
+
+/** Change port state with a delay.
+ *
+ * @warning If the port state changes during the waiting phase, the state
+ * is not changed.
+ *
+ * @param hub Hub in question.
+ * @param port_index Port index (zero based).
+ * @param delay_time_ms Delay time in miliseconds.
+ * @param old_state Old (current) state of the port.
+ * @param new_state New state of the port.
+ */
+static void set_port_state_delayed(hub_t *hub, size_t port_index,
+    suseconds_t delay_time_ms,
+    hub_port_state_t old_state, hub_port_state_t new_state)
+{
+	struct delay_port_state_change *change
+	    = malloc(sizeof(struct delay_port_state_change));
+
+	change->hub = hub;
+	change->port = port_index;
+	change->delay = delay_time_ms * 1000;
+	change->old_state = old_state;
+	change->new_state = new_state;
+	fid_t fibril = fibril_create(set_port_state_delayed_fibril, change);
+	if (fibril == 0) {
+		printf("Failed to create fibril\n");
+		free(change);
+		return;
+	}
+	fibril_add_ready(fibril);
+}
+
+
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/hub.h
===================================================================
--- uspace/drv/vhc/hub/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Representation of an USB hub.
+ */
+#ifndef VHC_HUB_HUB_H_
+#define VHC_HUB_HUB_H_
+
+#include <fibril_synch.h>
+
+#ifndef HUB_PORT_COUNT
+#define HUB_PORT_COUNT 2
+#endif
+#define BITS2BYTES(bits) (bits ? ((((bits)-1)>>3)+1) : 0)
+
+/** Hub port internal state.
+ * Some states (e.g. port over current) are not covered as they are not
+ * simulated at all.
+ */
+typedef enum {
+	HUB_PORT_STATE_UNKNOWN,
+	HUB_PORT_STATE_NOT_CONFIGURED,
+	HUB_PORT_STATE_POWERED_OFF,
+	HUB_PORT_STATE_DISCONNECTED,
+	HUB_PORT_STATE_DISABLED,
+	HUB_PORT_STATE_RESETTING,
+	HUB_PORT_STATE_ENABLED,
+	HUB_PORT_STATE_SUSPENDED,
+	HUB_PORT_STATE_RESUMING,
+	/* HUB_PORT_STATE_, */
+} hub_port_state_t;
+
+char hub_port_state_to_char(hub_port_state_t);
+
+/** Hub status change mask bits. */
+typedef enum {
+	HUB_STATUS_C_PORT_CONNECTION = (1 << 0),
+	HUB_STATUS_C_PORT_ENABLE = (1 << 1),
+	HUB_STATUS_C_PORT_SUSPEND = (1 << 2),
+	HUB_STATUS_C_PORT_OVER_CURRENT = (1 << 3),
+	HUB_STATUS_C_PORT_RESET = (1 << 4),
+	/* HUB_STATUS_C_ = (1 << ), */
+} hub_status_change_t;
+
+typedef struct hub hub_t;
+
+/** Hub port information. */
+typedef struct {
+	/** Custom pointer to connected device. */
+	void *connected_device;
+	/** Port index (one based). */
+	size_t index;
+	/** Port state. */
+	hub_port_state_t state;
+	/** Status change bitmap. */
+	uint16_t status_change;
+	/** Containing hub. */
+	hub_t *hub;
+} hub_port_t;
+
+/** Hub device type. */
+struct hub {
+	/** Hub ports. */
+	hub_port_t ports[HUB_PORT_COUNT];
+	/** Custom hub data. */
+	void *custom_data;
+	/** Access guard to the whole hub. */
+	fibril_mutex_t guard;
+	/** Last value of status change bitmap. */
+	bool signal_changes;
+};
+
+void hub_init(hub_t *);
+size_t hub_connect_device(hub_t *, void *);
+int hub_disconnect_device(hub_t *, void *);
+size_t hub_find_device(hub_t *, void *);
+void hub_acquire(hub_t *);
+void hub_release(hub_t *);
+void hub_set_port_state(hub_t *, size_t, hub_port_state_t);
+void hub_set_port_state_all(hub_t *, hub_port_state_t);
+hub_port_state_t hub_get_port_state(hub_t *, size_t);
+void hub_clear_port_status_change(hub_t *, size_t, hub_status_change_t);
+uint16_t hub_get_port_status_change(hub_t *, size_t);
+uint32_t hub_get_port_status(hub_t *, size_t);
+uint8_t hub_get_status_change_bitmap(hub_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/virthub.c
===================================================================
--- uspace/drv/vhc/hub/virthub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub/virthub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief
+ */
+#include <usb/classes/classes.h>
+#include <usbvirt/device.h>
+#include <assert.h>
+#include <errno.h>
+#include <str_error.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ddf/driver.h>
+
+#include "virthub.h"
+#include "hub.h"
+
+
+/** Standard device descriptor. */
+usb_standard_device_descriptor_t std_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_HUB,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+/** Standard interface descriptor. */
+usb_standard_interface_descriptor_t std_interface_descriptor = {
+	.length = sizeof(usb_standard_interface_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_INTERFACE,
+	.interface_number = 0,
+	.alternate_setting = 0,
+	.endpoint_count = 1,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.str_interface = 0
+};
+
+/** Hub descriptor. */
+hub_descriptor_t hub_descriptor = {
+	.length = sizeof(hub_descriptor_t),
+	.type = USB_DESCTYPE_HUB,
+	.port_count = HUB_PORT_COUNT,
+	.characteristics = 0, 
+	.power_on_warm_up = 50, /* Huh? */
+	.max_current = 100, /* Huh again. */
+	.removable_device = { 0 },
+	.port_power = { 0xFF }
+};
+
+/** Endpoint descriptor. */
+usb_standard_endpoint_descriptor_t endpoint_descriptor = {
+	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_ENDPOINT,
+	.endpoint_address = HUB_STATUS_CHANGE_PIPE | 128,
+	.attributes = USB_TRANSFER_INTERRUPT,
+	.max_packet_size = 8,
+	.poll_interval = 0xFF
+};
+
+/** Standard configuration descriptor. */
+usb_standard_configuration_descriptor_t std_configuration_descriptor = {
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	.total_length = 
+		sizeof(usb_standard_configuration_descriptor_t)
+		+ sizeof(std_interface_descriptor)
+		+ sizeof(hub_descriptor)
+		+ sizeof(endpoint_descriptor)
+		,
+	.interface_count = 1,
+	.configuration_number = HUB_CONFIGURATION_ID,
+	.str_configuration = 0,
+	.attributes = 128, /* denotes bus-powered device */
+	.max_power = 50
+};
+
+/** All hub configuration descriptors. */
+static usbvirt_device_configuration_extras_t extra_descriptors[] = {
+	{
+		.data = (uint8_t *) &std_interface_descriptor,
+		.length = sizeof(std_interface_descriptor)
+	},
+	{
+		.data = (uint8_t *) &hub_descriptor,
+		.length = sizeof(hub_descriptor)
+	},
+	{
+		.data = (uint8_t *) &endpoint_descriptor,
+		.length = sizeof(endpoint_descriptor)
+	}
+};
+
+/** Hub configuration. */
+usbvirt_device_configuration_t configuration = {
+	.descriptor = &std_configuration_descriptor,
+	.extra = extra_descriptors,
+	.extra_count = sizeof(extra_descriptors)/sizeof(extra_descriptors[0])
+};
+
+/** Hub standard descriptors. */
+usbvirt_descriptors_t descriptors = {
+	.device = &std_device_descriptor,
+	.configuration = &configuration,
+	.configuration_count = 1,
+};
+
+/** Initializes virtual hub device.
+ *
+ * @param dev Virtual USB device backend.
+ * @return Error code.
+ */
+int virthub_init(usbvirt_device_t *dev)
+{
+	if (dev == NULL) {
+		return EBADMEM;
+	}
+	dev->ops = &hub_ops;
+	dev->descriptors = &descriptors;
+
+	hub_t *hub = malloc(sizeof(hub_t));
+	if (hub == NULL) {
+		return ENOMEM;
+	}
+
+	hub_init(hub);
+	dev->device_data = hub;
+
+	return EOK;
+}
+
+/** Connect a device to a virtual hub.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param conn Device to be connected.
+ * @return Port device was connected to.
+ */
+int virthub_connect_device(usbvirt_device_t *dev, vhc_virtdev_t *conn)
+{
+	assert(dev != NULL);
+	assert(conn != NULL);
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+	size_t port = hub_connect_device(hub, conn);
+	hub_release(hub);
+
+	return port;
+}
+
+/** Disconnect a device from a virtual hub.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param conn Device to be disconnected.
+ * @return Error code.
+ */
+int virthub_disconnect_device(usbvirt_device_t *dev, vhc_virtdev_t *conn)
+{
+	assert(dev != NULL);
+	assert(conn != NULL);
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+	hub_disconnect_device(hub, conn);
+	hub_release(hub);
+
+	return EOK;
+}
+
+/** Whether trafic is propagated to given device.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param conn Connected device.
+ * @return Whether port is signalling to the device.
+ */
+bool virthub_is_device_enabled(usbvirt_device_t *dev, vhc_virtdev_t *conn)
+{
+	assert(dev != NULL);
+	assert(conn != NULL);
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	hub_port_state_t state = HUB_PORT_STATE_UNKNOWN;
+	size_t port = hub_find_device(hub, conn);
+	if (port != (size_t) -1) {
+		state = hub_get_port_state(hub, port);
+	}
+	hub_release(hub);
+
+	return state == HUB_PORT_STATE_ENABLED;
+}
+
+/** Format status of a virtual hub.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param[out] status Hub status information.
+ * @param[in] len Size of the @p status buffer.
+ */
+void virthub_get_status(usbvirt_device_t *dev, char *status, size_t len)
+{
+	assert(dev != NULL);
+	if (len == 0) {
+		return;
+	}
+
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	char port_status[HUB_PORT_COUNT + 1];
+
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		port_status[i] = hub_port_state_to_char(
+		    hub_get_port_state(hub, i));
+	}
+	port_status[HUB_PORT_COUNT] = 0;
+
+	snprintf(status, len, "vhub:%s", port_status);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/virthub.h
===================================================================
--- uspace/drv/vhc/hub/virthub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub/virthub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief USB hub as a virtual USB device.
+ */
+#ifndef VHC_HUB_VIRTHUB_H_
+#define VHC_HUB_VIRTHUB_H_
+
+#include <usbvirt/device.h>
+#include "hub.h"
+
+#ifdef STANDALONE_HUB
+#define virtdev_connection_t int
+#else
+#include "../vhcd.h"
+#endif
+
+/** Endpoint number for status change pipe. */
+#define HUB_STATUS_CHANGE_PIPE 1
+/** Configuration value for hub configuration. */
+#define HUB_CONFIGURATION_ID 1
+
+
+/** Hub descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_HUB). */
+	uint8_t type;
+	/** Number of downstream ports. */
+	uint8_t port_count;
+	/** Hub characteristics. */
+	uint16_t characteristics;
+	/** Time from power-on to stabilized current.
+	 * Expressed in 2ms unit.
+	 */
+	uint8_t power_on_warm_up;
+	/** Maximum current (in mA). */
+	uint8_t max_current;
+	/** Whether device at given port is removable. */
+	uint8_t removable_device[BITS2BYTES(HUB_PORT_COUNT+1)];
+	/** Port power control.
+	 * This is USB1.0 compatibility field, all bits must be 1.
+	 */
+	uint8_t port_power[BITS2BYTES(HUB_PORT_COUNT+1)];
+} __attribute__ ((packed)) hub_descriptor_t;
+
+extern usbvirt_device_ops_t hub_ops;
+extern hub_descriptor_t hub_descriptor;
+
+int virthub_init(usbvirt_device_t *);
+int virthub_connect_device(usbvirt_device_t *, vhc_virtdev_t *);
+int virthub_disconnect_device(usbvirt_device_t *, vhc_virtdev_t *);
+bool virthub_is_device_enabled(usbvirt_device_t *, vhc_virtdev_t *);
+void virthub_get_status(usbvirt_device_t *, char *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/vhc/hub/virthubops.c
===================================================================
--- uspace/drv/vhc/hub/virthubops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/hub/virthubops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Virtual USB hub operations.
+ */
+#include <errno.h>
+#include <usb/classes/hub.h>
+#include <usbvirt/device.h>
+#include "virthub.h"
+#include "hub.h"
+
+/** Callback when device changes states. */
+static void on_state_change(usbvirt_device_t *dev,
+    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state)
+{
+	hub_t *hub = (hub_t *)dev->device_data;
+
+	hub_acquire(hub);
+
+	switch (new_state) {
+		case USBVIRT_STATE_CONFIGURED:
+			hub_set_port_state_all(hub, HUB_PORT_STATE_POWERED_OFF);
+			break;
+		case USBVIRT_STATE_ADDRESS:
+			hub_set_port_state_all(hub, HUB_PORT_STATE_NOT_CONFIGURED);
+			break;
+		default:
+			break;
+	}
+
+	hub_release(hub);
+}
+
+/** Callback for data request. */
+static int req_on_status_change_pipe(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t tr_type,
+    void *buffer, size_t buffer_size, size_t *actual_size)
+{
+	if (endpoint != HUB_STATUS_CHANGE_PIPE) {
+		return ESTALL;
+	}
+	if (tr_type != USB_TRANSFER_INTERRUPT) {
+		return ESTALL;
+	}
+	
+	hub_t *hub = dev->device_data;
+
+	hub_acquire(hub);
+
+	if (!hub->signal_changes) {
+		hub_release(hub);
+
+		return ENAK;
+	}
+
+
+	uint8_t change_map = hub_get_status_change_bitmap(hub);
+
+	uint8_t *b = (uint8_t *) buffer;
+	if (buffer_size > 0) {
+		*b = change_map;
+		*actual_size = 1;
+	} else {
+		*actual_size = 0;
+	}
+	
+	hub->signal_changes = false;
+
+	hub_release(hub);
+
+	return EOK;
+}
+
+/** Handle ClearHubFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_clear_hub_feature(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	return ENOTSUP;
+}
+
+/** Handle ClearPortFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_clear_port_feature(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	int rc;
+	size_t port = request->index - 1;
+	usb_hub_class_feature_t feature = request->value;
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	hub_port_state_t port_state = hub_get_port_state(hub, port);
+
+	switch (feature) {
+		case USB_HUB_FEATURE_PORT_ENABLE:
+			if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED)
+			    && (port_state != HUB_PORT_STATE_POWERED_OFF)) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_DISABLED);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_SUSPEND:
+			if (port_state != HUB_PORT_STATE_SUSPENDED) {
+				rc = EOK;
+				break;
+			}
+			hub_set_port_state(hub, port, HUB_PORT_STATE_RESUMING);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_POWER:
+			if (port_state != HUB_PORT_STATE_NOT_CONFIGURED) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_POWERED_OFF);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_CONNECTION:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_CONNECTION);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_ENABLE:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_SUSPEND:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_OVER_CURRENT);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_RESET:
+			hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_RESET);
+			rc = EOK;
+			break;
+
+		default:
+			rc = ENOTSUP;
+			break;
+	}
+
+	hub_release(hub);
+
+	return rc;
+}
+
+/** Handle GetBusState request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_bus_state(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	return ENOTSUP;
+}
+
+/** Handle GetDescriptor request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_descriptor(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	if (request->value_high == USB_DESCTYPE_HUB) {
+		usbvirt_control_reply_helper(request, data, act_size,
+		    &hub_descriptor, hub_descriptor.length);
+
+		return EOK;
+	}
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+/** Handle GetHubStatus request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_hub_status(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	uint32_t hub_status = 0;
+
+	usbvirt_control_reply_helper(request, data, act_size,
+	    &hub_status, sizeof(hub_status));
+
+	return EOK;
+}
+
+/** Handle GetPortStatus request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_get_port_status(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	uint32_t status = hub_get_port_status(hub, request->index - 1);
+
+	hub_release(hub);
+
+	usbvirt_control_reply_helper(request, data, act_size,
+	    &status, sizeof(status));
+
+	return EOK;
+}
+
+/** Handle SetHubFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_set_hub_feature(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	return ENOTSUP;
+}
+
+/** Handle SetPortFeature request.
+ *
+ * @param dev Virtual device representing the hub.
+ * @param request The SETUP packet of the control request.
+ * @param data Extra data (when DATA stage present).
+ * @return Error code.
+ */
+static int req_set_port_feature(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *request, uint8_t *data,
+    size_t *act_size)
+{
+	int rc;
+	size_t port = request->index - 1;
+	usb_hub_class_feature_t feature = request->value;
+	hub_t *hub = (hub_t *) dev->device_data;
+
+	hub_acquire(hub);
+
+	hub_port_state_t port_state = hub_get_port_state(hub, port);
+
+	switch (feature) {
+		case USB_HUB_FEATURE_PORT_RESET:
+			if (port_state != HUB_PORT_STATE_POWERED_OFF) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_RESETTING);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_SUSPEND:
+			if (port_state == HUB_PORT_STATE_ENABLED) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED);
+			}
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_PORT_POWER:
+			if (port_state == HUB_PORT_STATE_POWERED_OFF) {
+				hub_set_port_state(hub, port, HUB_PORT_STATE_DISCONNECTED);
+			}
+			rc = EOK;
+			break;
+
+		default:
+			break;
+	}
+
+	hub_release(hub);
+
+	return rc;
+}
+
+
+/** IN class request. */
+#define CLASS_REQ_IN(recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_IN, \
+	USBVIRT_REQUEST_TYPE_CLASS, recipient)
+/** OUT class request. */
+#define CLASS_REQ_OUT(recipient) \
+	USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_OUT, \
+	USBVIRT_REQUEST_TYPE_CLASS, recipient)
+
+/** Recipient: other. */
+#define REC_OTHER USB_REQUEST_RECIPIENT_OTHER
+/** Recipient: device. */
+#define REC_DEVICE USB_REQUEST_RECIPIENT_DEVICE
+/** Direction: in. */
+#define DIR_IN USB_DIRECTION_IN
+/** Direction: out. */
+#define DIR_OUT USB_DIRECTION_OUT
+
+
+/** Create a class request.
+ *
+ * @param direction Request direction.
+ * @param recipient Request recipient.
+ * @param req Request code.
+ */
+#define CLASS_REQ(direction, recipient, req) \
+	.req_direction = direction, \
+	.req_recipient = recipient, \
+	.req_type = USB_REQUEST_TYPE_CLASS, \
+	.request = req
+
+/** Create a standard request.
+ *
+ * @param direction Request direction.
+ * @param recipient Request recipient.
+ * @param req Request code.
+ */
+#define STD_REQ(direction, recipient, req) \
+	.req_direction = direction, \
+	.req_recipient = recipient, \
+	.req_type = USB_REQUEST_TYPE_STANDARD, \
+	.request = req
+
+/** Hub operations on control endpoint zero. */
+static usbvirt_control_request_handler_t endpoint_zero_handlers[] = {
+	{
+		STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.name = "GetDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
+		.name = "GetDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
+		.name = "GetPortStatus",
+		.callback = req_get_port_status
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
+		.name = "ClearHubFeature",
+		.callback = req_clear_hub_feature
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
+		.name = "ClearPortFeature",
+		.callback = req_clear_port_feature
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATE),
+		.name = "GetBusState",
+		.callback = req_get_bus_state
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
+		.name = "GetHubDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_STATUS),
+		.name = "GetHubStatus",
+		.callback = req_get_hub_status
+	},
+	{
+		CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
+		.name = "GetPortStatus",
+		.callback = req_get_port_status
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
+		.name = "SetHubFeature",
+		.callback = req_set_hub_feature
+	},
+	{
+		CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_SET_FEATURE),
+		.name = "SetPortFeature",
+		.callback = req_set_port_feature
+	},
+	{
+		.callback = NULL
+	}
+};
+
+
+/** Hub operations. */
+usbvirt_device_ops_t hub_ops = {
+	.control = endpoint_zero_handlers,
+	.data_in[HUB_STATUS_CHANGE_PIPE] = req_on_status_change_pipe,
+	.state_changed = on_state_change,
+};
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/main.c
===================================================================
--- uspace/drv/vhc/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,153 @@
+/*
+ * 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * Virtual host controller.
+ */
+
+#include <devmap.h>
+#include <async.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sysinfo.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/driver.h>
+
+#include <usb/usb.h>
+#include <usb/ddfiface.h>
+#include <usb_iface.h>
+#include "vhcd.h"
+#include "hub.h"
+#include "conn.h"
+
+static ddf_dev_ops_t vhc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &vhc_iface,
+	.interfaces[USB_DEV_IFACE] = &vhc_usb_iface,
+	.close = on_client_close,
+	.default_handler = default_connection_handler
+};
+
+static int vhc_add_device(ddf_dev_t *dev)
+{
+	static int vhc_count = 0;
+	int rc;
+
+	if (vhc_count > 0) {
+		return ELIMIT;
+	}
+
+	vhc_data_t *data = malloc(sizeof(vhc_data_t));
+	if (data == NULL) {
+		usb_log_fatal("Failed to allocate memory.\n");
+		return ENOMEM;
+	}
+	data->magic = 0xDEADBEEF;
+	rc = usb_endpoint_manager_init(&data->ep_manager, (size_t) -1);
+	if (rc != EOK) {
+		usb_log_fatal("Failed to initialize endpoint manager.\n");
+		free(data);
+		return rc;
+	}
+	usb_device_keeper_init(&data->dev_keeper);
+
+	ddf_fun_t *hc = ddf_fun_create(dev, fun_exposed, "hc");
+	if (hc == NULL) {
+		usb_log_fatal("Failed to create device function.\n");
+		free(data);
+		return ENOMEM;
+	}
+
+	hc->ops = &vhc_ops;
+	list_initialize(&data->devices);
+	fibril_mutex_initialize(&data->guard);
+	data->hub = &virtual_hub_device;
+	data->hc_fun = hc;
+
+	dev->driver_data = data;
+
+	rc = ddf_fun_bind(hc);
+	if (rc != EOK) {
+		usb_log_fatal("Failed to bind HC function: %s.\n",
+		    str_error(rc));
+		free(data);
+		return rc;
+	}
+
+	rc = ddf_fun_add_to_class(hc, USB_HC_DDF_CLASS_NAME);
+	if (rc != EOK) {
+		usb_log_fatal("Failed to add function to HC class: %s.\n",
+		    str_error(rc));
+		free(data);
+		return rc;
+	}
+
+	virtual_hub_device_init(hc);
+
+	usb_log_info("Virtual USB host controller ready (dev %zu, hc %zu).\n",
+	    (size_t) dev->handle, (size_t) hc->handle);
+
+
+
+	rc = vhc_virtdev_plug_hub(data, data->hub, NULL);
+	if (rc != EOK) {
+		usb_log_fatal("Failed to plug root hub: %s.\n", str_error(rc));
+		free(data);
+		return rc;
+	}
+
+	return EOK;
+}
+
+static driver_ops_t vhc_driver_ops = {
+	.add_device = vhc_add_device,
+};
+
+static driver_t vhc_driver = {
+	.name = NAME,
+	.driver_ops = &vhc_driver_ops
+};
+
+
+int main(int argc, char * argv[])
+{	
+	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
+
+	printf(NAME ": virtual USB host controller driver.\n");
+
+	return ddf_driver_main(&vhc_driver);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/drv/vhc/transfer.c
===================================================================
--- uspace/drv/vhc/transfer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/transfer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <str_error.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include "vhcd.h"
+
+vhc_transfer_t *vhc_transfer_create(usb_address_t address, usb_endpoint_t ep,
+    usb_direction_t dir, usb_transfer_type_t tr_type,
+    ddf_fun_t *fun, void *callback_arg)
+{
+	vhc_transfer_t *result = malloc(sizeof(vhc_transfer_t));
+	if (result == NULL) {
+		return NULL;
+	}
+	link_initialize(&result->link);
+	result->address = address;
+	result->endpoint = ep;
+	result->direction = dir;
+	result->transfer_type = tr_type;
+	result->setup_buffer = NULL;
+	result->setup_buffer_size = 0;
+	result->data_buffer = NULL;
+	result->data_buffer_size = 0;
+	result->ddf_fun = fun;
+	result->callback_arg = callback_arg;
+	result->callback_in = NULL;
+	result->callback_out = NULL;
+
+	usb_log_debug2("Created transfer %p (%d.%d %s %s)\n", result,
+	    address, ep, usb_str_transfer_type_short(tr_type),
+	    dir == USB_DIRECTION_IN ? "in" : "out");
+
+	return result;
+}
+
+static bool is_set_address_transfer(vhc_transfer_t *transfer)
+{
+	if (transfer->endpoint != 0) {
+		return false;
+	}
+	if (transfer->transfer_type != USB_TRANSFER_CONTROL) {
+		return false;
+	}
+	if (transfer->direction != USB_DIRECTION_OUT) {
+		return false;
+	}
+	if (transfer->setup_buffer_size != sizeof(usb_device_request_setup_packet_t)) {
+		return false;
+	}
+	usb_device_request_setup_packet_t *setup = transfer->setup_buffer;
+	if (setup->request_type != 0) {
+		return false;
+	}
+	if (setup->request != USB_DEVREQ_SET_ADDRESS) {
+		return false;
+	}
+
+	return true;
+}
+
+int vhc_virtdev_add_transfer(vhc_data_t *vhc, vhc_transfer_t *transfer)
+{
+	fibril_mutex_lock(&vhc->guard);
+
+	bool target_found = false;
+	list_foreach(vhc->devices, pos) {
+		vhc_virtdev_t *dev = list_get_instance(pos, vhc_virtdev_t, link);
+		fibril_mutex_lock(&dev->guard);
+		if (dev->address == transfer->address) {
+			if (target_found) {
+				usb_log_warning("Transfer would be accepted by more devices!\n");
+				goto next;
+			}
+			target_found = true;
+			list_append(&transfer->link, &dev->transfer_queue);
+		}
+next:
+		fibril_mutex_unlock(&dev->guard);
+	}
+
+	fibril_mutex_unlock(&vhc->guard);
+
+	if (target_found) {
+		return EOK;
+	} else {
+		return ENOENT;
+	}
+}
+
+static int process_transfer_local(vhc_transfer_t *transfer,
+    usbvirt_device_t *dev, size_t *actual_data_size)
+{
+	int rc;
+
+	if (transfer->transfer_type == USB_TRANSFER_CONTROL) {
+		if (transfer->direction == USB_DIRECTION_IN) {
+			rc = usbvirt_control_read(dev,
+			    transfer->setup_buffer, transfer->setup_buffer_size,
+			    transfer->data_buffer, transfer->data_buffer_size,
+			    actual_data_size);
+		} else {
+			assert(transfer->direction == USB_DIRECTION_OUT);
+			rc = usbvirt_control_write(dev,
+			    transfer->setup_buffer, transfer->setup_buffer_size,
+			    transfer->data_buffer, transfer->data_buffer_size);
+		}
+	} else {
+		if (transfer->direction == USB_DIRECTION_IN) {
+			rc = usbvirt_data_in(dev, transfer->transfer_type,
+			    transfer->endpoint,
+			    transfer->data_buffer, transfer->data_buffer_size,
+			    actual_data_size);
+		} else {
+			assert(transfer->direction == USB_DIRECTION_OUT);
+			rc = usbvirt_data_out(dev, transfer->transfer_type,
+			    transfer->endpoint,
+			    transfer->data_buffer, transfer->data_buffer_size);
+		}
+	}
+
+	return rc;
+}
+
+static int process_transfer_remote(vhc_transfer_t *transfer,
+    async_sess_t *sess, size_t *actual_data_size)
+{
+	int rc;
+
+	if (transfer->transfer_type == USB_TRANSFER_CONTROL) {
+		if (transfer->direction == USB_DIRECTION_IN) {
+			rc = usbvirt_ipc_send_control_read(sess,
+			    transfer->setup_buffer, transfer->setup_buffer_size,
+			    transfer->data_buffer, transfer->data_buffer_size,
+			    actual_data_size);
+		} else {
+			assert(transfer->direction == USB_DIRECTION_OUT);
+			rc = usbvirt_ipc_send_control_write(sess,
+			    transfer->setup_buffer, transfer->setup_buffer_size,
+			    transfer->data_buffer, transfer->data_buffer_size);
+		}
+	} else {
+		if (transfer->direction == USB_DIRECTION_IN) {
+			rc = usbvirt_ipc_send_data_in(sess, transfer->endpoint,
+			    transfer->transfer_type,
+			    transfer->data_buffer, transfer->data_buffer_size,
+			    actual_data_size);
+		} else {
+			assert(transfer->direction == USB_DIRECTION_OUT);
+			rc = usbvirt_ipc_send_data_out(sess, transfer->endpoint,
+			    transfer->transfer_type,
+			    transfer->data_buffer, transfer->data_buffer_size);
+		}
+	}
+
+	return rc;
+}
+
+static vhc_transfer_t *dequeue_first_transfer(vhc_virtdev_t *dev)
+{
+	assert(fibril_mutex_is_locked(&dev->guard));
+	assert(!list_empty(&dev->transfer_queue));
+
+	vhc_transfer_t *transfer = list_get_instance(dev->transfer_queue.next,
+	    vhc_transfer_t, link);
+	list_remove(&transfer->link);
+
+	return transfer;
+}
+
+
+static void execute_transfer_callback_and_free(vhc_transfer_t *transfer,
+    size_t data_transfer_size, int outcome)
+{
+	assert(outcome != ENAK);
+
+	usb_log_debug2("Transfer %p ended: %s.\n",
+	    transfer, str_error(outcome));
+
+	if (transfer->direction == USB_DIRECTION_IN) {
+		transfer->callback_in(transfer->ddf_fun, outcome,
+		    data_transfer_size, transfer->callback_arg);
+	} else {
+		assert(transfer->direction == USB_DIRECTION_OUT);
+		transfer->callback_out(transfer->ddf_fun, outcome,
+		    transfer->callback_arg);
+	}
+
+	free(transfer);
+}
+
+int vhc_transfer_queue_processor(void *arg)
+{
+	vhc_virtdev_t *dev = arg;
+	fibril_mutex_lock(&dev->guard);
+	while (dev->plugged) {
+		if (list_empty(&dev->transfer_queue)) {
+			fibril_mutex_unlock(&dev->guard);
+			async_usleep(10 * 1000);
+			fibril_mutex_lock(&dev->guard);
+			continue;
+		}
+
+		vhc_transfer_t *transfer = dequeue_first_transfer(dev);
+		fibril_mutex_unlock(&dev->guard);
+
+		int rc = EOK;
+		size_t data_transfer_size = 0;
+		if (dev->dev_sess) {
+			rc = process_transfer_remote(transfer, dev->dev_sess,
+			    &data_transfer_size);
+		} else if (dev->dev_local != NULL) {
+			rc = process_transfer_local(transfer, dev->dev_local,
+			    &data_transfer_size);
+		} else {
+			usb_log_warning("Device has no remote phone nor local node.\n");
+			rc = ESTALL;
+		}
+
+		usb_log_debug2("Transfer %p processed: %s.\n",
+		    transfer, str_error(rc));
+
+		fibril_mutex_lock(&dev->guard);
+		if (rc == EOK) {
+			if (is_set_address_transfer(transfer)) {
+				usb_device_request_setup_packet_t *setup
+				    = transfer->setup_buffer;
+				dev->address = setup->value;
+				usb_log_debug2("Address changed to %d\n",
+				    dev->address);
+			}
+		}
+		if (rc == ENAK) {
+			// FIXME: this will work only because we do
+			// not NAK control transfers but this is generally
+			// a VERY bad idea indeed
+			list_append(&transfer->link, &dev->transfer_queue);
+		}
+		fibril_mutex_unlock(&dev->guard);
+
+		if (rc != ENAK) {
+			execute_transfer_callback_and_free(transfer,
+			    data_transfer_size, rc);
+		}
+
+		async_usleep(1000 * 100);
+		fibril_mutex_lock(&dev->guard);
+	}
+
+	/* Immediately fail all remaining transfers. */
+	while (!list_empty(&dev->transfer_queue)) {
+		vhc_transfer_t *transfer = dequeue_first_transfer(dev);
+		execute_transfer_callback_and_free(transfer, 0, EBADCHECKSUM);
+	}
+
+	fibril_mutex_unlock(&dev->guard);
+
+	return EOK;
+}
+
Index: uspace/drv/vhc/vhc.ma
===================================================================
--- uspace/drv/vhc/vhc.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/vhc.ma	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,2 @@
+10 usb&hc=vhc
+
Index: uspace/drv/vhc/vhcd.h
===================================================================
--- uspace/drv/vhc/vhcd.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/drv/vhc/vhcd.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2010 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 drvusbvhc
+ * @{
+ */
+/** @file
+ * @brief Virtual USB host controller common definitions.
+ */
+#ifndef VHCD_VHCD_H_
+#define VHCD_VHCD_H_
+
+#include <usb/debug.h>
+#include <usbvirt/device.h>
+#include <usb/host/usb_endpoint_manager.h>
+#include <usb/host/device_keeper.h>
+#include <usbhc_iface.h>
+#include <async.h>
+
+#define NAME "vhc"
+
+typedef struct {
+	link_t link;
+	async_sess_t *dev_sess;
+	usbvirt_device_t *dev_local;
+	bool plugged;
+	usb_address_t address;
+	fibril_mutex_t guard;
+	link_t transfer_queue;
+} vhc_virtdev_t;
+
+typedef struct {
+	uint32_t magic;
+	link_t devices;
+	fibril_mutex_t guard;
+	usb_endpoint_manager_t ep_manager;
+	usb_device_keeper_t dev_keeper;
+	usbvirt_device_t *hub;
+	ddf_fun_t *hc_fun;
+} vhc_data_t;
+
+typedef struct {
+	link_t link;
+	usb_address_t address;
+	usb_endpoint_t endpoint;
+	usb_direction_t direction;
+	usb_transfer_type_t transfer_type;
+	void *setup_buffer;
+	size_t setup_buffer_size;
+	void *data_buffer;
+	size_t data_buffer_size;
+	ddf_fun_t *ddf_fun;
+	void *callback_arg;
+	usbhc_iface_transfer_in_callback_t callback_in;
+	usbhc_iface_transfer_out_callback_t callback_out;
+} vhc_transfer_t;
+
+vhc_transfer_t *vhc_transfer_create(usb_address_t, usb_endpoint_t,
+    usb_direction_t, usb_transfer_type_t, ddf_fun_t *, void *);
+int vhc_virtdev_plug(vhc_data_t *, async_sess_t *, uintptr_t *);
+int vhc_virtdev_plug_local(vhc_data_t *, usbvirt_device_t *, uintptr_t *);
+int vhc_virtdev_plug_hub(vhc_data_t *, usbvirt_device_t *, uintptr_t *);
+void vhc_virtdev_unplug(vhc_data_t *, uintptr_t);
+int vhc_virtdev_add_transfer(vhc_data_t *, vhc_transfer_t *);
+
+int vhc_transfer_queue_processor(void *arg);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/block/libblock.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -2,4 +2,5 @@
  * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2008 Martin Decky
+ * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
  *
@@ -61,13 +62,13 @@
 static LIST_INITIALIZE(dcl_head);
 
-#define CACHE_BUCKETS_LOG2		10
-#define CACHE_BUCKETS			(1 << CACHE_BUCKETS_LOG2)
+#define CACHE_BUCKETS_LOG2  10
+#define CACHE_BUCKETS       (1 << CACHE_BUCKETS_LOG2)
 
 typedef struct {
 	fibril_mutex_t lock;
-	size_t lblock_size;		/**< Logical block size. */
-	unsigned blocks_cluster;	/**< Physical blocks per block_t */
-	unsigned block_count;		/**< Total number of blocks. */
-	unsigned blocks_cached;		/**< Number of cached blocks. */
+	size_t lblock_size;       /**< Logical block size. */
+	unsigned blocks_cluster;  /**< Physical blocks per block_t */
+	unsigned block_count;     /**< Total number of blocks. */
+	unsigned blocks_cached;   /**< Number of cached blocks. */
 	hash_table_t block_hash;
 	link_t free_head;
@@ -78,5 +79,5 @@
 	link_t link;
 	devmap_handle_t devmap_handle;
-	int dev_phone;
+	async_sess_t *sess;
 	fibril_mutex_t comm_area_lock;
 	void *comm_area;
@@ -84,19 +85,20 @@
 	void *bb_buf;
 	aoff64_t bb_addr;
-	size_t pblock_size;		/**< Physical block size. */
+	size_t pblock_size;  /**< Physical block size. */
 	cache_t *cache;
 } devcon_t;
 
-static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt);
-static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt);
-static int get_block_size(int dev_phone, size_t *bsize);
-static int get_num_blocks(int dev_phone, aoff64_t *nblocks);
-static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba);
+static int read_blocks(devcon_t *, aoff64_t, size_t);
+static int write_blocks(devcon_t *, aoff64_t, size_t);
+static int get_block_size(async_sess_t *, size_t *);
+static int get_num_blocks(async_sess_t *, aoff64_t *);
+static aoff64_t ba_ltop(devcon_t *, aoff64_t);
 
 static devcon_t *devcon_search(devmap_handle_t devmap_handle)
 {
 	link_t *cur;
-
+	
 	fibril_mutex_lock(&dcl_lock);
+	
 	for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
 		devcon_t *devcon = list_get_instance(cur, devcon_t, link);
@@ -106,17 +108,18 @@
 		}
 	}
+	
 	fibril_mutex_unlock(&dcl_lock);
 	return NULL;
 }
 
-static int devcon_add(devmap_handle_t devmap_handle, int dev_phone, size_t bsize,
-    void *comm_area, size_t comm_size)
+static int devcon_add(devmap_handle_t devmap_handle, async_sess_t *sess,
+    size_t bsize, void *comm_area, size_t comm_size)
 {
 	link_t *cur;
 	devcon_t *devcon;
-
+	
 	if (comm_size < bsize)
 		return EINVAL;
-
+	
 	devcon = malloc(sizeof(devcon_t));
 	if (!devcon)
@@ -125,5 +128,5 @@
 	link_initialize(&devcon->link);
 	devcon->devmap_handle = devmap_handle;
-	devcon->dev_phone = dev_phone;
+	devcon->sess = sess;
 	fibril_mutex_initialize(&devcon->comm_area_lock);
 	devcon->comm_area = comm_area;
@@ -133,5 +136,5 @@
 	devcon->pblock_size = bsize;
 	devcon->cache = NULL;
-
+	
 	fibril_mutex_lock(&dcl_lock);
 	for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) {
@@ -155,44 +158,46 @@
 }
 
-int block_init(devmap_handle_t devmap_handle, size_t comm_size)
-{
-	int rc;
-	int dev_phone;
-	void *comm_area;
-	size_t bsize;
-
-	comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE,
+int block_init(exch_mgmt_t mgmt, devmap_handle_t devmap_handle,
+    size_t comm_size)
+{
+	void *comm_area = mmap(NULL, comm_size, PROTO_READ | PROTO_WRITE,
 	    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
-	if (!comm_area) {
+	if (!comm_area)
 		return ENOMEM;
-	}
-
-	dev_phone = devmap_device_connect(devmap_handle, IPC_FLAG_BLOCKING);
-	if (dev_phone < 0) {
+	
+	async_sess_t *sess = devmap_device_connect(mgmt, devmap_handle,
+	    IPC_FLAG_BLOCKING);
+	if (!sess) {
 		munmap(comm_area, comm_size);
-		return dev_phone;
-	}
-
-	rc = async_share_out_start(dev_phone, comm_area,
+		return ENOENT;
+	}
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_share_out_start(exch, comm_area,
 	    AS_AREA_READ | AS_AREA_WRITE);
-	if (rc != EOK) {
-	    	munmap(comm_area, comm_size);
-		async_hangup(dev_phone);
-		return rc;
-	}
-
-	if (get_block_size(dev_phone, &bsize) != EOK) {
-		munmap(comm_area, comm_size);
-		async_hangup(dev_phone);
-		return rc;
-	}
-	
-	rc = devcon_add(devmap_handle, dev_phone, bsize, comm_area, comm_size);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		munmap(comm_area, comm_size);
-		async_hangup(dev_phone);
+		async_hangup(sess);
 		return rc;
 	}
-
+	
+	size_t bsize;
+	rc = get_block_size(sess, &bsize);
+	
+	if (rc != EOK) {
+		munmap(comm_area, comm_size);
+		async_hangup(sess);
+		return rc;
+	}
+	
+	rc = devcon_add(devmap_handle, sess, bsize, comm_area, comm_size);
+	if (rc != EOK) {
+		munmap(comm_area, comm_size);
+		async_hangup(sess);
+		return rc;
+	}
+	
 	return EOK;
 }
@@ -205,14 +210,14 @@
 	if (devcon->cache)
 		(void) block_cache_fini(devmap_handle);
-
+	
 	devcon_remove(devcon);
-
+	
 	if (devcon->bb_buf)
 		free(devcon->bb_buf);
-
+	
 	munmap(devcon->comm_area, devcon->comm_size);
-	async_hangup(devcon->dev_phone);
-
-	free(devcon);	
+	async_hangup(devcon->sess);
+	
+	free(devcon);
 }
 
@@ -807,5 +812,5 @@
 	assert(devcon);
 	
-	return get_block_size(devcon->dev_phone, bsize);
+	return get_block_size(devcon->sess, bsize);
 }
 
@@ -819,10 +824,60 @@
 int block_get_nblocks(devmap_handle_t devmap_handle, aoff64_t *nblocks)
 {
-	devcon_t *devcon;
-
-	devcon = devcon_search(devmap_handle);
-	assert(devcon);
-	
-	return get_num_blocks(devcon->dev_phone, nblocks);
+	devcon_t *devcon = devcon_search(devmap_handle);
+	assert(devcon);
+	
+	return get_num_blocks(devcon->sess, nblocks);
+}
+
+/** Read bytes directly from the device (bypass cache)
+ * 
+ * @param devmap_handle	Device handle of the block device.
+ * @param abs_offset	Absolute offset in bytes where to start reading
+ * @param bytes			Number of bytes to read
+ * @param data			Buffer that receives the data
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int block_read_bytes_direct(devmap_handle_t devmap_handle, aoff64_t abs_offset,
+    size_t bytes, void *data)
+{
+	int rc;
+	size_t phys_block_size;
+	size_t buf_size;
+	void *buffer;
+	aoff64_t first_block;
+	aoff64_t last_block;
+	size_t blocks;
+	size_t offset;
+	
+	rc = block_get_bsize(devmap_handle, &phys_block_size);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	/* calculate data position and required space */
+	first_block = abs_offset / phys_block_size;
+	offset = abs_offset % phys_block_size;
+	last_block = (abs_offset + bytes - 1) / phys_block_size;
+	blocks = last_block - first_block + 1;
+	buf_size = blocks * phys_block_size;
+	
+	/* read the data into memory */
+	buffer = malloc(buf_size);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+	
+	rc = block_read_direct(devmap_handle, first_block, blocks, buffer);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+	
+	/* copy the data from the buffer */
+	memcpy(data, buffer + offset, bytes);
+	free(buffer);
+	
+	return EOK;
 }
 
@@ -838,9 +893,11 @@
 static int read_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
 {
-	int rc;
-
-	assert(devcon);
-	rc = async_req_3_0(devcon->dev_phone, BD_READ_BLOCKS, LOWER32(ba),
+	assert(devcon);
+	
+	async_exch_t *exch = async_exchange_begin(devcon->sess);
+	int rc = async_req_3_0(exch, BD_READ_BLOCKS, LOWER32(ba),
 	    UPPER32(ba), cnt);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		printf("Error %d reading %zu blocks starting at block %" PRIuOFF64
@@ -851,4 +908,5 @@
 #endif
 	}
+	
 	return rc;
 }
@@ -865,9 +923,11 @@
 static int write_blocks(devcon_t *devcon, aoff64_t ba, size_t cnt)
 {
-	int rc;
-
-	assert(devcon);
-	rc = async_req_3_0(devcon->dev_phone, BD_WRITE_BLOCKS, LOWER32(ba),
+	assert(devcon);
+	
+	async_exch_t *exch = async_exchange_begin(devcon->sess);
+	int rc = async_req_3_0(exch, BD_WRITE_BLOCKS, LOWER32(ba),
 	    UPPER32(ba), cnt);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		printf("Error %d writing %zu blocks starting at block %" PRIuOFF64
@@ -877,31 +937,36 @@
 #endif
 	}
+	
 	return rc;
 }
 
 /** Get block size used by the device. */
-static int get_block_size(int dev_phone, size_t *bsize)
+static int get_block_size(async_sess_t *sess, size_t *bsize)
 {
 	sysarg_t bs;
-	int rc;
-
-	rc = async_req_0_1(dev_phone, BD_GET_BLOCK_SIZE, &bs);
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_0_1(exch, BD_GET_BLOCK_SIZE, &bs);
+	async_exchange_end(exch);
+	
 	if (rc == EOK)
 		*bsize = (size_t) bs;
-
+	
 	return rc;
 }
 
 /** Get total number of blocks on block device. */
-static int get_num_blocks(int dev_phone, aoff64_t *nblocks)
-{
-	sysarg_t nb_l, nb_h;
-	int rc;
-
-	rc = async_req_0_2(dev_phone, BD_GET_NUM_BLOCKS, &nb_l, &nb_h);
-	if (rc == EOK) {
+static int get_num_blocks(async_sess_t *sess, aoff64_t *nblocks)
+{
+	sysarg_t nb_l;
+	sysarg_t nb_h;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_0_2(exch, BD_GET_NUM_BLOCKS, &nb_l, &nb_h);
+	async_exchange_end(exch);
+	
+	if (rc == EOK)
 		*nblocks = (aoff64_t) MERGE_LOUP32(nb_l, nb_h);
-	}
-
+	
 	return rc;
 }
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/block/libblock.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -2,4 +2,5 @@
  * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2008 Martin Decky 
+ * Copyright (c) 2011 Martin Sucha 
  * All rights reserved.
  *
@@ -39,4 +40,5 @@
 
 #include <stdint.h>
+#include <async.h>
 #include "../../srv/vfs/vfs.h"
 #include <fibril_synch.h>
@@ -95,5 +97,5 @@
 };
 
-extern int block_init(devmap_handle_t, size_t);
+extern int block_init(exch_mgmt_t, devmap_handle_t, size_t);
 extern void block_fini(devmap_handle_t);
 
@@ -113,4 +115,5 @@
 extern int block_get_nblocks(devmap_handle_t, aoff64_t *);
 extern int block_read_direct(devmap_handle_t, aoff64_t, size_t, void *);
+extern int block_read_bytes_direct(devmap_handle_t, aoff64_t, size_t, void *);
 extern int block_write_direct(devmap_handle_t, aoff64_t, size_t, const void *);
 
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -68,5 +68,7 @@
 	generic/clipboard.c \
 	generic/devmap.c \
+	generic/devmap_obsolete.c \
 	generic/devman.c \
+	generic/devman_obsolete.c \
 	generic/device/hw_res.c \
 	generic/device/char_dev.c \
@@ -76,4 +78,5 @@
 	generic/str.c \
 	generic/str_error.c \
+	generic/l18n/langs.c \
 	generic/fibril.c \
 	generic/fibril_synch.c \
@@ -95,10 +98,11 @@
 	generic/io/console.c \
 	generic/io/screenbuffer.c \
-	generic/ipc/ns.c \
 	generic/malloc.c \
 	generic/sysinfo.c \
 	generic/ipc.c \
+	generic/ns.c \
+	generic/ns_obsolete.c \
 	generic/async.c \
-	generic/async_sess.c \
+	generic/async_obsolete.c \
 	generic/loader.c \
 	generic/getopt.c \
@@ -128,5 +132,5 @@
 	generic/assert.c
 
-ifeq ($(CONFIG_RTLD), y)
+ifeq ($(CONFIG_RTLD),y)
 	GENERIC_SOURCES += \
 		generic/dlfcn.c \
Index: uspace/lib/c/arch/abs32le/include/ddi.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/ddi.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/arch/abs32le/include/ddi.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -33,4 +33,7 @@
 #define LIBC_abs32le_DDI_H_
 
+#include <sys/types.h>
+#include <libarch/types.h>
+
 static inline void pio_write_8(ioport8_t *port, uint8_t v)
 {
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -54,5 +54,5 @@
  *
  */
-int hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys,
+bool hash_table_create(hash_table_t *h, hash_count_t m, hash_count_t max_keys,
     hash_table_operations_t *op)
 {
Index: uspace/lib/c/generic/adt/measured_strings.c
===================================================================
--- uspace/lib/c/generic/adt/measured_strings.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/adt/measured_strings.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,5 @@
 #include <errno.h>
 #include <async.h>
+#include <async_obsolete.h>
 
 /** Creates a new measured string bundled with a copy of the given string
@@ -326,5 +327,5 @@
 		return ENOMEM;
 
-	rc = async_data_read_start(phone, lengths,
+	rc = async_obsolete_data_read_start(phone, lengths,
 	    sizeof(size_t) * (count + 1));
 	if (rc != EOK) {
@@ -351,5 +352,5 @@
 		(*strings)[index].length = lengths[index];
 		if (lengths[index] > 0) {
-			rc = async_data_read_start(phone, next, lengths[index]);
+			rc = async_obsolete_data_read_start(phone, next, lengths[index]);
 			if (rc != EOK) {
 			    	free(lengths);
@@ -399,5 +400,5 @@
 		return ENOMEM;
 
-	rc = async_data_write_start(phone, lengths,
+	rc = async_obsolete_data_write_start(phone, lengths,
 	    sizeof(size_t) * (count + 1));
 	if (rc != EOK) {
@@ -410,5 +411,5 @@
 	for (index = 0; index < count; index++) {
 		if (strings[index].length > 0) {
-			rc = async_data_write_start(phone, strings[index].value,
+			rc = async_obsolete_data_write_start(phone, strings[index].value,
 			    strings[index].length);
 			if (rc != EOK)
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/as.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,4 +35,5 @@
 #include <as.h>
 #include <libc.h>
+#include <errno.h>
 #include <unistd.h>
 #include <align.h>
@@ -114,4 +115,30 @@
 }
 
+/** Find mapping to physical address.
+ *
+ * @param address Virtual address in question (virtual).
+ * @param[out] frame Frame address (physical).
+ * @return Error code.
+ * @retval EOK No error, @p frame holds the translation.
+ * @retval ENOENT Mapping not found.
+ */
+int as_get_physical_mapping(void *address, uintptr_t *frame)
+{
+	uintptr_t tmp_frame;
+	uintptr_t virt = (uintptr_t) address;
+	
+	int rc = (int) __SYSCALL2(SYS_PAGE_FIND_MAPPING,
+	    (sysarg_t) virt, (sysarg_t) &tmp_frame);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	if (frame != NULL) {
+		*frame = tmp_frame;
+	}
+	
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/async.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,6 +40,7 @@
  * programming.
  *
- * You should be able to write very simple multithreaded programs, the async
- * framework will automatically take care of most synchronization problems.
+ * You should be able to write very simple multithreaded programs. The async
+ * framework will automatically take care of most of the synchronization
+ * problems.
  *
  * Example of use (pseudo C):
@@ -53,7 +54,14 @@
  *   int fibril1(void *arg)
  *   {
- *     conn = async_connect_me_to();
- *     c1 = async_send(conn);
- *     c2 = async_send(conn);
+ *     conn = async_connect_me_to(...);
+ *
+ *     exch = async_exchange_begin(conn);
+ *     c1 = async_send(exch);
+ *     async_exchange_end(exch);
+ *
+ *     exch = async_exchange_begin(conn);
+ *     c2 = async_send(exch);
+ *     async_exchange_end(exch);
+ *
  *     async_wait_for(c1);
  *     async_wait_for(c2);
@@ -94,5 +102,4 @@
 #include <futex.h>
 #include <fibril.h>
-#include <stdio.h>
 #include <adt/hash_table.h>
 #include <adt/list.h>
@@ -102,8 +109,13 @@
 #include <arch/barrier.h>
 #include <bool.h>
+#include <malloc.h>
+#include <mem.h>
 #include <stdlib.h>
-#include <malloc.h>
 #include "private/async.h"
 
+#define CLIENT_HASH_TABLE_BUCKETS  32
+#define CONN_HASH_TABLE_BUCKETS    32
+
+/** Async framework global futex */
 atomic_t async_futex = FUTEX_INITIALIZER;
 
@@ -111,33 +123,25 @@
 atomic_t threads_in_ipc_wait = { 0 };
 
-typedef struct {
-	awaiter_t wdata;
-	
-	/** If reply was received. */
-	bool done;
-	
-	/** Pointer to where the answer data is stored. */
-	ipc_call_t *dataptr;
-	
-	sysarg_t retval;
-} amsg_t;
-
-/**
- * Structures of this type are used to group information about
- * a call and about a message queue link.
- */
+/** Naming service session */
+async_sess_t *session_ns;
+
+/** Call data */
 typedef struct {
 	link_t link;
+	
 	ipc_callid_t callid;
 	ipc_call_t call;
 } msg_t;
 
+/* Client connection data */
 typedef struct {
+	link_t link;
+	
 	sysarg_t in_task_hash;
-	link_t link;
-	int refcnt;
+	atomic_t refcnt;
 	void *data;
 } client_t;
 
+/* Server connection data */
 typedef struct {
 	awaiter_t wdata;
@@ -148,4 +152,5 @@
 	/** Incoming client task hash. */
 	sysarg_t in_task_hash;
+	
 	/** Incoming phone hash. */
 	sysarg_t in_phone_hash;
@@ -170,5 +175,5 @@
 
 /** Identifier of the incoming connection handled by the current fibril. */
-static fibril_local connection_t *FIBRIL_connection;
+static fibril_local connection_t *fibril_connection;
 
 static void *default_client_data_constructor(void)
@@ -196,8 +201,8 @@
 }
 
-void *async_client_data_get(void)
-{
-	assert(FIBRIL_connection);
-	return FIBRIL_connection->client->data;
+void *async_get_client_data(void)
+{
+	assert(fibril_connection);
+	return fibril_connection->client->data;
 }
 
@@ -215,9 +220,4 @@
 }
 
-/**
- * Pointer to a fibril function that will be used to handle connections.
- */
-static async_client_conn_t client_connection = default_client_connection;
-
 /** Default fibril function that gets called to handle interrupt notifications.
  *
@@ -232,9 +232,41 @@
 }
 
-/**
- * Pointer to a fibril function that will be used to handle interrupt
- * notifications.
- */
+static async_client_conn_t client_connection = default_client_connection;
 static async_client_conn_t interrupt_received = default_interrupt_received;
+
+/** Setter for client_connection function pointer.
+ *
+ * @param conn Function that will implement a new connection fibril.
+ *
+ */
+void async_set_client_connection(async_client_conn_t conn)
+{
+	client_connection = conn;
+}
+
+/** Setter for interrupt_received function pointer.
+ *
+ * @param intr Function that will implement a new interrupt
+ *             notification fibril.
+ */
+void async_set_interrupt_received(async_client_conn_t intr)
+{
+	interrupt_received = intr;
+}
+
+/** Mutex protecting inactive_exch_list and avail_phone_cv.
+ *
+ */
+static FIBRIL_MUTEX_INITIALIZE(async_sess_mutex);
+
+/** List of all currently inactive exchanges.
+ *
+ */
+static LIST_INITIALIZE(inactive_exch_list);
+
+/** Condition variable to wait for a phone to become available.
+ *
+ */
+static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
 
 static hash_table_t client_hash_table;
@@ -242,10 +274,8 @@
 static LIST_INITIALIZE(timeout_list);
 
-#define CLIENT_HASH_TABLE_BUCKETS  32
-#define CONN_HASH_TABLE_BUCKETS    32
-
 static hash_index_t client_hash(unsigned long key[])
 {
 	assert(key);
+	
 	return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
 }
@@ -253,4 +283,7 @@
 static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
 {
+	assert(key);
+	assert(item);
+	
 	client_t *client = hash_table_get_instance(item, client_t, link);
 	return (key[0] == client->in_task_hash);
@@ -278,4 +311,5 @@
 {
 	assert(key);
+	
 	return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
 }
@@ -292,4 +326,7 @@
 static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
 {
+	assert(key);
+	assert(item);
+	
 	connection_t *conn = hash_table_get_instance(item, connection_t, link);
 	return (key[0] == conn->in_phone_hash);
@@ -314,4 +351,6 @@
 void async_insert_timeout(awaiter_t *wd)
 {
+	assert(wd);
+	
 	wd->to_event.occurred = false;
 	wd->to_event.inlist = true;
@@ -346,4 +385,6 @@
 static bool route_call(ipc_callid_t callid, ipc_call_t *call)
 {
+	assert(call);
+	
 	futex_down(&async_futex);
 	
@@ -400,4 +441,6 @@
 static int notification_fibril(void *arg)
 {
+	assert(arg);
+	
 	msg_t *msg = (msg_t *) arg;
 	interrupt_received(msg->callid, &msg->call);
@@ -420,4 +463,6 @@
 static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
 {
+	assert(call);
+	
 	futex_down(&async_futex);
 	
@@ -458,13 +503,14 @@
 ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
 {
-	assert(FIBRIL_connection);
+	assert(call);
+	assert(fibril_connection);
 	
 	/* Why doing this?
-	 * GCC 4.1.0 coughs on FIBRIL_connection-> dereference.
+	 * GCC 4.1.0 coughs on fibril_connection-> dereference.
 	 * GCC 4.1.1 happilly puts the rdhwr instruction in delay slot.
 	 *           I would never expect to find so many errors in
 	 *           a compiler.
 	 */
-	connection_t *conn = FIBRIL_connection;
+	connection_t *conn = fibril_connection;
 	
 	futex_down(&async_futex);
@@ -541,8 +587,10 @@
 static int connection_fibril(void *arg)
 {
+	assert(arg);
+	
 	/*
 	 * Setup fibril-local connection pointer.
 	 */
-	FIBRIL_connection = (connection_t *) arg;
+	fibril_connection = (connection_t *) arg;
 	
 	futex_down(&async_futex);
@@ -554,5 +602,5 @@
 	 */
 	
-	unsigned long key = FIBRIL_connection->in_task_hash;
+	unsigned long key = fibril_connection->in_task_hash;
 	link_t *lnk = hash_table_find(&client_hash_table, &key);
 	
@@ -561,20 +609,17 @@
 	if (lnk) {
 		client = hash_table_get_instance(lnk, client_t, link);
-		client->refcnt++;
+		atomic_inc(&client->refcnt);
 	} else {
 		client = malloc(sizeof(client_t));
 		if (!client) {
-			ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
+			ipc_answer_0(fibril_connection->callid, ENOMEM);
 			futex_up(&async_futex);
 			return 0;
 		}
 		
-		client->in_task_hash = FIBRIL_connection->in_task_hash;
-		
-		async_serialize_start();
+		client->in_task_hash = fibril_connection->in_task_hash;
 		client->data = async_client_data_create();
-		async_serialize_end();
-		
-		client->refcnt = 1;
+		
+		atomic_set(&client->refcnt, 1);
 		hash_table_insert(&client_hash_table, &key, &client->link);
 	}
@@ -582,11 +627,11 @@
 	futex_up(&async_futex);
 	
-	FIBRIL_connection->client = client;
+	fibril_connection->client = client;
 	
 	/*
 	 * Call the connection handler function.
 	 */
-	FIBRIL_connection->cfibril(FIBRIL_connection->callid,
-	    &FIBRIL_connection->call);
+	fibril_connection->cfibril(fibril_connection->callid,
+	    &fibril_connection->call);
 	
 	/*
@@ -597,5 +642,5 @@
 	futex_down(&async_futex);
 	
-	if (--client->refcnt == 0) {
+	if (atomic_predec(&client->refcnt) == 0) {
 		hash_table_remove(&client_hash_table, &key, 1);
 		destroy = true;
@@ -616,5 +661,5 @@
 	 */
 	futex_down(&async_futex);
-	key = FIBRIL_connection->in_phone_hash;
+	key = fibril_connection->in_phone_hash;
 	hash_table_remove(&conn_hash_table, &key, 1);
 	futex_up(&async_futex);
@@ -623,7 +668,7 @@
 	 * Answer all remaining messages with EHANGUP.
 	 */
-	while (!list_empty(&FIBRIL_connection->msg_queue)) {
+	while (!list_empty(&fibril_connection->msg_queue)) {
 		msg_t *msg =
-		    list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
+		    list_get_instance(fibril_connection->msg_queue.next, msg_t,
 		    link);
 		
@@ -637,8 +682,8 @@
 	 * i.e. IPC_M_PHONE_HUNGUP.
 	 */
-	if (FIBRIL_connection->close_callid)
-		ipc_answer_0(FIBRIL_connection->close_callid, EOK);
-	
-	free(FIBRIL_connection);
+	if (fibril_connection->close_callid)
+		ipc_answer_0(fibril_connection->close_callid, EOK);
+	
+	free(fibril_connection);
 	return 0;
 }
@@ -646,5 +691,5 @@
 /** Create a new fibril for a new connection.
  *
- * Create new fibril for connection, fill in connection structures and inserts
+ * Create new fibril for connection, fill in connection structures and insert
  * it into the hash table, so that later we can easily do routing of messages to
  * particular fibrils.
@@ -665,5 +710,5 @@
 fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
     ipc_callid_t callid, ipc_call_t *call,
-    void (*cfibril)(ipc_callid_t, ipc_call_t *))
+    async_client_conn_t cfibril)
 {
 	connection_t *conn = malloc(sizeof(*conn));
@@ -721,4 +766,6 @@
 static void handle_call(ipc_callid_t callid, ipc_call_t *call)
 {
+	assert(call);
+	
 	/* Unrouted call - take some default action */
 	if ((callid & IPC_CALLID_NOTIFICATION)) {
@@ -878,11 +925,25 @@
 void __async_init(void)
 {
-	if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
-	    &client_hash_table_ops))
+	if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS,
+	    1, &client_hash_table_ops))
 		abort();
 	
-	if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1,
-	    &conn_hash_table_ops))
+	if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS,
+	    1, &conn_hash_table_ops))
 		abort();
+	
+	session_ns = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (session_ns == NULL)
+		abort();
+	
+	session_ns->mgmt = EXCHANGE_ATOMIC;
+	session_ns->phone = PHONE_NS;
+	session_ns->arg1 = 0;
+	session_ns->arg2 = 0;
+	session_ns->arg3 = 0;
+	
+	list_initialize(&session_ns->exch_list);
+	fibril_mutex_initialize(&session_ns->mutex);
+	atomic_set(&session_ns->refcnt, 0);
 }
 
@@ -899,6 +960,8 @@
  *
  */
-static void reply_received(void *arg, int retval, ipc_call_t *data)
-{
+void reply_received(void *arg, int retval, ipc_call_t *data)
+{
+	assert(arg);
+	
 	futex_down(&async_futex);
 	
@@ -930,6 +993,6 @@
  * completion.
  *
- * @param phoneid Handle of the phone that will be used for the send.
- * @param method  Service-defined method.
+ * @param exch    Exchange for sending the message.
+ * @param imethod Service-defined interface and method.
  * @param arg1    Service-defined payload argument.
  * @param arg2    Service-defined payload argument.
@@ -942,10 +1005,12 @@
  *
  */
-aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
 {
+	if (exch == NULL)
+		return 0;
+	
 	amsg_t *msg = malloc(sizeof(amsg_t));
-	
-	if (!msg)
+	if (msg == NULL)
 		return 0;
 	
@@ -961,5 +1026,5 @@
 	msg->wdata.active = true;
 	
-	ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
+	ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4, msg,
 	    reply_received, true);
 	
@@ -972,6 +1037,6 @@
  * completion.
  *
- * @param phoneid Handle of the phone that will be used for the send.
- * @param method  Service-defined method.
+ * @param exch    Exchange for sending the message.
+ * @param imethod Service-defined interface and method.
  * @param arg1    Service-defined payload argument.
  * @param arg2    Service-defined payload argument.
@@ -985,11 +1050,14 @@
  *
  */
-aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
+aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
     ipc_call_t *dataptr)
 {
+	if (exch == NULL)
+		return 0;
+	
 	amsg_t *msg = malloc(sizeof(amsg_t));
 	
-	if (!msg)
+	if (msg == NULL)
 		return 0;
 	
@@ -1005,6 +1073,6 @@
 	msg->wdata.active = true;
 	
-	ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
-	    reply_received, true);
+	ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4, arg5,
+	    msg, reply_received, true);
 	
 	return (aid_t) msg;
@@ -1020,4 +1088,6 @@
 void async_wait_for(aid_t amsgid, sysarg_t *retval)
 {
+	assert(amsgid);
+	
 	amsg_t *msg = (amsg_t *) amsgid;
 	
@@ -1056,4 +1126,6 @@
 int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout)
 {
+	assert(amsgid);
+	
 	amsg_t *msg = (amsg_t *) amsgid;
 	
@@ -1124,24 +1196,4 @@
 }
 
-/** Setter for client_connection function pointer.
- *
- * @param conn Function that will implement a new connection fibril.
- *
- */
-void async_set_client_connection(async_client_conn_t conn)
-{
-	client_connection = conn;
-}
-
-/** Setter for interrupt_received function pointer.
- *
- * @param intr Function that will implement a new interrupt
- *             notification fibril.
- */
-void async_set_interrupt_received(async_client_conn_t intr)
-{
-	interrupt_received = intr;
-}
-
 /** Pseudo-synchronous message sending - fast version.
  *
@@ -1151,6 +1203,6 @@
  * transferring more arguments, see the slower async_req_slow().
  *
- * @param phoneid Hash of the phone through which to make the call.
- * @param method  Method of the call.
+ * @param exch    Exchange for sending the message.
+ * @param imethod Interface and method of the call.
  * @param arg1    Service-defined payload argument.
  * @param arg2    Service-defined payload argument.
@@ -1166,14 +1218,17 @@
  *
  */
-sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+sysarg_t async_req_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
     sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
 {
+	if (exch == NULL)
+		return ENOENT;
+	
 	ipc_call_t result;
-	aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
+	aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
 	    &result);
 	
 	sysarg_t rc;
-	async_wait_for(eid, &rc);
+	async_wait_for(aid, &rc);
 	
 	if (r1)
@@ -1199,6 +1254,6 @@
  * Send message asynchronously and return only after the reply arrives.
  *
- * @param phoneid Hash of the phone through which to make the call.
- * @param method  Method of the call.
+ * @param exch    Exchange for sending the message.
+ * @param imethod Interface and method of the call.
  * @param arg1    Service-defined payload argument.
  * @param arg2    Service-defined payload argument.
@@ -1215,14 +1270,17 @@
  *
  */
-sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
+sysarg_t async_req_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
     sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
     sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
 {
+	if (exch == NULL)
+		return ENOENT;
+	
 	ipc_call_t result;
-	aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
+	aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
 	    &result);
 	
 	sysarg_t rc;
-	async_wait_for(eid, &rc);
+	async_wait_for(aid, &rc);
 	
 	if (r1)
@@ -1244,37 +1302,46 @@
 }
 
-void async_msg_0(int phone, sysarg_t imethod)
-{
-	ipc_call_async_0(phone, imethod, NULL, NULL, true);
-}
-
-void async_msg_1(int phone, sysarg_t imethod, sysarg_t arg1)
-{
-	ipc_call_async_1(phone, imethod, arg1, NULL, NULL, true);
-}
-
-void async_msg_2(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
-{
-	ipc_call_async_2(phone, imethod, arg1, arg2, NULL, NULL, true);
-}
-
-void async_msg_3(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3)
-{
-	ipc_call_async_3(phone, imethod, arg1, arg2, arg3, NULL, NULL, true);
-}
-
-void async_msg_4(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3, sysarg_t arg4)
-{
-	ipc_call_async_4(phone, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
-	    true);
-}
-
-void async_msg_5(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
-{
-	ipc_call_async_5(phone, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
-	    NULL, true);
+void async_msg_0(async_exch_t *exch, sysarg_t imethod)
+{
+	if (exch != NULL)
+		ipc_call_async_0(exch->phone, imethod, NULL, NULL, true);
+}
+
+void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
+{
+	if (exch != NULL)
+		ipc_call_async_1(exch->phone, imethod, arg1, NULL, NULL, true);
+}
+
+void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
+    sysarg_t arg2)
+{
+	if (exch != NULL)
+		ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL, NULL,
+		    true);
+}
+
+void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3)
+{
+	if (exch != NULL)
+		ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL,
+		    NULL, true);
+}
+
+void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
+{
+	if (exch != NULL)
+		ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
+		    NULL, NULL, true);
+}
+
+void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
+{
+	if (exch != NULL)
+		ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
+		    arg5, NULL, NULL, true);
 }
 
@@ -1313,16 +1380,22 @@
 }
 
-int async_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
-    sysarg_t arg1, sysarg_t arg2, unsigned int mode)
-{
-	return ipc_forward_fast(callid, phoneid, imethod, arg1, arg2, mode);
-}
-
-int async_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
-    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
-    unsigned int mode)
-{
-	return ipc_forward_slow(callid, phoneid, imethod, arg1, arg2, arg3, arg4,
-	    arg5, mode);
+int async_forward_fast(ipc_callid_t callid, async_exch_t *exch,
+    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
+	return ipc_forward_fast(callid, exch->phone, imethod, arg1, arg2, mode);
+}
+
+int async_forward_slow(ipc_callid_t callid, async_exch_t *exch,
+    sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
+    sysarg_t arg4, sysarg_t arg5, unsigned int mode)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
+	return ipc_forward_slow(callid, exch->phone, imethod, arg1, arg2, arg3,
+	    arg4, arg5, mode);
 }
 
@@ -1331,5 +1404,5 @@
  * Ask through phone for a new connection to some service.
  *
- * @param phone           Phone handle used for contacting the other side.
+ * @param exch            Exchange for sending the message.
  * @param arg1            User defined argument.
  * @param arg2            User defined argument.
@@ -1337,13 +1410,16 @@
  * @param client_receiver Connection handing routine.
  *
- * @return New phone handle on success or a negative error code.
- *
- */
-int async_connect_to_me(int phone, sysarg_t arg1, sysarg_t arg2,
+ * @return Zero on success or a negative error code.
+ *
+ */
+int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
     sysarg_t arg3, async_client_conn_t client_receiver)
 {
+	if (exch == NULL)
+		return ENOENT;
+	
 	sysarg_t task_hash;
 	sysarg_t phone_hash;
-	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
+	int rc = async_req_3_5(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
 	    NULL, NULL, NULL, &task_hash, &phone_hash);
 	if (rc != EOK)
@@ -1357,27 +1433,159 @@
 }
 
-/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
- *
- * Ask through phone for a new connection to some service.
- *
- * @param phone Phone handle used for contacting the other side.
- * @param arg1  User defined argument.
- * @param arg2  User defined argument.
- * @param arg3  User defined argument.
- *
- * @return New phone handle on success or a negative error code.
- *
- */
-int async_connect_me_to(int phone, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3)
-{
-	sysarg_t newphid;
-	int rc = async_req_3_5(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
-	    NULL, NULL, NULL, NULL, &newphid);
+/** Wrapper for making IPC_M_CONNECT_ME calls using the async framework.
+ *
+ * Ask through for a cloned connection to some service.
+ *
+ * @param mgmt Exchange management style.
+ * @param exch Exchange for sending the message.
+ *
+ * @return New session on success or NULL on error.
+ *
+ */
+async_sess_t *async_connect_me(exch_mgmt_t mgmt, async_exch_t *exch)
+{
+	if (exch == NULL) {
+		errno = ENOENT;
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	ipc_call_t result;
+	
+	amsg_t *msg = malloc(sizeof(amsg_t));
+	if (msg == NULL) {
+		free(sess);
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	msg->done = false;
+	msg->dataptr = &result;
+	
+	msg->wdata.to_event.inlist = false;
+	
+	/*
+	 * We may sleep in the next method,
+	 * but it will use its own means
+	 */
+	msg->wdata.active = true;
+	
+	ipc_call_async_0(exch->phone, IPC_M_CONNECT_ME, msg,
+	    reply_received, true);
+	
+	sysarg_t rc;
+	async_wait_for((aid_t) msg, &rc);
+	
+	if (rc != EOK) {
+		errno = rc;
+		free(sess);
+		return NULL;
+	}
+	
+	int phone = (int) IPC_GET_ARG5(result);
+	
+	if (phone < 0) {
+		errno = phone;
+		free(sess);
+		return NULL;
+	}
+	
+	sess->mgmt = mgmt;
+	sess->phone = phone;
+	sess->arg1 = 0;
+	sess->arg2 = 0;
+	sess->arg3 = 0;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
+}
+
+static int async_connect_me_to_internal(int phone, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3, sysarg_t arg4)
+{
+	ipc_call_t result;
+	
+	amsg_t *msg = malloc(sizeof(amsg_t));
+	if (msg == NULL)
+		return ENOENT;
+	
+	msg->done = false;
+	msg->dataptr = &result;
+	
+	msg->wdata.to_event.inlist = false;
+	
+	/*
+	 * We may sleep in the next method,
+	 * but it will use its own means
+	 */
+	msg->wdata.active = true;
+	
+	ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3, arg4,
+	    msg, reply_received, true);
+	
+	sysarg_t rc;
+	async_wait_for((aid_t) msg, &rc);
 	
 	if (rc != EOK)
 		return rc;
 	
-	return newphid;
+	return (int) IPC_GET_ARG5(result);
+}
+
+/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
+ *
+ * Ask through for a new connection to some service.
+ *
+ * @param mgmt Exchange management style.
+ * @param exch Exchange for sending the message.
+ * @param arg1 User defined argument.
+ * @param arg2 User defined argument.
+ * @param arg3 User defined argument.
+ *
+ * @return New session on success or NULL on error.
+ *
+ */
+async_sess_t *async_connect_me_to(exch_mgmt_t mgmt, async_exch_t *exch,
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
+{
+	if (exch == NULL) {
+		errno = ENOENT;
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
+	    0);
+	
+	if (phone < 0) {
+		errno = phone;
+		free(sess);
+		return NULL;
+	}
+	
+	sess->mgmt = mgmt;
+	sess->phone = phone;
+	sess->arg1 = arg1;
+	sess->arg2 = arg2;
+	sess->arg3 = arg3;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
 }
 
@@ -1387,23 +1595,47 @@
  * success.
  *
- * @param phoneid Phone handle used for contacting the other side.
- * @param arg1    User defined argument.
- * @param arg2    User defined argument.
- * @param arg3    User defined argument.
- *
- * @return New phone handle on success or a negative error code.
- *
- */
-int async_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3)
-{
-	sysarg_t newphid;
-	int rc = async_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
-	    IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
-	
-	if (rc != EOK)
-		return rc;
-	
-	return newphid;
+ * @param mgmt Exchange management style.
+ * @param exch Exchange for sending the message.
+ * @param arg1 User defined argument.
+ * @param arg2 User defined argument.
+ * @param arg3 User defined argument.
+ *
+ * @return New session on success or NULL on error.
+ *
+ */
+async_sess_t *async_connect_me_to_blocking(exch_mgmt_t mgmt, async_exch_t *exch,
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
+{
+	if (exch == NULL) {
+		errno = ENOENT;
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
+	    IPC_FLAG_BLOCKING);
+	
+	if (phone < 0) {
+		errno = phone;
+		free(sess);
+		return NULL;
+	}
+	
+	sess->mgmt = mgmt;
+	sess->phone = phone;
+	sess->arg1 = arg1;
+	sess->arg2 = arg2;
+	sess->arg3 = arg3;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
 }
 
@@ -1411,19 +1643,56 @@
  *
  */
-int async_connect_kbox(task_id_t id)
-{
-	return ipc_connect_kbox(id);
+async_sess_t *async_connect_kbox(task_id_t id)
+{
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int phone = ipc_connect_kbox(id);
+	if (phone < 0) {
+		errno = phone;
+		free(sess);
+		return NULL;
+	}
+	
+	sess->mgmt = EXCHANGE_ATOMIC;
+	sess->phone = phone;
+	sess->arg1 = 0;
+	sess->arg2 = 0;
+	sess->arg3 = 0;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
+}
+
+static int async_hangup_internal(int phone)
+{
+	return ipc_hangup(phone);
 }
 
 /** Wrapper for ipc_hangup.
  *
- * @param phone Phone handle to hung up.
+ * @param sess Session to hung up.
  *
  * @return Zero on success or a negative error code.
  *
  */
-int async_hangup(int phone)
-{
-	return ipc_hangup(phone);
+int async_hangup(async_sess_t *sess)
+{
+	assert(sess);
+	
+	if (atomic_get(&sess->refcnt) > 0)
+		return EBUSY;
+	
+	int rc = async_hangup_internal(sess->phone);
+	if (rc == EOK)
+		free(sess);
+	
+	return rc;
 }
 
@@ -1434,20 +1703,140 @@
 }
 
+/** Start new exchange in a session.
+ *
+ * @param session Session.
+ *
+ * @return New exchange or NULL on error.
+ *
+ */
+async_exch_t *async_exchange_begin(async_sess_t *sess)
+{
+	if (sess == NULL)
+		return NULL;
+	
+	async_exch_t *exch;
+	
+	fibril_mutex_lock(&async_sess_mutex);
+	
+	if (!list_empty(&sess->exch_list)) {
+		/*
+		 * There are inactive exchanges in the session.
+		 */
+		exch = (async_exch_t *)
+		    list_get_instance(sess->exch_list.next, async_exch_t, sess_link);
+		list_remove(&exch->sess_link);
+		list_remove(&exch->global_link);
+	} else {
+		/*
+		 * There are no available exchanges in the session.
+		 */
+		
+		if ((sess->mgmt == EXCHANGE_ATOMIC) ||
+		    (sess->mgmt == EXCHANGE_SERIALIZE)) {
+			exch = (async_exch_t *) malloc(sizeof(async_exch_t));
+			if (exch != NULL) {
+				list_initialize(&exch->sess_link);
+				list_initialize(&exch->global_link);
+				exch->sess = sess;
+				exch->phone = sess->phone;
+			}
+		} else {  /* EXCHANGE_PARALLEL */
+			/*
+			 * Make a one-time attempt to connect a new data phone.
+			 */
+			
+			int phone;
+			
+retry:
+			phone = async_connect_me_to_internal(sess->phone, sess->arg1,
+			    sess->arg2, sess->arg3, 0);
+			if (phone >= 0) {
+				exch = (async_exch_t *) malloc(sizeof(async_exch_t));
+				if (exch != NULL) {
+					list_initialize(&exch->sess_link);
+					list_initialize(&exch->global_link);
+					exch->sess = sess;
+					exch->phone = phone;
+				} else
+					async_hangup_internal(phone);
+			} else if (!list_empty(&inactive_exch_list)) {
+				/*
+				 * We did not manage to connect a new phone. But we
+				 * can try to close some of the currently inactive
+				 * connections in other sessions and try again.
+				 */
+				exch = (async_exch_t *)
+				    list_get_instance(inactive_exch_list.next, async_exch_t,
+				    global_link);
+				list_remove(&exch->sess_link);
+				list_remove(&exch->global_link);
+				async_hangup_internal(exch->phone);
+				free(exch);
+				goto retry;
+			} else {
+				/*
+				 * Wait for a phone to become available.
+				 */
+				fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
+				goto retry;
+			}
+		}
+	}
+	
+	fibril_mutex_unlock(&async_sess_mutex);
+	
+	if (exch != NULL) {
+		atomic_inc(&sess->refcnt);
+		
+		if (sess->mgmt == EXCHANGE_SERIALIZE)
+			fibril_mutex_lock(&sess->mutex);
+	}
+	
+	return exch;
+}
+
+/** Finish an exchange.
+ *
+ * @param exch Exchange to finish.
+ *
+ */
+void async_exchange_end(async_exch_t *exch)
+{
+	if (exch == NULL)
+		return;
+	
+	async_sess_t *sess = exch->sess;
+	
+	if (sess->mgmt == EXCHANGE_SERIALIZE)
+		fibril_mutex_unlock(&sess->mutex);
+	
+	fibril_mutex_lock(&async_sess_mutex);
+	
+	list_append(&exch->sess_link, &sess->exch_list);
+	list_append(&exch->global_link, &inactive_exch_list);
+	fibril_condvar_signal(&avail_phone_cv);
+	
+	fibril_mutex_unlock(&async_sess_mutex);
+}
+
 /** Wrapper for IPC_M_SHARE_IN calls using the async framework.
  *
- * @param phoneid Phone that will be used to contact the receiving side.
- * @param dst     Destination address space area base.
- * @param size    Size of the destination address space area.
- * @param arg     User defined argument.
- * @param flags   Storage for the received flags. Can be NULL.
+ * @param exch  Exchange for sending the message.
+ * @param dst   Destination address space area base.
+ * @param size  Size of the destination address space area.
+ * @param arg   User defined argument.
+ * @param flags Storage for the received flags. Can be NULL.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
-    unsigned int *flags)
-{
+int async_share_in_start(async_exch_t *exch, void *dst, size_t size,
+    sysarg_t arg, unsigned int *flags)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
 	sysarg_t tmp_flags;
-	int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
+	int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
 	    (sysarg_t) size, arg, NULL, &tmp_flags);
 	
@@ -1507,14 +1896,17 @@
 /** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
  *
- * @param phoneid Phone that will be used to contact the receiving side.
- * @param src     Source address space area base address.
- * @param flags   Flags to be used for sharing. Bits can be only cleared.
+ * @param exch  Exchange for sending the message.
+ * @param src   Source address space area base address.
+ * @param flags Flags to be used for sharing. Bits can be only cleared.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int async_share_out_start(int phoneid, void *src, unsigned int flags)
-{
-	return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
+int async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
+	return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
 	    (sysarg_t) flags);
 }
@@ -1569,19 +1961,37 @@
 }
 
+/** Start IPC_M_DATA_READ using the async framework.
+ *
+ * @param exch    Exchange for sending the message.
+ * @param dst     Address of the beginning of the destination buffer.
+ * @param size    Size of the destination buffer (in bytes).
+ * @param dataptr Storage of call data (arg 2 holds actual data size).
+ *
+ * @return Hash of the sent message or 0 on error.
+ *
+ */
+aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
+    ipc_call_t *dataptr)
+{
+	return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
+	    (sysarg_t) size, dataptr);
+}
+
 /** Wrapper for IPC_M_DATA_READ calls using the async framework.
  *
- * @param phoneid Phone that will be used to contact the receiving side.
- * @param dst     Address of the beginning of the destination buffer.
- * @param size    Size of the destination buffer.
- * @param flags   Flags to control the data transfer.
+ * @param exch Exchange for sending the message.
+ * @param dst  Address of the beginning of the destination buffer.
+ * @param size Size of the destination buffer.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int
-async_data_read_start_generic(int phoneid, void *dst, size_t size, int flags)
-{
-	return async_req_3_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
-	    (sysarg_t) size, (sysarg_t) flags);
+int async_data_read_start(async_exch_t *exch, void *dst, size_t size)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
+	return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
+	    (sysarg_t) size);
 }
 
@@ -1638,7 +2048,11 @@
  *
  */
-int async_data_read_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
-{
+int async_data_read_forward_fast(async_exch_t *exch, sysarg_t imethod,
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
+    ipc_call_t *dataptr)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
 	ipc_callid_t callid;
 	if (!async_data_read_receive(&callid, NULL)) {
@@ -1647,5 +2061,5 @@
 	}
 	
-	aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
+	aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
 	    dataptr);
 	if (msg == 0) {
@@ -1654,5 +2068,5 @@
 	}
 	
-	int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
+	int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
 	    IPC_FF_ROUTE_FROM_ME);
 	if (retval != EOK) {
@@ -1670,18 +2084,18 @@
 /** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
  *
- * @param phoneid Phone that will be used to contact the receiving side.
- * @param src     Address of the beginning of the source buffer.
- * @param size    Size of the source buffer.
- * @param flags   Flags to control the data transfer.
+ * @param exch Exchange for sending the message.
+ * @param src  Address of the beginning of the source buffer.
+ * @param size Size of the source buffer.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int
-async_data_write_start_generic(int phoneid, const void *src, size_t size,
-    int flags)
-{
-	return async_req_3_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
-	    (sysarg_t) size, (sysarg_t) flags);
+int async_data_write_start(async_exch_t *exch, const void *src, size_t size)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
+	return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
+	    (sysarg_t) size);
 }
 
@@ -1759,4 +2173,6 @@
     size_t *received)
 {
+	assert(data);
+	
 	ipc_callid_t callid;
 	size_t size;
@@ -1826,7 +2242,11 @@
  *
  */
-int async_data_write_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
-{
+int async_data_write_forward_fast(async_exch_t *exch, sysarg_t imethod,
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
+    ipc_call_t *dataptr)
+{
+	if (exch == NULL)
+		return ENOENT;
+	
 	ipc_callid_t callid;
 	if (!async_data_write_receive(&callid, NULL)) {
@@ -1835,5 +2255,5 @@
 	}
 	
-	aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
+	aid_t msg = async_send_fast(exch, imethod, arg1, arg2, arg3, arg4,
 	    dataptr);
 	if (msg == 0) {
@@ -1842,5 +2262,5 @@
 	}
 	
-	int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
+	int retval = ipc_forward_fast(callid, exch->phone, 0, 0, 0,
 	    IPC_FF_ROUTE_FROM_ME);
 	if (retval != EOK) {
@@ -1856,4 +2276,145 @@
 }
 
+/** Wrapper for sending an exchange over different exchange for cloning
+ *
+ * @param exch       Exchange to be used for sending.
+ * @param clone_exch Exchange to be cloned.
+ *
+ */
+int async_exchange_clone(async_exch_t *exch, async_exch_t *clone_exch)
+{
+	return async_req_1_0(exch, IPC_M_CONNECTION_CLONE, clone_exch->phone);
+}
+
+/** Wrapper for receiving the IPC_M_CONNECTION_CLONE calls.
+ *
+ * If the current call is IPC_M_CONNECTION_CLONE then a new
+ * async session is created for the accepted phone.
+ *
+ * @param mgmt Exchange management style.
+ *
+ * @return New async session or NULL on failure.
+ *
+ */
+async_sess_t *async_clone_receive(exch_mgmt_t mgmt)
+{
+	/* Accept the phone */
+	ipc_call_t call;
+	ipc_callid_t callid = async_get_call(&call);
+	int phone = (int) IPC_GET_ARG1(call);
+	
+	if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECTION_CLONE) ||
+	    (phone < 0)) {
+		async_answer_0(callid, EINVAL);
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return NULL;
+	}
+	
+	sess->mgmt = mgmt;
+	sess->phone = phone;
+	sess->arg1 = 0;
+	sess->arg2 = 0;
+	sess->arg3 = 0;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	/* Acknowledge the cloned phone */
+	async_answer_0(callid, EOK);
+	
+	return sess;
+}
+
+/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
+ *
+ * If the current call is IPC_M_CONNECT_TO_ME then a new
+ * async session is created for the accepted phone.
+ *
+ * @param mgmt Exchange management style.
+ *
+ * @return New async session.
+ * @return NULL on failure.
+ *
+ */
+async_sess_t *async_callback_receive(exch_mgmt_t mgmt)
+{
+	/* Accept the phone */
+	ipc_call_t call;
+	ipc_callid_t callid = async_get_call(&call);
+	int phone = (int) IPC_GET_ARG5(call);
+	
+	if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) ||
+	    (phone < 0)) {
+		async_answer_0(callid, EINVAL);
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return NULL;
+	}
+	
+	sess->mgmt = mgmt;
+	sess->phone = phone;
+	sess->arg1 = 0;
+	sess->arg2 = 0;
+	sess->arg3 = 0;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	/* Acknowledge the connected phone */
+	async_answer_0(callid, EOK);
+	
+	return sess;
+}
+
+/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
+ *
+ * If the call is IPC_M_CONNECT_TO_ME then a new
+ * async session is created. However, the phone is
+ * not accepted automatically.
+ *
+ * @param mgmt   Exchange management style.
+ * @param call   Call data.
+ *
+ * @return New async session.
+ * @return NULL on failure.
+ * @return NULL if the call is not IPC_M_CONNECT_TO_ME.
+ *
+ */
+async_sess_t *async_callback_receive_start(exch_mgmt_t mgmt, ipc_call_t *call)
+{
+	int phone = (int) IPC_GET_ARG5(*call);
+	
+	if ((IPC_GET_IMETHOD(*call) != IPC_M_CONNECT_TO_ME) ||
+	    (phone < 0))
+		return NULL;
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL)
+		return NULL;
+	
+	sess->mgmt = mgmt;
+	sess->phone = phone;
+	sess->arg1 = 0;
+	sess->arg2 = 0;
+	sess->arg3 = 0;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/async_obsolete.c
===================================================================
--- uspace/lib/c/generic/async_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/async_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#define LIBC_ASYNC_C_
+#define LIBC_ASYNC_OBSOLETE_C_
+#include <ipc/ipc.h>
+#include <async.h>
+#include <async_obsolete.h>
+#undef LIBC_ASYNC_C_
+#undef LIBC_ASYNC_OBSOLETE_C_
+
+#include <fibril.h>
+#include <malloc.h>
+#include <errno.h>
+#include "private/async.h"
+
+/** Send message and return id of the sent message.
+ *
+ * The return value can be used as input for async_wait() to wait for
+ * completion.
+ *
+ * @param phoneid Handle of the phone that will be used for the send.
+ * @param method  Service-defined method.
+ * @param arg1    Service-defined payload argument.
+ * @param arg2    Service-defined payload argument.
+ * @param arg3    Service-defined payload argument.
+ * @param arg4    Service-defined payload argument.
+ * @param dataptr If non-NULL, storage where the reply data will be
+ *                stored.
+ *
+ * @return Hash of the sent message or 0 on error.
+ *
+ */
+aid_t async_obsolete_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
+{
+	amsg_t *msg = malloc(sizeof(amsg_t));
+	
+	if (!msg)
+		return 0;
+	
+	msg->done = false;
+	msg->dataptr = dataptr;
+	
+	msg->wdata.to_event.inlist = false;
+	
+	/*
+	 * We may sleep in the next method,
+	 * but it will use its own means
+	 */
+	msg->wdata.active = true;
+	
+	ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
+	    reply_received, true);
+	
+	return (aid_t) msg;
+}
+
+/** Pseudo-synchronous message sending - fast version.
+ *
+ * Send message asynchronously and return only after the reply arrives.
+ *
+ * This function can only transfer 4 register payload arguments. For
+ * transferring more arguments, see the slower async_req_slow().
+ *
+ * @param phoneid Hash of the phone through which to make the call.
+ * @param method  Method of the call.
+ * @param arg1    Service-defined payload argument.
+ * @param arg2    Service-defined payload argument.
+ * @param arg3    Service-defined payload argument.
+ * @param arg4    Service-defined payload argument.
+ * @param r1      If non-NULL, storage for the 1st reply argument.
+ * @param r2      If non-NULL, storage for the 2nd reply argument.
+ * @param r3      If non-NULL, storage for the 3rd reply argument.
+ * @param r4      If non-NULL, storage for the 4th reply argument.
+ * @param r5      If non-NULL, storage for the 5th reply argument.
+ *
+ * @return Return code of the reply or a negative error code.
+ *
+ */
+sysarg_t async_obsolete_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
+    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
+{
+	ipc_call_t result;
+	aid_t eid = async_obsolete_send_4(phoneid, method, arg1, arg2, arg3, arg4,
+	    &result);
+	
+	sysarg_t rc;
+	async_wait_for(eid, &rc);
+	
+	if (r1)
+		*r1 = IPC_GET_ARG1(result);
+	
+	if (r2)
+		*r2 = IPC_GET_ARG2(result);
+	
+	if (r3)
+		*r3 = IPC_GET_ARG3(result);
+	
+	if (r4)
+		*r4 = IPC_GET_ARG4(result);
+	
+	if (r5)
+		*r5 = IPC_GET_ARG5(result);
+	
+	return rc;
+}
+
+/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
+ *
+ * @param phoneid Phone that will be used to contact the receiving side.
+ * @param src     Source address space area base address.
+ * @param flags   Flags to be used for sharing. Bits can be only cleared.
+ *
+ * @return Zero on success or a negative error code from errno.h.
+ *
+ */
+int async_obsolete_share_out_start(int phoneid, void *src, unsigned int flags)
+{
+	return async_obsolete_req_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
+	    (sysarg_t) flags);
+}
+
+/** Wrapper for ipc_hangup.
+ *
+ * @param phone Phone handle to hung up.
+ *
+ * @return Zero on success or a negative error code.
+ *
+ */
+int async_obsolete_hangup(int phone)
+{
+	return ipc_hangup(phone);
+}
+
+void async_obsolete_serialize_start(void)
+{
+	fibril_inc_sercount();
+}
+
+void async_obsolete_serialize_end(void)
+{
+	fibril_dec_sercount();
+}
+
+/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
+ *
+ * @param phoneid Phone that will be used to contact the receiving side.
+ * @param src     Address of the beginning of the source buffer.
+ * @param size    Size of the source buffer.
+ * @param flags   Flags to control the data transfer.
+ *
+ * @return Zero on success or a negative error code from errno.h.
+ *
+ */
+int async_obsolete_data_write_start_generic(int phoneid, const void *src, size_t size,
+    int flags)
+{
+	return async_obsolete_req_3_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
+	    (sysarg_t) size, (sysarg_t) flags);
+}
+
+/** Start IPC_M_DATA_READ using the async framework.
+ *
+ * @param phoneid Phone that will be used to contact the receiving side.
+ * @param dst     Address of the beginning of the destination buffer.
+ * @param size    Size of the destination buffer (in bytes).
+ * @param dataptr Storage of call data (arg 2 holds actual data size).
+ *
+ * @return Hash of the sent message or 0 on error.
+ *
+ */
+aid_t async_obsolete_data_read(int phone, void *dst, size_t size,
+    ipc_call_t *dataptr)
+{
+	return async_obsolete_send_2(phone, IPC_M_DATA_READ, (sysarg_t) dst,
+	    (sysarg_t) size, dataptr);
+}
+
+/** Wrapper for IPC_M_DATA_READ calls using the async framework.
+ *
+ * @param phoneid Phone that will be used to contact the receiving side.
+ * @param dst     Address of the beginning of the destination buffer.
+ * @param size    Size of the destination buffer.
+ * @param flags   Flags to control the data transfer.
+ *
+ * @return Zero on success or a negative error code from errno.h.
+ *
+ */
+int async_obsolete_data_read_start_generic(int phoneid, void *dst, size_t size, int flags)
+{
+	return async_obsolete_req_3_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
+	    (sysarg_t) size, (sysarg_t) flags);
+}
+
+/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
+ *
+ * Ask through phone for a new connection to some service.
+ *
+ * @param phone           Phone handle used for contacting the other side.
+ * @param arg1            User defined argument.
+ * @param arg2            User defined argument.
+ * @param arg3            User defined argument.
+ * @param client_receiver Connection handing routine.
+ *
+ * @return New phone handle on success or a negative error code.
+ *
+ */
+int async_obsolete_connect_to_me(int phone, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3, async_client_conn_t client_receiver)
+{
+	sysarg_t task_hash;
+	sysarg_t phone_hash;
+	int rc = async_obsolete_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
+	    NULL, NULL, NULL, &task_hash, &phone_hash);
+	if (rc != EOK)
+		return rc;
+	
+	if (client_receiver != NULL)
+		async_new_connection(task_hash, phone_hash, 0, NULL,
+		    client_receiver);
+	
+	return EOK;
+}
+
+/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
+ *
+ * Ask through phone for a new connection to some service.
+ *
+ * @param phone Phone handle used for contacting the other side.
+ * @param arg1  User defined argument.
+ * @param arg2  User defined argument.
+ * @param arg3  User defined argument.
+ *
+ * @return New phone handle on success or a negative error code.
+ *
+ */
+int async_obsolete_connect_me_to(int phone, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3)
+{
+	sysarg_t newphid;
+	int rc = async_obsolete_req_3_5(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
+	    NULL, NULL, NULL, NULL, &newphid);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return newphid;
+}
+
+/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
+ *
+ * Ask through phone for a new connection to some service and block until
+ * success.
+ *
+ * @param phoneid Phone handle used for contacting the other side.
+ * @param arg1    User defined argument.
+ * @param arg2    User defined argument.
+ * @param arg3    User defined argument.
+ *
+ * @return New phone handle on success or a negative error code.
+ *
+ */
+int async_obsolete_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3)
+{
+	sysarg_t newphid;
+	int rc = async_obsolete_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
+	    IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return newphid;
+}
+
+/** Send message and return id of the sent message
+ *
+ * The return value can be used as input for async_wait() to wait for
+ * completion.
+ *
+ * @param phoneid Handle of the phone that will be used for the send.
+ * @param method  Service-defined method.
+ * @param arg1    Service-defined payload argument.
+ * @param arg2    Service-defined payload argument.
+ * @param arg3    Service-defined payload argument.
+ * @param arg4    Service-defined payload argument.
+ * @param arg5    Service-defined payload argument.
+ * @param dataptr If non-NULL, storage where the reply data will be
+ *                stored.
+ *
+ * @return Hash of the sent message or 0 on error.
+ *
+ */
+aid_t async_obsolete_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
+    ipc_call_t *dataptr)
+{
+	amsg_t *msg = malloc(sizeof(amsg_t));
+	
+	if (!msg)
+		return 0;
+	
+	msg->done = false;
+	msg->dataptr = dataptr;
+	
+	msg->wdata.to_event.inlist = false;
+	
+	/*
+	 * We may sleep in the next method,
+	 * but it will use its own means
+	 */
+	msg->wdata.active = true;
+	
+	ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
+	    reply_received, true);
+	
+	return (aid_t) msg;
+}
+
+void async_obsolete_msg_0(int phone, sysarg_t imethod)
+{
+	ipc_call_async_0(phone, imethod, NULL, NULL, true);
+}
+
+void async_obsolete_msg_1(int phone, sysarg_t imethod, sysarg_t arg1)
+{
+	ipc_call_async_1(phone, imethod, arg1, NULL, NULL, true);
+}
+
+void async_obsolete_msg_2(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
+{
+	ipc_call_async_2(phone, imethod, arg1, arg2, NULL, NULL, true);
+}
+
+void async_obsolete_msg_3(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3)
+{
+	ipc_call_async_3(phone, imethod, arg1, arg2, arg3, NULL, NULL, true);
+}
+
+void async_obsolete_msg_4(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3, sysarg_t arg4)
+{
+	ipc_call_async_4(phone, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
+	    true);
+}
+
+void async_obsolete_msg_5(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
+{
+	ipc_call_async_5(phone, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
+	    NULL, true);
+}
+
+/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
+ *
+ * @param phoneid Phone that will be used to contact the receiving side.
+ * @param dst     Destination address space area base.
+ * @param size    Size of the destination address space area.
+ * @param arg     User defined argument.
+ * @param flags   Storage for the received flags. Can be NULL.
+ *
+ * @return Zero on success or a negative error code from errno.h.
+ *
+ */
+int async_obsolete_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
+    unsigned int *flags)
+{
+	sysarg_t tmp_flags;
+	int res = async_obsolete_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
+	    (sysarg_t) size, arg, NULL, &tmp_flags);
+	
+	if (flags)
+		*flags = (unsigned int) tmp_flags;
+	
+	return res;
+}
+
+int async_obsolete_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
+    sysarg_t arg1, sysarg_t arg2, unsigned int mode)
+{
+	return ipc_forward_fast(callid, phoneid, imethod, arg1, arg2, mode);
+}
+
+int async_obsolete_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
+    unsigned int mode)
+{
+	return ipc_forward_slow(callid, phoneid, imethod, arg1, arg2, arg3, arg4,
+	    arg5, mode);
+}
+
+/** Wrapper for forwarding any data that is about to be received
+ *
+ */
+int async_obsolete_data_write_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
+{
+	ipc_callid_t callid;
+	if (!async_data_write_receive(&callid, NULL)) {
+		ipc_answer_0(callid, EINVAL);
+		return EINVAL;
+	}
+	
+	aid_t msg = async_obsolete_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
+	    dataptr);
+	if (msg == 0) {
+		ipc_answer_0(callid, EINVAL);
+		return EINVAL;
+	}
+	
+	int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
+	    IPC_FF_ROUTE_FROM_ME);
+	if (retval != EOK) {
+		async_wait_for(msg, NULL);
+		ipc_answer_0(callid, retval);
+		return retval;
+	}
+	
+	sysarg_t rc;
+	async_wait_for(msg, &rc);
+	
+	return (int) rc;
+}
+
+/** @}
+ */
Index: pace/lib/c/generic/async_sess.c
===================================================================
--- uspace/lib/c/generic/async_sess.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,309 +1,0 @@
-/*
- * Copyright (c) 2010 Jakub Jermar
- * 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 libc
- * @{
- */
-/** @file
- */
-
-/**
- * This file implements simple session support for the async framework.
- *
- * By the term 'session', we mean a logical data path between a client and a
- * server over which the client can perform multiple concurrent exchanges.
- * Each exchange consists of one or more requests (IPC calls) which can
- * be potentially blocking.
- *
- * Clients and servers are naturally connected using IPC phones, thus an IPC
- * phone represents a session between a client and a server. In one
- * session, there can be many outstanding exchanges. In the current
- * implementation each concurrent exchanges takes place over a different
- * connection (there can be at most one active exchage per connection).
- *
- * Sessions make it useful for a client or client API to support concurrent
- * requests, independent of the actual implementation. Sessions provide
- * an abstract interface to concurrent IPC communication. This is especially
- * useful for client API stubs that aim to be reentrant (i.e. that allow
- * themselves to be called from different fibrils and threads concurrently).
- *
- * There are several possible implementations of sessions. This implementation
- * uses additional phones to represent sessions. Using phones both for the
- * session and also for its exchages/connections has several advantages:
- *
- * - to make a series of exchanges over a session, the client can continue to
- *   use the existing async framework APIs
- * - the server supports sessions by the virtue of spawning a new connection
- *   fibril, just as it does for every new connection even without sessions
- * - the implementation is pretty straightforward; a very naive implementation
- *   would be to make each exchage using a fresh phone (that is what we
- *   have done in the past); a slightly better approach would be to cache
- *   connections so that they can be reused by a later exchange within
- *   the same session (that is what this implementation does)
- *
- * The main disadvantages of using phones to represent sessions are:
- *
- * - if there are too many exchanges (even cached ones), the task may hit its
- *   limit on the maximum number of connected phones, which could prevent the
- *   task from making new IPC connections to other tasks
- * - if there are too many IPC connections already, it may be impossible to
- *   create an exchange by connecting a new phone thanks to the task's limit on
- *   the maximum number of connected phones
- *
- * These problems can be alleviated by increasing the limit on the maximum
- * number of connected phones to some reasonable value and by limiting the number
- * of cached connections to some fraction of this limit.
- *
- * The cache itself has a mechanism to close some number of unused phones if a
- * new phone cannot be connected, but the outer world currently does not have a
- * way to ask the phone cache to shrink.
- *
- * To minimize the confusion stemming from the fact that we use phones for two
- * things (the session itself and also one for each data connection), this file
- * makes the distinction by using the term 'session phone' for the former and
- * 'data phone' for the latter. Under the hood, all phones remain equal,
- * of course.
- *
- * There is a small inefficiency in that the cache repeatedly allocates and
- * deallocates the conn_node_t structures when in fact it could keep the
- * allocated structures around and reuse them later. But such a solution would
- * be effectively implementing a poor man's slab allocator while it would be
- * better to have the slab allocator ported to uspace so that everyone could
- * benefit from it.
- */
-
-#include <async_sess.h>
-#include <fibril_synch.h>
-#include <adt/list.h>
-#include <adt/hash_table.h>
-#include <malloc.h>
-#include <errno.h>
-#include <assert.h>
-#include <async.h>
-#include "private/async_sess.h"
-
-/** An inactive open connection. */
-typedef struct {
-	link_t sess_link;	/**< Link for the session list of inactive connections. */
-	link_t global_link;	/**< Link for the global list of inactive connections. */
-	int data_phone;		/**< Connected data phone. */
-} conn_node_t;
-
-/**
- * Mutex protecting the inactive_conn_head list, the session list and the
- * avail_phone condition variable.
- */
-static fibril_mutex_t async_sess_mutex;
-
-/**
- * List of all currently inactive connections.
- */
-static LIST_INITIALIZE(inactive_conn_head);
-
-/**
- * List of all open sessions.
- */
-static LIST_INITIALIZE(session_list_head);
-
-/**
- * Condition variable used to wait for a phone to become available.
- */
-static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
-
-/** Initialize the async_sess subsystem.
- *
- * Needs to be called prior to any other interface in this file.
- *
- */
-void __async_sess_init(void)
-{
-	fibril_mutex_initialize(&async_sess_mutex);
-	list_initialize(&inactive_conn_head);
-	list_initialize(&session_list_head);
-}
-
-/** Create a session.
- *
- * Session is a logical datapath from a client task to a server task.
- * One session can accomodate multiple concurrent exchanges. Here
- * @a phone is a phone connected to the desired server task.
- *
- * This function always succeeds.
- *
- * @param sess	Session structure provided by caller, will be filled in.
- * @param phone	Phone connected to the desired server task.
- * @param arg1	Value to pass as first argument upon creating a new
- *		connection. Typical use is to identify a resource within
- *		the server that the caller wants to access (port ID,
- *		interface ID, device ID, etc.).
- */
-void async_session_create(async_sess_t *sess, int phone, sysarg_t arg1)
-{
-	sess->sess_phone = phone;
-	sess->connect_arg1 = arg1;
-	list_initialize(&sess->conn_head);
-	
-	/* Add to list of sessions. */
-	fibril_mutex_lock(&async_sess_mutex);
-	list_append(&sess->sess_link, &session_list_head);
-	fibril_mutex_unlock(&async_sess_mutex);
-}
-
-/** Destroy a session.
- *
- * Dismantle session structure @a sess and release any resources (connections)
- * held by the session.
- *
- * @param sess	Session to destroy.
- */
-void async_session_destroy(async_sess_t *sess)
-{
-	conn_node_t *conn;
-
-	/* Remove from list of sessions. */
-	fibril_mutex_lock(&async_sess_mutex);
-	list_remove(&sess->sess_link);
-	fibril_mutex_unlock(&async_sess_mutex);
-
-	/* We did not connect the phone so we do not hang it up either. */
-	sess->sess_phone = -1;
-
-	/* Tear down all data connections. */
-	while (!list_empty(&sess->conn_head)) {
-		conn = list_get_instance(sess->conn_head.next, conn_node_t,
-		    sess_link);
-
-		list_remove(&conn->sess_link);
-		list_remove(&conn->global_link);
-		
-		async_hangup(conn->data_phone);
-		free(conn);
-	}
-	
-	fibril_condvar_broadcast(&avail_phone_cv);
-}
-
-static void conn_node_initialize(conn_node_t *conn)
-{
-	link_initialize(&conn->sess_link);
-	link_initialize(&conn->global_link);
-	conn->data_phone = -1;
-}
-
-/** Start new exchange in a session.
- *
- * @param sess_phone	Session.
- * @return		Phone representing the new exchange or a negative error
- *			code.
- */
-int async_exchange_begin(async_sess_t *sess)
-{
-	conn_node_t *conn;
-	int data_phone;
-
-	fibril_mutex_lock(&async_sess_mutex);
-
-	if (!list_empty(&sess->conn_head)) {
-		/*
-		 * There are inactive connections in the session.
-		 */
-		conn = list_get_instance(sess->conn_head.next, conn_node_t,
-		    sess_link);
-		list_remove(&conn->sess_link);
-		list_remove(&conn->global_link);
-		
-		data_phone = conn->data_phone;
-		free(conn);
-	} else {
-		/*
-		 * There are no available connections in the session.
-		 * Make a one-time attempt to connect a new data phone.
-		 */
-retry:
-		data_phone = async_connect_me_to(sess->sess_phone,
-		    sess->connect_arg1, 0, 0);
-		if (data_phone >= 0) {
-			/* success, do nothing */
-		} else if (!list_empty(&inactive_conn_head)) {
-			/*
-			 * We did not manage to connect a new phone. But we can
-			 * try to close some of the currently inactive
-			 * connections in other sessions and try again.
-			 */
-			conn = list_get_instance(inactive_conn_head.next,
-			    conn_node_t, global_link);
-			list_remove(&conn->global_link);
-			list_remove(&conn->sess_link);
-			data_phone = conn->data_phone;
-			free(conn);
-			async_hangup(data_phone);
-			goto retry;
-		} else {
-			/*
-			 * Wait for a phone to become available.
-			 */
-			fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
-			goto retry;
-		}
-	}
-
-	fibril_mutex_unlock(&async_sess_mutex);
-	return data_phone;
-}
-
-/** Finish an exchange.
- *
- * @param sess		Session.
- * @param data_phone	Phone representing the exchange within the session.
- */
-void async_exchange_end(async_sess_t *sess, int data_phone)
-{
-	conn_node_t *conn;
-
-	fibril_mutex_lock(&async_sess_mutex);
-	fibril_condvar_signal(&avail_phone_cv);
-	conn = (conn_node_t *) malloc(sizeof(conn_node_t));
-	if (!conn) {
-		/*
-		 * Being unable to remember the connected data phone here
-		 * means that we simply hang up.
-		 */
-		async_hangup(data_phone);
-		fibril_mutex_unlock(&async_sess_mutex);
-		return;
-	}
-
-	conn_node_initialize(conn);
-	conn->data_phone = data_phone;
-	list_append(&conn->sess_link, &sess->conn_head);
-	list_append(&conn->global_link, &inactive_conn_head);
-	fibril_mutex_unlock(&async_sess_mutex);
-}
-
-/** @}
- */
Index: uspace/lib/c/generic/clipboard.c
===================================================================
--- uspace/lib/c/generic/clipboard.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/clipboard.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,7 +39,8 @@
 
 #include <clipboard.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <ipc/services.h>
 #include <ipc/clipboard.h>
+#include <fibril_synch.h>
 #include <async.h>
 #include <str.h>
@@ -47,13 +48,33 @@
 #include <malloc.h>
 
-static int clip_phone = -1;
-
-/** Connect to clipboard server
- *
- */
-static void clip_connect(void)
-{
-	while (clip_phone < 0)
-		clip_phone = service_connect_blocking(SERVICE_CLIPBOARD, 0, 0);
+static FIBRIL_MUTEX_INITIALIZE(clip_mutex);
+static async_sess_t *clip_sess = NULL;
+
+/** Start an async exchange on the clipboard session.
+ *
+ * @return New exchange.
+ *
+ */
+static async_exch_t *clip_exchange_begin(void)
+{
+	fibril_mutex_lock(&clip_mutex);
+	
+	while (clip_sess == NULL)
+		clip_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_CLIPBOARD, 0, 0);
+	
+	fibril_mutex_unlock(&clip_mutex);
+	
+	return async_exchange_begin(clip_sess);
+}
+
+/** Finish an async exchange on the clipboard session.
+ *
+ * @param exch Exchange to be finished.
+ *
+ */
+static void clip_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
 }
 
@@ -73,22 +94,20 @@
 	
 	if (size == 0) {
-		async_serialize_start();
-		clip_connect();
-		
-		sysarg_t rc = async_req_1_0(clip_phone, CLIPBOARD_PUT_DATA, CLIPBOARD_TAG_NONE);
-		
-		async_serialize_end();
+		async_exch_t *exch = clip_exchange_begin();
+		sysarg_t rc = async_req_1_0(exch, CLIPBOARD_PUT_DATA,
+		    CLIPBOARD_TAG_NONE);
+		clip_exchange_end(exch);
 		
 		return (int) rc;
 	} else {
-		async_serialize_start();
-		clip_connect();
-		
-		aid_t req = async_send_1(clip_phone, CLIPBOARD_PUT_DATA, CLIPBOARD_TAG_DATA, NULL);
-		sysarg_t rc = async_data_write_start(clip_phone, (void *) str, size);
+		async_exch_t *exch = clip_exchange_begin();
+		aid_t req = async_send_1(exch, CLIPBOARD_PUT_DATA, CLIPBOARD_TAG_DATA,
+		    NULL);
+		sysarg_t rc = async_data_write_start(exch, (void *) str, size);
+		clip_exchange_end(exch);
+		
 		if (rc != EOK) {
 			sysarg_t rc_orig;
 			async_wait_for(req, &rc_orig);
-			async_serialize_end();
 			if (rc_orig == EOK)
 				return (int) rc;
@@ -98,5 +117,4 @@
 		
 		async_wait_for(req, &rc);
-		async_serialize_end();
 		
 		return (int) rc;
@@ -117,12 +135,11 @@
 	/* Loop until clipboard read succesful */
 	while (true) {
-		async_serialize_start();
-		clip_connect();
+		async_exch_t *exch = clip_exchange_begin();
 		
 		sysarg_t size;
 		sysarg_t tag;
-		sysarg_t rc = async_req_0_2(clip_phone, CLIPBOARD_CONTENT, &size, &tag);
-		
-		async_serialize_end();
+		sysarg_t rc = async_req_0_2(exch, CLIPBOARD_CONTENT, &size, &tag);
+		
+		clip_exchange_end(exch);
 		
 		if (rc != EOK)
@@ -145,8 +162,9 @@
 				return ENOMEM;
 			
-			async_serialize_start();
-			
-			aid_t req = async_send_1(clip_phone, CLIPBOARD_GET_DATA, tag, NULL);
-			rc = async_data_read_start(clip_phone, (void *) sbuf, size);
+			exch = clip_exchange_begin();
+			aid_t req = async_send_1(exch, CLIPBOARD_GET_DATA, tag, NULL);
+			rc = async_data_read_start(exch, (void *) sbuf, size);
+			clip_exchange_end(exch);
+			
 			if ((int) rc == EOVERFLOW) {
 				/*
@@ -154,5 +172,4 @@
 				 * the last call of CLIPBOARD_CONTENT
 				 */
-				async_serialize_end();
 				break;
 			}
@@ -161,5 +178,4 @@
 				sysarg_t rc_orig;
 				async_wait_for(req, &rc_orig);
-				async_serialize_end();
 				if (rc_orig == EOK)
 					return (int) rc;
@@ -169,5 +185,4 @@
 			
 			async_wait_for(req, &rc);
-			async_serialize_end();
 			
 			if (rc == EOK) {
Index: uspace/lib/c/generic/device/char_dev.c
===================================================================
--- uspace/lib/c/generic/device/char_dev.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/device/char_dev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -45,35 +45,37 @@
  * using its character interface.
  *
- * @param dev_phone	Phone to the device.
- * @param buf		Buffer for the data read from or written to the device.
- * @param size		Maximum size of data (in bytes) to be read or written.
- * @param read		Read from the device if true, write to it otherwise.
+ * @param sess Session to the device.
+ * @param buf  Buffer for the data read from or written to the device.
+ * @param size Maximum size of data (in bytes) to be read or written.
+ * @param read Read from the device if true, write to it otherwise.
  *
- * @return		Non-negative number of bytes actually read from or
- *			written to the device on success, negative error number
- *			otherwise.
+ * @return Non-negative number of bytes actually read from or
+ *         written to the device on success, negative error number
+ *         otherwise.
+ *
  */
-static ssize_t char_dev_rw(int dev_phone, void *buf, size_t size, bool read)
+static ssize_t char_dev_rw(async_sess_t *sess, void *buf, size_t size, bool read)
 {
-	async_serialize_start();
-	
 	ipc_call_t answer;
 	aid_t req;
 	int ret;
 	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
 	if (read) {
-		req = async_send_1(dev_phone, DEV_IFACE_ID(CHAR_DEV_IFACE),
+		req = async_send_1(exch, DEV_IFACE_ID(CHAR_DEV_IFACE),
 		    CHAR_DEV_READ, &answer);
-		ret = async_data_read_start(dev_phone, buf, size);
+		ret = async_data_read_start(exch, buf, size);
 	} else {
-		req = async_send_1(dev_phone, DEV_IFACE_ID(CHAR_DEV_IFACE),
+		req = async_send_1(exch, DEV_IFACE_ID(CHAR_DEV_IFACE),
 		    CHAR_DEV_WRITE, &answer);
-		ret = async_data_write_start(dev_phone, buf, size);
+		ret = async_data_write_start(exch, buf, size);
 	}
+	
+	async_exchange_end(exch);
 	
 	sysarg_t rc;
 	if (ret != EOK) {
 		async_wait_for(req, &rc);
-		async_serialize_end();
 		if (rc == EOK)
 			return (ssize_t) ret;
@@ -83,5 +85,4 @@
 	
 	async_wait_for(req, &rc);
-	async_serialize_end();
 	
 	ret = (int) rc;
@@ -94,29 +95,31 @@
 /** Read from character device.
  *
- * @param dev_phone	Phone to the device.
- * @param buf		Output buffer for the data read from the device.
- * @param size		Maximum size (in bytes) of the data to be read.
+ * @param sess Session to the device.
+ * @param buf  Output buffer for the data read from the device.
+ * @param size Maximum size (in bytes) of the data to be read.
  *
- * @return		Non-negative number of bytes actually read from the
- *			device on success, negative error number otherwise.
+ * @return Non-negative number of bytes actually read from the
+ *         device on success, negative error number otherwise.
+ *
  */
-ssize_t char_dev_read(int dev_phone, void *buf, size_t size)
+ssize_t char_dev_read(async_sess_t *sess, void *buf, size_t size)
 {
-	return char_dev_rw(dev_phone, buf, size, true);
+	return char_dev_rw(sess, buf, size, true);
 }
 
 /** Write to character device.
  *
- * @param dev_phone	Phone to the device.
- * @param buf		Input buffer containg the data to be written to the
- *			device.
- * @param size		Maximum size (in bytes) of the data to be written.
+ * @param sess Session to the device.
+ * @param buf  Input buffer containg the data to be written to the
+ *             device.
+ * @param size Maximum size (in bytes) of the data to be written.
  *
- * @return		Non-negative number of bytes actually written to the
- *			device on success, negative error number otherwise.
+ * @return Non-negative number of bytes actually written to the
+ *         device on success, negative error number otherwise.
+ *
  */
-ssize_t char_dev_write(int dev_phone, void *buf, size_t size)
+ssize_t char_dev_write(async_sess_t *sess, void *buf, size_t size)
 {
-	return char_dev_rw(dev_phone, buf, size, false);
+	return char_dev_rw(sess, buf, size, false);
 }
 
Index: uspace/lib/c/generic/device/hw_res.c
===================================================================
--- uspace/lib/c/generic/device/hw_res.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/device/hw_res.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,36 +38,48 @@
 #include <malloc.h>
 
-int hw_res_get_resource_list(int dev_phone, hw_resource_list_t *hw_resources)
+int hw_res_get_resource_list(async_sess_t *sess,
+    hw_resource_list_t *hw_resources)
 {
 	sysarg_t count = 0;
-
-	int rc = async_req_1_1(dev_phone, DEV_IFACE_ID(HW_RES_DEV_IFACE),
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(HW_RES_DEV_IFACE),
 	    HW_RES_GET_RESOURCE_LIST, &count);
-
-	hw_resources->count = count;
-	if (rc != EOK)
+	
+	if (rc != EOK) {
+		async_exchange_end(exch);
 		return rc;
+	}
 	
 	size_t size = count * sizeof(hw_resource_t);
-	hw_resources->resources = (hw_resource_t *)malloc(size);
-	if (!hw_resources->resources)
+	hw_resource_t *resources = (hw_resource_t *) malloc(size);
+	if (resources == NULL) {
+		// FIXME: This is protocol violation
+		async_exchange_end(exch);
 		return ENOMEM;
+	}
 	
-	rc = async_data_read_start(dev_phone, hw_resources->resources, size);
+	rc = async_data_read_start(exch, resources, size);
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
-		free(hw_resources->resources);
-		hw_resources->resources = NULL;
+		free(resources);
 		return rc;
 	}
+	
+	hw_resources->resources = resources;
+	hw_resources->count = count;
 	
 	return EOK;
 }
 
-bool hw_res_enable_interrupt(int dev_phone)
+bool hw_res_enable_interrupt(async_sess_t *sess)
 {
-	int rc = async_req_1_0(dev_phone, DEV_IFACE_ID(HW_RES_DEV_IFACE),
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(HW_RES_DEV_IFACE),
 	    HW_RES_ENABLE_INTERRUPT);
-
-	return rc == EOK;
+	async_exchange_end(exch);
+	
+	return (rc == EOK);
 }
 
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/devman.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -36,59 +36,141 @@
 
 #include <str.h>
-#include <stdio.h>
 #include <ipc/services.h>
+#include <ns.h>
 #include <ipc/devman.h>
 #include <devman.h>
+#include <fibril_synch.h>
 #include <async.h>
-#include <fibril_synch.h>
 #include <errno.h>
 #include <malloc.h>
 #include <bool.h>
-#include <adt/list.h>
-
-static int devman_phone_driver = -1;
-static int devman_phone_client = -1;
-
-static FIBRIL_MUTEX_INITIALIZE(devman_phone_mutex);
-
-int devman_get_phone(devman_interface_t iface, unsigned int flags)
+
+static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex);
+static FIBRIL_MUTEX_INITIALIZE(devman_client_block_mutex);
+
+static FIBRIL_MUTEX_INITIALIZE(devman_driver_mutex);
+static FIBRIL_MUTEX_INITIALIZE(devman_client_mutex);
+
+static async_sess_t *devman_driver_block_sess = NULL;
+static async_sess_t *devman_client_block_sess = NULL;
+
+static async_sess_t *devman_driver_sess = NULL;
+static async_sess_t *devman_client_sess = NULL;
+
+static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
+    async_sess_t **dst)
+{
+	fibril_mutex_lock(mtx);
+	
+	if ((*dst == NULL) && (src != NULL))
+		*dst = src;
+	
+	fibril_mutex_unlock(mtx);
+}
+
+/** Start an async exchange on the devman session (blocking).
+ *
+ * @param iface Device manager interface to choose
+ *
+ * @return New exchange.
+ *
+ */
+async_exch_t *devman_exchange_begin_blocking(devman_interface_t iface)
 {
 	switch (iface) {
 	case DEVMAN_DRIVER:
-		fibril_mutex_lock(&devman_phone_mutex);
-		if (devman_phone_driver >= 0) {
-			fibril_mutex_unlock(&devman_phone_mutex);
-			return devman_phone_driver;
+		fibril_mutex_lock(&devman_driver_block_mutex);
+		
+		while (devman_driver_block_sess == NULL) {
+			clone_session(&devman_driver_mutex, devman_driver_sess,
+			    &devman_driver_block_sess);
+			
+			if (devman_driver_block_sess == NULL)
+				devman_driver_block_sess =
+				    service_connect_blocking(EXCHANGE_SERIALIZE,
+				    SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
 		}
 		
-		if (flags & IPC_FLAG_BLOCKING)
-			devman_phone_driver = async_connect_me_to_blocking(
-			    PHONE_NS, SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
-		else
-			devman_phone_driver = async_connect_me_to(PHONE_NS,
-			    SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
-		
-		fibril_mutex_unlock(&devman_phone_mutex);
-		return devman_phone_driver;
+		fibril_mutex_unlock(&devman_driver_block_mutex);
+		
+		clone_session(&devman_driver_mutex, devman_driver_block_sess,
+		    &devman_driver_sess);
+		
+		return async_exchange_begin(devman_driver_block_sess);
 	case DEVMAN_CLIENT:
-		fibril_mutex_lock(&devman_phone_mutex);
-		if (devman_phone_client >= 0) {
-			fibril_mutex_unlock(&devman_phone_mutex);
-			return devman_phone_client;
+		fibril_mutex_lock(&devman_client_block_mutex);
+		
+		while (devman_client_block_sess == NULL) {
+			clone_session(&devman_client_mutex, devman_client_sess,
+			    &devman_client_block_sess);
+			
+			if (devman_client_block_sess == NULL)
+				devman_client_block_sess =
+				    service_connect_blocking(EXCHANGE_SERIALIZE,
+				    SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
 		}
 		
-		if (flags & IPC_FLAG_BLOCKING) {
-			devman_phone_client = async_connect_me_to_blocking(
-			    PHONE_NS, SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
-		} else {
-			devman_phone_client = async_connect_me_to(PHONE_NS,
-			    SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
-		}
-		
-		fibril_mutex_unlock(&devman_phone_mutex);
-		return devman_phone_client;
+		fibril_mutex_unlock(&devman_client_block_mutex);
+		
+		clone_session(&devman_client_mutex, devman_client_block_sess,
+		    &devman_client_sess);
+		
+		return async_exchange_begin(devman_client_block_sess);
 	default:
-		return -1;
-	}
+		return NULL;
+	}
+}
+
+/** Start an async exchange on the devman session.
+ *
+ * @param iface Device manager interface to choose
+ *
+ * @return New exchange.
+ *
+ */
+async_exch_t *devman_exchange_begin(devman_interface_t iface)
+{
+	switch (iface) {
+	case DEVMAN_DRIVER:
+		fibril_mutex_lock(&devman_driver_mutex);
+		
+		if (devman_driver_sess == NULL)
+			devman_driver_sess =
+			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
+			    DEVMAN_DRIVER, 0);
+		
+		fibril_mutex_unlock(&devman_driver_mutex);
+		
+		if (devman_driver_sess == NULL)
+			return NULL;
+		
+		return async_exchange_begin(devman_driver_sess);
+	case DEVMAN_CLIENT:
+		fibril_mutex_lock(&devman_client_mutex);
+		
+		if (devman_client_sess == NULL)
+			devman_client_sess =
+			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
+			    DEVMAN_CLIENT, 0);
+		
+		fibril_mutex_unlock(&devman_client_mutex);
+		
+		if (devman_client_sess == NULL)
+			return NULL;
+		
+		return async_exchange_begin(devman_client_sess);
+	default:
+		return NULL;
+	}
+}
+
+/** Finish an async exchange on the devman session.
+ *
+ * @param exch Exchange to be finished.
+ *
+ */
+void devman_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
 }
 
@@ -96,119 +178,96 @@
 int devman_driver_register(const char *name, async_client_conn_t conn)
 {
-	int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, name, str_size(name));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		return -1;
+	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	
+	devman_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
 	}
 	
 	async_set_client_connection(conn);
 	
-	async_connect_to_me(phone, 0, 0, 0, NULL);
+	exch = devman_exchange_begin(DEVMAN_DRIVER);
+	async_connect_to_me(exch, 0, 0, 0, NULL);
+	devman_exchange_end(exch);
+	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
-	
 	return retval;
 }
 
-static int devman_send_match_id(int phone, match_id_t *match_id)
-{
-	ipc_call_t answer;
-
-	aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score,
-	    &answer);
-	int retval = async_data_write_start(phone, match_id->id,
-	    str_size(match_id->id));
-
-	async_wait_for(req, NULL);
-	return retval;
-}
-
-
-static int devman_send_match_ids(int phone, match_id_list_t *match_ids)
-{
+/** Add function to a device.
+ *
+ * Request devman to add a new function to the specified device owned by
+ * this driver task.
+ *
+ * @param name      Name of the new function
+ * @param ftype     Function type, fun_inner or fun_exposed
+ * @param match_ids Match IDs (should be empty for fun_exposed)
+ * @param devh      Devman handle of the device
+ * @param funh      Place to store handle of the new function
+ *
+ * @return EOK on success or negative error code.
+ *
+ */
+int devman_add_function(const char *name, fun_type_t ftype,
+    match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
+{
+	int match_count = list_count(&match_ids->ids);
+	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_3(exch, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
+	    devh, match_count, &answer);
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	if (retval != EOK) {
+		devman_exchange_end(exch);
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
 	link_t *link = match_ids->ids.next;
 	match_id_t *match_id = NULL;
-	int ret = EOK;
-
+	
 	while (link != &match_ids->ids) {
-		match_id = list_get_instance(link, match_id_t, link); 
-		ret = devman_send_match_id(phone, match_id);
-		if (ret != EOK) {
-			return ret;
+		match_id = list_get_instance(link, match_id_t, link);
+		
+		ipc_call_t answer2;
+		aid_t req2 = async_send_1(exch, DEVMAN_ADD_MATCH_ID,
+		    match_id->score, &answer2);
+		retval = async_data_write_start(exch, match_id->id,
+		    str_size(match_id->id));
+		if (retval != EOK) {
+			devman_exchange_end(exch);
+			async_wait_for(req2, NULL);
+			async_wait_for(req, NULL);
+			return retval;
 		}
-
+		
+		async_wait_for(req2, &retval);
+		if (retval != EOK) {
+			devman_exchange_end(exch);
+			async_wait_for(req, NULL);
+			return retval;
+		}
+		
 		link = link->next;
 	}
-
-	return ret;
-}
-
-/** Add function to a device.
- *
- * Request devman to add a new function to the specified device owned by
- * this driver task.
- *
- * @param name		Name of the new function
- * @param ftype		Function type, fun_inner or fun_exposed
- * @param match_ids	Match IDs (should be empty for fun_exposed)
- * @param devh		Devman handle of the device
- * @param funh		Place to store handle of the new function
- *
- * @return		EOK on success or negative error code.
- */
-int devman_add_function(const char *name, fun_type_t ftype,
-    match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
-{
-	int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
-	int fun_handle;
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
-	
-	int match_count = list_count(&match_ids->ids);
-	ipc_call_t answer;
-
-	aid_t req = async_send_3(phone, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
-	    devh, match_count, &answer);
-
-	sysarg_t retval = async_data_write_start(phone, name, str_size(name));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		return retval;
-	}
-	
-	int match_ids_rc = devman_send_match_ids(phone, match_ids);
+	
+	devman_exchange_end(exch);
 	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
-	
-	/* Prefer the answer to DEVMAN_ADD_FUNCTION in case of errors. */
-	if ((match_ids_rc != EOK) && (retval == EOK)) {
-		retval = match_ids_rc;
-	}
-
-	if (retval == EOK)
-		fun_handle = (int) IPC_GET_ARG1(answer);
-	else
-		fun_handle = -1;
-	
-	*funh = fun_handle;
-
+	if (retval == EOK) {
+		if (funh != NULL)
+			*funh = (int) IPC_GET_ARG1(answer);
+	} else {
+		if (funh != NULL)
+			*funh = -1;
+	}
+	
 	return retval;
 }
@@ -217,76 +276,51 @@
     const char *class_name)
 {
-	int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
-	ipc_call_t answer;
-	aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS,
+	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CLASS,
 	    devman_handle, &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, class_name,
+	sysarg_t retval = async_data_write_start(exch, class_name,
 	    str_size(class_name));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
+	
+	devman_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
 		return retval;
 	}
 	
 	async_wait_for(req, &retval);
-	async_serialize_end();
-	
 	return retval;
 }
 
-void devman_hangup_phone(devman_interface_t iface)
-{
-	switch (iface) {
-	case DEVMAN_DRIVER:
-		if (devman_phone_driver >= 0) {
-			async_hangup(devman_phone_driver);
-			devman_phone_driver = -1;
-		}
-		break;
-	case DEVMAN_CLIENT:
-		if (devman_phone_client >= 0) {
-			async_hangup(devman_phone_client);
-			devman_phone_client = -1;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-int devman_device_connect(devman_handle_t handle, unsigned int flags)
-{
-	int phone;
-	
-	if (flags & IPC_FLAG_BLOCKING) {
-		phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
-		    DEVMAN_CONNECT_TO_DEVICE, handle);
-	} else {
-		phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
-		    DEVMAN_CONNECT_TO_DEVICE, handle);
-	}
-	
-	return phone;
-}
-
-int devman_parent_device_connect(devman_handle_t handle, unsigned int flags)
-{
-	int phone;
-	
-	if (flags & IPC_FLAG_BLOCKING) {
-		phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
-		    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
-	} else {
-		phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
-		    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
-	}
-	
-	return phone;
+async_sess_t *devman_device_connect(exch_mgmt_t mgmt, devman_handle_t handle,
+    unsigned int flags)
+{
+	async_sess_t *sess;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
+			    DEVMAN_CONNECT_TO_DEVICE, handle);
+	else
+		sess = service_connect(mgmt, SERVICE_DEVMAN,
+			    DEVMAN_CONNECT_TO_DEVICE, handle);
+	
+	return sess;
+}
+
+async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
+    devman_handle_t handle, unsigned int flags)
+{
+	async_sess_t *sess;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
+			    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
+	else
+		sess = service_connect(mgmt, SERVICE_DEVMAN,
+			    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
+	
+	return sess;
 }
 
@@ -294,30 +328,33 @@
     unsigned int flags)
 {
-	int phone = devman_get_phone(DEVMAN_CLIENT, flags);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
+	else {
+		exch = devman_exchange_begin(DEVMAN_CLIENT);
+		if (exch == NULL)
+			return errno;
+	}
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
 	    &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, pathname,
+	sysarg_t retval = async_data_write_start(exch, pathname,
 	    str_size(pathname));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
+	
+	devman_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
 		return retval;
 	}
 	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
 	
 	if (retval != EOK) {
 		if (handle != NULL)
 			*handle = (devman_handle_t) -1;
+		
 		return retval;
 	}
@@ -332,46 +369,99 @@
     const char *devname, devman_handle_t *handle, unsigned int flags)
 {
-	int phone = devman_get_phone(DEVMAN_CLIENT, flags);
-
-	if (phone < 0)
-		return phone;
-
-	async_serialize_start();
-
-	ipc_call_t answer;
-	aid_t req = async_send_1(phone, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
+	else {
+		exch = devman_exchange_begin(DEVMAN_CLIENT);
+		if (exch == NULL)
+			return errno;
+	}
+	
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
 	    flags, &answer);
-
-	sysarg_t retval = async_data_write_start(phone, classname,
+	sysarg_t retval = async_data_write_start(exch, classname,
 	    str_size(classname));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		return retval;
-	}
-	retval = async_data_write_start(phone, devname,
+	
+	if (retval != EOK) {
+		devman_exchange_end(exch);
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
+	retval = async_data_write_start(exch, devname,
 	    str_size(devname));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		return retval;
-	}
-
+	
+	devman_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
 	async_wait_for(req, &retval);
-
-	async_serialize_end();
-
+	
 	if (retval != EOK) {
 		if (handle != NULL)
 			*handle = (devman_handle_t) -1;
-		return retval;
-	}
-
+		
+		return retval;
+	}
+	
 	if (handle != NULL)
 		*handle = (devman_handle_t) IPC_GET_ARG1(answer);
-
+	
 	return retval;
 }
 
+int devman_get_device_path(devman_handle_t handle, char *path, size_t path_size)
+{
+	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	if (exch == NULL)
+		return errno;
+	
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_DEVICE_PATH,
+	    handle, &answer);
+	
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, path, path_size,
+	    &data_request_call);
+	
+	devman_exchange_end(exch);
+	
+	if (data_request == 0) {
+		async_wait_for(req, NULL);
+		return ENOMEM;
+	}
+	
+	sysarg_t data_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	
+	sysarg_t opening_request_rc;
+	async_wait_for(req, &opening_request_rc);
+	
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK)
+			return (int) opening_request_rc;
+		else
+			return (int) data_request_rc;
+	}
+	
+	if (opening_request_rc != EOK)
+		return (int) opening_request_rc;
+	
+	/* To be on the safe-side. */
+	path[path_size - 1] = 0;
+	size_t transferred_size = IPC_GET_ARG2(data_request_call);
+	if (transferred_size >= path_size)
+		return ELIMIT;
+	
+	/* Terminate the string (trailing 0 not send over IPC). */
+	path[transferred_size] = 0;
+	return EOK;
+}
 
 /** @}
Index: uspace/lib/c/generic/devman_obsolete.c
===================================================================
--- uspace/lib/c/generic/devman_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/devman_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2007 Josef Cejka
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2010 Lenka Trochtova
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <str.h>
+#include <stdio.h>
+#include <ipc/services.h>
+#include <ipc/devman.h>
+#include <devman_obsolete.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <ns.h>
+#include <ns_obsolete.h>
+#include <fibril_synch.h>
+#include <errno.h>
+#include <malloc.h>
+#include <bool.h>
+#include <adt/list.h>
+
+static int devman_phone_driver = -1;
+static int devman_phone_client = -1;
+
+static FIBRIL_MUTEX_INITIALIZE(devman_phone_mutex);
+
+int devman_obsolete_get_phone(devman_interface_t iface, unsigned int flags)
+{
+	switch (iface) {
+	case DEVMAN_DRIVER:
+		fibril_mutex_lock(&devman_phone_mutex);
+		if (devman_phone_driver >= 0) {
+			fibril_mutex_unlock(&devman_phone_mutex);
+			return devman_phone_driver;
+		}
+		
+		if (flags & IPC_FLAG_BLOCKING)
+			devman_phone_driver = service_obsolete_connect_blocking(
+			    SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
+		else
+			devman_phone_driver = service_obsolete_connect(SERVICE_DEVMAN,
+			    DEVMAN_DRIVER, 0);
+		
+		fibril_mutex_unlock(&devman_phone_mutex);
+		return devman_phone_driver;
+	case DEVMAN_CLIENT:
+		fibril_mutex_lock(&devman_phone_mutex);
+		if (devman_phone_client >= 0) {
+			fibril_mutex_unlock(&devman_phone_mutex);
+			return devman_phone_client;
+		}
+		
+		if (flags & IPC_FLAG_BLOCKING) {
+			devman_phone_client = service_obsolete_connect_blocking(
+			    SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
+		} else {
+			devman_phone_client = service_obsolete_connect(SERVICE_DEVMAN,
+			    DEVMAN_CLIENT, 0);
+		}
+		
+		fibril_mutex_unlock(&devman_phone_mutex);
+		return devman_phone_client;
+	default:
+		return -1;
+	}
+}
+
+void devman_obsolete_hangup_phone(devman_interface_t iface)
+{
+	switch (iface) {
+	case DEVMAN_DRIVER:
+		if (devman_phone_driver >= 0) {
+			async_obsolete_hangup(devman_phone_driver);
+			devman_phone_driver = -1;
+		}
+		break;
+	case DEVMAN_CLIENT:
+		if (devman_phone_client >= 0) {
+			async_obsolete_hangup(devman_phone_client);
+			devman_phone_client = -1;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+int devman_obsolete_device_connect(devman_handle_t handle, unsigned int flags)
+{
+	int phone;
+	
+	if (flags & IPC_FLAG_BLOCKING) {
+		phone = service_obsolete_connect_blocking(SERVICE_DEVMAN,
+		    DEVMAN_CONNECT_TO_DEVICE, handle);
+	} else {
+		phone = service_obsolete_connect(SERVICE_DEVMAN,
+		    DEVMAN_CONNECT_TO_DEVICE, handle);
+	}
+	
+	return phone;
+}
+
+int devman_obsolete_parent_device_connect(devman_handle_t handle, unsigned int flags)
+{
+	int phone;
+	
+	if (flags & IPC_FLAG_BLOCKING) {
+		phone = service_obsolete_connect_blocking(SERVICE_DEVMAN,
+		    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
+	} else {
+		phone = service_obsolete_connect(SERVICE_DEVMAN,
+		    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
+	}
+	
+	return phone;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/devmap.c
===================================================================
--- uspace/lib/c/generic/devmap.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/devmap.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -30,7 +30,8 @@
 #include <str.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <ipc/devmap.h>
 #include <devmap.h>
+#include <fibril_synch.h>
 #include <async.h>
 #include <errno.h>
@@ -38,58 +39,131 @@
 #include <bool.h>
 
-static int devmap_phone_driver = -1;
-static int devmap_phone_client = -1;
-
-/** Get phone to device mapper task. */
-int devmap_get_phone(devmap_interface_t iface, unsigned int flags)
+static FIBRIL_MUTEX_INITIALIZE(devmap_driver_block_mutex);
+static FIBRIL_MUTEX_INITIALIZE(devmap_client_block_mutex);
+
+static FIBRIL_MUTEX_INITIALIZE(devmap_driver_mutex);
+static FIBRIL_MUTEX_INITIALIZE(devmap_client_mutex);
+
+static async_sess_t *devmap_driver_block_sess = NULL;
+static async_sess_t *devmap_client_block_sess = NULL;
+
+static async_sess_t *devmap_driver_sess = NULL;
+static async_sess_t *devmap_client_sess = NULL;
+
+static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
+    async_sess_t **dst)
+{
+	fibril_mutex_lock(mtx);
+	
+	if ((*dst == NULL) && (src != NULL))
+		*dst = src;
+	
+	fibril_mutex_unlock(mtx);
+}
+
+/** Start an async exchange on the devmap session (blocking).
+ *
+ * @param iface Device mapper interface to choose
+ *
+ * @return New exchange.
+ *
+ */
+async_exch_t *devmap_exchange_begin_blocking(devmap_interface_t iface)
 {
 	switch (iface) {
 	case DEVMAP_DRIVER:
-		if (devmap_phone_driver >= 0)
-			return devmap_phone_driver;
-		
-		if (flags & IPC_FLAG_BLOCKING)
-			devmap_phone_driver = service_connect_blocking(SERVICE_DEVMAP,
-			    DEVMAP_DRIVER, 0);
-		else
-			devmap_phone_driver = service_connect(SERVICE_DEVMAP,
-			    DEVMAP_DRIVER, 0);
-		
-		return devmap_phone_driver;
+		fibril_mutex_lock(&devmap_driver_block_mutex);
+		
+		while (devmap_driver_block_sess == NULL) {
+			clone_session(&devmap_driver_mutex, devmap_driver_sess,
+			    &devmap_driver_block_sess);
+			
+			if (devmap_driver_block_sess == NULL)
+				devmap_driver_block_sess =
+				    service_connect_blocking(EXCHANGE_SERIALIZE,
+				    SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
+		}
+		
+		fibril_mutex_unlock(&devmap_driver_block_mutex);
+		
+		clone_session(&devmap_driver_mutex, devmap_driver_block_sess,
+		    &devmap_driver_sess);
+		
+		return async_exchange_begin(devmap_driver_block_sess);
 	case DEVMAP_CLIENT:
-		if (devmap_phone_client >= 0)
-			return devmap_phone_client;
-		
-		if (flags & IPC_FLAG_BLOCKING)
-			devmap_phone_client = service_connect_blocking(SERVICE_DEVMAP,
-			    DEVMAP_CLIENT, 0);
-		else
-			devmap_phone_client = service_connect(SERVICE_DEVMAP,
-			    DEVMAP_CLIENT, 0);
-		
-		return devmap_phone_client;
+		fibril_mutex_lock(&devmap_client_block_mutex);
+		
+		while (devmap_client_block_sess == NULL) {
+			clone_session(&devmap_client_mutex, devmap_client_sess,
+			    &devmap_client_block_sess);
+			
+			if (devmap_client_block_sess == NULL)
+				devmap_client_block_sess =
+				    service_connect_blocking(EXCHANGE_SERIALIZE,
+				    SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
+		}
+		
+		fibril_mutex_unlock(&devmap_client_block_mutex);
+		
+		clone_session(&devmap_client_mutex, devmap_client_block_sess,
+		    &devmap_client_sess);
+		
+		return async_exchange_begin(devmap_client_block_sess);
 	default:
-		return -1;
-	}
-}
-
-void devmap_hangup_phone(devmap_interface_t iface)
+		return NULL;
+	}
+}
+
+/** Start an async exchange on the devmap session.
+ *
+ * @param iface Device mapper interface to choose
+ *
+ * @return New exchange.
+ *
+ */
+async_exch_t *devmap_exchange_begin(devmap_interface_t iface)
 {
 	switch (iface) {
 	case DEVMAP_DRIVER:
-		if (devmap_phone_driver >= 0) {
-			async_hangup(devmap_phone_driver);
-			devmap_phone_driver = -1;
-		}
-		break;
+		fibril_mutex_lock(&devmap_driver_mutex);
+		
+		if (devmap_driver_sess == NULL)
+			devmap_driver_sess =
+			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAP,
+			    DEVMAP_DRIVER, 0);
+		
+		fibril_mutex_unlock(&devmap_driver_mutex);
+		
+		if (devmap_driver_sess == NULL)
+			return NULL;
+		
+		return async_exchange_begin(devmap_driver_sess);
 	case DEVMAP_CLIENT:
-		if (devmap_phone_client >= 0) {
-			async_hangup(devmap_phone_client);
-			devmap_phone_client = -1;
-		}
-		break;
+		fibril_mutex_lock(&devmap_client_mutex);
+		
+		if (devmap_client_sess == NULL)
+			devmap_client_sess =
+			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAP,
+			    DEVMAP_CLIENT, 0);
+		
+		fibril_mutex_unlock(&devmap_client_mutex);
+		
+		if (devmap_client_sess == NULL)
+			return NULL;
+		
+		return async_exchange_begin(devmap_client_sess);
 	default:
-		break;
-	}
+		return NULL;
+	}
+}
+
+/** Finish an async exchange on the devmap session.
+ *
+ * @param exch Exchange to be finished.
+ *
+ */
+void devmap_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
 }
 
@@ -97,28 +171,24 @@
 int devmap_driver_register(const char *name, async_client_conn_t conn)
 {
-	int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
 	
 	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, name, str_size(name));
+	aid_t req = async_send_2(exch, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	
+	devmap_exchange_end(exch);
+	
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
-		async_serialize_end();
-		return -1;
+		return retval;
 	}
 	
 	async_set_client_connection(conn);
 	
-	async_connect_to_me(phone, 0, 0, 0, NULL);
+	exch = devmap_exchange_begin(DEVMAP_DRIVER);
+	async_connect_to_me(exch, 0, 0, 0, NULL);
+	devmap_exchange_end(exch);
+	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
-	
 	return retval;
 }
@@ -129,10 +199,11 @@
  * If not 0, the first argument is the interface and the second argument
  * is the devmap handle of the device.
+ *
  * When the interface is zero (default), the first argument is directly
  * the handle (to ensure backward compatibility).
  *
- * @param fqdn Fully qualified device name.
- * @param[out] handle Handle to the created instance of device.
- * @param interface Interface when forwarding.
+ * @param      fqdn      Fully qualified device name.
+ * @param[out] handle    Handle to the created instance of device.
+ * @param      interface Interface when forwarding.
  *
  */
@@ -140,29 +211,24 @@
     devmap_handle_t *handle, sysarg_t interface)
 {
-	int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
 	
 	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAP_DEVICE_REGISTER, interface, 0,
+	aid_t req = async_send_2(exch, DEVMAP_DEVICE_REGISTER, interface, 0,
 	    &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, fqdn, str_size(fqdn));
+	sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
+	
+	devmap_exchange_end(exch);
+	
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
-		async_serialize_end();
 		return retval;
 	}
 	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
 	
 	if (retval != EOK) {
 		if (handle != NULL)
 			*handle = -1;
+		
 		return retval;
 	}
@@ -176,6 +242,6 @@
 /** Register new device.
  *
- * @param fqdn      Fully qualified device name.
- * @param handle    Output: Handle to the created instance of device.
+ * @param fqdn   Fully qualified device name.
+ * @param handle Output: Handle to the created instance of device.
  *
  */
@@ -185,32 +251,35 @@
 }
 
-
-int devmap_device_get_handle(const char *fqdn, devmap_handle_t *handle, unsigned int flags)
-{
-	int phone = devmap_get_phone(DEVMAP_CLIENT, flags);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
+int devmap_device_get_handle(const char *fqdn, devmap_handle_t *handle,
+    unsigned int flags)
+{
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+	else {
+		exch = devmap_exchange_begin(DEVMAP_CLIENT);
+		if (exch == NULL)
+			return errno;
+	}
 	
 	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
+	aid_t req = async_send_2(exch, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
 	    &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, fqdn, str_size(fqdn));
+	sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
+	
+	devmap_exchange_end(exch);
+	
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
-		async_serialize_end();
 		return retval;
 	}
 	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
 	
 	if (retval != EOK) {
 		if (handle != NULL)
 			*handle = (devmap_handle_t) -1;
+		
 		return retval;
 	}
@@ -222,31 +291,35 @@
 }
 
-int devmap_namespace_get_handle(const char *name, devmap_handle_t *handle, unsigned int flags)
-{
-	int phone = devmap_get_phone(DEVMAP_CLIENT, flags);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
+int devmap_namespace_get_handle(const char *name, devmap_handle_t *handle,
+    unsigned int flags)
+{
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+	else {
+		exch = devmap_exchange_begin(DEVMAP_CLIENT);
+		if (exch == NULL)
+			return errno;
+	}
 	
 	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAP_NAMESPACE_GET_HANDLE, flags, 0,
+	aid_t req = async_send_2(exch, DEVMAP_NAMESPACE_GET_HANDLE, flags, 0,
 	    &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, name, str_size(name));
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	
+	devmap_exchange_end(exch);
+	
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
-		async_serialize_end();
 		return retval;
 	}
 	
 	async_wait_for(req, &retval);
-	
-	async_serialize_end();
 	
 	if (retval != EOK) {
 		if (handle != NULL)
 			*handle = (devmap_handle_t) -1;
+		
 		return retval;
 	}
@@ -260,11 +333,11 @@
 devmap_handle_type_t devmap_handle_probe(devmap_handle_t handle)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return phone;
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
 	
 	sysarg_t type;
-	int retval = async_req_1_1(phone, DEVMAP_HANDLE_PROBE, handle, &type);
+	int retval = async_req_1_1(exch, DEVMAP_HANDLE_PROBE, handle, &type);
+	
+	devmap_exchange_end(exch);
+	
 	if (retval != EOK)
 		return DEV_HANDLE_NONE;
@@ -273,28 +346,28 @@
 }
 
-int devmap_device_connect(devmap_handle_t handle, unsigned int flags)
-{
-	int phone;
-	
-	if (flags & IPC_FLAG_BLOCKING) {
-		phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP,
+async_sess_t *devmap_device_connect(exch_mgmt_t mgmt, devmap_handle_t handle,
+    unsigned int flags)
+{
+	async_sess_t *sess;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		sess = service_connect_blocking(mgmt, SERVICE_DEVMAP,
 		    DEVMAP_CONNECT_TO_DEVICE, handle);
-	} else {
-		phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
+	else
+		sess = service_connect(mgmt, SERVICE_DEVMAP,
 		    DEVMAP_CONNECT_TO_DEVICE, handle);
-	}
-	
-	return phone;
+	
+	return sess;
 }
 
 int devmap_null_create(void)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return -1;
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
 	
 	sysarg_t null_id;
-	int retval = async_req_0_1(phone, DEVMAP_NULL_CREATE, &null_id);
+	int retval = async_req_0_1(exch, DEVMAP_NULL_CREATE, &null_id);
+	
+	devmap_exchange_end(exch);
+	
 	if (retval != EOK)
 		return -1;
@@ -305,16 +378,13 @@
 void devmap_null_destroy(int null_id)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return;
-	
-	async_req_1_0(phone, DEVMAP_NULL_DESTROY, (sysarg_t) null_id);
-}
-
-static size_t devmap_count_namespaces_internal(int phone)
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+	async_req_1_0(exch, DEVMAP_NULL_DESTROY, (sysarg_t) null_id);
+	devmap_exchange_end(exch);
+}
+
+static size_t devmap_count_namespaces_internal(async_exch_t *exch)
 {
 	sysarg_t count;
-	int retval = async_req_0_1(phone, DEVMAP_GET_NAMESPACE_COUNT, &count);
+	int retval = async_req_0_1(exch, DEVMAP_GET_NAMESPACE_COUNT, &count);
 	if (retval != EOK)
 		return 0;
@@ -323,8 +393,10 @@
 }
 
-static size_t devmap_count_devices_internal(int phone, devmap_handle_t ns_handle)
+static size_t devmap_count_devices_internal(async_exch_t *exch,
+    devmap_handle_t ns_handle)
 {
 	sysarg_t count;
-	int retval = async_req_1_1(phone, DEVMAP_GET_DEVICE_COUNT, ns_handle, &count);
+	int retval = async_req_1_1(exch, DEVMAP_GET_DEVICE_COUNT, ns_handle,
+	    &count);
 	if (retval != EOK)
 		return 0;
@@ -335,32 +407,28 @@
 size_t devmap_count_namespaces(void)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return 0;
-	
-	return devmap_count_namespaces_internal(phone);
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+	size_t size = devmap_count_namespaces_internal(exch);
+	devmap_exchange_end(exch);
+	
+	return size;
 }
 
 size_t devmap_count_devices(devmap_handle_t ns_handle)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return 0;
-	
-	return devmap_count_devices_internal(phone, ns_handle);
+	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+	size_t size = devmap_count_devices_internal(exch, ns_handle);
+	devmap_exchange_end(exch);
+	
+	return size;
 }
 
 size_t devmap_get_namespaces(dev_desc_t **data)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return 0;
-	
 	/* Loop until namespaces read succesful */
 	while (true) {
-		size_t count = devmap_count_namespaces_internal(phone);
+		async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+		size_t count = devmap_count_namespaces_internal(exch);
+		devmap_exchange_end(exch);
+		
 		if (count == 0)
 			return 0;
@@ -370,10 +438,12 @@
 			return 0;
 		
-		async_serialize_start();
+		exch = devmap_exchange_begin(DEVMAP_CLIENT);
 		
 		ipc_call_t answer;
-		aid_t req = async_send_0(phone, DEVMAP_GET_NAMESPACES, &answer);
-		
-		int rc = async_data_read_start(phone, devs, count * sizeof(dev_desc_t));
+		aid_t req = async_send_0(exch, DEVMAP_GET_NAMESPACES, &answer);
+		int rc = async_data_read_start(exch, devs, count * sizeof(dev_desc_t));
+		
+		devmap_exchange_end(exch);
+		
 		if (rc == EOVERFLOW) {
 			/*
@@ -381,5 +451,4 @@
 			 * the last call of DEVMAP_DEVICE_GET_NAMESPACE_COUNT
 			 */
-			async_serialize_end();
 			free(devs);
 			continue;
@@ -388,5 +457,4 @@
 		if (rc != EOK) {
 			async_wait_for(req, NULL);
-			async_serialize_end();
 			free(devs);
 			return 0;
@@ -395,5 +463,4 @@
 		sysarg_t retval;
 		async_wait_for(req, &retval);
-		async_serialize_end();
 		
 		if (retval != EOK)
@@ -407,12 +474,10 @@
 size_t devmap_get_devices(devmap_handle_t ns_handle, dev_desc_t **data)
 {
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return 0;
-	
-	/* Loop until namespaces read succesful */
+	/* Loop until devices read succesful */
 	while (true) {
-		size_t count = devmap_count_devices_internal(phone, ns_handle);
+		async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
+		size_t count = devmap_count_devices_internal(exch, ns_handle);
+		devmap_exchange_end(exch);
+		
 		if (count == 0)
 			return 0;
@@ -422,10 +487,12 @@
 			return 0;
 		
-		async_serialize_start();
+		exch = devmap_exchange_begin(DEVMAP_CLIENT);
 		
 		ipc_call_t answer;
-		aid_t req = async_send_1(phone, DEVMAP_GET_DEVICES, ns_handle, &answer);
-		
-		int rc = async_data_read_start(phone, devs, count * sizeof(dev_desc_t));
+		aid_t req = async_send_1(exch, DEVMAP_GET_DEVICES, ns_handle, &answer);
+		int rc = async_data_read_start(exch, devs, count * sizeof(dev_desc_t));
+		
+		devmap_exchange_end(exch);
+		
 		if (rc == EOVERFLOW) {
 			/*
@@ -433,5 +500,4 @@
 			 * the last call of DEVMAP_DEVICE_GET_DEVICE_COUNT
 			 */
-			async_serialize_end();
 			free(devs);
 			continue;
@@ -440,5 +506,4 @@
 		if (rc != EOK) {
 			async_wait_for(req, NULL);
-			async_serialize_end();
 			free(devs);
 			return 0;
@@ -447,5 +512,4 @@
 		sysarg_t retval;
 		async_wait_for(req, &retval);
-		async_serialize_end();
 		
 		if (retval != EOK)
Index: uspace/lib/c/generic/devmap_obsolete.c
===================================================================
--- uspace/lib/c/generic/devmap_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/devmap_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2007 Josef Cejka
+ * Copyright (c) 2009 Jiri Svoboda
+ * 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.
+ */
+
+#include <str.h>
+#include <ipc/services.h>
+#include <ns.h>
+#include <ns_obsolete.h>
+#include <ipc/devmap.h>
+#include <devmap_obsolete.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <errno.h>
+#include <malloc.h>
+#include <bool.h>
+
+static int devmap_phone_driver = -1;
+static int devmap_phone_client = -1;
+
+/** Get phone to device mapper task. */
+int devmap_obsolete_get_phone(devmap_interface_t iface, unsigned int flags)
+{
+	switch (iface) {
+	case DEVMAP_DRIVER:
+		if (devmap_phone_driver >= 0)
+			return devmap_phone_driver;
+		
+		if (flags & IPC_FLAG_BLOCKING)
+			devmap_phone_driver = service_obsolete_connect_blocking(SERVICE_DEVMAP,
+			    DEVMAP_DRIVER, 0);
+		else
+			devmap_phone_driver = service_obsolete_connect(SERVICE_DEVMAP,
+			    DEVMAP_DRIVER, 0);
+		
+		return devmap_phone_driver;
+	case DEVMAP_CLIENT:
+		if (devmap_phone_client >= 0)
+			return devmap_phone_client;
+		
+		if (flags & IPC_FLAG_BLOCKING)
+			devmap_phone_client = service_obsolete_connect_blocking(SERVICE_DEVMAP,
+			    DEVMAP_CLIENT, 0);
+		else
+			devmap_phone_client = service_obsolete_connect(SERVICE_DEVMAP,
+			    DEVMAP_CLIENT, 0);
+		
+		return devmap_phone_client;
+	default:
+		return -1;
+	}
+}
+
+void devmap_obsolete_hangup_phone(devmap_interface_t iface)
+{
+	switch (iface) {
+	case DEVMAP_DRIVER:
+		if (devmap_phone_driver >= 0) {
+			async_obsolete_hangup(devmap_phone_driver);
+			devmap_phone_driver = -1;
+		}
+		break;
+	case DEVMAP_CLIENT:
+		if (devmap_phone_client >= 0) {
+			async_obsolete_hangup(devmap_phone_client);
+			devmap_phone_client = -1;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+int devmap_obsolete_device_connect(devmap_handle_t handle, unsigned int flags)
+{
+	int phone;
+	
+	if (flags & IPC_FLAG_BLOCKING) {
+		phone = service_obsolete_connect_blocking(SERVICE_DEVMAP,
+		    DEVMAP_CONNECT_TO_DEVICE, handle);
+	} else {
+		phone = service_obsolete_connect(SERVICE_DEVMAP,
+		    DEVMAP_CONNECT_TO_DEVICE, handle);
+	}
+	
+	return phone;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/io/console.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,73 +37,204 @@
 #include <libc.h>
 #include <async.h>
+#include <errno.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <vfs/vfs_sess.h>
 #include <io/console.h>
 #include <ipc/console.h>
 
-void console_clear(int phone)
-{
-	async_msg_0(phone, CONSOLE_CLEAR);
-}
-
-int console_get_size(int phone, sysarg_t *cols, sysarg_t *rows)
-{
-	return async_req_0_2(phone, CONSOLE_GET_SIZE, cols, rows);
-}
-
-void console_set_style(int phone, uint8_t style)
-{
-	async_msg_1(phone, CONSOLE_SET_STYLE, style);
-}
-
-void console_set_color(int phone, uint8_t fg_color, uint8_t bg_color,
+console_ctrl_t *console_init(FILE *ifile, FILE *ofile)
+{
+	console_ctrl_t *ctrl = malloc(sizeof(console_ctrl_t));
+	if (!ctrl)
+		return NULL;
+	
+	ctrl->input_sess = fsession(EXCHANGE_SERIALIZE, ifile);
+	if (!ctrl->input_sess) {
+		free(ctrl);
+		return NULL;
+	}
+	
+	ctrl->output_sess = fsession(EXCHANGE_SERIALIZE, ofile);
+	if (!ctrl->output_sess) {
+		free(ctrl);
+		return NULL;
+	}
+	
+	ctrl->input = ifile;
+	ctrl->output = ofile;
+	ctrl->input_aid = 0;
+	
+	return ctrl;
+}
+
+void console_done(console_ctrl_t *ctrl)
+{
+	free(ctrl);
+}
+
+bool console_kcon(void)
+{
+#if 0
+	return __SYSCALL0(SYS_DEBUG_ACTIVATE_CONSOLE);
+#endif
+	
+	return false;
+}
+
+void console_flush(console_ctrl_t *ctrl)
+{
+	fflush(ctrl->output);
+}
+
+void console_clear(console_ctrl_t *ctrl)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	async_msg_0(exch, CONSOLE_CLEAR);
+	async_exchange_end(exch);
+}
+
+int console_get_size(console_ctrl_t *ctrl, sysarg_t *cols, sysarg_t *rows)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	int rc = async_req_0_2(exch, CONSOLE_GET_SIZE, cols, rows);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+void console_set_style(console_ctrl_t *ctrl, uint8_t style)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	async_msg_1(exch, CONSOLE_SET_STYLE, style);
+	async_exchange_end(exch);
+}
+
+void console_set_color(console_ctrl_t *ctrl, uint8_t fg_color, uint8_t bg_color,
     uint8_t flags)
 {
-	async_msg_3(phone, CONSOLE_SET_COLOR, fg_color, bg_color, flags);
-}
-
-void console_set_rgb_color(int phone, uint32_t fg_color, uint32_t bg_color)
-{
-	async_msg_2(phone, CONSOLE_SET_RGB_COLOR, fg_color, bg_color);
-}
-
-void console_cursor_visibility(int phone, bool show)
-{
-	async_msg_1(phone, CONSOLE_CURSOR_VISIBILITY, (show != false));
-}
-
-int console_get_color_cap(int phone, sysarg_t *ccap)
-{
-	return async_req_0_1(phone, CONSOLE_GET_COLOR_CAP, ccap);
-}
-
-void console_kcon_enable(int phone)
-{
-	async_msg_0(phone, CONSOLE_KCON_ENABLE);
-}
-
-int console_get_pos(int phone, sysarg_t *col, sysarg_t *row)
-{
-	return async_req_0_2(phone, CONSOLE_GET_POS, col, row);
-}
-
-void console_set_pos(int phone, sysarg_t col, sysarg_t row)
-{
-	async_msg_2(phone, CONSOLE_GOTO, col, row);
-}
-
-bool console_get_event(int phone, console_event_t *event)
-{
-	sysarg_t type;
-	sysarg_t key;
-	sysarg_t mods;
-	sysarg_t c;
-	
-	int rc = async_req_0_4(phone, CONSOLE_GET_EVENT, &type, &key, &mods, &c);
-	if (rc < 0)
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	async_msg_3(exch, CONSOLE_SET_COLOR, fg_color, bg_color, flags);
+	async_exchange_end(exch);
+}
+
+void console_set_rgb_color(console_ctrl_t *ctrl, uint32_t fg_color,
+    uint32_t bg_color)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	async_msg_2(exch, CONSOLE_SET_RGB_COLOR, fg_color, bg_color);
+	async_exchange_end(exch);
+}
+
+void console_cursor_visibility(console_ctrl_t *ctrl, bool show)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	async_msg_1(exch, CONSOLE_CURSOR_VISIBILITY, (show != false));
+	async_exchange_end(exch);
+}
+
+int console_get_color_cap(console_ctrl_t *ctrl, sysarg_t *ccap)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	int rc = async_req_0_1(exch, CONSOLE_GET_COLOR_CAP, ccap);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+int console_get_pos(console_ctrl_t *ctrl, sysarg_t *col, sysarg_t *row)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	int rc = async_req_0_2(exch, CONSOLE_GET_POS, col, row);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+void console_set_pos(console_ctrl_t *ctrl, sysarg_t col, sysarg_t row)
+{
+	async_exch_t *exch = async_exchange_begin(ctrl->output_sess);
+	async_msg_2(exch, CONSOLE_GOTO, col, row);
+	async_exchange_end(exch);
+}
+
+bool console_get_kbd_event(console_ctrl_t *ctrl, kbd_event_t *event)
+{
+	if (ctrl->input_aid == 0) {
+		sysarg_t type;
+		sysarg_t key;
+		sysarg_t mods;
+		sysarg_t c;
+		
+		async_exch_t *exch = async_exchange_begin(ctrl->input_sess);
+		int rc = async_req_0_4(exch, CONSOLE_GET_EVENT, &type, &key, &mods, &c);
+		async_exchange_end(exch);
+		
+		if (rc != EOK) {
+			errno = rc;
+			return false;
+		}
+		
+		event->type = type;
+		event->key = key;
+		event->mods = mods;
+		event->c = c;
+	} else {
+		sysarg_t retval;
+		async_wait_for(ctrl->input_aid, &retval);
+		
+		ctrl->input_aid = 0;
+		
+		if (retval != EOK) {
+			errno = (int) retval;
+			return false;
+		}
+		
+		event->type = IPC_GET_ARG1(ctrl->input_call);
+		event->key = IPC_GET_ARG2(ctrl->input_call);
+		event->mods = IPC_GET_ARG3(ctrl->input_call);
+		event->c = IPC_GET_ARG4(ctrl->input_call);
+	}
+	
+	return true;
+}
+
+bool console_get_kbd_event_timeout(console_ctrl_t *ctrl, kbd_event_t *event,
+    suseconds_t *timeout)
+{
+	struct timeval t0;
+	gettimeofday(&t0, NULL);
+	
+	if (ctrl->input_aid == 0) {
+		async_exch_t *exch = async_exchange_begin(ctrl->input_sess);
+		ctrl->input_aid = async_send_0(exch, CONSOLE_GET_EVENT,
+		    &ctrl->input_call);
+		async_exchange_end(exch);
+	}
+	
+	sysarg_t retval;
+	int rc = async_wait_timeout(ctrl->input_aid, &retval, *timeout);
+	if (rc != EOK) {
+		*timeout = 0;
+		errno = rc;
 		return false;
-	
-	event->type = type;
-	event->key = key;
-	event->mods = mods;
-	event->c = c;
+	}
+	
+	ctrl->input_aid = 0;
+	
+	if (retval != EOK) {
+		errno = (int) retval;
+		return false;
+	}
+	
+	event->type = IPC_GET_ARG1(ctrl->input_call);
+	event->key = IPC_GET_ARG2(ctrl->input_call);
+	event->mods = IPC_GET_ARG3(ctrl->input_call);
+	event->c = IPC_GET_ARG4(ctrl->input_call);
+	
+	/* Update timeout */
+	struct timeval t1;
+	gettimeofday(&t1, NULL);
+	*timeout -= tv_sub(&t1, &t0);
 	
 	return true;
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/io/io.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,7 +44,9 @@
 #include <io/klog.h>
 #include <vfs/vfs.h>
+#include <vfs/vfs_sess.h>
 #include <ipc/devmap.h>
 #include <adt/list.h>
 #include "../private/io.h"
+#include "../private/stdio.h"
 
 static void _ffillbuf(FILE *stream);
@@ -56,5 +58,5 @@
 	.eof = true,
 	.klog = false,
-	.phone = -1,
+	.sess = NULL,
 	.btype = _IONBF,
 	.buf = NULL,
@@ -70,5 +72,5 @@
 	.eof = false,
 	.klog = true,
-	.phone = -1,
+	.sess = NULL,
 	.btype = _IOLBF,
 	.buf = NULL,
@@ -84,5 +86,5 @@
 	.eof = false,
 	.klog = true,
-	.phone = -1,
+	.sess = NULL,
 	.btype = _IONBF,
 	.buf = NULL,
@@ -255,5 +257,5 @@
 	stream->eof = false;
 	stream->klog = false;
-	stream->phone = -1;
+	stream->sess = NULL;
 	stream->need_sync = false;
 	_setvbuf(stream);
@@ -277,5 +279,5 @@
 	stream->eof = false;
 	stream->klog = false;
-	stream->phone = -1;
+	stream->sess = NULL;
 	stream->need_sync = false;
 	_setvbuf(stream);
@@ -309,5 +311,5 @@
 	stream->eof = false;
 	stream->klog = false;
-	stream->phone = -1;
+	stream->sess = NULL;
 	stream->need_sync = false;
 	_setvbuf(stream);
@@ -324,6 +326,6 @@
 	fflush(stream);
 	
-	if (stream->phone >= 0)
-		async_hangup(stream->phone);
+	if (stream->sess != NULL)
+		async_hangup(stream->sess);
 	
 	if (stream->fd >= 0)
@@ -732,5 +734,5 @@
 	}
 	
-	if (stream->fd >= 0 && stream->need_sync) {
+	if ((stream->fd >= 0) && (stream->need_sync)) {
 		/**
 		 * Better than syncing always, but probably still not the
@@ -770,14 +772,14 @@
 }
 
-int fphone(FILE *stream)
+async_sess_t *fsession(exch_mgmt_t mgmt, FILE *stream)
 {
 	if (stream->fd >= 0) {
-		if (stream->phone < 0)
-			stream->phone = fd_phone(stream->fd);
-		
-		return stream->phone;
-	}
-	
-	return -1;
+		if (stream->sess == NULL)
+			stream->sess = fd_session(mgmt, stream->fd);
+		
+		return stream->sess;
+	}
+	
+	return NULL;
 }
 
Index: uspace/lib/c/generic/ipc.c
===================================================================
--- uspace/lib/c/generic/ipc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/ipc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -632,4 +632,22 @@
 }
 
+/** Request cloned connection.
+ *
+ * @param phoneid Phone handle used for contacting the other side.
+ *
+ * @return Cloned phone handle on success or a negative error code.
+ *
+ */
+int ipc_connect_me(int phoneid)
+{
+	sysarg_t newphid;
+	int res = ipc_call_sync_0_5(phoneid, IPC_M_CONNECT_ME, NULL, NULL,
+	    NULL, NULL, &newphid);
+	if (res)
+		return res;
+	
+	return newphid;
+}
+
 /** Request new connection.
  *
Index: pace/lib/c/generic/ipc/ns.c
===================================================================
--- uspace/lib/c/generic/ipc/ns.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Decky
- * 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 libc
- * @{
- */
-/** @file
- */
-
-#include <async.h>
-#include <ipc/ns.h>
-
-int service_register(sysarg_t service)
-{
-	return async_connect_to_me(PHONE_NS, service, 0, 0, NULL);
-}
-
-int service_connect(sysarg_t service, sysarg_t arg2, sysarg_t arg3)
-{
-	return async_connect_me_to(PHONE_NS, service, arg2, arg3);
-}
-
-int service_connect_blocking(sysarg_t service, sysarg_t arg2, sysarg_t arg3)
-{
-	return async_connect_me_to_blocking(PHONE_NS, service, arg2, arg3);
-}
-
-/** @}
- */
Index: uspace/lib/c/generic/l18n/langs.c
===================================================================
--- uspace/lib/c/generic/l18n/langs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/l18n/langs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,76 @@
+/*
+ * 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 libc
+ * @{
+ */
+/** @file
+ * Language and locale ids.
+ */
+
+#include <l18n/langs.h>
+#include <stdio.h>
+#include <fibril.h>
+
+#define UNKNOWN_LOCALE_LEN 64
+
+static fibril_local char unknown_locale[UNKNOWN_LOCALE_LEN];
+
+/** Get string representation of a given locale.
+ *
+ * @param locale The locale.
+ * @return Name of the locale.
+ */
+const char *str_l18_win_locale(l18_win_locales_t locale)
+{
+	/*
+	 * Static array with names might be better but it would be
+	 * way too big.
+	 */
+	switch (locale) {
+		case L18N_WIN_LOCALE_AFRIKAANS:
+			return "Afrikaans";
+		case L18N_WIN_LOCALE_CZECH:
+			return "Czech";
+		case L18N_WIN_LOCALE_ENGLISH_UNITED_STATES:
+			return "English (US)";
+		case L18N_WIN_LOCALE_SLOVAK:
+			return "Slovak";
+		case L18N_WIN_LOCALE_SPANISH_TRADITIONAL:
+			return "Spanish (traditional)";
+		case L18N_WIN_LOCALE_ZULU:
+			return "Zulu";
+	}
+
+	snprintf(unknown_locale, UNKNOWN_LOCALE_LEN, "Unknown locale 0x%04d",
+	    (int) locale);
+	return unknown_locale;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/libc.c
===================================================================
--- uspace/lib/c/generic/libc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/libc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -49,5 +49,4 @@
 #include "private/libc.h"
 #include "private/async.h"
-#include "private/async_sess.h"
 #include "private/malloc.h"
 #include "private/io.h"
@@ -64,5 +63,4 @@
 	__malloc_init();
 	__async_init();
-	__async_sess_init();
 	
 	fibril_t *fibril = fibril_setup();
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/loader.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,5 +35,5 @@
 #include <ipc/loader.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <libc.h>
 #include <task.h>
@@ -44,4 +44,5 @@
 #include <vfs/vfs.h>
 #include <loader/loader.h>
+#include "private/loader.h"
 
 /** Connect to a new program loader.
@@ -63,13 +64,16 @@
 loader_t *loader_connect(void)
 {
-	int phone_id = service_connect_blocking(SERVICE_LOAD, 0, 0);
-	if (phone_id < 0)
-		return NULL;
-	
 	loader_t *ldr = malloc(sizeof(loader_t));
 	if (ldr == NULL)
 		return NULL;
 	
-	ldr->phone_id = phone_id;
+	async_sess_t *sess =
+	    service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOAD, 0, 0);
+	if (sess == NULL) {
+		free(ldr);
+		return NULL;
+	}
+	
+	ldr->sess = sess;
 	return ldr;
 }
@@ -88,15 +92,19 @@
 {
 	/* Get task ID. */
-	ipc_call_t answer;
-	aid_t req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer);
-	int rc = async_data_read_start(ldr->phone_id, task_id, sizeof(task_id_t));
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		return rc;
-	}
-	
-	sysarg_t retval;
-	async_wait_for(req, &retval);
-	return (int) retval;
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, LOADER_GET_TASKID, &answer);
+	sysarg_t rc = async_data_read_start(exch, task_id, sizeof(task_id_t));
+	
+	async_exchange_end(exch);
+	
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return (int) rc;
+	}
+	
+	async_wait_for(req, &rc);
+	return (int) rc;
 }
 
@@ -112,26 +120,29 @@
 int loader_set_cwd(loader_t *ldr)
 {
-	char *cwd;
-	size_t len;
-
-	cwd = (char *) malloc(MAX_PATH_LEN + 1);
+	char *cwd = (char *) malloc(MAX_PATH_LEN + 1);
 	if (!cwd)
 		return ENOMEM;
+	
 	if (!getcwd(cwd, MAX_PATH_LEN + 1))
-		str_cpy(cwd, MAX_PATH_LEN + 1, "/"); 
-	len = str_length(cwd);
-	
-	ipc_call_t answer;
-	aid_t req = async_send_0(ldr->phone_id, LOADER_SET_CWD, &answer);
-	int rc = async_data_write_start(ldr->phone_id, cwd, len);
+		str_cpy(cwd, MAX_PATH_LEN + 1, "/");
+	
+	size_t len = str_length(cwd);
+	
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, LOADER_SET_CWD, &answer);
+	sysarg_t rc = async_data_write_start(exch, cwd, len);
+	
+	async_exchange_end(exch);
 	free(cwd);
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		return rc;
-	}
-	
-	sysarg_t retval;
-	async_wait_for(req, &retval);
-	return (int) retval;
+	
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return (int) rc;
+	}
+	
+	async_wait_for(req, &rc);
+	return (int) rc;
 }
 
@@ -153,21 +164,23 @@
 	char *pa = absolutize(path, &pa_len);
 	if (!pa)
-		return 0;
+		return ENOMEM;
 	
 	/* Send program pathname */
-	ipc_call_t answer;
-	aid_t req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer);
-	int rc = async_data_write_start(ldr->phone_id, (void *) pa, pa_len);
-	if (rc != EOK) {
-		free(pa);
-		async_wait_for(req, NULL);
-		return rc;
-	}
-	
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, LOADER_SET_PATHNAME, &answer);
+	sysarg_t rc = async_data_write_start(exch, (void *) pa, pa_len);
+	
+	async_exchange_end(exch);
 	free(pa);
 	
-	sysarg_t retval;
-	async_wait_for(req, &retval);
-	return (int) retval;
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return (int) rc;
+	}
+	
+	async_wait_for(req, &rc);
+	return (int) rc;
 }
 
@@ -212,20 +225,21 @@
 	
 	/* Send serialized arguments to the loader */
-	ipc_call_t answer;
-	aid_t req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer);
-	sysarg_t rc = async_data_write_start(ldr->phone_id, (void *) arg_buf, buffer_size);
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		return rc;
-	}
-	
-	async_wait_for(req, &rc);
-	if (rc != EOK)
-		return rc;
-	
-	/* Free temporary buffer */
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, LOADER_SET_ARGS, &answer);
+	sysarg_t rc = async_data_write_start(exch, (void *) arg_buf,
+	    buffer_size);
+	
+	async_exchange_end(exch);
 	free(arg_buf);
 	
-	return EOK;
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return (int) rc;
+	}
+	
+	async_wait_for(req, &rc);
+	return (int) rc;
 }
 
@@ -266,21 +280,21 @@
 	
 	/* Send serialized files to the loader */
-	ipc_call_t answer;
-	aid_t req = async_send_0(ldr->phone_id, LOADER_SET_FILES, &answer);
-	sysarg_t rc = async_data_write_start(ldr->phone_id, (void *) files_buf,
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, LOADER_SET_FILES, &answer);
+	sysarg_t rc = async_data_write_start(exch, (void *) files_buf,
 	    count * sizeof(fdi_node_t));
-	if (rc != EOK) {
-		async_wait_for(req, NULL);
-		return rc;
-	}
-	
-	async_wait_for(req, &rc);
-	if (rc != EOK)
-		return rc;
-	
-	/* Free temporary buffer */
+	
+	async_exchange_end(exch);
 	free(files_buf);
 	
-	return EOK;
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return (int) rc;
+	}
+	
+	async_wait_for(req, &rc);
+	return (int) rc;
 }
 
@@ -297,5 +311,9 @@
 int loader_load_program(loader_t *ldr)
 {
-	return (int) async_req_0_0(ldr->phone_id, LOADER_LOAD);
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	int rc = async_req_0_0(exch, LOADER_LOAD);
+	async_exchange_end(exch);
+	
+	return rc;
 }
 
@@ -306,6 +324,6 @@
  * the task and its thread is stopped.
  *
- * After using this function, no further operations must be performed
- * on the loader structure. It should be de-allocated using free().
+ * After using this function, no further operations can be performed
+ * on the loader structure and it is deallocated.
  *
  * @param ldr Loader connection structure.
@@ -316,10 +334,14 @@
 int loader_run(loader_t *ldr)
 {
-	int rc = async_req_0_0(ldr->phone_id, LOADER_RUN);
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	int rc = async_req_0_0(exch, LOADER_RUN);
+	async_exchange_end(exch);
+	
 	if (rc != EOK)
 		return rc;
 	
-	async_hangup(ldr->phone_id);
-	ldr->phone_id = 0;
+	async_hangup(ldr->sess);
+	free(ldr);
+	
 	return EOK;
 }
@@ -327,7 +349,7 @@
 /** Cancel the loader session.
  *
- * Tells the loader not to load any program and terminate.
- * After using this function, no further operations must be performed
- * on the loader structure. It should be de-allocated using free().
+ * Tell the loader not to load any program and terminate.
+ * After using this function, no further operations can be performed
+ * on the loader structure and it is deallocated.
  *
  * @param ldr Loader connection structure.
@@ -338,6 +360,6 @@
 void loader_abort(loader_t *ldr)
 {
-	async_hangup(ldr->phone_id);
-	ldr->phone_id = 0;
+	async_hangup(ldr->sess);
+	free(ldr);
 }
 
Index: uspace/lib/c/generic/net/icmp_api.c
===================================================================
--- uspace/lib/c/generic/net/icmp_api.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/net/icmp_api.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,5 @@
 #include <net/ip_codes.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -83,9 +84,9 @@
 		return EINVAL;
 
-	message_id = async_send_5(icmp_phone, NET_ICMP_ECHO, size, timeout, ttl,
+	message_id = async_obsolete_send_5(icmp_phone, NET_ICMP_ECHO, size, timeout, ttl,
 	    tos, (sysarg_t) dont_fragment, NULL);
 
 	/* Send the address */
-	async_data_write_start(icmp_phone, addr, (size_t) addrlen);
+	async_obsolete_data_write_start(icmp_phone, addr, (size_t) addrlen);
 
 	async_wait_for(message_id, &result);
Index: uspace/lib/c/generic/net/modules.c
===================================================================
--- uspace/lib/c/generic/net/modules.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/net/modules.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,4 +40,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <malloc.h>
 #include <errno.h>
@@ -45,7 +46,9 @@
 #include <ipc/services.h>
 #include <net/modules.h>
+#include <ns.h>
+#include <ns_obsolete.h>
 
 /** The time between connect requests in microseconds. */
-#define MODULE_WAIT_TIME	(10 * 1000)
+#define MODULE_WAIT_TIME  (10 * 1000)
 
 /** Answer a call.
@@ -138,7 +141,7 @@
 	if (phone >= 0) {
 		/* Request the bidirectional connection */
-		int rc = async_connect_to_me(phone, arg1, arg2, arg3, client_receiver);
+		int rc = async_obsolete_connect_to_me(phone, arg1, arg2, arg3, client_receiver);
 		if (rc != EOK) {
-			async_hangup(phone);
+			async_obsolete_hangup(phone);
 			return rc;
 		}
@@ -172,8 +175,8 @@
 	/* If no timeout is set */
 	if (timeout <= 0)
-		return async_connect_me_to_blocking(PHONE_NS, need, 0, 0);
-
+		return service_obsolete_connect_blocking(need, 0, 0);
+	
 	while (true) {
-		phone = async_connect_me_to(PHONE_NS, need, 0, 0);
+		phone = service_obsolete_connect(need, 0, 0);
 		if ((phone >= 0) || (phone != ENOENT))
 			return phone;
Index: uspace/lib/c/generic/net/socket_client.c
===================================================================
--- uspace/lib/c/generic/net/socket_client.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/net/socket_client.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,4 +39,5 @@
 #include <assert.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <fibril_synch.h>
 #include <stdint.h>
@@ -472,5 +473,5 @@
 	}
 
-	rc = (int) async_req_3_3(phone, NET_SOCKET, socket_id, 0, service, NULL,
+	rc = (int) async_obsolete_req_3_3(phone, NET_SOCKET, socket_id, 0, service, NULL,
 	    &fragment_size, &header_size);
 	if (rc != EOK) {
@@ -493,5 +494,5 @@
 		dyn_fifo_destroy(&socket->accepted);
 		free(socket);
-		async_msg_3(phone, NET_SOCKET_CLOSE, (sysarg_t) socket_id, 0,
+		async_obsolete_msg_3(phone, NET_SOCKET_CLOSE, (sysarg_t) socket_id, 0,
 		    service);
 		return rc;
@@ -538,8 +539,8 @@
 
 	/* Request the message */
-	message_id = async_send_3(socket->phone, message,
+	message_id = async_obsolete_send_3(socket->phone, message,
 	    (sysarg_t) socket->socket_id, arg2, socket->service, NULL);
 	/* Send the address */
-	async_data_write_start(socket->phone, data, datalength);
+	async_obsolete_data_write_start(socket->phone, data, datalength);
 
 	fibril_rwlock_read_unlock(&socket_globals.lock);
@@ -598,5 +599,5 @@
 
 	/* Request listen backlog change */
-	result = (int) async_req_3_0(socket->phone, NET_SOCKET_LISTEN,
+	result = (int) async_obsolete_req_3_0(socket->phone, NET_SOCKET_LISTEN,
 	    (sysarg_t) socket->socket_id, (sysarg_t) backlog, socket->service);
 
@@ -681,10 +682,10 @@
 
 	/* Request accept */
-	message_id = async_send_5(socket->phone, NET_SOCKET_ACCEPT,
+	message_id = async_obsolete_send_5(socket->phone, NET_SOCKET_ACCEPT,
 	    (sysarg_t) socket->socket_id, 0, socket->service, 0,
 	    new_socket->socket_id, &answer);
 
 	/* Read address */
-	async_data_read_start(socket->phone, cliaddr, *addrlen);
+	async_obsolete_data_read_start(socket->phone, cliaddr, *addrlen);
 	fibril_rwlock_write_unlock(&socket_globals.lock);
 	async_wait_for(message_id, &ipc_result);
@@ -780,5 +781,5 @@
 
 	/* Request close */
-	rc = (int) async_req_3_0(socket->phone, NET_SOCKET_CLOSE,
+	rc = (int) async_obsolete_req_3_0(socket->phone, NET_SOCKET_CLOSE,
 	    (sysarg_t) socket->socket_id, 0, socket->service);
 	if (rc != EOK) {
@@ -853,5 +854,5 @@
 
 	/* Request send */
-	message_id = async_send_5(socket->phone, message,
+	message_id = async_obsolete_send_5(socket->phone, message,
 	    (sysarg_t) socket->socket_id,
 	    (fragments == 1 ? datalength : socket->data_fragment_size),
@@ -860,11 +861,11 @@
 	/* Send the address if given */
 	if (!toaddr ||
-	    (async_data_write_start(socket->phone, toaddr, addrlen) == EOK)) {
+	    (async_obsolete_data_write_start(socket->phone, toaddr, addrlen) == EOK)) {
 		if (fragments == 1) {
 			/* Send all if only one fragment */
-			async_data_write_start(socket->phone, data, datalength);
+			async_obsolete_data_write_start(socket->phone, data, datalength);
 		} else {
 			/* Send the first fragment */
-			async_data_write_start(socket->phone, data,
+			async_obsolete_data_write_start(socket->phone, data,
 			    socket->data_fragment_size - socket->header_size);
 			data = ((const uint8_t *) data) +
@@ -873,5 +874,5 @@
 			/* Send the middle fragments */
 			while (--fragments > 1) {
-				async_data_write_start(socket->phone, data,
+				async_obsolete_data_write_start(socket->phone, data,
 				    socket->data_fragment_size);
 				data = ((const uint8_t *) data) +
@@ -880,5 +881,5 @@
 
 			/* Send the last fragment */
-			async_data_write_start(socket->phone, data,
+			async_obsolete_data_write_start(socket->phone, data,
 			    (datalength + socket->header_size) %
 			    socket->data_fragment_size);
@@ -1038,5 +1039,5 @@
 
 		/* Request packet data */
-		message_id = async_send_4(socket->phone, message,
+		message_id = async_obsolete_send_4(socket->phone, message,
 		    (sysarg_t) socket->socket_id, 0, socket->service,
 		    (sysarg_t) flags, &answer);
@@ -1044,8 +1045,8 @@
 		/* Read the address if desired */
 		if(!fromaddr ||
-		    (async_data_read_start(socket->phone, fromaddr,
+		    (async_obsolete_data_read_start(socket->phone, fromaddr,
 		    *addrlen) == EOK)) {
 			/* Read the fragment lengths */
-			if (async_data_read_start(socket->phone, lengths,
+			if (async_obsolete_data_read_start(socket->phone, lengths,
 			    sizeof(int) * (fragments + 1)) == EOK) {
 				if (lengths[fragments] <= datalength) {
@@ -1054,5 +1055,5 @@
 					for (index = 0; index < fragments;
 					    ++index) {
-						async_data_read_start(
+						async_obsolete_data_read_start(
 						    socket->phone, data,
 						    lengths[index]);
@@ -1067,5 +1068,5 @@
 	} else { /* fragments == 1 */
 		/* Request packet data */
-		message_id = async_send_4(socket->phone, message,
+		message_id = async_obsolete_send_4(socket->phone, message,
 		    (sysarg_t) socket->socket_id, 0, socket->service,
 		    (sysarg_t) flags, &answer);
@@ -1073,8 +1074,8 @@
 		/* Read the address if desired */
 		if (!fromaddr ||
-		    (async_data_read_start(socket->phone, fromaddr,
+		    (async_obsolete_data_read_start(socket->phone, fromaddr,
 		        *addrlen) == EOK)) {
 			/* Read all if only one fragment */
-			async_data_read_start(socket->phone, data, datalength);
+			async_obsolete_data_read_start(socket->phone, data, datalength);
 		}
 	}
@@ -1190,13 +1191,13 @@
 
 	/* Request option value */
-	message_id = async_send_3(socket->phone, NET_SOCKET_GETSOCKOPT,
+	message_id = async_obsolete_send_3(socket->phone, NET_SOCKET_GETSOCKOPT,
 	    (sysarg_t) socket->socket_id, (sysarg_t) optname, socket->service,
 	    NULL);
 
 	/* Read the length */
-	if (async_data_read_start(socket->phone, optlen,
+	if (async_obsolete_data_read_start(socket->phone, optlen,
 	    sizeof(*optlen)) == EOK) {
 		/* Read the value */
-		async_data_read_start(socket->phone, value, *optlen);
+		async_obsolete_data_read_start(socket->phone, value, *optlen);
 	}
 
Index: uspace/lib/c/generic/ns.c
===================================================================
--- uspace/lib/c/generic/ns.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/ns.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <ns.h>
+#include <ipc/ns.h>
+#include <async.h>
+#include <macros.h>
+#include "private/ns.h"
+
+int service_register(sysarg_t service)
+{
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	int rc = async_connect_to_me(exch, service, 0, 0, NULL);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+async_sess_t *service_connect(exch_mgmt_t mgmt, sysarg_t service, sysarg_t arg2,
+    sysarg_t arg3)
+{
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	async_sess_t *sess =
+	    async_connect_me_to(mgmt, exch, service, arg2, arg3);
+	async_exchange_end(exch);
+	
+	return sess;
+}
+
+async_sess_t *service_connect_blocking(exch_mgmt_t mgmt, sysarg_t service,
+    sysarg_t arg2, sysarg_t arg3)
+{
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	async_sess_t *sess =
+	    async_connect_me_to_blocking(mgmt, exch, service, arg2, arg3);
+	async_exchange_end(exch);
+	
+	return sess;
+}
+
+int ns_ping(void)
+{
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	int rc = async_req_0_0(exch, NS_PING);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+int ns_intro(task_id_t id)
+{
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	int rc = async_req_2_0(exch, NS_ID_INTRO, LOWER32(id), UPPER32(id));
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/ns_obsolete.c
===================================================================
--- uspace/lib/c/generic/ns_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/ns_obsolete.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <async_obsolete.h>
+#include <ns_obsolete.h>
+#include <kernel/ipc/ipc_methods.h>
+
+int service_obsolete_connect(sysarg_t service, sysarg_t arg2, sysarg_t arg3)
+{
+	return async_obsolete_connect_me_to(PHONE_NS, service, arg2, arg3);
+}
+
+int service_obsolete_connect_blocking(sysarg_t service, sysarg_t arg2, sysarg_t arg3)
+{
+	return async_obsolete_connect_me_to_blocking(PHONE_NS, service, arg2, arg3);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/private/async.h
===================================================================
--- uspace/lib/c/generic/private/async.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/private/async.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -79,6 +79,20 @@
 } awaiter_t;
 
+/** Message data */
+typedef struct {
+	awaiter_t wdata;
+	
+	/** If reply was received. */
+	bool done;
+	
+	/** Pointer to where the answer data is stored. */
+	ipc_call_t *dataptr;
+	
+	sysarg_t retval;
+} amsg_t;
+
 extern void __async_init(void);
 extern void async_insert_timeout(awaiter_t *);
+extern void reply_received(void *, int, ipc_call_t *);
 
 #endif
Index: pace/lib/c/generic/private/async_sess.h
===================================================================
--- uspace/lib/c/generic/private/async_sess.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,43 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Decky
- * 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 libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_PRIVATE_ASYNC_SESS_H_
-#define LIBC_PRIVATE_ASYNC_SESS_H_
-
-extern void __async_sess_init(void);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/generic/private/loader.h
===================================================================
--- uspace/lib/c/generic/private/loader.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/private/loader.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_PRIVATE_LOADER_H_
+#define LIBC_PRIVATE_LOADER_H_
+
+#include <loader/loader.h>
+
+/** Abstraction of a loader connection */
+struct loader {
+	/** Session to the loader. */
+	async_sess_t *sess;
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/private/ns.h
===================================================================
--- uspace/lib/c/generic/private/ns.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/private/ns.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_PRIVATE_NS_H_
+#define LIBC_PRIVATE_NS_H_
+
+#include <async.h>
+
+extern async_sess_t *session_ns;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/private/stdio.h
===================================================================
--- uspace/lib/c/generic/private/stdio.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/generic/private/stdio.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_PRIVATE_STDIO_H_
+#define LIBC_PRIVATE_STDIO_H_
+
+#include <adt/list.h>
+#include <stdio.h>
+#include <async.h>
+
+struct _IO_FILE {
+	/** Linked list pointer. */
+	link_t link;
+	
+	/** Underlying file descriptor. */
+	int fd;
+	
+	/** Error indicator. */
+	int error;
+	
+	/** End-of-file indicator. */
+	int eof;
+	
+	/** Klog indicator */
+	int klog;
+	
+	/** Session to the file provider */
+	async_sess_t *sess;
+	
+	/**
+	 * Non-zero if the stream needs sync on fflush(). XXX change
+	 * console semantics so that sync is not needed.
+	 */
+	int need_sync;
+	
+	/** Buffering type */
+	enum _buffer_type btype;
+	
+	/** Buffer */
+	uint8_t *buf;
+	
+	/** Buffer size */
+	size_t buf_size;
+	
+	/** Buffer state */
+	enum _buffer_state buf_state;
+	
+	/** Buffer I/O pointer */
+	uint8_t *buf_head;
+	
+	/** Points to end of occupied space when in read mode. */
+	uint8_t *buf_tail;
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/str_error.c
===================================================================
--- uspace/lib/c/generic/str_error.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/str_error.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -33,4 +33,5 @@
  */
 
+#include <errno.h>
 #include <str_error.h>
 #include <stdio.h>
@@ -63,10 +64,25 @@
 static fibril_local char noerr[NOERR_LEN];
 
-const char *str_error(const int errno)
+const char *str_error(const int e)
 {
-	if ((errno <= 0) && (errno >= MIN_ERRNO))
-		return err_desc[-errno];
+	if ((e <= 0) && (e >= MIN_ERRNO))
+		return err_desc[-e];
 	
-	snprintf(noerr, NOERR_LEN, "Unkown error code %d", errno);
+	/* Ad hoc descriptions of error codes interesting for USB. */
+	// FIXME: integrate these as first-class error values
+	switch (e) {
+		case EBADCHECKSUM:
+			return "Bad checksum";
+		case ESTALL:
+			return "Operation stalled";
+		case EAGAIN:
+			return "Resource temporarily unavailable";
+		case EEMPTY:
+			return "Resource is empty";
+		default:
+			break;
+	}
+
+	snprintf(noerr, NOERR_LEN, "Unkown error code %d", e);
 	return noerr;
 }
Index: uspace/lib/c/generic/task.c
===================================================================
--- uspace/lib/c/generic/task.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/task.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,7 +35,4 @@
 
 #include <task.h>
-#include <libc.h>
-#include <stdlib.h>
-#include <errno.h>
 #include <loader/loader.h>
 #include <stdarg.h>
@@ -43,5 +40,10 @@
 #include <ipc/ns.h>
 #include <macros.h>
+#include <assert.h>
 #include <async.h>
+#include <errno.h>
+#include <malloc.h>
+#include <libc.h>
+#include "private/ns.h"
 
 task_id_t task_get_id(void)
@@ -68,4 +70,6 @@
 int task_set_name(const char *name)
 {
+	assert(name);
+	
 	return __SYSCALL2(SYS_TASK_SET_NAME, (sysarg_t) name, str_size(name));
 }
@@ -88,23 +92,21 @@
  * loader API. Arguments are passed as a null-terminated array of strings.
  *
- * @param id 	If not NULL, the ID of the task is stored here on success.
- * @param path	Pathname of the binary to execute.
- * @param argv	Command-line arguments.
- *
- * @return	Zero on success or negative error code.
+ * @param id   If not NULL, the ID of the task is stored here on success.
+ * @param path Pathname of the binary to execute.
+ * @param argv Command-line arguments.
+ *
+ * @return Zero on success or negative error code.
+ *
  */
 int task_spawnv(task_id_t *id, const char *path, const char *const args[])
 {
-	loader_t *ldr;
-	task_id_t task_id;
-	int rc;
-
 	/* Connect to a program loader. */
-	ldr = loader_connect();
+	loader_t *ldr = loader_connect();
 	if (ldr == NULL)
 		return EREFUSED;
 	
 	/* Get task ID. */
-	rc = loader_get_task_id(ldr, &task_id);
+	task_id_t task_id;
+	int rc = loader_get_task_id(ldr, &task_id);
 	if (rc != EOK)
 		goto error;
@@ -163,6 +165,4 @@
 	
 	/* Success */
-	free(ldr);
-	
 	if (id != NULL)
 		*id = task_id;
@@ -173,5 +173,4 @@
 	/* Error exit */
 	loader_abort(ldr);
-	free(ldr);
 	return rc;
 }
@@ -182,19 +181,20 @@
  * loader API. Arguments are passed as a null-terminated list of arguments.
  *
- * @param id 	If not NULL, the ID of the task is stored here on success.
- * @param path	Pathname of the binary to execute.
- * @param ...	Command-line arguments.
- *
- * @return	Zero on success or negative error code.
+ * @param id   If not NULL, the ID of the task is stored here on success.
+ * @param path Pathname of the binary to execute.
+ * @param ...  Command-line arguments.
+ *
+ * @return Zero on success or negative error code.
+ *
  */
 int task_spawnl(task_id_t *task_id, const char *path, ...)
 {
+	/* Count the number of arguments. */
+	
 	va_list ap;
-	int rc, cnt;
 	const char *arg;
 	const char **arglist;
-
-	/* Count the number of arguments. */
-	cnt = 0;
+	int cnt = 0;
+	
 	va_start(ap, path);
 	do {
@@ -203,10 +203,10 @@
 	} while (arg != NULL);
 	va_end(ap);
-
+	
 	/* Allocate argument list. */
 	arglist = malloc(cnt * sizeof(const char *));
 	if (arglist == NULL)
 		return ENOMEM;
-
+	
 	/* Fill in arguments. */
 	cnt = 0;
@@ -217,8 +217,8 @@
 	} while (arg != NULL);
 	va_end(ap);
-
+	
 	/* Spawn task. */
-	rc = task_spawnv(task_id, path, arglist);
-
+	int rc = task_spawnv(task_id, path, arglist);
+	
 	/* Free argument list. */
 	free(arglist);
@@ -228,12 +228,16 @@
 int task_wait(task_id_t id, task_exit_t *texit, int *retval)
 {
+	assert(texit);
+	assert(retval);
+	
+	async_exch_t *exch = async_exchange_begin(session_ns);
 	sysarg_t te, rv;
-	int rc;
-
-	rc = (int) async_req_2_2(PHONE_NS, NS_TASK_WAIT, LOWER32(id),
+	int rc = (int) async_req_2_2(exch, NS_TASK_WAIT, LOWER32(id),
 	    UPPER32(id), &te, &rv);
+	async_exchange_end(exch);
+	
 	*texit = te;
 	*retval = rv;
-
+	
 	return rc;
 }
@@ -241,5 +245,9 @@
 int task_retval(int val)
 {
-	return (int) async_req_1_0(PHONE_NS, NS_RETVAL, val);
+	async_exch_t *exch = async_exchange_begin(session_ns);
+	int rc = (int) async_req_1_0(exch, NS_RETVAL, val);
+	async_exchange_end(exch);
+	
+	return rc;
 }
 
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/time.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -207,4 +207,10 @@
 }
 
+void udelay(useconds_t time)
+{
+	(void) __SYSCALL1(SYS_THREAD_UDELAY, (sysarg_t) time);
+}
+
+
 /** Wait unconditionally for specified number of seconds
  *
Index: uspace/lib/c/generic/udebug.c
===================================================================
--- uspace/lib/c/generic/udebug.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/udebug.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,102 +35,108 @@
 #include <udebug.h>
 #include <sys/types.h>
+#include <kernel/ipc/ipc_methods.h>
 #include <async.h>
 
-int udebug_begin(int phoneid)
+int udebug_begin(async_sess_t *sess)
 {
-	return async_req_1_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_BEGIN);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_1_0(exch, IPC_M_DEBUG, UDEBUG_M_BEGIN);
 }
 
-int udebug_end(int phoneid)
+int udebug_end(async_sess_t *sess)
 {
-	return async_req_1_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_END);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_1_0(exch, IPC_M_DEBUG, UDEBUG_M_END);
 }
 
-int udebug_set_evmask(int phoneid, udebug_evmask_t mask)
+int udebug_set_evmask(async_sess_t *sess, udebug_evmask_t mask)
 {
-	return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_SET_EVMASK,
-		mask);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_2_0(exch, IPC_M_DEBUG, UDEBUG_M_SET_EVMASK, mask);
 }
 
-int udebug_thread_read(int phoneid, void *buffer, size_t n,
-	size_t *copied, size_t *needed)
+int udebug_thread_read(async_sess_t *sess, void *buffer, size_t n,
+    size_t *copied, size_t *needed)
 {
 	sysarg_t a_copied, a_needed;
-	int rc;
-
-	rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ,
-		(sysarg_t)buffer, n, NULL, &a_copied, &a_needed);
-
-	*copied = (size_t)a_copied;
-	*needed = (size_t)a_needed;
-
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_3(exch, IPC_M_DEBUG, UDEBUG_M_THREAD_READ,
+	    (sysarg_t) buffer, n, NULL, &a_copied, &a_needed);
+	
+	*copied = (size_t) a_copied;
+	*needed = (size_t) a_needed;
+	
 	return rc;
 }
 
-int udebug_name_read(int phoneid, void *buffer, size_t n,
-	size_t *copied, size_t *needed)
+int udebug_name_read(async_sess_t *sess, void *buffer, size_t n,
+    size_t *copied, size_t *needed)
 {
 	sysarg_t a_copied, a_needed;
-	int rc;
-
-	rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_NAME_READ,
-		(sysarg_t)buffer, n, NULL, &a_copied, &a_needed);
-
-	*copied = (size_t)a_copied;
-	*needed = (size_t)a_needed;
-
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_3(exch, IPC_M_DEBUG, UDEBUG_M_NAME_READ,
+	    (sysarg_t) buffer, n, NULL, &a_copied, &a_needed);
+	
+	*copied = (size_t) a_copied;
+	*needed = (size_t) a_needed;
+	
 	return rc;
 }
 
-int udebug_areas_read(int phoneid, void *buffer, size_t n,
-	size_t *copied, size_t *needed)
+int udebug_areas_read(async_sess_t *sess, void *buffer, size_t n,
+    size_t *copied, size_t *needed)
 {
 	sysarg_t a_copied, a_needed;
-	int rc;
-
-	rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_AREAS_READ,
-		(sysarg_t)buffer, n, NULL, &a_copied, &a_needed);
-
-	*copied = (size_t)a_copied;
-	*needed = (size_t)a_needed;
-
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_3(exch, IPC_M_DEBUG, UDEBUG_M_AREAS_READ,
+	    (sysarg_t) buffer, n, NULL, &a_copied, &a_needed);
+	
+	*copied = (size_t) a_copied;
+	*needed = (size_t) a_needed;
+	
 	return rc;
 }
 
-int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n)
+int udebug_mem_read(async_sess_t *sess, void *buffer, uintptr_t addr, size_t n)
 {
-	return async_req_4_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_MEM_READ,
-	    (sysarg_t)buffer, addr, n);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_4_0(exch, IPC_M_DEBUG, UDEBUG_M_MEM_READ,
+	    (sysarg_t) buffer, addr, n);
 }
 
-int udebug_args_read(int phoneid, thash_t tid, sysarg_t *buffer)
+int udebug_args_read(async_sess_t *sess, thash_t tid, sysarg_t *buffer)
 {
-	return async_req_3_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_ARGS_READ,
-	    tid, (sysarg_t)buffer);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_3_0(exch, IPC_M_DEBUG, UDEBUG_M_ARGS_READ,
+	    tid, (sysarg_t) buffer);
 }
 
-int udebug_regs_read(int phoneid, thash_t tid, void *buffer)
+int udebug_regs_read(async_sess_t *sess, thash_t tid, void *buffer)
 {
-	return async_req_3_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_REGS_READ,
-	    tid, (sysarg_t)buffer);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_3_0(exch, IPC_M_DEBUG, UDEBUG_M_REGS_READ,
+	    tid, (sysarg_t) buffer);
 }
 
-int udebug_go(int phoneid, thash_t tid, udebug_event_t *ev_type,
+int udebug_go(async_sess_t *sess, thash_t tid, udebug_event_t *ev_type,
     sysarg_t *val0, sysarg_t *val1)
 {
 	sysarg_t a_ev_type;
-	int rc;
-
-	rc =  async_req_2_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_GO,
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_3(exch, IPC_M_DEBUG, UDEBUG_M_GO,
 	    tid, &a_ev_type, val0, val1);
-
+	
 	*ev_type = a_ev_type;
 	return rc;
 }
 
-int udebug_stop(int phoneid, thash_t tid)
+int udebug_stop(async_sess_t *sess, thash_t tid)
 {
-	return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_STOP,
-	    tid);
+	async_exch_t *exch = async_exchange_begin(sess);
+	return async_req_2_0(exch, IPC_M_DEBUG, UDEBUG_M_STOP, tid);
 }
 
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -33,6 +33,7 @@
  */
 
+#include <vfs/canonify.h>
 #include <vfs/vfs.h>
-#include <vfs/canonify.h>
+#include <vfs/vfs_sess.h>
 #include <macros.h>
 #include <stdlib.h>
@@ -44,5 +45,5 @@
 #include <sys/types.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <fibril_synch.h>
@@ -54,8 +55,6 @@
 #include <ipc/devmap.h>
 
-static async_sess_t vfs_session;
-
-static FIBRIL_MUTEX_INITIALIZE(vfs_phone_mutex);
-static int vfs_phone = -1;
+static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
+static async_sess_t *vfs_sess = NULL;
 
 static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
@@ -65,9 +64,36 @@
 static size_t cwd_size = 0;
 
+/** Start an async exchange on the VFS session.
+ *
+ * @return New exchange.
+ *
+ */
+static async_exch_t *vfs_exchange_begin(void)
+{
+	fibril_mutex_lock(&vfs_mutex);
+	
+	while (vfs_sess == NULL)
+		vfs_sess = service_connect_blocking(EXCHANGE_PARALLEL, SERVICE_VFS,
+		    0, 0);
+	
+	fibril_mutex_unlock(&vfs_mutex);
+	
+	return async_exchange_begin(vfs_sess);
+}
+
+/** Finish an async exchange on the VFS session.
+ *
+ * @param exch Exchange to be finished.
+ *
+ */
+static void vfs_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
+}
+
 char *absolutize(const char *path, size_t *retlen)
 {
 	char *ncwd_path;
 	char *ncwd_path_nc;
-	size_t total_size; 
 
 	fibril_mutex_lock(&cwd_mutex);
@@ -78,16 +104,14 @@
 			return NULL;
 		}
-		total_size = cwd_size + 1 + size + 1;
-		ncwd_path_nc = malloc(total_size);
+		ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
 		if (!ncwd_path_nc) {
 			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
 		}
-		str_cpy(ncwd_path_nc, total_size, cwd_path);
+		str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
 		ncwd_path_nc[cwd_size] = '/';
 		ncwd_path_nc[cwd_size + 1] = '\0';
 	} else {
-		total_size = size + 1;
-		ncwd_path_nc = malloc(total_size);
+		ncwd_path_nc = malloc(size + 1);
 		if (!ncwd_path_nc) {
 			fibril_mutex_unlock(&cwd_mutex);
@@ -96,5 +120,5 @@
 		ncwd_path_nc[0] = '\0';
 	}
-	str_append(ncwd_path_nc, total_size, path);
+	str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
 	ncwd_path = canonify(ncwd_path_nc, retlen);
 	if (!ncwd_path) {
@@ -118,36 +142,4 @@
 }
 
-/** Connect to VFS service and create session. */
-static void vfs_connect(void)
-{
-	while (vfs_phone < 0)
-		vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
-	
-	async_session_create(&vfs_session, vfs_phone, 0);
-}
-
-/** Start an async exchange on the VFS session.
- *
- * @return		New phone to be used during the exchange.
- */
-static int vfs_exchange_begin(void)
-{
-	fibril_mutex_lock(&vfs_phone_mutex);
-	if (vfs_phone < 0)
-		vfs_connect();
-	fibril_mutex_unlock(&vfs_phone_mutex);
-
-	return async_exchange_begin(&vfs_session);
-}
-
-/** End an async exchange on the VFS session.
- *
- * @param phone		Phone used during the exchange.
- */
-static void vfs_exchange_end(int phone)
-{
-	async_exchange_end(&vfs_session, phone);
-}
-
 int mount(const char *fs_name, const char *mp, const char *fqdn,
     const char *opts, unsigned int flags)
@@ -186,11 +178,11 @@
 	}
 	
-	int vfs_phone = vfs_exchange_begin();
+	async_exch_t *exch = vfs_exchange_begin();
 
 	sysarg_t rc_orig;
-	aid_t req = async_send_2(vfs_phone, VFS_IN_MOUNT, devmap_handle, flags, NULL);
-	sysarg_t rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	aid_t req = async_send_2(exch, VFS_IN_MOUNT, devmap_handle, flags, NULL);
+	sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(mpa);
 		async_wait_for(req, &rc_orig);
@@ -205,7 +197,7 @@
 	}
 	
-	rc = async_data_write_start(vfs_phone, (void *) opts, str_size(opts));
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	rc = async_data_write_start(exch, (void *) opts, str_size(opts));
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(mpa);
 		async_wait_for(req, &rc_orig);
@@ -220,7 +212,7 @@
 	}
 	
-	rc = async_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	rc = async_data_write_start(exch, (void *) fs_name, str_size(fs_name));
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(mpa);
 		async_wait_for(req, &rc_orig);
@@ -236,7 +228,7 @@
 	
 	/* Ask VFS whether it likes fs_name. */
-	rc = async_req_0_0(vfs_phone, IPC_M_PING);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	rc = async_req_0_0(exch, VFS_IN_PING);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(mpa);
 		async_wait_for(req, &rc_orig);
@@ -251,5 +243,5 @@
 	}
 	
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	free(mpa);
 	async_wait_for(req, &rc);
@@ -273,10 +265,10 @@
 		return ENOMEM;
 	
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_0(vfs_phone, VFS_IN_UNMOUNT, NULL);
-	rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_0(exch, VFS_IN_UNMOUNT, NULL);
+	rc = async_data_write_start(exch, (void *) mpa, mpa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(mpa);
 		async_wait_for(req, &rc_orig);
@@ -288,5 +280,5 @@
 	
 
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	free(mpa);
 	async_wait_for(req, &rc);
@@ -297,12 +289,12 @@
 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
 {
-	int vfs_phone = vfs_exchange_begin();
+	async_exch_t *exch = vfs_exchange_begin();
 	
 	ipc_call_t answer;
-	aid_t req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer);
-	sysarg_t rc = async_data_write_start(vfs_phone, abs, abs_size);
-	
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
+	sysarg_t rc = async_data_write_start(exch, abs, abs_size);
+	
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 
 		sysarg_t rc_orig;
@@ -315,5 +307,5 @@
 	}
 	
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
 	
@@ -339,11 +331,11 @@
 int open_node(fdi_node_t *node, int oflag)
 {
-	int vfs_phone = vfs_exchange_begin();
+	async_exch_t *exch = vfs_exchange_begin();
 	
 	ipc_call_t answer;
-	aid_t req = async_send_4(vfs_phone, VFS_IN_OPEN_NODE, node->fs_handle,
+	aid_t req = async_send_4(exch, VFS_IN_OPEN_NODE, node->fs_handle,
 	    node->devmap_handle, node->index, oflag, &answer);
 	
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 
 	sysarg_t rc;
@@ -360,11 +352,9 @@
 	sysarg_t rc;
 	
-	int vfs_phone = vfs_exchange_begin();
-	
-	rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes);
-	
-	vfs_exchange_end(vfs_phone);
-	
-	return (int)rc;
+	async_exch_t *exch = vfs_exchange_begin();
+	rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes);
+	vfs_exchange_end(exch);
+	
+	return (int) rc;
 }
 
@@ -374,12 +364,11 @@
 	ipc_call_t answer;
 	aid_t req;
-
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer);
-	rc = async_data_read_start_generic(vfs_phone, (void *) buf, nbyte,
-	    IPC_XF_RESTRICT);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
+	rc = async_data_read_start(exch, (void *)buf, nbyte);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 
 		sysarg_t rc_orig;
@@ -391,5 +380,5 @@
 			return (ssize_t) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
 	if (rc == EOK)
@@ -404,12 +393,11 @@
 	ipc_call_t answer;
 	aid_t req;
-
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
-	rc = async_data_write_start_generic(vfs_phone, (void *) buf, nbyte,
-	    IPC_XF_RESTRICT);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
+	rc = async_data_write_start(exch, (void *)buf, nbyte);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 
 		sysarg_t rc_orig;
@@ -421,5 +409,5 @@
 			return (ssize_t) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
 	if (rc == EOK)
@@ -431,9 +419,7 @@
 int fsync(int fildes)
 {
-	int vfs_phone = vfs_exchange_begin();
-	
-	sysarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
-	
-	vfs_exchange_end(vfs_phone);
+	async_exch_t *exch = vfs_exchange_begin();
+	sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
+	vfs_exchange_end(exch);
 	
 	return (int) rc;
@@ -442,13 +428,13 @@
 off64_t lseek(int fildes, off64_t offset, int whence)
 {
-	int vfs_phone = vfs_exchange_begin();
+	async_exch_t *exch = vfs_exchange_begin();
 	
 	sysarg_t newoff_lo;
 	sysarg_t newoff_hi;
-	sysarg_t rc = async_req_4_2(vfs_phone, VFS_IN_SEEK, fildes,
+	sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
 	    LOWER32(offset), UPPER32(offset), whence,
 	    &newoff_lo, &newoff_hi);
 	
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	
 	if (rc != EOK)
@@ -462,9 +448,8 @@
 	sysarg_t rc;
 	
-	int vfs_phone = vfs_exchange_begin();
-	
-	rc = async_req_3_0(vfs_phone, VFS_IN_TRUNCATE, fildes,
+	async_exch_t *exch = vfs_exchange_begin();
+	rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
 	    LOWER32(length), UPPER32(length));
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	
 	return (int) rc;
@@ -475,11 +460,11 @@
 	sysarg_t rc;
 	aid_t req;
-
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
-	rc = async_data_read_start(vfs_phone, (void *) stat, sizeof(struct stat));
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
+	rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 
 		sysarg_t rc_orig;
@@ -491,5 +476,5 @@
 			return (ssize_t) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
 
@@ -508,10 +493,10 @@
 		return ENOMEM;
 	
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_0(vfs_phone, VFS_IN_STAT, NULL);
-	rc = async_data_write_start(vfs_phone, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_0(exch, VFS_IN_STAT, NULL);
+	rc = async_data_write_start(exch, pa, pa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(pa);
 		async_wait_for(req, &rc_orig);
@@ -521,7 +506,7 @@
 			return (int) rc_orig;
 	}
-	rc = async_data_read_start(vfs_phone, stat, sizeof(struct stat));
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	rc = async_data_read_start(exch, stat, sizeof(struct stat));
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(pa);
 		async_wait_for(req, &rc_orig);
@@ -531,5 +516,5 @@
 			return (int) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	free(pa);
 	async_wait_for(req, &rc);
@@ -592,10 +577,10 @@
 		return ENOMEM;
 	
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
-	rc = async_data_write_start(vfs_phone, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
+	rc = async_data_write_start(exch, pa, pa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(pa);
 
@@ -608,5 +593,5 @@
 			return (int) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	free(pa);
 	async_wait_for(req, &rc);
@@ -623,11 +608,11 @@
 	if (!pa)
 		return ENOMEM;
-
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
-	rc = async_data_write_start(vfs_phone, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_0(exch, VFS_IN_UNLINK, NULL);
+	rc = async_data_write_start(exch, pa, pa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(pa);
 
@@ -640,5 +625,5 @@
 			return (int) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	free(pa);
 	async_wait_for(req, &rc);
@@ -673,11 +658,11 @@
 		return ENOMEM;
 	}
-
-	int vfs_phone = vfs_exchange_begin();
-	
-	req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
-	rc = async_data_write_start(vfs_phone, olda, olda_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_0(exch, VFS_IN_RENAME, NULL);
+	rc = async_data_write_start(exch, olda, olda_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(olda);
 		free(newa);
@@ -688,7 +673,7 @@
 			return (int) rc_orig;
 	}
-	rc = async_data_write_start(vfs_phone, newa, newa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(vfs_phone);
+	rc = async_data_write_start(exch, newa, newa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
 		free(olda);
 		free(newa);
@@ -699,5 +684,5 @@
 			return (int) rc_orig;
 	}
-	vfs_exchange_end(vfs_phone);
+	vfs_exchange_end(exch);
 	free(olda);
 	free(newa);
@@ -755,16 +740,19 @@
 }
 
-int fd_phone(int fildes)
+async_sess_t *fd_session(exch_mgmt_t mgmt, int fildes)
 {
 	struct stat stat;
-	
 	int rc = fstat(fildes, &stat);
-	if (rc != 0)
-		return rc;
-	
-	if (!stat.device)
-		return -1;
-	
-	return devmap_device_connect(stat.device, 0);
+	if (rc != 0) {
+		errno = rc;
+		return NULL;
+	}
+	
+	if (!stat.device) {
+		errno = ENOENT;
+		return NULL;
+	}
+	
+	return devmap_device_connect(mgmt, stat.device, 0);
 }
 
@@ -772,7 +760,5 @@
 {
 	struct stat stat;
-	int rc;
-
-	rc = fstat(fildes, &stat);
+	int rc = fstat(fildes, &stat);
 	
 	if (rc == EOK) {
@@ -787,10 +773,10 @@
 int dup2(int oldfd, int newfd)
 {
-	int vfs_phone = vfs_exchange_begin();
+	async_exch_t *exch = vfs_exchange_begin();
 	
 	sysarg_t ret;
-	sysarg_t rc = async_req_2_1(vfs_phone, VFS_IN_DUP, oldfd, newfd, &ret);
-	
-	vfs_exchange_end(vfs_phone);
+	sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
+	
+	vfs_exchange_end(exch);
 	
 	if (rc == EOK)
Index: uspace/lib/c/include/adt/hash_table.h
===================================================================
--- uspace/lib/c/include/adt/hash_table.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/adt/hash_table.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,4 +38,5 @@
 #include <adt/list.h>
 #include <unistd.h>
+#include <bool.h>
 
 typedef unsigned long hash_count_t;
@@ -83,5 +84,5 @@
     list_get_instance((item), type, member)
 
-extern int hash_table_create(hash_table_t *, hash_count_t, hash_count_t,
+extern bool hash_table_create(hash_table_t *, hash_count_t, hash_count_t,
     hash_table_operations_t *);
 extern void hash_table_insert(hash_table_t *, unsigned long [], link_t *);
Index: uspace/lib/c/include/as.h
===================================================================
--- uspace/lib/c/include/as.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/as.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -60,4 +60,5 @@
 extern void *set_maxheapsize(size_t);
 extern void *as_get_mappable_page(size_t);
+extern int as_get_physical_mapping(void *, uintptr_t *);
 
 #endif
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/async.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,6 +41,6 @@
 
 #include <ipc/common.h>
-#include <async_sess.h>
 #include <fibril.h>
+#include <fibril_synch.h>
 #include <sys/time.h>
 #include <atomic.h>
@@ -55,4 +55,76 @@
 typedef void (*async_client_conn_t)(ipc_callid_t, ipc_call_t *);
 
+/** Exchange management style
+ *
+ */
+typedef enum {
+	/** No explicit exchange management
+	 *
+	 * Suitable for protocols which use a single
+	 * IPC message per exchange only.
+	 *
+	 */
+	EXCHANGE_ATOMIC = 0,
+	
+	/** Exchange management via phone cloning
+	 *
+	 * Suitable for servers which support client
+	 * data tracking by task hashes and do not
+	 * mind cloned phones.
+	 *
+	 */
+	EXCHANGE_PARALLEL,
+	
+	/** Exchange management via mutual exclusion
+	 *
+	 * Suitable for any kind of client/server communication,
+	 * but can limit parallelism.
+	 *
+	 */
+	EXCHANGE_SERIALIZE
+} exch_mgmt_t;
+
+/** Session data */
+typedef struct {
+	/** List of inactive exchanges */
+	link_t exch_list;
+	
+	/** Exchange management style */
+	exch_mgmt_t mgmt;
+	
+	/** Session identification */
+	int phone;
+	
+	/** First clone connection argument */
+	sysarg_t arg1;
+	
+	/** Second clone connection argument */
+	sysarg_t arg2;
+	
+	/** Third clone connection argument */
+	sysarg_t arg3;
+	
+	/** Exchange mutex */
+	fibril_mutex_t mutex;
+	
+	/** Number of opened exchanges */
+	atomic_t refcnt;
+} async_sess_t;
+
+/** Exchange data */
+typedef struct {
+	/** Link into list of inactive exchanges */
+	link_t sess_link;
+	
+	/** Link into global list of inactive exchanges */
+	link_t global_link;
+	
+	/** Session pointer */
+	async_sess_t *sess;
+	
+	/** Exchange identification */
+	int phone;
+} async_exch_t;
+
 extern atomic_t threads_in_ipc_wait;
 
@@ -68,32 +140,32 @@
  * User-friendly wrappers for async_send_fast() and async_send_slow(). The
  * macros are in the form async_send_m(), where m denotes the number of payload
- * arguments.  Each macros chooses between the fast and the slow version based
+ * arguments. Each macros chooses between the fast and the slow version based
  * on m.
  */
 
-#define async_send_0(phoneid, method, dataptr) \
-	async_send_fast((phoneid), (method), 0, 0, 0, 0, (dataptr))
-#define async_send_1(phoneid, method, arg1, dataptr) \
-	async_send_fast((phoneid), (method), (arg1), 0, 0, 0, (dataptr))
-#define async_send_2(phoneid, method, arg1, arg2, dataptr) \
-	async_send_fast((phoneid), (method), (arg1), (arg2), 0, 0, (dataptr))
-#define async_send_3(phoneid, method, arg1, arg2, arg3, dataptr) \
-	async_send_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (dataptr))
-#define async_send_4(phoneid, method, arg1, arg2, arg3, arg4, dataptr) \
-	async_send_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (dataptr))
-#define async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, dataptr) \
-	async_send_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), (dataptr))
-
-extern aid_t async_send_fast(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, ipc_call_t *);
-extern aid_t async_send_slow(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+#define async_send_0(exch, method, dataptr) \
+	async_send_fast(exch, method, 0, 0, 0, 0, dataptr)
+#define async_send_1(exch, method, arg1, dataptr) \
+	async_send_fast(exch, method, arg1, 0, 0, 0, dataptr)
+#define async_send_2(exch, method, arg1, arg2, dataptr) \
+	async_send_fast(exch, method, arg1, arg2, 0, 0, dataptr)
+#define async_send_3(exch, method, arg1, arg2, arg3, dataptr) \
+	async_send_fast(exch, method, arg1, arg2, arg3, 0, dataptr)
+#define async_send_4(exch, method, arg1, arg2, arg3, arg4, dataptr) \
+	async_send_fast(exch, method, arg1, arg2, arg3, arg4, dataptr)
+#define async_send_5(exch, method, arg1, arg2, arg3, arg4, arg5, dataptr) \
+	async_send_slow(exch, method, arg1, arg2, arg3, arg4, arg5, dataptr)
+
+extern aid_t async_send_fast(async_exch_t *, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, ipc_call_t *);
+extern aid_t async_send_slow(async_exch_t *, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t, ipc_call_t *);
+
 extern void async_wait_for(aid_t, sysarg_t *);
 extern int async_wait_timeout(aid_t, sysarg_t *, suseconds_t);
 
 extern fid_t async_new_connection(sysarg_t, sysarg_t, ipc_callid_t,
-    ipc_call_t *, void (*)(ipc_callid_t, ipc_call_t *));
+    ipc_call_t *, async_client_conn_t);
+
 extern void async_usleep(suseconds_t);
 extern void async_create_manager(void);
@@ -102,6 +174,5 @@
 extern void async_set_client_data_constructor(async_client_data_ctor_t);
 extern void async_set_client_data_destructor(async_client_data_dtor_t);
-
-extern void *async_client_data_get(void);
+extern void *async_get_client_data(void);
 
 extern void async_set_client_connection(async_client_conn_t);
@@ -112,11 +183,12 @@
  */
 
-extern void async_msg_0(int, sysarg_t);
-extern void async_msg_1(int, sysarg_t, sysarg_t);
-extern void async_msg_2(int, sysarg_t, sysarg_t, sysarg_t);
-extern void async_msg_3(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t);
-extern void async_msg_4(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t, sysarg_t);
-extern void async_msg_5(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+extern void async_msg_0(async_exch_t *, sysarg_t);
+extern void async_msg_1(async_exch_t *, sysarg_t, sysarg_t);
+extern void async_msg_2(async_exch_t *, sysarg_t, sysarg_t, sysarg_t);
+extern void async_msg_3(async_exch_t *, sysarg_t, sysarg_t, sysarg_t, sysarg_t);
+extern void async_msg_4(async_exch_t *, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t);
+extern void async_msg_5(async_exch_t *, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t);
 
 /*
@@ -138,8 +210,8 @@
  */
 
-extern int async_forward_fast(ipc_callid_t, int, sysarg_t, sysarg_t, sysarg_t,
-    unsigned int);
-extern int async_forward_slow(ipc_callid_t, int, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, sysarg_t, sysarg_t, unsigned int);
+extern int async_forward_fast(ipc_callid_t, async_exch_t *, sysarg_t, sysarg_t,
+    sysarg_t, unsigned int);
+extern int async_forward_slow(ipc_callid_t, async_exch_t *, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t, sysarg_t, unsigned int);
 
 /*
@@ -150,161 +222,160 @@
  */
 
-#define async_req_0_0(phoneid, method) \
-	async_req_fast((phoneid), (method), 0, 0, 0, 0, NULL, NULL, NULL, NULL, \
-	    NULL)
-#define async_req_0_1(phoneid, method, r1) \
-	async_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), NULL, NULL, NULL, \
-	    NULL)
-#define async_req_0_2(phoneid, method, r1, r2) \
-	async_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), NULL, NULL, \
-	    NULL)
-#define async_req_0_3(phoneid, method, r1, r2, r3) \
-	async_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), (r3), NULL, \
-	    NULL)
-#define async_req_0_4(phoneid, method, r1, r2, r3, r4) \
-	async_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), (r3), (r4), \
-	    NULL)
-#define async_req_0_5(phoneid, method, r1, r2, r3, r4, r5) \
-	async_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), (r3), (r4), \
-	    (r5))
-#define async_req_1_0(phoneid, method, arg1) \
-	async_req_fast((phoneid), (method), (arg1), 0, 0, 0, NULL, NULL, NULL, \
-	    NULL, NULL)
-#define async_req_1_1(phoneid, method, arg1, rc1) \
-	async_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), NULL, NULL, \
-	    NULL, NULL)
-#define async_req_1_2(phoneid, method, arg1, rc1, rc2) \
-	async_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), NULL, \
-	    NULL, NULL)
-#define async_req_1_3(phoneid, method, arg1, rc1, rc2, rc3) \
-	async_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), (rc3), \
-	    NULL, NULL)
-#define async_req_1_4(phoneid, method, arg1, rc1, rc2, rc3, rc4) \
-	async_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), (rc3), \
-	    (rc4), NULL)
-#define async_req_1_5(phoneid, method, arg1, rc1, rc2, rc3, rc4, rc5) \
-	async_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), (rc3), \
-	    (rc4), (rc5))
-#define async_req_2_0(phoneid, method, arg1, arg2) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, NULL, NULL, \
+#define async_req_0_0(exch, method) \
+	async_req_fast(exch, method, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)
+#define async_req_0_1(exch, method, r1) \
+	async_req_fast(exch, method, 0, 0, 0, 0, r1, NULL, NULL, NULL, NULL)
+#define async_req_0_2(exch, method, r1, r2) \
+	async_req_fast(exch, method, 0, 0, 0, 0, r1, r2, NULL, NULL, NULL)
+#define async_req_0_3(exch, method, r1, r2, r3) \
+	async_req_fast(exch, method, 0, 0, 0, 0, r1, r2, r3, NULL, NULL)
+#define async_req_0_4(exch, method, r1, r2, r3, r4) \
+	async_req_fast(exch, method, 0, 0, 0, 0, r1, r2, r3, r4, NULL)
+#define async_req_0_5(exch, method, r1, r2, r3, r4, r5) \
+	async_req_fast(exch, method, 0, 0, 0, 0, r1, r2, r3, r4, r5)
+
+#define async_req_1_0(exch, method, arg1) \
+	async_req_fast(exch, method, arg1, 0, 0, 0, NULL, NULL, NULL, NULL, \
+	    NULL)
+#define async_req_1_1(exch, method, arg1, rc1) \
+	async_req_fast(exch, method, arg1, 0, 0, 0, rc1, NULL, NULL, NULL, \
+	    NULL)
+#define async_req_1_2(exch, method, arg1, rc1, rc2) \
+	async_req_fast(exch, method, arg1, 0, 0, 0, rc1, rc2, NULL, NULL, \
+	    NULL)
+#define async_req_1_3(exch, method, arg1, rc1, rc2, rc3) \
+	async_req_fast(exch, method, arg1, 0, 0, 0, rc1, rc2, rc3, NULL, \
+	    NULL)
+#define async_req_1_4(exch, method, arg1, rc1, rc2, rc3, rc4) \
+	async_req_fast(exch, method, arg1, 0, 0, 0, rc1, rc2, rc3, rc4, \
+	    NULL)
+#define async_req_1_5(exch, method, arg1, rc1, rc2, rc3, rc4, rc5) \
+	async_req_fast(exch, method, arg1, 0, 0, 0, rc1, rc2, rc3, rc4, \
+	    rc5)
+
+#define async_req_2_0(exch, method, arg1, arg2) \
+	async_req_fast(exch, method, arg1, arg2, 0, 0, NULL, NULL, NULL, \
+	    NULL, NULL)
+#define async_req_2_1(exch, method, arg1, arg2, rc1) \
+	async_req_fast(exch, method, arg1, arg2, 0, 0, rc1, NULL, NULL, \
+	    NULL, NULL)
+#define async_req_2_2(exch, method, arg1, arg2, rc1, rc2) \
+	async_req_fast(exch, method, arg1, arg2, 0, 0, rc1, rc2, NULL, NULL, \
+	    NULL)
+#define async_req_2_3(exch, method, arg1, arg2, rc1, rc2, rc3) \
+	async_req_fast(exch, method, arg1, arg2, 0, 0, rc1, rc2, rc3, NULL, \
+	    NULL)
+#define async_req_2_4(exch, method, arg1, arg2, rc1, rc2, rc3, rc4) \
+	async_req_fast(exch, method, arg1, arg2, 0, 0, rc1, rc2, rc3, rc4, \
+	    NULL)
+#define async_req_2_5(exch, method, arg1, arg2, rc1, rc2, rc3, rc4, rc5) \
+	async_req_fast(exch, method, arg1, arg2, 0, 0, rc1, rc2, rc3, rc4, \
+	    rc5)
+
+#define async_req_3_0(exch, method, arg1, arg2, arg3) \
+	async_req_fast(exch, method, arg1, arg2, arg3, 0, NULL, NULL, NULL, \
+	    NULL, NULL)
+#define async_req_3_1(exch, method, arg1, arg2, arg3, rc1) \
+	async_req_fast(exch, method, arg1, arg2, arg3, 0, rc1, NULL, NULL, \
+	    NULL, NULL)
+#define async_req_3_2(exch, method, arg1, arg2, arg3, rc1, rc2) \
+	async_req_fast(exch, method, arg1, arg2, arg3, 0, rc1, rc2, NULL, \
+	    NULL, NULL)
+#define async_req_3_3(exch, method, arg1, arg2, arg3, rc1, rc2, rc3) \
+	async_req_fast(exch, method, arg1, arg2, arg3, 0, rc1, rc2, rc3, \
+	    NULL, NULL)
+#define async_req_3_4(exch, method, arg1, arg2, arg3, rc1, rc2, rc3, rc4) \
+	async_req_fast(exch, method, arg1, arg2, arg3, 0, rc1, rc2, rc3, \
+	    rc4, NULL)
+#define async_req_3_5(exch, method, arg1, arg2, arg3, rc1, rc2, rc3, rc4, \
+    rc5) \
+	async_req_fast(exch, method, arg1, arg2, arg3, 0, rc1, rc2, rc3, \
+	    rc4, rc5)
+
+#define async_req_4_0(exch, method, arg1, arg2, arg3, arg4) \
+	async_req_fast(exch, method, arg1, arg2, arg3, arg4, NULL, NULL, \
 	    NULL, NULL, NULL)
-#define async_req_2_1(phoneid, method, arg1, arg2, rc1) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), NULL, \
+#define async_req_4_1(exch, method, arg1, arg2, arg3, arg4, rc1) \
+	async_req_fast(exch, method, arg1, arg2, arg3, arg4, rc1, NULL, \
 	    NULL, NULL, NULL)
-#define async_req_2_2(phoneid, method, arg1, arg2, rc1, rc2) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
+#define async_req_4_2(exch, method, arg1, arg2, arg3, arg4, rc1, rc2) \
+	async_req_fast(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, NULL, \
+	    NULL, NULL)
+#define async_req_4_3(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3) \
+	async_req_fast(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+	    NULL, NULL)
+#define async_req_4_4(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+    rc4) \
+	async_req_fast(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+	    rc4, NULL)
+#define async_req_4_5(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+    rc4, rc5) \
+	async_req_fast(exch, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+	    rc4, rc5)
+
+#define async_req_5_0(exch, method, arg1, arg2, arg3, arg4, arg5) \
+	async_req_slow(exch, method, arg1, arg2, arg3, arg4, arg5, NULL, \
+	    NULL, NULL, NULL, NULL)
+#define async_req_5_1(exch, method, arg1, arg2, arg3, arg4, arg5, rc1) \
+	async_req_slow(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, \
+	    NULL, NULL, NULL, NULL)
+#define async_req_5_2(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2) \
+	async_req_slow(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
 	    NULL, NULL, NULL)
-#define async_req_2_3(phoneid, method, arg1, arg2, rc1, rc2, rc3) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
-	    (rc3), NULL, NULL)
-#define async_req_2_4(phoneid, method, arg1, arg2, rc1, rc2, rc3, rc4) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
-	    (rc3), (rc4), NULL)
-#define async_req_2_5(phoneid, method, arg1, arg2, rc1, rc2, rc3, rc4, rc5) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
-	    (rc3), (rc4), (rc5))
-#define async_req_3_0(phoneid, method, arg1, arg2, arg3) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, NULL, NULL, \
-	    NULL, NULL, NULL)
-#define async_req_3_1(phoneid, method, arg1, arg2, arg3, rc1) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
-	    NULL, NULL, NULL, NULL)
-#define async_req_3_2(phoneid, method, arg1, arg2, arg3, rc1, rc2) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
-	    (rc2), NULL, NULL, NULL)
-#define async_req_3_3(phoneid, method, arg1, arg2, arg3, rc1, rc2, rc3) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
-	    (rc2), (rc3), NULL, NULL)
-#define async_req_3_4(phoneid, method, arg1, arg2, arg3, rc1, rc2, rc3, rc4) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
-	    (rc2), (rc3), (rc4), NULL)
-#define async_req_3_5(phoneid, method, arg1, arg2, arg3, rc1, rc2, rc3, rc4, \
-    rc5) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
-	    (rc2), (rc3), (rc4), (rc5))
-#define async_req_4_0(phoneid, method, arg1, arg2, arg3, arg4) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), NULL, \
-	    NULL, NULL, NULL, NULL)
-#define async_req_4_1(phoneid, method, arg1, arg2, arg3, arg4, rc1) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), (rc1), \
-	    NULL, NULL, NULL, NULL)
-#define async_req_4_2(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), (rc1), \
-	    (rc2), NULL, NULL, NULL)
-#define async_req_4_3(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), (rc1), \
-	    (rc2), (rc3), NULL, NULL)
-#define async_req_4_4(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
-    rc4) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (rc1), (rc2), (rc3), (rc4), NULL)
-#define async_req_4_5(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
-    rc4, rc5) \
-	async_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (rc1), (rc2), (rc3), (rc4), (rc5))
-#define async_req_5_0(phoneid, method, arg1, arg2, arg3, arg4, arg5) \
-	async_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), NULL, NULL, NULL, NULL, NULL)
-#define async_req_5_1(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1) \
-	async_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), (rc1), NULL, NULL, NULL, NULL)
-#define async_req_5_2(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2) \
-	async_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), (rc1), (rc2), NULL, NULL, NULL)
-#define async_req_5_3(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+#define async_req_5_3(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
     rc3) \
-	async_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), (rc1), (rc2), (rc3), NULL, NULL)
-#define async_req_5_4(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+	async_req_slow(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+	    rc3, NULL, NULL)
+#define async_req_5_4(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
     rc3, rc4) \
-	async_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), (rc1), (rc2), (rc3), (rc4), NULL)
-#define async_req_5_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+	async_req_slow(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+	    rc3, rc4, NULL)
+#define async_req_5_5(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
     rc3, rc4, rc5) \
-	async_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
-	    (arg5), (rc1), (rc2), (rc3), (rc4), (rc5))
-
-extern sysarg_t async_req_fast(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, sysarg_t *, sysarg_t *, sysarg_t *, sysarg_t *, sysarg_t *);
-extern sysarg_t async_req_slow(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+	async_req_slow(exch, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+	    rc3, rc4, rc5)
+
+extern sysarg_t async_req_fast(async_exch_t *, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, sysarg_t *, sysarg_t *, sysarg_t *, sysarg_t *,
     sysarg_t *);
-
-static inline void async_serialize_start(void)
-{
-	fibril_inc_sercount();
-}
-
-static inline void async_serialize_end(void)
-{
-	fibril_dec_sercount();
-}
-
-extern int async_connect_to_me(int, sysarg_t, sysarg_t, sysarg_t,
+extern sysarg_t async_req_slow(async_exch_t *, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t, sysarg_t *, sysarg_t *, sysarg_t *,
+    sysarg_t *, sysarg_t *);
+
+extern async_sess_t *async_connect_me(exch_mgmt_t, async_exch_t *);
+extern async_sess_t *async_connect_me_to(exch_mgmt_t, async_exch_t *, sysarg_t,
+    sysarg_t, sysarg_t);
+extern async_sess_t *async_connect_me_to_blocking(exch_mgmt_t, async_exch_t *,
+    sysarg_t, sysarg_t, sysarg_t);
+extern async_sess_t *async_connect_kbox(task_id_t);
+
+extern int async_connect_to_me(async_exch_t *, sysarg_t, sysarg_t, sysarg_t,
     async_client_conn_t);
-extern int async_connect_me_to(int, sysarg_t, sysarg_t, sysarg_t);
-extern int async_connect_me_to_blocking(int, sysarg_t, sysarg_t, sysarg_t);
-extern int async_connect_kbox(task_id_t);
-extern int async_hangup(int);
+
+extern int async_hangup(async_sess_t *);
 extern void async_poke(void);
 
+extern async_exch_t *async_exchange_begin(async_sess_t *);
+extern void async_exchange_end(async_exch_t *);
+
 /*
  * User-friendly wrappers for async_share_in_start().
  */
 
-#define async_share_in_start_0_0(phoneid, dst, size) \
-	async_share_in_start((phoneid), (dst), (size), 0, NULL)
-#define async_share_in_start_0_1(phoneid, dst, size, flags) \
-	async_share_in_start((phoneid), (dst), (size), 0, (flags))
-#define async_share_in_start_1_0(phoneid, dst, size, arg) \
-	async_share_in_start((phoneid), (dst), (size), (arg), NULL)
-#define async_share_in_start_1_1(phoneid, dst, size, arg, flags) \
-	async_share_in_start((phoneid), (dst), (size), (arg), (flags))
-
-extern int async_share_in_start(int, void *, size_t, sysarg_t, unsigned int *);
+#define async_share_in_start_0_0(exch, dst, size) \
+	async_share_in_start(exch, dst, size, 0, NULL)
+#define async_share_in_start_0_1(exch, dst, size, flags) \
+	async_share_in_start(exch, dst, size, 0, flags)
+#define async_share_in_start_1_0(exch, dst, size, arg) \
+	async_share_in_start(exch, dst, size, arg, NULL)
+#define async_share_in_start_1_1(exch, dst, size, arg, flags) \
+	async_share_in_start(exch, dst, size, arg, flags)
+
+extern int async_share_in_start(async_exch_t *, void *, size_t, sysarg_t,
+    unsigned int *);
 extern bool async_share_in_receive(ipc_callid_t *, size_t *);
 extern int async_share_in_finalize(ipc_callid_t, void *, unsigned int);
 
-extern int async_share_out_start(int, void *, unsigned int);
+extern int async_share_out_start(async_exch_t *, void *, unsigned int);
 extern bool async_share_out_receive(ipc_callid_t *, size_t *, unsigned int *);
 extern int async_share_out_finalize(ipc_callid_t, void *);
@@ -314,39 +385,37 @@
  */
 
-#define async_data_read_forward_0_0(phoneid, method, answer) \
-	async_data_read_forward_fast((phoneid), (method), 0, 0, 0, 0, NULL)
-#define async_data_read_forward_0_1(phoneid, method, answer) \
-	async_data_read_forward_fast((phoneid), (method), 0, 0, 0, 0, (answer))
-#define async_data_read_forward_1_0(phoneid, method, arg1, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), 0, 0, 0, NULL)
-#define async_data_read_forward_1_1(phoneid, method, arg1, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), 0, 0, 0, (answer))
-#define async_data_read_forward_2_0(phoneid, method, arg1, arg2, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), (arg2), 0, 0, NULL)
-#define async_data_read_forward_2_1(phoneid, method, arg1, arg2, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
-	    (answer))
-#define async_data_read_forward_3_0(phoneid, method, arg1, arg2, arg3, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, \
-	    NULL)
-#define async_data_read_forward_3_1(phoneid, method, arg1, arg2, arg3, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, \
-	    (answer))
-#define async_data_read_forward_4_0(phoneid, method, arg1, arg2, arg3, arg4, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    (arg4), NULL)
-#define async_data_read_forward_4_1(phoneid, method, arg1, arg2, arg3, arg4, answer) \
-	async_data_read_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    (arg4), (answer))
-
-#define async_data_read_start(p, buf, len) \
-	async_data_read_start_generic((p), (buf), (len), IPC_XF_NONE)
-
-extern int async_data_read_start_generic(int, void *, size_t, int);
+#define async_data_read_forward_0_0(exch, method, answer) \
+	async_data_read_forward_fast(exch, method, 0, 0, 0, 0, NULL)
+#define async_data_read_forward_0_1(exch, method, answer) \
+	async_data_read_forward_fast(exch, method, 0, 0, 0, 0, answer)
+#define async_data_read_forward_1_0(exch, method, arg1, answer) \
+	async_data_read_forward_fast(exch, method, arg1, 0, 0, 0, NULL)
+#define async_data_read_forward_1_1(exch, method, arg1, answer) \
+	async_data_read_forward_fast(exch, method, arg1, 0, 0, 0, answer)
+#define async_data_read_forward_2_0(exch, method, arg1, arg2, answer) \
+	async_data_read_forward_fast(exch, method, arg1, arg2, 0, 0, NULL)
+#define async_data_read_forward_2_1(exch, method, arg1, arg2, answer) \
+	async_data_read_forward_fast(exch, method, arg1, arg2, 0, 0, answer)
+#define async_data_read_forward_3_0(exch, method, arg1, arg2, arg3, answer) \
+	async_data_read_forward_fast(exch, method, arg1, arg2, arg3, 0, NULL)
+#define async_data_read_forward_3_1(exch, method, arg1, arg2, arg3, answer) \
+	async_data_read_forward_fast(exch, method, arg1, arg2, arg3, 0, \
+	    answer)
+#define async_data_read_forward_4_0(exch, method, arg1, arg2, arg3, arg4, \
+    answer) \
+	async_data_read_forward_fast(exch, method, arg1, arg2, arg3, arg4, \
+	    NULL)
+#define async_data_read_forward_4_1(exch, method, arg1, arg2, arg3, arg4, \
+    answer) \
+	async_data_read_forward_fast(exch, method, arg1, arg2, arg3, arg4, \
+	    answer)
+
+extern aid_t async_data_read(async_exch_t *, void *, size_t, ipc_call_t *);
+extern int async_data_read_start(async_exch_t *, void *, size_t);
 extern bool async_data_read_receive(ipc_callid_t *, size_t *);
 extern int async_data_read_finalize(ipc_callid_t, const void *, size_t);
 
-extern int async_data_read_forward_fast(int, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, sysarg_t, ipc_call_t *);
+extern int async_data_read_forward_fast(async_exch_t *, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t, ipc_call_t *);
 
 /*
@@ -354,36 +423,32 @@
  */
 
-#define async_data_write_forward_0_0(phoneid, method, answer) \
-	async_data_write_forward_fast((phoneid), (method), 0, 0, 0, 0, NULL)
-#define async_data_write_forward_0_1(phoneid, method, answer) \
-	async_data_write_forward_fast((phoneid), (method), 0, 0, 0, 0, (answer))
-#define async_data_write_forward_1_0(phoneid, method, arg1, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), 0, 0, 0, NULL)
-#define async_data_write_forward_1_1(phoneid, method, arg1, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), 0, 0, 0, \
-	    (answer))
-#define async_data_write_forward_2_0(phoneid, method, arg1, arg2, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
-	    NULL)
-#define async_data_write_forward_2_1(phoneid, method, arg1, arg2, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
-	    (answer))
-#define async_data_write_forward_3_0(phoneid, method, arg1, arg2, arg3, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    0, NULL)
-#define async_data_write_forward_3_1(phoneid, method, arg1, arg2, arg3, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    0, (answer))
-#define async_data_write_forward_4_0(phoneid, method, arg1, arg2, arg3, arg4, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    (arg4), NULL)
-#define async_data_write_forward_4_1(phoneid, method, arg1, arg2, arg3, arg4, answer) \
-	async_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    (arg4), (answer))
-
-#define async_data_write_start(p, buf, len) \
-	async_data_write_start_generic((p), (buf), (len), IPC_XF_NONE)
-
-extern int async_data_write_start_generic(int, const void *, size_t, int);
+#define async_data_write_forward_0_0(exch, method, answer) \
+	async_data_write_forward_fast(exch, method, 0, 0, 0, 0, NULL)
+#define async_data_write_forward_0_1(exch, method, answer) \
+	async_data_write_forward_fast(exch, method, 0, 0, 0, 0, answer)
+#define async_data_write_forward_1_0(exch, method, arg1, answer) \
+	async_data_write_forward_fast(exch, method, arg1, 0, 0, 0, NULL)
+#define async_data_write_forward_1_1(exch, method, arg1, answer) \
+	async_data_write_forward_fast(exch, method, arg1, 0, 0, 0, answer)
+#define async_data_write_forward_2_0(exch, method, arg1, arg2, answer) \
+	async_data_write_forward_fast(exch, method, arg1, arg2, 0, 0, NULL)
+#define async_data_write_forward_2_1(exch, method, arg1, arg2, answer) \
+	async_data_write_forward_fast(exch, method, arg1, arg2, 0, 0, answer)
+#define async_data_write_forward_3_0(exch, method, arg1, arg2, arg3, answer) \
+	async_data_write_forward_fast(exch, method, arg1, arg2, arg3, 0, \
+	    NULL)
+#define async_data_write_forward_3_1(exch, method, arg1, arg2, arg3, answer) \
+	async_data_write_forward_fast(exch, method, arg1, arg2, arg3, 0, \
+	    answer)
+#define async_data_write_forward_4_0(exch, method, arg1, arg2, arg3, arg4, \
+    answer) \
+	async_data_write_forward_fast(exch, method, arg1, arg2, arg3, arg4, \
+	    NULL)
+#define async_data_write_forward_4_1(exch, method, arg1, arg2, arg3, arg4, \
+    answer) \
+	async_data_write_forward_fast(exch, method, arg1, arg2, arg3, arg4, \
+	    answer)
+
+extern int async_data_write_start(async_exch_t *, const void *, size_t);
 extern bool async_data_write_receive(ipc_callid_t *, size_t *);
 extern int async_data_write_finalize(ipc_callid_t, void *, size_t);
@@ -393,6 +458,11 @@
 extern void async_data_write_void(sysarg_t);
 
-extern int async_data_write_forward_fast(int, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, sysarg_t, ipc_call_t *);
+extern int async_data_write_forward_fast(async_exch_t *, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t, ipc_call_t *);
+
+extern int async_exchange_clone(async_exch_t *, async_exch_t *);
+extern async_sess_t *async_clone_receive(exch_mgmt_t);
+extern async_sess_t *async_callback_receive(exch_mgmt_t);
+extern async_sess_t *async_callback_receive_start(exch_mgmt_t, ipc_call_t *);
 
 #endif
Index: uspace/lib/c/include/async_obsolete.h
===================================================================
--- uspace/lib/c/include/async_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/async_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#if ((defined(LIBC_IPC_H_)) && (!defined(LIBC_ASYNC_OBSOLETE_C_)))
+	#error Do not intermix low-level IPC interface and async framework
+#endif
+
+#ifndef LIBC_ASYNC_OBSOLETE_H_
+#define LIBC_ASYNC_OBSOLETE_H_
+
+extern void async_obsolete_serialize_start(void);
+extern void async_obsolete_serialize_end(void);
+
+#define async_obsolete_send_0(phoneid, method, dataptr) \
+	async_obsolete_send_fast((phoneid), (method), 0, 0, 0, 0, (dataptr))
+#define async_obsolete_send_1(phoneid, method, arg1, dataptr) \
+	async_obsolete_send_fast((phoneid), (method), (arg1), 0, 0, 0, (dataptr))
+#define async_obsolete_send_2(phoneid, method, arg1, arg2, dataptr) \
+	async_obsolete_send_fast((phoneid), (method), (arg1), (arg2), 0, 0, (dataptr))
+#define async_obsolete_send_3(phoneid, method, arg1, arg2, arg3, dataptr) \
+	async_obsolete_send_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (dataptr))
+#define async_obsolete_send_4(phoneid, method, arg1, arg2, arg3, arg4, dataptr) \
+	async_obsolete_send_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (dataptr))
+#define async_obsolete_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, dataptr) \
+	async_obsolete_send_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), (dataptr))
+
+extern aid_t async_obsolete_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr);
+extern aid_t async_obsolete_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
+    ipc_call_t *dataptr);
+
+#define async_obsolete_req_0_0(phoneid, method) \
+	async_obsolete_req_fast((phoneid), (method), 0, 0, 0, 0, NULL, NULL, NULL, NULL, \
+	    NULL)
+#define async_obsolete_req_0_1(phoneid, method, r1) \
+	async_obsolete_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), NULL, NULL, NULL, \
+	    NULL)
+#define async_obsolete_req_0_2(phoneid, method, r1, r2) \
+	async_obsolete_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), NULL, NULL, \
+	    NULL)
+#define async_obsolete_req_0_3(phoneid, method, r1, r2, r3) \
+	async_obsolete_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), (r3), NULL, \
+	    NULL)
+#define async_obsolete_req_0_4(phoneid, method, r1, r2, r3, r4) \
+	async_obsolete_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), (r3), (r4), \
+	    NULL)
+#define async_obsolete_req_0_5(phoneid, method, r1, r2, r3, r4, r5) \
+	async_obsolete_req_fast((phoneid), (method), 0, 0, 0, 0, (r1), (r2), (r3), (r4), \
+	    (r5))
+#define async_obsolete_req_1_0(phoneid, method, arg1) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), 0, 0, 0, NULL, NULL, NULL, \
+	    NULL, NULL)
+#define async_obsolete_req_1_1(phoneid, method, arg1, rc1) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), NULL, NULL, \
+	    NULL, NULL)
+#define async_obsolete_req_1_2(phoneid, method, arg1, rc1, rc2) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), NULL, \
+	    NULL, NULL)
+#define async_obsolete_req_1_3(phoneid, method, arg1, rc1, rc2, rc3) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), (rc3), \
+	    NULL, NULL)
+#define async_obsolete_req_1_4(phoneid, method, arg1, rc1, rc2, rc3, rc4) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), (rc3), \
+	    (rc4), NULL)
+#define async_obsolete_req_1_5(phoneid, method, arg1, rc1, rc2, rc3, rc4, rc5) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), 0, 0, 0, (rc1), (rc2), (rc3), \
+	    (rc4), (rc5))
+#define async_obsolete_req_2_0(phoneid, method, arg1, arg2) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, NULL, NULL, \
+	    NULL, NULL, NULL)
+#define async_obsolete_req_2_1(phoneid, method, arg1, arg2, rc1) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), NULL, \
+	    NULL, NULL, NULL)
+#define async_obsolete_req_2_2(phoneid, method, arg1, arg2, rc1, rc2) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
+	    NULL, NULL, NULL)
+#define async_obsolete_req_2_3(phoneid, method, arg1, arg2, rc1, rc2, rc3) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
+	    (rc3), NULL, NULL)
+#define async_obsolete_req_2_4(phoneid, method, arg1, arg2, rc1, rc2, rc3, rc4) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
+	    (rc3), (rc4), NULL)
+#define async_obsolete_req_2_5(phoneid, method, arg1, arg2, rc1, rc2, rc3, rc4, rc5) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), 0, 0, (rc1), (rc2), \
+	    (rc3), (rc4), (rc5))
+#define async_obsolete_req_3_0(phoneid, method, arg1, arg2, arg3) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, NULL, NULL, \
+	    NULL, NULL, NULL)
+#define async_obsolete_req_3_1(phoneid, method, arg1, arg2, arg3, rc1) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
+	    NULL, NULL, NULL, NULL)
+#define async_obsolete_req_3_2(phoneid, method, arg1, arg2, arg3, rc1, rc2) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
+	    (rc2), NULL, NULL, NULL)
+#define async_obsolete_req_3_3(phoneid, method, arg1, arg2, arg3, rc1, rc2, rc3) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
+	    (rc2), (rc3), NULL, NULL)
+#define async_obsolete_req_3_4(phoneid, method, arg1, arg2, arg3, rc1, rc2, rc3, rc4) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
+	    (rc2), (rc3), (rc4), NULL)
+#define async_obsolete_req_3_5(phoneid, method, arg1, arg2, arg3, rc1, rc2, rc3, rc4, \
+    rc5) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, (rc1), \
+	    (rc2), (rc3), (rc4), (rc5))
+#define async_obsolete_req_4_0(phoneid, method, arg1, arg2, arg3, arg4) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), NULL, \
+	    NULL, NULL, NULL, NULL)
+#define async_obsolete_req_4_1(phoneid, method, arg1, arg2, arg3, arg4, rc1) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), (rc1), \
+	    NULL, NULL, NULL, NULL)
+#define async_obsolete_req_4_2(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), (rc1), \
+	    (rc2), NULL, NULL, NULL)
+#define async_obsolete_req_4_3(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), (rc1), \
+	    (rc2), (rc3), NULL, NULL)
+#define async_obsolete_req_4_4(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+    rc4) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (rc1), (rc2), (rc3), (rc4), NULL)
+#define async_obsolete_req_4_5(phoneid, method, arg1, arg2, arg3, arg4, rc1, rc2, rc3, \
+    rc4, rc5) \
+	async_obsolete_req_fast((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (rc1), (rc2), (rc3), (rc4), (rc5))
+#define async_obsolete_req_5_0(phoneid, method, arg1, arg2, arg3, arg4, arg5) \
+	async_obsolete_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), NULL, NULL, NULL, NULL, NULL)
+#define async_obsolete_req_5_1(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1) \
+	async_obsolete_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), (rc1), NULL, NULL, NULL, NULL)
+#define async_obsolete_req_5_2(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2) \
+	async_obsolete_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), (rc1), (rc2), NULL, NULL, NULL)
+#define async_obsolete_req_5_3(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+    rc3) \
+	async_obsolete_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), (rc1), (rc2), (rc3), NULL, NULL)
+#define async_obsolete_req_5_4(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+    rc3, rc4) \
+	async_obsolete_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), (rc1), (rc2), (rc3), (rc4), NULL)
+#define async_obsolete_req_5_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, rc1, rc2, \
+    rc3, rc4, rc5) \
+	async_obsolete_req_slow((phoneid), (method), (arg1), (arg2), (arg3), (arg4), \
+	    (arg5), (rc1), (rc2), (rc3), (rc4), (rc5))
+
+extern sysarg_t async_obsolete_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
+    sysarg_t *r3, sysarg_t *r4, sysarg_t *r5);
+extern sysarg_t async_obsolete_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
+    sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5);
+
+extern void async_obsolete_msg_0(int, sysarg_t);
+extern void async_obsolete_msg_1(int, sysarg_t, sysarg_t);
+extern void async_obsolete_msg_2(int, sysarg_t, sysarg_t, sysarg_t);
+extern void async_obsolete_msg_3(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t);
+extern void async_obsolete_msg_4(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t, sysarg_t);
+extern void async_obsolete_msg_5(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t);
+
+extern int async_obsolete_forward_slow(ipc_callid_t, int, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, sysarg_t, unsigned int);
+
+extern int async_obsolete_connect_to_me(int, sysarg_t, sysarg_t, sysarg_t,
+    async_client_conn_t);
+extern int async_obsolete_connect_me_to(int, sysarg_t, sysarg_t, sysarg_t);
+extern int async_obsolete_connect_me_to_blocking(int, sysarg_t, sysarg_t, sysarg_t);
+extern int async_obsolete_hangup(int);
+
+#define async_obsolete_share_in_start_0_0(phoneid, dst, size) \
+	async_obsolete_share_in_start((phoneid), (dst), (size), 0, NULL)
+#define async_obsolete_share_in_start_0_1(phoneid, dst, size, flags) \
+	async_obsolete_share_in_start((phoneid), (dst), (size), 0, (flags))
+#define async_obsolete_share_in_start_1_0(phoneid, dst, size, arg) \
+	async_obsolete_share_in_start((phoneid), (dst), (size), (arg), NULL)
+#define async_obsolete_share_in_start_1_1(phoneid, dst, size, arg, flags) \
+	async_obsolete_share_in_start((phoneid), (dst), (size), (arg), (flags))
+
+extern int async_obsolete_share_in_start(int, void *, size_t, sysarg_t,
+    unsigned int *);
+extern int async_obsolete_share_out_start(int, void *, unsigned int);
+
+#define async_obsolete_data_write_start(p, buf, len) \
+	async_obsolete_data_write_start_generic((p), (buf), (len), IPC_XF_NONE)
+
+#define async_obsolete_data_read_start(p, buf, len) \
+	async_obsolete_data_read_start_generic((p), (buf), (len), IPC_XF_NONE)
+
+#define async_obsolete_data_write_forward_0_0(phoneid, method, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), 0, 0, 0, 0, NULL)
+#define async_obsolete_data_write_forward_0_1(phoneid, method, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), 0, 0, 0, 0, (answer))
+#define async_obsolete_data_write_forward_1_0(phoneid, method, arg1, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), 0, 0, 0, NULL)
+#define async_obsolete_data_write_forward_1_1(phoneid, method, arg1, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), 0, 0, 0, \
+	    (answer))
+#define async_obsolete_data_write_forward_2_0(phoneid, method, arg1, arg2, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
+	    NULL)
+#define async_obsolete_data_write_forward_2_1(phoneid, method, arg1, arg2, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
+	    (answer))
+#define async_obsolete_data_write_forward_3_0(phoneid, method, arg1, arg2, arg3, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
+	    0, NULL)
+#define async_obsolete_data_write_forward_3_1(phoneid, method, arg1, arg2, arg3, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
+	    0, (answer))
+#define async_obsolete_data_write_forward_4_0(phoneid, method, arg1, arg2, arg3, arg4, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
+	    (arg4), NULL)
+#define async_obsolete_data_write_forward_4_1(phoneid, method, arg1, arg2, arg3, arg4, answer) \
+	async_obsolete_data_write_forward_fast((phoneid), (method), (arg1), (arg2), (arg3), \
+	    (arg4), (answer))
+
+extern aid_t async_obsolete_data_read(int, void *, size_t, ipc_call_t *);
+extern int async_obsolete_data_read_start_generic(int, void *, size_t, int);
+
+extern int async_obsolete_data_write_start_generic(int, const void *, size_t, int);
+extern void async_obsolete_data_write_void(const int);
+
+extern int async_obsolete_forward_fast(ipc_callid_t, int, sysarg_t, sysarg_t,
+    sysarg_t, unsigned int);
+
+extern int async_obsolete_data_write_forward_fast(int, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t, sysarg_t, ipc_call_t *);
+
+#endif
+
+/** @}
+ */
Index: pace/lib/c/include/async_sess.h
===================================================================
--- uspace/lib/c/include/async_sess.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * Copyright (c) 2010 Jakub Jermar
- * 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 libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_ASYNC_SESS_H_
-#define LIBC_ASYNC_SESS_H_
-
-#include <adt/list.h>
-
-typedef struct {
-	int sess_phone;		/**< Phone for cloning off the connections. */
-	sysarg_t connect_arg1;  /**< Argument for CONNECT_ME_TO. */
-	link_t conn_head;	/**< List of open data connections. */
-	link_t sess_link;	/**< Link in global list of open sessions. */
-} async_sess_t;
-
-extern void async_session_create(async_sess_t *, int, sysarg_t);
-extern void async_session_destroy(async_sess_t *);
-extern int async_exchange_begin(async_sess_t *);
-extern void async_exchange_end(async_sess_t *, int);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/device/char_dev.h
===================================================================
--- uspace/lib/c/include/device/char_dev.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/device/char_dev.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -36,4 +36,6 @@
 #define LIBC_DEVICE_CHAR_DEV_H_
 
+#include <async.h>
+
 typedef enum {
 	CHAR_DEV_READ = 0,
@@ -41,6 +43,6 @@
 } char_dev_method_t;
 
-ssize_t char_dev_read(int dev_phone, void *buf, size_t len);
-ssize_t char_dev_write(int dev_phone, void *buf, size_t len);
+extern ssize_t char_dev_read(async_sess_t *, void *, size_t);
+extern ssize_t char_dev_write(async_sess_t *, void *, size_t);
 
 #endif
Index: uspace/lib/c/include/device/hw_res.h
===================================================================
--- uspace/lib/c/include/device/hw_res.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/device/hw_res.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -26,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 /** @addtogroup libc
  * @{
@@ -32,9 +32,10 @@
 /** @file
  */
- 
+
 #ifndef LIBC_DEVICE_HW_RES_H_
 #define LIBC_DEVICE_HW_RES_H_
 
 #include <ipc/dev_iface.h>
+#include <async.h>
 #include <bool.h>
 
@@ -48,5 +49,5 @@
 typedef enum {
 	INTERRUPT,
-	IO_RANGE, 
+	IO_RANGE,
 	MEM_RANGE
 } hw_res_type_t;
@@ -66,5 +67,5 @@
 			size_t size;
 		} mem_range;
-
+		
 		struct {
 			uint64_t address;
@@ -72,5 +73,5 @@
 			size_t size;
 		} io_range;
-
+		
 		struct {
 			int irq;
@@ -88,13 +89,12 @@
 	if (hw_res->resources != NULL) {
 		free(hw_res->resources);
-
 		hw_res->resources = NULL;
 	}
-
+	
 	hw_res->count = 0;
 }
 
-extern int hw_res_get_resource_list(int, hw_resource_list_t *);
-extern bool hw_res_enable_interrupt(int);
+extern int hw_res_get_resource_list(async_sess_t *, hw_resource_list_t *);
+extern bool hw_res_enable_interrupt(async_sess_t *);
 
 #endif
Index: uspace/lib/c/include/devman.h
===================================================================
--- uspace/lib/c/include/devman.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/devman.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,6 +41,7 @@
 #include <bool.h>
 
-extern int devman_get_phone(devman_interface_t, unsigned int);
-extern void devman_hangup_phone(devman_interface_t);
+extern async_exch_t *devman_exchange_begin_blocking(devman_interface_t);
+extern async_exch_t *devman_exchange_begin(devman_interface_t);
+extern void devman_exchange_end(async_exch_t *);
 
 extern int devman_driver_register(const char *, async_client_conn_t);
@@ -48,6 +49,8 @@
     devman_handle_t, devman_handle_t *);
 
-extern int devman_device_connect(devman_handle_t, unsigned int);
-extern int devman_parent_device_connect(devman_handle_t, unsigned int);
+extern async_sess_t *devman_device_connect(exch_mgmt_t, devman_handle_t,
+    unsigned int);
+extern async_sess_t *devman_parent_device_connect(exch_mgmt_t, devman_handle_t,
+    unsigned int);
 
 extern int devman_device_get_handle(const char *, devman_handle_t *,
@@ -55,4 +58,5 @@
 extern int devman_device_get_handle_by_class(const char *, const char *,
     devman_handle_t *, unsigned int);
+extern int devman_get_device_path(devman_handle_t, char *, size_t);
 
 extern int devman_add_device_to_class(devman_handle_t, const char *);
Index: uspace/lib/c/include/devman_obsolete.h
===================================================================
--- uspace/lib/c/include/devman_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/devman_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2010 Lenka Trochtova 
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVMAN_OBSOLETE_H_
+#define LIBC_DEVMAN_OBSOLETE_H_
+
+#include <ipc/devman.h>
+#include <async.h>
+#include <bool.h>
+
+extern int devman_obsolete_get_phone(devman_interface_t, unsigned int);
+extern void devman_obsolete_hangup_phone(devman_interface_t);
+
+extern int devman_obsolete_device_connect(devman_handle_t, unsigned int);
+extern int devman_obsolete_parent_device_connect(devman_handle_t, unsigned int);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/devmap.h
===================================================================
--- uspace/lib/c/include/devmap.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/devmap.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,16 +40,21 @@
 #include <bool.h>
 
-extern int devmap_get_phone(devmap_interface_t, unsigned int);
-extern void devmap_hangup_phone(devmap_interface_t iface);
+extern async_exch_t *devmap_exchange_begin_blocking(devmap_interface_t);
+extern async_exch_t *devmap_exchange_begin(devmap_interface_t);
+extern void devmap_exchange_end(async_exch_t *);
 
 extern int devmap_driver_register(const char *, async_client_conn_t);
 extern int devmap_device_register(const char *, devmap_handle_t *);
-extern int devmap_device_register_with_iface(const char *, devmap_handle_t *, sysarg_t);
+extern int devmap_device_register_with_iface(const char *, devmap_handle_t *,
+    sysarg_t);
 
-extern int devmap_device_get_handle(const char *, devmap_handle_t *, unsigned int);
-extern int devmap_namespace_get_handle(const char *, devmap_handle_t *, unsigned int);
+extern int devmap_device_get_handle(const char *, devmap_handle_t *,
+    unsigned int);
+extern int devmap_namespace_get_handle(const char *, devmap_handle_t *,
+    unsigned int);
 extern devmap_handle_type_t devmap_handle_probe(devmap_handle_t);
 
-extern int devmap_device_connect(devmap_handle_t, unsigned int);
+extern async_sess_t *devmap_device_connect(exch_mgmt_t, devmap_handle_t,
+    unsigned int);
 
 extern int devmap_null_create(void);
Index: uspace/lib/c/include/devmap_obsolete.h
===================================================================
--- uspace/lib/c/include/devmap_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/devmap_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVMAP_OBSOLETE_H_
+#define LIBC_DEVMAP_OBSOLETE_H_
+
+#include <ipc/devmap.h>
+#include <async.h>
+#include <bool.h>
+
+extern int devmap_obsolete_get_phone(devmap_interface_t, unsigned int);
+extern void devmap_obsolete_hangup_phone(devmap_interface_t iface);
+
+extern int devmap_obsolete_device_connect(devmap_handle_t, unsigned int);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/errno.h
===================================================================
--- uspace/lib/c/include/errno.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/errno.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -56,4 +56,16 @@
 #define EMLINK        (-266)
 
+/** Bad checksum. */
+#define EBADCHECKSUM  (-300)
+
+/** USB: stalled operation. */
+#define ESTALL (-301)
+
+/** Empty resource (no data). */
+#define EEMPTY (-302)
+
+/** Negative acknowledgment. */
+#define ENAK (-303)
+
 /** An API function is called while another blocking function is in progress. */
 #define EINPROGRESS  (-10036)
Index: uspace/lib/c/include/io/console.h
===================================================================
--- uspace/lib/c/include/io/console.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/io/console.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -36,10 +36,8 @@
 #define LIBC_IO_CONSOLE_H_
 
+#include <sys/time.h>
+#include <async.h>
 #include <bool.h>
-
-typedef enum {
-	KEY_PRESS,
-	KEY_RELEASE
-} console_ev_type_t;
+#include <stdio.h>
 
 typedef enum {
@@ -50,8 +48,34 @@
 } console_caps_t;
 
+/** Console control structure. */
+typedef struct {
+	/** Console input file */
+	FILE *input;
+	
+	/** Console output file */
+	FILE *output;
+	
+	/** Console input session */
+	async_sess_t *input_sess;
+	
+	/** Console output session */
+	async_sess_t *output_sess;
+	
+	/** Input request call with timeout */
+	ipc_call_t input_call;
+	
+	/** Input response with timeout */
+	aid_t input_aid;
+} console_ctrl_t;
+
+typedef enum {
+	KEY_PRESS,
+	KEY_RELEASE
+} kbd_event_type_t;
+
 /** Console event structure. */
 typedef struct {
 	/** Press or release event. */
-	console_ev_type_t type;
+	kbd_event_type_t type;
 	
 	/** Keycode of the key that was pressed or released. */
@@ -63,22 +87,26 @@
 	/** The character that was generated or '\0' for none. */
 	wchar_t c;
-} console_event_t;
+} kbd_event_t;
 
-extern void console_clear(int phone);
+extern console_ctrl_t *console_init(FILE *, FILE *);
+extern void console_done(console_ctrl_t *);
+extern bool console_kcon(void);
 
-extern int console_get_size(int phone, sysarg_t *cols, sysarg_t *rows);
-extern int console_get_pos(int phone, sysarg_t *col, sysarg_t *row);
-extern void console_set_pos(int phone, sysarg_t col, sysarg_t row);
+extern void console_flush(console_ctrl_t *);
+extern void console_clear(console_ctrl_t *);
 
-extern void console_set_style(int phone, uint8_t style);
-extern void console_set_color(int phone, uint8_t fg_color, uint8_t bg_color,
-    uint8_t flags);
-extern void console_set_rgb_color(int phone, uint32_t fg_color, uint32_t bg_color);
+extern int console_get_size(console_ctrl_t *, sysarg_t *, sysarg_t *);
+extern int console_get_pos(console_ctrl_t *, sysarg_t *, sysarg_t *);
+extern void console_set_pos(console_ctrl_t *, sysarg_t, sysarg_t);
 
-extern void console_cursor_visibility(int phone, bool show);
-extern int console_get_color_cap(int phone, sysarg_t *ccap);
-extern void console_kcon_enable(int phone);
+extern void console_set_style(console_ctrl_t *, uint8_t);
+extern void console_set_color(console_ctrl_t *, uint8_t, uint8_t, uint8_t);
+extern void console_set_rgb_color(console_ctrl_t *, uint32_t, uint32_t);
 
-extern bool console_get_event(int phone, console_event_t *event);
+extern void console_cursor_visibility(console_ctrl_t *, bool);
+extern int console_get_color_cap(console_ctrl_t *, sysarg_t *);
+extern bool console_get_kbd_event(console_ctrl_t *, kbd_event_t *);
+extern bool console_get_kbd_event_timeout(console_ctrl_t *, kbd_event_t *,
+    suseconds_t *);
 
 #endif
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,15 @@
 	HW_RES_DEV_IFACE = 0,
 	CHAR_DEV_IFACE,
+
+	/** Interface provided by any PCI device. */
+	PCI_DEV_IFACE,
+
+	/** Interface provided by any USB device. */
+	USB_DEV_IFACE,
+	/** Interface provided by USB host controller. */
+	USBHC_DEV_IFACE,
+	/** Interface provided by USB HID devices. */
+	USBHID_DEV_IFACE,
+
 	DEV_IFACE_MAX
 } dev_inferface_idx_t;
@@ -48,4 +59,14 @@
 	DEV_IFACE_ID(DEV_FIRST_CUSTOM_METHOD_IDX)
 
+/*
+ * The first argument is actually method (as the "real" method is used
+ * for indexing into interfaces.
+ */
+
+#define DEV_IPC_GET_ARG1(call) IPC_GET_ARG2((call))
+#define DEV_IPC_GET_ARG2(call) IPC_GET_ARG3((call))
+#define DEV_IPC_GET_ARG3(call) IPC_GET_ARG4((call))
+#define DEV_IPC_GET_ARG4(call) IPC_GET_ARG5((call))
+
 
 #endif
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/devman.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -149,5 +149,6 @@
 typedef enum {
 	DEVMAN_DEVICE_GET_HANDLE = IPC_FIRST_USER_METHOD,
-	DEVMAN_DEVICE_GET_HANDLE_BY_CLASS
+	DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
+	DEVMAN_DEVICE_GET_DEVICE_PATH
 } client_to_devman_t;
 
Index: uspace/lib/c/include/ipc/devmap.h
===================================================================
--- uspace/lib/c/include/ipc/devmap.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/devmap.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -31,6 +31,6 @@
  */
 
-#ifndef DEVMAP_DEVMAP_H_
-#define DEVMAP_DEVMAP_H_
+#ifndef LIBC_IPC_DEVMAP_H_
+#define LIBC_IPC_DEVMAP_H_
 
 #include <ipc/common.h>
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/ipc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,5 @@
 #include <sys/types.h>
 #include <ipc/common.h>
+#include <kernel/ipc/ipc_methods.h>
 #include <kernel/synch/synch.h>
 #include <task.h>
@@ -255,4 +256,5 @@
 extern int ipc_connect_to_me(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t *,
     sysarg_t *);
+extern int ipc_connect_me(int);
 extern int ipc_connect_me_to(int, sysarg_t, sysarg_t, sysarg_t);
 extern int ipc_connect_me_to_blocking(int, sysarg_t, sysarg_t, sysarg_t);
Index: uspace/lib/c/include/ipc/kbd.h
===================================================================
--- uspace/lib/c/include/ipc/kbd.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/kbd.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,7 +39,8 @@
 
 #include <ipc/common.h>
+#include <ipc/dev_iface.h>
 
 typedef enum {
-	KBD_YIELD = IPC_FIRST_USER_METHOD,
+	KBD_YIELD = DEV_FIRST_CUSTOM_METHOD,
 	KBD_RECLAIM
 } kbd_request_t;
Index: uspace/lib/c/include/ipc/ns.h
===================================================================
--- uspace/lib/c/include/ipc/ns.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/ns.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -33,8 +33,7 @@
  */
 
-#ifndef LIBC_NS_H_
-#define LIBC_NS_H_
+#ifndef LIBC_IPC_NS_H_
+#define LIBC_IPC_NS_H_
 
-#include <sys/types.h>
 #include <ipc/common.h>
 
@@ -46,8 +45,4 @@
 } ns_request_t;
 
-extern int service_register(sysarg_t);
-extern int service_connect(sysarg_t, sysarg_t, sysarg_t);
-extern int service_connect_blocking(sysarg_t, sysarg_t, sysarg_t);
-
 #endif
 
Index: uspace/lib/c/include/ipc/serial_ctl.h
===================================================================
--- uspace/lib/c/include/ipc/serial_ctl.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/serial_ctl.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -32,11 +32,13 @@
 #include <ipc/dev_iface.h>
 
-/** ipc methods for getting/setting serial communication properties
- * 	1st ipc arg: baud rate
- * 	2nd ipc arg: parity
- *	3rd ipc arg: number of bits in one word
- *	4th ipc arg: number of stop bits
+/** IPC methods for getting/setting serial communication properties
+ *
+ * 1st IPC arg: baud rate
+ * 2nd IPC arg: parity
+ * 3rd IPC arg: number of bits in one word
+ * 4th IPC arg: number of stop bits
+ *
  */
-typedef enum {	
+typedef enum {
 	SERIAL_GET_COM_PROPS = DEV_FIRST_CUSTOM_METHOD,
 	SERIAL_SET_COM_PROPS
@@ -48,5 +50,5 @@
 	SERIAL_EVEN_PARITY = 3,
 	SERIAL_MARK_PARITY = 5,
-	SERIAL_SPACE_PARITY = 7	
+	SERIAL_SPACE_PARITY = 7
 } serial_parity_t;
 
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -69,4 +69,5 @@
 	VFS_IN_FSTAT,
 	VFS_IN_CLOSE,
+	VFS_IN_PING,
 	VFS_IN_MOUNT,
 	VFS_IN_UNMOUNT,
Index: uspace/lib/c/include/l18n/langs.h
===================================================================
--- uspace/lib/c/include/l18n/langs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/l18n/langs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2005 Jakub Jermar
+ * 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 libc
+ * @{
+ */
+/** @file
+ * Language and locale ids.
+ */
+
+#ifndef LIBC_L18N_LANGS_H_
+#define LIBC_L18N_LANGS_H_
+
+/** Windows locale IDs.
+ * Codes taken from
+ * Developing International Software For Windows 95 and Windows NT
+ * by Nadine Kano (Microsoft Press).
+ * FIXME: add missing codes.
+ */
+typedef enum {
+	L18N_WIN_LOCALE_AFRIKAANS = 0x0436,
+	/* ... */
+	L18N_WIN_LOCALE_CZECH = 0x0405,
+	/* ... */
+	L18N_WIN_LOCALE_ENGLISH_UNITED_STATES = 0x0409,
+	/* ... */
+	L18N_WIN_LOCALE_SLOVAK = 0x041B,
+	/* ... */
+	L18N_WIN_LOCALE_SPANISH_TRADITIONAL = 0x040A,
+	/* ... */
+	L18N_WIN_LOCALE_ZULU = 0x0435
+} l18_win_locales_t;
+
+const char *str_l18_win_locale(l18_win_locales_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/loader/loader.h
===================================================================
--- uspace/lib/c/include/loader/loader.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/loader/loader.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,9 +40,7 @@
 #include <vfs/vfs.h>
 
-/** Abstraction of a loader connection */
-typedef struct {
-	/** ID of the phone connected to the loader. */
-	int phone_id;
-} loader_t;
+/** Forward declararion */
+struct loader;
+typedef struct loader loader_t;
 
 extern int loader_spawn(const char *);
Index: uspace/lib/c/include/ns.h
===================================================================
--- uspace/lib/c/include/ns.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/ns.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_NS_H_
+#define LIBC_NS_H_
+
+#include <sys/types.h>
+#include <task.h>
+#include <async.h>
+
+extern int service_register(sysarg_t);
+extern async_sess_t *service_connect(exch_mgmt_t, sysarg_t, sysarg_t, sysarg_t);
+extern async_sess_t *service_connect_blocking(exch_mgmt_t, sysarg_t, sysarg_t,
+    sysarg_t);
+
+extern int ns_ping(void);
+extern int ns_intro(task_id_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ns_obsolete.h
===================================================================
--- uspace/lib/c/include/ns_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/ns_obsolete.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006 Ondrej Palkovsky
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_NS_OBSOLETE_H_
+#define LIBC_NS_OBSOLETE_H_
+
+#include <sys/types.h>
+#include <task.h>
+
+extern int service_obsolete_connect(sysarg_t, sysarg_t, sysarg_t);
+extern int service_obsolete_connect_blocking(sysarg_t, sysarg_t,
+    sysarg_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/stdio.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -97,47 +97,7 @@
 };
 
-typedef struct {
-	/** Linked list pointer. */
-	link_t link;
-	
-	/** Underlying file descriptor. */
-	int fd;
-	
-	/** Error indicator. */
-	int error;
-	
-	/** End-of-file indicator. */
-	int eof;
-	
-	/** Klog indicator */
-	int klog;
-	
-	/** Phone to the file provider */
-	int phone;
-
-	/**
-	 * Non-zero if the stream needs sync on fflush(). XXX change
-	 * console semantics so that sync is not needed.
-	 */
-	int need_sync;
-
-	/** Buffering type */
-	enum _buffer_type btype;
-
-	/** Buffer */
-	uint8_t *buf;
-
-	/** Buffer size */
-	size_t buf_size;
-
-	/** Buffer state */
-	enum _buffer_state buf_state;
-
-	/** Buffer I/O pointer */
-	uint8_t *buf_head;
-
-	/** Points to end of occupied space when in read mode. */
-	uint8_t *buf_tail;
-} FILE;
+/** Forward declaration */
+struct _IO_FILE;
+typedef struct _IO_FILE FILE;
 
 extern FILE *stdin;
Index: uspace/lib/c/include/sys/time.h
===================================================================
--- uspace/lib/c/include/sys/time.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/sys/time.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -62,4 +62,6 @@
 extern int gettimeofday(struct timeval *tv, struct timezone *tz);
 
+extern void udelay(useconds_t);
+
 #endif
 
Index: uspace/lib/c/include/udebug.h
===================================================================
--- uspace/lib/c/include/udebug.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/udebug.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,18 +38,23 @@
 #include <kernel/udebug/udebug.h>
 #include <sys/types.h>
+#include <async.h>
 
 typedef sysarg_t thash_t;
 
-int udebug_begin(int);
-int udebug_end(int);
-int udebug_set_evmask(int, udebug_evmask_t);
-int udebug_thread_read(int, void *, size_t , size_t *, size_t *);
-int udebug_name_read(int, void *, size_t, size_t *, size_t *);
-int udebug_areas_read(int, void *, size_t, size_t *, size_t *);
-int udebug_mem_read(int, void *, uintptr_t, size_t);
-int udebug_args_read(int, thash_t, sysarg_t *);
-int udebug_regs_read(int, thash_t, void *);
-int udebug_go(int, thash_t, udebug_event_t *, sysarg_t *, sysarg_t *);
-int udebug_stop(int, thash_t);
+extern int udebug_begin(async_sess_t *);
+extern int udebug_end(async_sess_t *);
+extern int udebug_set_evmask(async_sess_t *, udebug_evmask_t);
+extern int udebug_thread_read(async_sess_t *, void *, size_t , size_t *,
+    size_t *);
+extern int udebug_name_read(async_sess_t *, void *, size_t, size_t *,
+    size_t *);
+extern int udebug_areas_read(async_sess_t *, void *, size_t, size_t *,
+    size_t *);
+extern int udebug_mem_read(async_sess_t *, void *, uintptr_t, size_t);
+extern int udebug_args_read(async_sess_t *, thash_t, sysarg_t *);
+extern int udebug_regs_read(async_sess_t *, thash_t, void *);
+extern int udebug_go(async_sess_t *, thash_t, udebug_event_t *, sysarg_t *,
+    sysarg_t *);
+extern int udebug_stop(async_sess_t *, thash_t);
 
 #endif
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,7 +41,9 @@
 #include <stdio.h>
 
-/**
- * This type is a libc version of the VFS triplet.
- * It uniquely identifies a file system node within a file system instance.
+/** Libc version of the VFS triplet.
+ *
+ * Unique identification of a file system node
+ * within a file system instance.
+ *
  */
 typedef struct {
@@ -58,9 +60,7 @@
 
 extern int open_node(fdi_node_t *, int);
-extern int fd_phone(int);
 extern int fd_node(int, fdi_node_t *);
 
 extern FILE *fopen_node(fdi_node_t *, const char *);
-extern int fphone(FILE *);
 extern int fnode(FILE *, fdi_node_t *);
 
Index: uspace/lib/c/include/vfs/vfs_sess.h
===================================================================
--- uspace/lib/c/include/vfs/vfs_sess.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/c/include/vfs/vfs_sess.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007 Jakub Jermar
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_VFS_SESS_H_
+#define LIBC_VFS_SESS_H_
+
+#include <async.h>
+#include <stdio.h>
+
+extern async_sess_t *fd_session(exch_mgmt_t, int);
+extern async_sess_t *fsession(exch_mgmt_t, FILE *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/clui/tinput.c
===================================================================
--- uspace/lib/clui/tinput.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/clui/tinput.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -54,8 +54,8 @@
 static void tinput_sel_all(tinput_t *);
 static void tinput_sel_delete(tinput_t *);
-static void tinput_key_ctrl(tinput_t *, console_event_t *);
-static void tinput_key_shift(tinput_t *, console_event_t *);
-static void tinput_key_ctrl_shift(tinput_t *, console_event_t *);
-static void tinput_key_unmod(tinput_t *, console_event_t *);
+static void tinput_key_ctrl(tinput_t *, kbd_event_t *);
+static void tinput_key_shift(tinput_t *, kbd_event_t *);
+static void tinput_key_ctrl_shift(tinput_t *, kbd_event_t *);
+static void tinput_key_unmod(tinput_t *, kbd_event_t *);
 static void tinput_pre_seek(tinput_t *, bool);
 static void tinput_post_seek(tinput_t *, bool);
@@ -88,7 +88,7 @@
 	tinput_sel_get_bounds(ti, &sa, &sb);
 	
-	console_set_pos(fphone(stdout), (ti->col0 + start) % ti->con_cols,
+	console_set_pos(ti->console, (ti->col0 + start) % ti->con_cols,
 	    ti->row0 + (ti->col0 + start) / ti->con_cols);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_set_style(ti->console, STYLE_NORMAL);
 	
 	size_t p = start;
@@ -101,6 +101,7 @@
 	
 	if (p < sb) {
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_SELECTED);
+		console_flush(ti->console);
+		console_set_style(ti->console, STYLE_SELECTED);
+		
 		memcpy(dbuf, ti->buffer + p,
 		    (sb - p) * sizeof(wchar_t));
@@ -110,6 +111,6 @@
 	}
 	
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(ti->console);
+	console_set_style(ti->console, STYLE_NORMAL);
 	
 	if (p < ti->nc) {
@@ -123,5 +124,5 @@
 		putchar(' ');
 	
-	fflush(stdout);
+	console_flush(ti->console);
 }
 
@@ -133,5 +134,5 @@
 static void tinput_position_caret(tinput_t *ti)
 {
-	console_set_pos(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols,
+	console_set_pos(ti->console, (ti->col0 + ti->pos) % ti->con_cols,
 	    ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
 }
@@ -516,4 +517,5 @@
 static void tinput_init(tinput_t *ti)
 {
+	ti->console = console_init(stdin, stdout);
 	ti->hnum = 0;
 	ti->hpos = 0;
@@ -533,9 +535,9 @@
 int tinput_read(tinput_t *ti, char **dstr)
 {
-	fflush(stdout);
-	if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)
+	console_flush(ti->console);
+	if (console_get_size(ti->console, &ti->con_cols, &ti->con_rows) != EOK)
 		return EIO;
 	
-	if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)
+	if (console_get_pos(ti->console, &ti->col0, &ti->row0) != EOK)
 		return EIO;
 	
@@ -548,8 +550,8 @@
 	
 	while (!ti->done) {
-		fflush(stdout);
-		
-		console_event_t ev;
-		if (!console_get_event(fphone(stdin), &ev))
+		console_flush(ti->console);
+		
+		kbd_event_t ev;
+		if (!console_get_kbd_event(ti->console, &ev))
 			return EIO;
 		
@@ -596,5 +598,5 @@
 }
 
-static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev)
+static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)
 {
 	switch (ev->key) {
@@ -635,5 +637,5 @@
 }
 
-static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev)
+static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)
 {
 	switch (ev->key) {
@@ -655,5 +657,5 @@
 }
 
-static void tinput_key_shift(tinput_t *ti, console_event_t *ev)
+static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)
 {
 	switch (ev->key) {
@@ -681,5 +683,5 @@
 }
 
-static void tinput_key_unmod(tinput_t *ti, console_event_t *ev)
+static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)
 {
 	switch (ev->key) {
Index: uspace/lib/clui/tinput.h
===================================================================
--- uspace/lib/clui/tinput.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/clui/tinput.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,9 @@
 #define LIBCLUI_TINPUT_H_
 
+#include <stdio.h>
+#include <async.h>
+#include <inttypes.h>
+#include <io/console.h>
+
 #define HISTORY_LEN     10
 #define INPUT_MAX_SIZE  1024
@@ -45,4 +50,7 @@
  */
 typedef struct {
+	/** Console */
+	console_ctrl_t *console;
+	
 	/** Buffer holding text currently being edited */
 	wchar_t buffer[INPUT_MAX_SIZE + 1];
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/drv/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -29,5 +29,5 @@
 
 USPACE_PREFIX = ../..
-EXTRA_CFLAGS = -Iinclude
+EXTRA_CFLAGS = -Iinclude -I$(LIBUSB_PREFIX)/include
 LIBRARY = libdrv
 
@@ -37,5 +37,9 @@
 	generic/log.c \
 	generic/remote_hw_res.c \
-	generic/remote_char_dev.c
+	generic/remote_char_dev.c \
+	generic/remote_usb.c \
+	generic/remote_pci.c \
+	generic/remote_usbhc.c \
+	generic/remote_usbhid.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,9 +41,19 @@
 #include "remote_hw_res.h"
 #include "remote_char_dev.h"
+#include "remote_usb.h"
+#include "remote_usbhc.h"
+#include "remote_usbhid.h"
+#include "remote_pci.h"
+
+#include <stdio.h>
 
 static iface_dipatch_table_t remote_ifaces = {
 	.ifaces = {
 		&remote_hw_res_iface,
-		&remote_char_dev_iface
+		&remote_char_dev_iface,
+		&remote_pci_iface,
+		&remote_usb_iface,
+		&remote_usbhc_iface,
+		&remote_usbhid_iface
 	}
 };
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/drv/generic/driver.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -285,13 +285,12 @@
 	async_answer_0(iid, EOK);
 	
-	bool cont = true;
-	while (cont) {
+	while (true) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			cont = false;
-			continue;
 		case DRIVER_ADD_DEVICE:
 			driver_add_device(callid, &call);
@@ -303,9 +302,9 @@
 }
 
-/**
- * Generic client connection handler both for applications and drivers.
- *
- * @param drv		True for driver client, false for other clients
- *			(applications, services etc.).
+/** Generic client connection handler both for applications and drivers.
+ *
+ * @param drv True for driver client, false for other clients
+ *            (applications, services, etc.).
+ *
  */
 static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv)
@@ -317,5 +316,5 @@
 	devman_handle_t handle = IPC_GET_ARG2(*icall);
 	ddf_fun_t *fun = driver_get_function(&functions, handle);
-
+	
 	if (fun == NULL) {
 		printf("%s: driver_connection_gen error - no function with handle"
@@ -325,5 +324,4 @@
 	}
 	
-	
 	/*
 	 * TODO - if the client is not a driver, check whether it is allowed to
@@ -340,13 +338,11 @@
 		return;
 	
-	while (1) {
+	while (true) {
 		ipc_callid_t callid;
 		ipc_call_t call;
 		callid = async_get_call(&call);
 		sysarg_t method = IPC_GET_IMETHOD(call);
-		int iface_idx;
-		
-		switch  (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* Close device function */
 			if (fun->ops != NULL && fun->ops->close != NULL)
@@ -354,69 +350,68 @@
 			async_answer_0(callid, EOK);
 			return;
-		default:
-			/* convert ipc interface id to interface index */
-			
-			iface_idx = DEV_IFACE_IDX(method);
-			
-			if (!is_valid_iface_idx(iface_idx)) {
-				remote_handler_t *default_handler =
-				    function_get_default_handler(fun);
-				if (default_handler != NULL) {
-					(*default_handler)(fun, callid, &call);
-					break;
-				}
-				
-				/*
-				 * Function has no such interface and
-				 * default handler is not provided.
-				 */
-				printf("%s: driver_connection_gen error - "
-				    "invalid interface id %d.",
-				    driver->name, iface_idx);
-				async_answer_0(callid, ENOTSUP);
-				break;
-			}
-			
-			/* calling one of the function's interfaces */
-			
-			/* Get the interface ops structure. */
-			void *ops = function_get_ops(fun, iface_idx);
-			if (ops == NULL) {
-				printf("%s: driver_connection_gen error - ",
-				    driver->name);
-				printf("Function with handle %" PRIun " has no interface "
-				    "with id %d.\n", handle, iface_idx);
-				async_answer_0(callid, ENOTSUP);
+		}
+		
+		/* Convert ipc interface id to interface index */
+		
+		int iface_idx = DEV_IFACE_IDX(method);
+		
+		if (!is_valid_iface_idx(iface_idx)) {
+			remote_handler_t *default_handler =
+			    function_get_default_handler(fun);
+			if (default_handler != NULL) {
+				(*default_handler)(fun, callid, &call);
 				break;
 			}
 			
 			/*
-			 * Get the corresponding interface for remote request
-			 * handling ("remote interface").
+			 * Function has no such interface and
+			 * default handler is not provided.
 			 */
-			remote_iface_t *rem_iface = get_remote_iface(iface_idx);
-			assert(rem_iface != NULL);
-			
-			/* get the method of the remote interface */
-			sysarg_t iface_method_idx = IPC_GET_ARG1(call);
-			remote_iface_func_ptr_t iface_method_ptr =
-			    get_remote_method(rem_iface, iface_method_idx);
-			if (iface_method_ptr == NULL) {
-				/* The interface has not such method */
-				printf("%s: driver_connection_gen error - "
-				    "invalid interface method.", driver->name);
-				async_answer_0(callid, ENOTSUP);
-				break;
-			}
-			
-			/*
-			 * Call the remote interface's method, which will
-			 * receive parameters from the remote client and it will
-			 * pass it to the corresponding local interface method
-			 * associated with the function by its driver.
-			 */
-			(*iface_method_ptr)(fun, ops, callid, &call);
+			printf("%s: driver_connection_gen error - "
+			    "invalid interface id %d.",
+			    driver->name, iface_idx);
+			async_answer_0(callid, ENOTSUP);
 			break;
 		}
+		
+		/* Calling one of the function's interfaces */
+		
+		/* Get the interface ops structure. */
+		void *ops = function_get_ops(fun, iface_idx);
+		if (ops == NULL) {
+			printf("%s: driver_connection_gen error - ", driver->name);
+			printf("Function with handle %" PRIun " has no interface "
+			    "with id %d.\n", handle, iface_idx);
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+		
+		/*
+		 * Get the corresponding interface for remote request
+		 * handling ("remote interface").
+		 */
+		remote_iface_t *rem_iface = get_remote_iface(iface_idx);
+		assert(rem_iface != NULL);
+		
+		/* get the method of the remote interface */
+		sysarg_t iface_method_idx = IPC_GET_ARG1(call);
+		remote_iface_func_ptr_t iface_method_ptr =
+		    get_remote_method(rem_iface, iface_method_idx);
+		if (iface_method_ptr == NULL) {
+			/* The interface has not such method */
+			printf("%s: driver_connection_gen error - "
+			    "invalid interface method.", driver->name);
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+		
+		/*
+		 * Call the remote interface's method, which will
+		 * receive parameters from the remote client and it will
+		 * pass it to the corresponding local interface method
+		 * associated with the function by its driver.
+		 */
+		(*iface_method_ptr)(fun, ops, callid, &call);
+		break;
 	}
 }
Index: uspace/lib/drv/generic/remote_pci.c
===================================================================
--- uspace/lib/drv/generic/remote_pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/generic/remote_pci.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,179 @@
+/*
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+#include <assert.h>
+#include <async.h>
+#include <errno.h>
+
+#include "pci_dev_iface.h"
+#include "ddf/driver.h"
+
+static void remote_config_space_read_8(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_config_space_read_16(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_config_space_read_32(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
+static void remote_config_space_write_8(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_config_space_write_16(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_config_space_write_32(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB interface operations. */
+static remote_iface_func_ptr_t remote_pci_iface_ops [] = {
+	remote_config_space_read_8,
+	remote_config_space_read_16,
+	remote_config_space_read_32,
+
+	remote_config_space_write_8,
+	remote_config_space_write_16,
+	remote_config_space_write_32
+};
+
+/** Remote USB interface structure.
+ */
+remote_iface_t remote_pci_iface = {
+	.method_count = sizeof(remote_pci_iface_ops) /
+	    sizeof(remote_pci_iface_ops[0]),
+	.methods = remote_pci_iface_ops
+};
+
+void remote_config_space_read_8(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(iface);
+	pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface;
+	if (pci_iface->config_space_read_8 == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	uint32_t address = DEV_IPC_GET_ARG1(*call);
+	uint8_t value;
+	int ret = pci_iface->config_space_read_8(fun, address, &value);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_1(callid, EOK, value);
+	}
+}
+
+void remote_config_space_read_16(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(iface);
+	pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface;
+	if (pci_iface->config_space_read_16 == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	uint32_t address = DEV_IPC_GET_ARG1(*call);
+	uint16_t value;
+	int ret = pci_iface->config_space_read_16(fun, address, &value);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_1(callid, EOK, value);
+	}
+}
+void remote_config_space_read_32(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(iface);
+	pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface;
+	if (pci_iface->config_space_read_32 == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	uint32_t address = DEV_IPC_GET_ARG1(*call);
+	uint32_t value;
+	int ret = pci_iface->config_space_read_32(fun, address, &value);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_1(callid, EOK, value);
+	}
+}
+
+void remote_config_space_write_8(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(iface);
+	pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface;
+	if (pci_iface->config_space_write_8 == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	uint32_t address = DEV_IPC_GET_ARG1(*call);
+	uint8_t value = DEV_IPC_GET_ARG2(*call);
+	int ret = pci_iface->config_space_write_8(fun, address, value);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_0(callid, EOK);
+	}
+}
+
+void remote_config_space_write_16(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(iface);
+	pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface;
+	if (pci_iface->config_space_write_16 == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	uint32_t address = DEV_IPC_GET_ARG1(*call);
+	uint16_t value = DEV_IPC_GET_ARG2(*call);
+	int ret = pci_iface->config_space_write_16(fun, address, value);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_0(callid, EOK);
+	}
+}
+
+void remote_config_space_write_32(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	assert(iface);
+	pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface;
+	if (pci_iface->config_space_write_32 == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	uint32_t address = DEV_IPC_GET_ARG1(*call);
+	uint32_t value = DEV_IPC_GET_ARG2(*call);
+	int ret = pci_iface->config_space_write_32(fun, address, value);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_0(callid, EOK);
+	}
+}
+
+
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/generic/remote_usb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2010 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+
+#include "usb_iface.h"
+#include "ddf/driver.h"
+
+
+static void remote_usb_get_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usb_get_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+//static void remote_usb(device_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB interface operations. */
+static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
+	remote_usb_get_address,
+	remote_usb_get_interface,
+	remote_usb_get_hc_handle
+};
+
+/** Remote USB interface structure.
+ */
+remote_iface_t remote_usb_iface = {
+	.method_count = sizeof(remote_usb_iface_ops) /
+	    sizeof(remote_usb_iface_ops[0]),
+	.methods = remote_usb_iface_ops
+};
+
+
+void remote_usb_get_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+
+	if (usb_iface->get_address == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
+
+	usb_address_t address;
+	int rc = usb_iface->get_address(fun, handle, &address);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+	} else {
+		async_answer_1(callid, EOK, address);
+	}
+}
+
+void remote_usb_get_interface(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+
+	if (usb_iface->get_interface == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
+
+	int iface_no;
+	int rc = usb_iface->get_interface(fun, handle, &iface_no);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+	} else {
+		async_answer_1(callid, EOK, iface_no);
+	}
+}
+
+void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+
+	if (usb_iface->get_hc_handle == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	devman_handle_t handle;
+	int rc = usb_iface->get_hc_handle(fun, &handle);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+	}
+
+	async_answer_1(callid, EOK, (sysarg_t) handle);
+}
+
+
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2010-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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "usbhc_iface.h"
+#include "ddf/driver.h"
+
+#define USB_MAX_PAYLOAD_SIZE 1020
+#define HACK_MAX_PACKET_SIZE 8
+#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
+
+static void remote_usbhc_interrupt_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_interrupt_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_bulk_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_bulk_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+//static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB host controller interface operations. */
+static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
+	remote_usbhc_request_address,
+	remote_usbhc_bind_address,
+	remote_usbhc_find_by_address,
+	remote_usbhc_release_address,
+
+	remote_usbhc_interrupt_out,
+	remote_usbhc_interrupt_in,
+
+	remote_usbhc_bulk_out,
+	remote_usbhc_bulk_in,
+
+	remote_usbhc_control_write,
+	remote_usbhc_control_read,
+
+	remote_usbhc_register_endpoint,
+	remote_usbhc_unregister_endpoint
+};
+
+/** Remote USB host controller interface structure.
+ */
+remote_iface_t remote_usbhc_iface = {
+	.method_count = sizeof(remote_usbhc_iface_ops) /
+	    sizeof(remote_usbhc_iface_ops[0]),
+	.methods = remote_usbhc_iface_ops
+};
+
+typedef struct {
+	ipc_callid_t caller;
+	ipc_callid_t data_caller;
+	void *buffer;
+	void *setup_packet;
+	size_t size;
+} async_transaction_t;
+
+static void async_transaction_destroy(async_transaction_t *trans)
+{
+	if (trans == NULL) {
+		return;
+	}
+
+	if (trans->setup_packet != NULL) {
+		free(trans->setup_packet);
+	}
+	if (trans->buffer != NULL) {
+		free(trans->buffer);
+	}
+
+	free(trans);
+}
+
+static async_transaction_t *async_transaction_create(ipc_callid_t caller)
+{
+	async_transaction_t *trans = malloc(sizeof(async_transaction_t));
+	if (trans == NULL) {
+		return NULL;
+	}
+
+	trans->caller = caller;
+	trans->data_caller = 0;
+	trans->buffer = NULL;
+	trans->setup_packet = NULL;
+	trans->size = 0;
+
+	return trans;
+}
+
+void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->request_address) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
+
+	usb_address_t address;
+	int rc = usb_iface->request_address(fun, speed, &address);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+	} else {
+		async_answer_1(callid, EOK, (sysarg_t) address);
+	}
+}
+
+void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->bind_address) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
+
+	int rc = usb_iface->bind_address(fun, address, handle);
+
+	async_answer_0(callid, rc);
+}
+
+void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->find_by_address) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	devman_handle_t handle;
+	int rc = usb_iface->find_by_address(fun, address, &handle);
+
+	if (rc == EOK) {
+		async_answer_1(callid, EOK, handle);
+	} else {
+		async_answer_0(callid, rc);
+	}
+}
+
+void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->release_address) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+
+	int rc = usb_iface->release_address(fun, address);
+
+	async_answer_0(callid, rc);
+}
+
+
+static void callback_out(ddf_fun_t *fun,
+    int outcome, void *arg)
+{
+	async_transaction_t *trans = (async_transaction_t *)arg;
+
+	async_answer_0(trans->caller, outcome);
+
+	async_transaction_destroy(trans);
+}
+
+static void callback_in(ddf_fun_t *fun,
+    int outcome, size_t actual_size, void *arg)
+{
+	async_transaction_t *trans = (async_transaction_t *)arg;
+
+	if (outcome != EOK) {
+		async_answer_0(trans->caller, outcome);
+		if (trans->data_caller) {
+			async_answer_0(trans->data_caller, EINTR);
+		}
+		async_transaction_destroy(trans);
+		return;
+	}
+
+	trans->size = actual_size;
+
+	if (trans->data_caller) {
+		async_data_read_finalize(trans->data_caller,
+		    trans->buffer, actual_size);
+	}
+
+	async_answer_0(trans->caller, EOK);
+
+	async_transaction_destroy(trans);
+}
+
+/** Process an outgoing transfer (both OUT and SETUP).
+ *
+ * @param device Target device.
+ * @param callid Initiating caller.
+ * @param call Initiating call.
+ * @param transfer_func Transfer function (might be NULL).
+ */
+static void remote_usbhc_out_transfer(ddf_fun_t *fun,
+    ipc_callid_t callid, ipc_call_t *call,
+    usbhc_iface_transfer_out_t transfer_func)
+{
+	if (!transfer_func) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	size_t len = 0;
+	void *buffer = NULL;
+
+	int rc = async_data_write_accept(&buffer, false,
+	    1, USB_MAX_PAYLOAD_SIZE,
+	    0, &len);
+
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		if (buffer != NULL) {
+			free(buffer);
+		}
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	trans->buffer = buffer;
+	trans->size = len;
+
+	rc = transfer_func(fun, target,
+	    buffer, len,
+	    callback_out, trans);
+
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+/** Process an incoming transfer.
+ *
+ * @param device Target device.
+ * @param callid Initiating caller.
+ * @param call Initiating call.
+ * @param transfer_func Transfer function (might be NULL).
+ */
+static void remote_usbhc_in_transfer(ddf_fun_t *fun,
+    ipc_callid_t callid, ipc_call_t *call,
+    usbhc_iface_transfer_in_t transfer_func)
+{
+	if (!transfer_func) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	size_t len;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &len)) {
+		async_answer_0(callid, EPARTY);
+		return;
+	}
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+	trans->data_caller = data_callid;
+	trans->buffer = malloc(len);
+	trans->size = len;
+
+	int rc = transfer_func(fun, target,
+	    trans->buffer, len,
+	    callback_in, trans);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_out_transfer(fun, callid, call,
+	    usb_iface->interrupt_out);
+}
+
+void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_in_transfer(fun, callid, call,
+	    usb_iface->interrupt_in);
+}
+
+void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_out_transfer(fun, callid, call,
+	    usb_iface->bulk_out);
+}
+
+void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	return remote_usbhc_in_transfer(fun, callid, call,
+	    usb_iface->bulk_in);
+}
+
+void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
+ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	if (!usb_iface->control_write) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+	size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
+
+	int rc;
+
+	void *setup_packet = NULL;
+	void *data_buffer = NULL;
+	size_t setup_packet_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (data_buffer_len > 0) {
+		rc = async_data_write_accept(&data_buffer, false,
+		    1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			free(setup_packet);
+			return;
+		}
+	}
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(callid, ENOMEM);
+		free(setup_packet);
+		free(data_buffer);
+		return;
+	}
+	trans->setup_packet = setup_packet;
+	trans->buffer = data_buffer;
+	trans->size = data_buffer_len;
+
+	rc = usb_iface->control_write(fun, target,
+	    setup_packet, setup_packet_len,
+	    data_buffer, data_buffer_len,
+	    callback_out, trans);
+
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+
+void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
+ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	assert(usb_iface != NULL);
+
+	if (!usb_iface->control_read) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_target_t target = {
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
+	};
+
+	int rc;
+
+	void *setup_packet = NULL;
+	size_t setup_packet_len = 0;
+	size_t data_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(callid, EPARTY);
+		free(setup_packet);
+		return;
+	}
+
+	async_transaction_t *trans = async_transaction_create(callid);
+	if (trans == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		free(setup_packet);
+		return;
+	}
+	trans->data_caller = data_callid;
+	trans->setup_packet = setup_packet;
+	trans->size = data_len;
+	trans->buffer = malloc(data_len);
+	if (trans->buffer == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		async_transaction_destroy(trans);
+		return;
+	}
+
+	rc = usb_iface->control_read(fun, target,
+	    setup_packet, setup_packet_len,
+	    trans->buffer, trans->size,
+	    callback_in, trans);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(callid, rc);
+		async_transaction_destroy(trans);
+	}
+}
+
+
+void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->register_endpoint) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
+#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
+#define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
+#define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
+	type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
+#define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
+	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
+
+	_INIT_FROM_HIGH_DATA2(usb_address_t, address, 1);
+	_INIT_FROM_LOW_DATA2(usb_endpoint_t, endpoint, 1);
+
+	_INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
+	_INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
+	_INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
+
+	_INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
+	_INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
+
+#undef _INIT_FROM_HIGH_DATA2
+#undef _INIT_FROM_LOW_DATA2
+#undef _INIT_FROM_HIGH_DATA3
+#undef _INIT_FROM_MIDDLE_DATA3
+#undef _INIT_FROM_LOW_DATA3
+
+	int rc = usb_iface->register_endpoint(fun, address, speed, endpoint,
+	    transfer_type, direction, max_packet_size, interval);
+
+	async_answer_0(callid, rc);
+}
+
+
+void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->unregister_endpoint) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG2(*call);
+	usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG3(*call);
+
+	int rc = usb_iface->unregister_endpoint(fun,
+	    address, endpoint, direction);
+
+	async_answer_0(callid, rc);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/generic/remote_usbhid.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhid.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/generic/remote_usbhid.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2010-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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "usbhid_iface.h"
+#include "ddf/driver.h"
+
+static void remote_usbhid_get_event_length(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhid_get_event(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhid_get_report_descriptor_length(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhid_get_report_descriptor(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+// static void remote_usbhid_(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB HID interface operations. */
+static remote_iface_func_ptr_t remote_usbhid_iface_ops [] = {
+	remote_usbhid_get_event_length,
+	remote_usbhid_get_event,
+	remote_usbhid_get_report_descriptor_length,
+	remote_usbhid_get_report_descriptor
+};
+
+/** Remote USB HID interface structure.
+ */
+remote_iface_t remote_usbhid_iface = {
+	.method_count = sizeof(remote_usbhid_iface_ops) /
+	    sizeof(remote_usbhid_iface_ops[0]),
+	.methods = remote_usbhid_iface_ops
+};
+
+//usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+
+void remote_usbhid_get_event_length(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	printf("remote_usbhid_get_event_length()\n");
+	
+	usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
+
+	if (!hid_iface->get_event_length) {
+		printf("Get event length not set!\n");
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	size_t len = hid_iface->get_event_length(fun);
+//	if (len == 0) {
+//		len = EEMPTY;
+//	}
+	async_answer_1(callid, EOK, len);
+	
+//	if (len < 0) {
+//		async_answer_0(callid, len);
+//	} else {
+//		async_answer_1(callid, EOK, len);
+//	}
+}
+
+void remote_usbhid_get_event(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
+
+	if (!hid_iface->get_event) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	unsigned int flags = DEV_IPC_GET_ARG1(*call);
+
+	size_t len;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &len)) {
+		async_answer_0(callid, EPARTY);
+		return;
+	}
+//	/* Check that length is even number. Truncate otherwise. */
+//	if ((len % 2) == 1) {
+//		len--;
+//	}
+	if (len == 0) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	int rc;
+
+	uint8_t *data = malloc(len);
+	if (data == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	size_t act_length;
+	int event_nr;
+	rc = hid_iface->get_event(fun, data, len, &act_length, &event_nr, flags);
+	if (rc != EOK) {
+		free(data);
+		async_answer_0(data_callid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+	if (act_length >= len) {
+		/* This shall not happen. */
+		// FIXME: how about an assert here?
+		act_length = len;
+	}
+
+	async_data_read_finalize(data_callid, data, act_length);
+
+	free(data);
+
+	async_answer_1(callid, EOK, event_nr);
+}
+
+void remote_usbhid_get_report_descriptor_length(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
+
+	if (!hid_iface->get_report_descriptor_length) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	size_t len = hid_iface->get_report_descriptor_length(fun);
+	async_answer_1(callid, EOK, (sysarg_t) len);
+}
+
+void remote_usbhid_get_report_descriptor(ddf_fun_t *fun, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
+
+	if (!hid_iface->get_report_descriptor) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	size_t len;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &len)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (len == 0) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	uint8_t *descriptor = malloc(len);
+	if (descriptor == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	size_t act_len = 0;
+	int rc = hid_iface->get_report_descriptor(fun, descriptor, len,
+	    &act_len);
+	if (act_len > len) {
+		rc = ELIMIT;
+	}
+	if (rc != EOK) {
+		free(descriptor);
+		async_answer_0(data_callid, rc);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, descriptor, act_len);
+	async_answer_0(callid, EOK);
+
+	free(descriptor);
+}
+
+
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,7 +37,7 @@
 #define DDF_DRIVER_H_
 
+#include <async.h>
 #include <ipc/devman.h>
 #include <ipc/dev_iface.h>
-
 #include "../dev_iface.h"
 
@@ -83,8 +83,8 @@
 	
 	/**
-	 * Phone to the parent device driver (if it is different from this
+	 * Session to the parent device driver (if it is different from this
 	 * driver)
 	 */
-	int parent_phone;
+	async_sess_t *parent_sess;
 	
 	/** Device name */
Index: uspace/lib/drv/include/pci_dev_iface.h
===================================================================
--- uspace/lib/drv/include/pci_dev_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/pci_dev_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,68 @@
+/*
+ * 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 libdrv
+ * @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief PCI device interface definition.
+ */
+
+#ifndef LIBDRV_PCI_DEV_IFACE_H_
+#define LIBDRV_PCI_DEV_IFACE_H_
+
+#include "ddf/driver.h"
+
+typedef enum {
+	IPC_M_CONFIG_SPACE_READ_8,
+	IPC_M_CONFIG_SPACE_READ_16,
+	IPC_M_CONFIG_SPACE_READ_32,
+
+	IPC_M_CONFIG_SPACE_WRITE_8,
+	IPC_M_CONFIG_SPACE_WRITE_16,
+	IPC_M_CONFIG_SPACE_WRITE_32
+} pci_dev_iface_funcs_t;
+
+/** PCI device communication interface. */
+typedef struct {
+	int (*config_space_read_8)(ddf_fun_t *, uint32_t address, uint8_t *data);
+	int (*config_space_read_16)(ddf_fun_t *, uint32_t address, uint16_t *data);
+	int (*config_space_read_32)(ddf_fun_t *, uint32_t address, uint32_t *data);
+
+	int (*config_space_write_8)(ddf_fun_t *, uint32_t address, uint8_t data);
+	int (*config_space_write_16)(ddf_fun_t *, uint32_t address, uint16_t data);
+	int (*config_space_write_32)(ddf_fun_t *, uint32_t address, uint32_t data);
+} pci_dev_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/include/remote_pci.h
===================================================================
--- uspace/lib/drv/include/remote_pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/remote_pci.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_PCI_H_
+#define LIBDRV_REMOTE_PCI_H_
+
+extern remote_iface_t remote_pci_iface;
+
+#endif
+
+/**
+ * @}
+ */
+
Index: uspace/lib/drv/include/remote_usb.h
===================================================================
--- uspace/lib/drv/include/remote_usb.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/remote_usb.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_USB_H_
+#define LIBDRV_REMOTE_USB_H_
+
+extern remote_iface_t remote_usb_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_usbhc.h
===================================================================
--- uspace/lib/drv/include/remote_usbhc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/remote_usbhc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_USBHC_H_
+#define LIBDRV_REMOTE_USBHC_H_
+
+extern remote_iface_t remote_usbhc_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_usbhid.h
===================================================================
--- uspace/lib/drv/include/remote_usbhid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/remote_usbhid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,44 @@
+/*
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_USBHID_H_
+#define LIBDRV_REMOTE_USBHID_H_
+
+extern remote_iface_t remote_usbhid_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/usb_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2010 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 libdrv
+ * @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief USB interface definition.
+ */
+
+#ifndef LIBDRV_USB_IFACE_H_
+#define LIBDRV_USB_IFACE_H_
+
+#include "ddf/driver.h"
+#include <usb/usb.h>
+typedef enum {
+	/** Tell USB address assigned to device.
+	 * Parameters:
+	 * - devman handle id
+	 * Answer:
+	 * - EINVAL - unknown handle or handle not managed by this driver
+	 * - ENOTSUP - operation not supported (shall not happen)
+	 * - arbitrary error code if returned by remote implementation
+	 * - EOK - handle found, first parameter contains the USB address
+	 *
+	 * The handle must be the one used for binding USB address with
+	 * it (IPC_M_USBHC_BIND_ADDRESS), otherwise the host controller
+	 * (that this request would eventually reach) would not be able
+	 * to find it.
+	 * The problem is that this handle is actually assigned to the
+	 * function inside driver of the parent device (usually hub driver).
+	 * To bypass this problem, the initial caller specify handle as
+	 * zero and the first parent assigns the actual value.
+	 * See usb_iface_get_address_hub_child_impl() implementation
+	 * that could be assigned to device ops of a child device of in a
+	 * hub driver.
+	 * For example, the USB multi interface device driver (MID)
+	 * passes this initial zero without any modification because the
+	 * handle must be resolved by its parent.
+	 */
+	IPC_M_USB_GET_ADDRESS,
+
+	/** Tell interface number given device can use.
+	 * Parameters
+	 * - devman handle id of the device
+	 * Answer:
+	 * - ENOTSUP - operation not supported (can also mean any interface)
+	 * - EOK - operation okay, first parameter contains interface number
+	 */
+	IPC_M_USB_GET_INTERFACE,
+
+	/** Tell devman handle of device host controller.
+	 * Parameters:
+	 * - none
+	 * Answer:
+	 * - EOK - request processed without errors
+	 * - ENOTSUP - this indicates invalid USB driver
+	 * Parameters of the answer:
+	 * - devman handle of HC caller is physically connected to
+	 */
+	IPC_M_USB_GET_HOST_CONTROLLER_HANDLE
+} usb_iface_funcs_t;
+
+/** USB device communication interface. */
+typedef struct {
+	int (*get_address)(ddf_fun_t *, devman_handle_t, usb_address_t *);
+	int (*get_interface)(ddf_fun_t *, devman_handle_t, int *);
+	int (*get_hc_handle)(ddf_fun_t *, devman_handle_t *);
+} usb_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2010 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 libdrv
+ * @addtogroup usb
+ * @{
+ */
+/** @file
+ * @brief USB host controller interface definition.
+ */
+
+#ifndef LIBDRV_USBHC_IFACE_H_
+#define LIBDRV_USBHC_IFACE_H_
+
+#include "ddf/driver.h"
+#include <usb/usb.h>
+#include <bool.h>
+
+
+/** IPC methods for communication with HC through DDF interface.
+ *
+ * Notes for async methods:
+ *
+ * Methods for sending data to device (OUT transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
+ * always use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ *   - argument #3 is max packet size of the endpoint
+ * - this call is immediately followed by IPC data write (from caller)
+ * - the initial call (and the whole transaction) is answer after the
+ *   transaction is scheduled by the HC and acknowledged by the device
+ *   or immediately after error is detected
+ * - the answer carries only the error code
+ *
+ * Methods for retrieving data from device (IN transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_IN -
+ * also use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ * - this call is immediately followed by IPC data read (async version)
+ * - the call is not answered until the device returns some data (or until
+ *   error occurs)
+ *
+ * Some special methods (NO-DATA transactions) do not send any data. These
+ * might behave as both OUT or IN transactions because communication parts
+ * where actual buffers are exchanged are omitted.
+ **
+ * For all these methods, wrap functions exists. Important rule: functions
+ * for IN transactions have (as parameters) buffers where retrieved data
+ * will be stored. These buffers must be already allocated and shall not be
+ * touch until the transaction is completed
+ * (e.g. not before calling usb_wait_for() with appropriate handle).
+ * OUT transactions buffers can be freed immediately after call is dispatched
+ * (i.e. after return from wrapping function).
+ *
+ */
+typedef enum {
+	/** Asks for address assignment by host controller.
+	 * Answer:
+	 * - ELIMIT - host controller run out of address
+	 * - EOK - address assigned
+	 * Answer arguments:
+	 * - assigned address
+	 *
+	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
+	 */
+	IPC_M_USBHC_REQUEST_ADDRESS,
+
+	/** Bind USB address with devman handle.
+	 * Parameters:
+	 * - USB address
+	 * - devman handle
+	 * Answer:
+	 * - EOK - address binded
+	 * - ENOENT - address is not in use
+	 */
+	IPC_M_USBHC_BIND_ADDRESS,
+
+	/** Get handle binded with given USB address.
+	 * Parameters
+	 * - USB address
+	 * Answer:
+	 * - EOK - address binded, first parameter is the devman handle
+	 * - ENOENT - address is not in use at the moment
+	 */
+	IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
+
+	/** Release address in use.
+	 * Arguments:
+	 * - address to be released
+	 * Answer:
+	 * - ENOENT - address not in use
+	 * - EPERM - trying to release default USB address
+	 */
+	IPC_M_USBHC_RELEASE_ADDRESS,
+
+
+	/** Send interrupt data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_INTERRUPT_OUT,
+
+	/** Get interrupt data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_INTERRUPT_IN,
+
+	/** Send bulk data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_BULK_OUT,
+
+	/** Get bulk data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_BULK_IN,
+
+	/** Issue control WRITE transfer.
+	 * See explanation at usb_iface_funcs_t (OUT transaction) for
+	 * call parameters.
+	 * This call is immediately followed by two IPC data writes
+	 * from the caller (setup packet and actual data).
+	 */
+	IPC_M_USBHC_CONTROL_WRITE,
+
+	/** Issue control READ transfer.
+	 * See explanation at usb_iface_funcs_t (IN transaction) for
+	 * call parameters.
+	 * This call is immediately followed by IPC data write from the caller
+	 * (setup packet) and IPC data read (buffer that was read).
+	 */
+	IPC_M_USBHC_CONTROL_READ,
+
+	/** Register endpoint attributes at host controller.
+	 * This is used to reserve portion of USB bandwidth.
+	 * When speed is invalid, speed of the device is used.
+	 * Parameters:
+	 * - USB address + endpoint number
+	 *   - packed as ADDR << 16 + EP
+	 * - speed + transfer type + direction
+	 *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
+	 * - maximum packet size + interval (in milliseconds)
+	 *   - packed as MPS << 16 + INT
+	 * Answer:
+	 * - EOK - reservation successful
+	 * - ELIMIT - not enough bandwidth to satisfy the request
+	 */
+	IPC_M_USBHC_REGISTER_ENDPOINT,
+
+	/** Revert endpoint registration.
+	 * Parameters:
+	 * - USB address
+	 * - endpoint number
+	 * - data direction
+	 * Answer:
+	 * - EOK - endpoint unregistered
+	 * - ENOENT - unknown endpoint
+	 */
+	IPC_M_USBHC_UNREGISTER_ENDPOINT
+} usbhc_iface_funcs_t;
+
+/** Callback for outgoing transfer. */
+typedef void (*usbhc_iface_transfer_out_callback_t)(ddf_fun_t *,
+    int, void *);
+
+/** Callback for incoming transfer. */
+typedef void (*usbhc_iface_transfer_in_callback_t)(ddf_fun_t *,
+    int, size_t, void *);
+
+
+/** Out transfer processing function prototype. */
+typedef int (*usbhc_iface_transfer_out_t)(ddf_fun_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_out_callback_t, void *);
+
+/** Setup transfer processing function prototype. @deprecated */
+typedef usbhc_iface_transfer_out_t usbhc_iface_transfer_setup_t;
+
+/** In transfer processing function prototype. */
+typedef int (*usbhc_iface_transfer_in_t)(ddf_fun_t *, usb_target_t,
+    void *, size_t,
+    usbhc_iface_transfer_in_callback_t, void *);
+
+/** USB host controller communication interface. */
+typedef struct {
+	int (*request_address)(ddf_fun_t *, usb_speed_t, usb_address_t *);
+	int (*bind_address)(ddf_fun_t *, usb_address_t, devman_handle_t);
+	int (*find_by_address)(ddf_fun_t *, usb_address_t, devman_handle_t *);
+	int (*release_address)(ddf_fun_t *, usb_address_t);
+
+	int (*register_endpoint)(ddf_fun_t *,
+	    usb_address_t, usb_speed_t, usb_endpoint_t,
+	    usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
+	int (*unregister_endpoint)(ddf_fun_t *, usb_address_t, usb_endpoint_t,
+	    usb_direction_t);
+
+	usbhc_iface_transfer_out_t interrupt_out;
+	usbhc_iface_transfer_in_t interrupt_in;
+
+	usbhc_iface_transfer_out_t bulk_out;
+	usbhc_iface_transfer_in_t bulk_in;
+
+	int (*control_write)(ddf_fun_t *, usb_target_t,
+	    void *, size_t, void *, size_t,
+	    usbhc_iface_transfer_out_callback_t, void *);
+
+	int (*control_read)(ddf_fun_t *, usb_target_t,
+	    void *, size_t, void *, size_t,
+	    usbhc_iface_transfer_in_callback_t, void *);
+} usbhc_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usbhid_iface.h
===================================================================
--- uspace/lib/drv/include/usbhid_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/drv/include/usbhid_iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2010 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 libdrv
+ * @{
+ */
+/** @file
+ * USB HID interface definition.
+ */
+
+#ifndef LIBDRV_USBHID_IFACE_H_
+#define LIBDRV_USBHID_IFACE_H_
+
+#include "ddf/driver.h"
+#include <usb/usb.h>
+
+/** IPC methods for USB HID device interface. */
+typedef enum {
+	/** Get number of events reported in single burst.
+	 * Parameters: none
+	 * Answer:
+	 * - Size of one report in bytes.
+	 */
+	IPC_M_USBHID_GET_EVENT_LENGTH,
+	/** Get single event from the HID device.
+	 * The word single refers to set of individual events that were
+	 * available at particular point in time.
+	 * Parameters:
+	 * - flags
+	 * The call is followed by data read expecting two concatenated
+	 * arrays.
+	 * Answer:
+	 * - EOK - events returned
+	 * - EAGAIN - no event ready (only in non-blocking mode)
+	 *
+	 * It is okay if the client requests less data. Extra data must
+	 * be truncated by the driver.
+	 *
+	 * @todo Change this comment.
+	 */
+	IPC_M_USBHID_GET_EVENT,
+	
+	/** Get the size of the report descriptor from the HID device.
+	 *
+	 * Parameters:
+	 * - none
+	 * Answer:
+	 * - EOK - method is implemented (expected always)
+	 * Parameters of the answer:
+	 * - Size of the report in bytes.
+	 */
+	IPC_M_USBHID_GET_REPORT_DESCRIPTOR_LENGTH,
+	
+	/** Get the report descriptor from the HID device.
+	 *
+	 * Parameters:
+	 * - none
+	 * The call is followed by data read expecting the descriptor itself.
+	 * Answer:
+	 * - EOK - report descriptor returned.
+	 */
+	IPC_M_USBHID_GET_REPORT_DESCRIPTOR
+} usbhid_iface_funcs_t;
+
+/** USB HID interface flag - return immediately if no data are available. */
+#define USBHID_IFACE_FLAG_NON_BLOCKING (1 << 0)
+
+/** USB HID device communication interface. */
+typedef struct {
+	/** Get size of the event in bytes.
+	 *
+	 * @param[in] fun DDF function answering the request.
+	 * @return Size of the event in bytes.
+	 */
+	size_t (*get_event_length)(ddf_fun_t *fun);
+
+	/** Get single event from the HID device.
+	 *
+	 * @param[in] fun DDF function answering the request.
+	 * @param[out] buffer Buffer with raw data from the device.
+	 * @param[out] act_size Actual number of returned events.
+	 * @param[in] flags Flags (see USBHID_IFACE_FLAG_*).
+	 * @return Error code.
+	 */
+	int (*get_event)(ddf_fun_t *fun, uint8_t *buffer, size_t size,
+	    size_t *act_size, int *event_nr, unsigned int flags);
+	
+	/** Get size of the report descriptor in bytes.
+	 *
+	 * @param[in] fun DDF function answering the request.
+	 * @return Size of the report descriptor in bytes.
+	 */
+	size_t (*get_report_descriptor_length)(ddf_fun_t *fun);
+	
+	/** Get the report descriptor from the HID device.
+	 *
+	 * @param[in] fun DDF function answering the request.
+	 * @param[out] desc Buffer with the report descriptor.
+	 * @param[in] size Size of the allocated @p desc buffer.
+	 * @param[out] act_size Actual size of the report descriptor returned.
+	 * @return Error code.
+	 */
+	int (*get_report_descriptor)(ddf_fun_t *fun, uint8_t *desc, 
+	    size_t size, size_t *act_size);
+} usbhid_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/ext2/Makefile
===================================================================
--- uspace/lib/ext2/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2010 Martin Sucha
+# 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 = ../..
+LIBRARY = libext2
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a
+
+SOURCES = \
+	libext2_filesystem.c \
+	libext2_superblock.c \
+	libext2_block_group.c \
+	libext2_inode.c \
+	libext2_directory.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/ext2/libext2.h
===================================================================
--- uspace/lib/ext2/libext2.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_H_
+#define LIBEXT2_LIBEXT2_H_
+
+#include "libext2_superblock.h"
+#include "libext2_block_group.h"
+#include "libext2_inode.h"
+#include "libext2_filesystem.h"
+#include "libext2_directory.h"
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_block_group.c
===================================================================
--- uspace/lib/ext2/libext2_block_group.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_block_group.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include "libext2_block_group.h"
+#include <byteorder.h>
+
+/**
+ * Get block ID corresponding to the block bitmap of this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+uint32_t ext2_block_group_get_block_bitmap_block(ext2_block_group_t *bg)
+{
+	return uint32_t_le2host(bg->block_bitmap_block);
+}
+
+/**
+ * Get block ID corresponding to the inode bitmap of this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+uint32_t ext2_block_group_get_inode_bitmap_block(ext2_block_group_t *bg)
+{
+	return uint32_t_le2host(bg->inode_bitmap_block);
+}
+
+/**
+ * Get block ID of first block in inode table
+ * 
+ * @param bg pointer to block group descriptor
+ */
+uint32_t ext2_block_group_get_inode_table_first_block(ext2_block_group_t *bg)
+{
+	return uint32_t_le2host(bg->inode_table_first_block);
+}
+
+/**
+ * Get amount of free blocks in this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+uint16_t ext2_block_group_get_free_block_count(ext2_block_group_t *bg)
+{
+	return uint16_t_le2host(bg->free_block_count);
+}
+
+/**
+ * Set amount of free blocks in this block group
+ * 
+ * @param bg pointer to block group descriptor
+ * @param val new value
+ */
+void ext2_block_group_set_free_block_count(ext2_block_group_t *bg,
+	uint16_t val)
+{
+	bg->free_block_count = host2uint16_t_le(val);
+}
+
+/**
+ * Get amount of free inodes in this block group
+ * 
+ * @param bg pointer to block group descriptor
+ */
+uint16_t ext2_block_group_get_free_inode_count(ext2_block_group_t *bg)
+{
+	return uint16_t_le2host(bg->free_inode_count);
+}
+
+/**
+ * Get amount of inodes allocated for directories
+ * 
+ * @param bg pointer to block group descriptor
+ */
+uint16_t ext2_block_group_get_directory_inode_count(ext2_block_group_t *bg)
+{
+	return uint16_t_le2host(bg->directory_inode_count);
+}
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_block_group.h
===================================================================
--- uspace/lib/ext2/libext2_block_group.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_block_group.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_BLOCK_GROUP_H_
+#define LIBEXT2_LIBEXT2_BLOCK_GROUP_H_
+
+#include <libblock.h>
+
+typedef struct ext2_block_group {
+	uint32_t block_bitmap_block; // Block ID for block bitmap
+	uint32_t inode_bitmap_block; // Block ID for inode bitmap
+	uint32_t inode_table_first_block; // Block ID of first block of inode table 
+	uint16_t free_block_count; // Count of free blocks
+	uint16_t free_inode_count; // Count of free inodes
+	uint16_t directory_inode_count; // Number of inodes allocated to directories
+} ext2_block_group_t;
+
+typedef struct ext2_block_group_ref {
+	block_t *block; // Reference to a block containing this block group descr
+	ext2_block_group_t *block_group;
+} ext2_block_group_ref_t;
+
+#define EXT2_BLOCK_GROUP_DESCRIPTOR_SIZE 32
+
+extern uint32_t	ext2_block_group_get_block_bitmap_block(ext2_block_group_t *);
+extern uint32_t	ext2_block_group_get_inode_bitmap_block(ext2_block_group_t *);
+extern uint32_t	ext2_block_group_get_inode_table_first_block(ext2_block_group_t *);
+extern uint16_t	ext2_block_group_get_free_block_count(ext2_block_group_t *);
+extern uint16_t	ext2_block_group_get_free_inode_count(ext2_block_group_t *);
+extern uint16_t	ext2_block_group_get_directory_inode_count(ext2_block_group_t *);
+
+extern void	ext2_block_group_set_free_block_count(ext2_block_group_t *, uint16_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_directory.c
===================================================================
--- uspace/lib/ext2/libext2_directory.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_directory.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include "libext2_directory.h"
+#include <byteorder.h>
+#include <errno.h>
+#include <assert.h>
+
+static int ext2_directory_iterator_set(ext2_directory_iterator_t *it,
+    uint32_t block_size);
+
+/**
+ * Get inode number for the directory entry
+ * 
+ * @param de pointer to linked list directory entry
+ */
+uint32_t ext2_directory_entry_ll_get_inode(ext2_directory_entry_ll_t *de)
+{
+	return uint32_t_le2host(de->inode);
+}
+
+/**
+ * Get length of the directory entry
+ * 
+ * @param de pointer to linked list directory entry
+ */
+uint16_t ext2_directory_entry_ll_get_entry_length(
+    ext2_directory_entry_ll_t *de)
+{
+	return uint16_t_le2host(de->entry_length);
+}
+
+/**
+ * Get length of the name stored in the directory entry
+ * 
+ * @param de pointer to linked list directory entry
+ */
+uint16_t ext2_directory_entry_ll_get_name_length(
+    ext2_superblock_t *sb, ext2_directory_entry_ll_t *de)
+{
+	if (ext2_superblock_get_rev_major(sb) == 0 &&
+	    ext2_superblock_get_rev_minor(sb) < 5) {
+		return ((uint16_t)de->name_length_high) << 8 | 
+		    ((uint16_t)de->name_length);
+	}
+	return de->name_length;
+}
+
+/**
+ * Initialize a directory iterator
+ * 
+ * @param it pointer to iterator to initialize
+ * @param fs pointer to filesystem structure
+ * @param inode pointer to inode reference structure
+ * @return EOK on success or negative error code on failure
+ */
+int ext2_directory_iterator_init(ext2_directory_iterator_t *it,
+    ext2_filesystem_t *fs, ext2_inode_ref_t *inode_ref)
+{
+	int rc;
+	uint32_t block_id;
+	uint32_t block_size;
+	
+	it->inode_ref = inode_ref;
+	it->fs = fs;
+	
+	/* Get the first data block, so we can get the first entry */
+	rc = ext2_filesystem_get_inode_data_block_index(fs, inode_ref->inode, 0, 
+	    &block_id);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	rc = block_get(&it->current_block, fs->device, block_id, 0);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	block_size = ext2_superblock_get_block_size(fs->superblock);
+	
+	it->current_offset = 0;	
+	return ext2_directory_iterator_set(it, block_size);
+}
+
+/**
+ * Advance the directory iterator to the next entry
+ * 
+ * @param it pointer to iterator to initialize
+ * @return EOK on success or negative error code on failure
+ */
+int ext2_directory_iterator_next(ext2_directory_iterator_t *it)
+{
+	int rc;
+	uint16_t skip;
+	uint64_t size;
+	aoff64_t current_block_idx;
+	aoff64_t next_block_idx;
+	uint32_t next_block_phys_idx;
+	uint32_t block_size;
+	
+	assert(it->current != NULL);
+	
+	skip = ext2_directory_entry_ll_get_entry_length(it->current);
+	size = ext2_inode_get_size(it->fs->superblock, it->inode_ref->inode);
+	
+	/* Are we at the end? */
+	if (it->current_offset + skip >= size) {
+		rc = block_put(it->current_block);
+		it->current_block = NULL;
+		it->current = NULL;
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		it->current_offset += skip;
+		return EOK;
+	}
+	
+	block_size = ext2_superblock_get_block_size(it->fs->superblock);
+	current_block_idx = it->current_offset / block_size;
+	next_block_idx = (it->current_offset + skip) / block_size;
+	
+	/* If we are moving accross block boundary,
+	 * we need to get another block
+	 */
+	if (current_block_idx != next_block_idx) {
+		rc = block_put(it->current_block);
+		it->current_block = NULL;
+		it->current = NULL;
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		rc = ext2_filesystem_get_inode_data_block_index(it->fs,
+		    it->inode_ref->inode, next_block_idx, &next_block_phys_idx);
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		rc = block_get(&it->current_block, it->fs->device, next_block_phys_idx,
+		    BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			it->current_block = NULL;
+			return rc;
+		}
+	}
+	
+	it->current_offset += skip;
+	return ext2_directory_iterator_set(it, block_size);
+}
+
+static int ext2_directory_iterator_set(ext2_directory_iterator_t *it,
+    uint32_t block_size)
+{
+	uint32_t offset_in_block = it->current_offset % block_size;
+	
+	it->current = NULL;
+	
+	/* Ensure proper alignment */
+	if ((offset_in_block % 4) != 0) {
+		return EIO;
+	}
+	
+	/* Ensure that the core of the entry does not overflow the block */
+	if (offset_in_block > block_size - 8) {
+		return EIO;
+	}
+	
+	ext2_directory_entry_ll_t *entry = it->current_block->data + offset_in_block;
+	
+	/* Ensure that the whole entry does not overflow the block */
+	uint16_t length = ext2_directory_entry_ll_get_entry_length(entry);
+	if (offset_in_block + length > block_size) {
+		return EIO;
+	}
+	
+	/* Ensure the name length is not too large */
+	if (ext2_directory_entry_ll_get_name_length(it->fs->superblock, 
+	    entry) > length-8) {
+		return EIO;
+	}
+	
+	it->current = entry;
+	return EOK;
+}
+
+/**
+ * Release all resources asociated with the directory iterator
+ * 
+ * @param it pointer to iterator to initialize
+ * @return EOK on success or negative error code on failure
+ */
+int ext2_directory_iterator_fini(ext2_directory_iterator_t *it)
+{
+	int rc;
+	
+	it->fs = NULL;
+	it->inode_ref = NULL;
+	it->current = NULL;
+	
+	if (it->current_block) {
+		rc = block_put(it->current_block);
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+	
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_directory.h
===================================================================
--- uspace/lib/ext2/libext2_directory.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_directory.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_DIRECTORY_H_
+#define LIBEXT2_LIBEXT2_DIRECTORY_H_
+
+#include <libblock.h>
+#include "libext2_filesystem.h"
+#include "libext2_inode.h"
+
+/**
+ * Linked list directory entry structure
+ */
+typedef struct ext2_directory_entry_ll {
+	uint32_t inode; // Inode for the entry
+	uint16_t entry_length; // Distance to the next directory entry
+	uint8_t name_length; // Lower 8 bits of name length
+	union {
+		uint8_t name_length_high; // Higher 8 bits of name length
+		uint8_t inode_type; // Type of referenced inode (in rev >= 0.5)
+	} __attribute__ ((packed));
+	uint8_t name; // First byte of name, if present
+} __attribute__ ((packed)) ext2_directory_entry_ll_t;
+
+typedef struct ext2_directory_iterator {
+	ext2_filesystem_t *fs;
+	ext2_inode_ref_t *inode_ref;
+	block_t *current_block;
+	aoff64_t current_offset;
+	ext2_directory_entry_ll_t *current;
+} ext2_directory_iterator_t;
+
+
+extern uint32_t	ext2_directory_entry_ll_get_inode(ext2_directory_entry_ll_t *);
+extern uint16_t	ext2_directory_entry_ll_get_entry_length(
+    ext2_directory_entry_ll_t *);
+extern uint16_t	ext2_directory_entry_ll_get_name_length(
+    ext2_superblock_t *, ext2_directory_entry_ll_t *);
+
+extern int ext2_directory_iterator_init(ext2_directory_iterator_t *,
+    ext2_filesystem_t *, ext2_inode_ref_t *);
+extern int ext2_directory_iterator_next(ext2_directory_iterator_t *);
+extern int ext2_directory_iterator_fini(ext2_directory_iterator_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_filesystem.c
===================================================================
--- uspace/lib/ext2/libext2_filesystem.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_filesystem.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2_filesystem.h"
+#include "libext2_superblock.h"
+#include "libext2_block_group.h"
+#include "libext2_inode.h"
+#include <errno.h>
+#include <libblock.h>
+#include <malloc.h>
+#include <assert.h>
+#include <byteorder.h>
+
+/**
+ * Initialize an instance of filesystem on the device.
+ * This function reads superblock from the device and
+ * initializes libblock cache with appropriate logical block size.
+ * 
+ * @param fs			Pointer to ext2_filesystem_t to initialize
+ * @param devmap_handle	Device handle of the block device
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_init(ext2_filesystem_t *fs, devmap_handle_t devmap_handle)
+{
+	int rc;
+	ext2_superblock_t *temp_superblock;
+	size_t block_size;
+	
+	fs->device = devmap_handle;
+	
+	rc = block_init(EXCHANGE_SERIALIZE, fs->device, 2048);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	rc = ext2_superblock_read_direct(fs->device, &temp_superblock);
+	if (rc != EOK) {
+		block_fini(fs->device);
+		return rc;
+	}
+	
+	block_size = ext2_superblock_get_block_size(temp_superblock);
+	
+	if (block_size > EXT2_MAX_BLOCK_SIZE) {
+		block_fini(fs->device);
+		return ENOTSUP;
+	}
+	
+	rc = block_cache_init(devmap_handle, block_size, 0, CACHE_MODE_WT);
+	if (rc != EOK) {
+		block_fini(fs->device);
+		return rc;
+	}
+	
+	fs->superblock = temp_superblock;
+	
+	return EOK; 
+}
+
+/**
+ * Check filesystem for sanity
+ * 
+ * @param fs			Pointer to ext2_filesystem_t to check
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_check_sanity(ext2_filesystem_t *fs)
+{
+	int rc;
+	
+	rc = ext2_superblock_check_sanity(fs->superblock);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Check feature flags
+ * 
+ * @param fs Pointer to ext2_filesystem_t to check
+ * @param read_only bool to set to true if the fs needs to be read-only
+ * @return EOK on success or negative error code on failure
+ */
+int ext2_filesystem_check_flags(ext2_filesystem_t *fs, bool *o_read_only)
+{
+	/* feature flags are present in rev 1 and later */
+	if (ext2_superblock_get_rev_major(fs->superblock) == 0) {
+		*o_read_only = false;
+		return EOK;
+	}
+	
+	uint32_t incompatible;
+	uint32_t read_only;
+	
+	incompatible = ext2_superblock_get_features_incompatible(fs->superblock);
+	read_only = ext2_superblock_get_features_read_only(fs->superblock);
+	
+	/* check whether we support all features
+	 * first unset any supported feature flags
+	 * and see whether any unspported feature remains */
+	incompatible &= ~EXT2_SUPPORTED_INCOMPATIBLE_FEATURES;
+	read_only &= ~EXT2_SUPPORTED_READ_ONLY_FEATURES;
+	
+	if (incompatible > 0) {
+		*o_read_only = true;
+		return ENOTSUP;
+	}
+	
+	if (read_only > 0) {
+		*o_read_only = true;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Get a reference to block descriptor
+ * 
+ * @param fs Pointer to filesystem information
+ * @param bgid Index of block group to find
+ * @param ref Pointer where to store pointer to block group reference
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_get_block_group_ref(ext2_filesystem_t *fs, uint32_t bgid,
+    ext2_block_group_ref_t **ref)
+{
+	int rc;
+	aoff64_t block_id;
+	uint32_t descriptors_per_block;
+	size_t offset;
+	ext2_block_group_ref_t *newref;
+	
+	newref = malloc(sizeof(ext2_block_group_ref_t));
+	if (newref == NULL) {
+		return ENOMEM;
+	}
+	
+	descriptors_per_block = ext2_superblock_get_block_size(fs->superblock)
+	    / EXT2_BLOCK_GROUP_DESCRIPTOR_SIZE;
+	
+	/* Block group descriptor table starts at the next block after superblock */
+	block_id = ext2_superblock_get_first_block(fs->superblock) + 1;
+	
+	/* Find the block containing the descriptor we are looking for */
+	block_id += bgid / descriptors_per_block;
+	offset = (bgid % descriptors_per_block) * EXT2_BLOCK_GROUP_DESCRIPTOR_SIZE;
+	
+	rc = block_get(&newref->block, fs->device, block_id, 0);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+	
+	newref->block_group = newref->block->data + offset;
+	
+	*ref = newref;
+	
+	return EOK;
+}
+
+/**
+ * Free a reference to block group
+ * 
+ * @param ref Pointer to block group reference to free
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_put_block_group_ref(ext2_block_group_ref_t *ref)
+{
+	int rc;
+	
+	rc = block_put(ref->block);
+	free(ref);
+	
+	return rc;
+}
+
+/**
+ * Get a reference to inode
+ * 
+ * @param fs Pointer to filesystem information
+ * @param index The index number of the inode
+ * @param ref Pointer where to store pointer to inode reference
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_get_inode_ref(ext2_filesystem_t *fs, uint32_t index,
+    ext2_inode_ref_t **ref)
+{
+	int rc;
+	aoff64_t block_id;
+	uint32_t block_group;
+	uint32_t offset_in_group;
+	uint32_t byte_offset_in_group;
+	size_t offset_in_block;
+	uint32_t inodes_per_group;
+	uint32_t inode_table_start;
+	uint16_t inode_size;
+	uint32_t block_size;
+	ext2_block_group_ref_t *bg_ref;
+	ext2_inode_ref_t *newref;
+	
+	newref = malloc(sizeof(ext2_inode_ref_t));
+	if (newref == NULL) {
+		return ENOMEM;
+	}
+	
+	inodes_per_group = ext2_superblock_get_inodes_per_group(fs->superblock);
+	
+	/* inode numbers are 1-based, but it is simpler to work with 0-based
+	 * when computing indices
+	 */
+	index -= 1;
+	block_group = index / inodes_per_group;
+	offset_in_group = index % inodes_per_group;
+	
+	rc = ext2_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+	
+	inode_table_start = ext2_block_group_get_inode_table_first_block(
+	    bg_ref->block_group);
+	
+	inode_size = ext2_superblock_get_inode_size(fs->superblock);
+	block_size = ext2_superblock_get_block_size(fs->superblock);
+	
+	byte_offset_in_group = offset_in_group * inode_size;
+	
+	block_id = inode_table_start + (byte_offset_in_group / block_size);
+	offset_in_block = byte_offset_in_group % block_size;
+	
+	rc = block_get(&newref->block, fs->device, block_id, 0);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+	
+	newref->inode = newref->block->data + offset_in_block;
+	/* we decremented index above, but need to store the original value
+	 * in the reference
+	 */
+	newref->index = index+1;
+	
+	*ref = newref;
+	
+	return EOK;
+}
+
+/**
+ * Free a reference to inode
+ * 
+ * @param ref Pointer to inode reference to free
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_put_inode_ref(ext2_inode_ref_t *ref)
+{
+	int rc;
+	
+	rc = block_put(ref->block);
+	free(ref);
+	
+	return rc;
+}
+
+/**
+ * Find a filesystem block number where iblock-th data block
+ * of the given inode is located.
+ * 
+ * @param fblock the number of filesystem block, or 0 if no such block is allocated yet
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_get_inode_data_block_index(ext2_filesystem_t *fs, ext2_inode_t* inode,
+    aoff64_t iblock, uint32_t* fblock)
+{
+	int rc;
+	aoff64_t limits[4];
+	uint32_t block_ids_per_block;
+	aoff64_t blocks_per_level[4];
+	uint32_t offset_in_block;
+	uint32_t current_block;
+	aoff64_t block_offset_in_level;
+	int i;
+	int level;
+	block_t *block;
+	
+	/* Handle simple case when we are dealing with direct reference */ 
+	if (iblock < EXT2_INODE_DIRECT_BLOCKS) {
+		current_block = ext2_inode_get_direct_block(inode, (uint32_t)iblock);
+		*fblock = current_block;
+		return EOK;
+	}
+	
+	/* Compute limits for indirect block levels
+	 * TODO: compute this once when loading filesystem and store in ext2_filesystem_t
+	 */
+	block_ids_per_block = ext2_superblock_get_block_size(fs->superblock) / sizeof(uint32_t);
+	limits[0] = EXT2_INODE_DIRECT_BLOCKS;
+	blocks_per_level[0] = 1;
+	for (i = 1; i < 4; i++) {
+		blocks_per_level[i]  = blocks_per_level[i-1] *
+		    block_ids_per_block;
+		limits[i] = limits[i-1] + blocks_per_level[i];
+	}
+	
+	/* Determine the indirection level needed to get the desired block */
+	level = -1;
+	for (i = 1; i < 4; i++) {
+		if (iblock < limits[i]) {
+			level = i;
+			break;
+		}
+	}
+	
+	if (level == -1) {
+		return EIO;
+	}
+	
+	/* Compute offsets for the topmost level */
+	block_offset_in_level = iblock - limits[level-1];
+	current_block = ext2_inode_get_indirect_block(inode, level-1);
+	offset_in_block = block_offset_in_level / blocks_per_level[level-1];
+	
+	/* Navigate through other levels, until we find the block number
+	 * or find null reference meaning we are dealing with sparse file
+	 */
+	while (level > 0) {
+		rc = block_get(&block, fs->device, current_block, 0);
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		assert(offset_in_block < block_ids_per_block);
+		current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
+		
+		rc = block_put(block);
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		if (current_block == 0) {
+			/* This is a sparse file */
+			*fblock = 0;
+			return EOK;
+		}
+		
+		level -= 1;
+		
+		/* If we are on the last level, break here as
+		 * there is no next level to visit
+		 */
+		if (level == 0) {
+			break;
+		}
+		
+		/* Visit the next level */
+		block_offset_in_level %= blocks_per_level[level];
+		offset_in_block = block_offset_in_level / blocks_per_level[level-1];
+	}
+	
+	*fblock = current_block;
+	
+	return EOK;
+}
+
+/**
+ * Allocate a given number of blocks and store their ids in blocks
+ * 
+ * @todo TODO: This function is not finished and really has never been
+ *             used (and tested) yet
+ * 
+ * @param fs pointer to filesystem
+ * @param blocks array of count uint32_t values where store block ids
+ * @param count number of blocks to allocate and elements in blocks array
+ * @param preferred_bg preferred block group number
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_allocate_blocks(ext2_filesystem_t *fs, uint32_t *blocks,
+    size_t count, uint32_t preferred_bg)
+{
+	uint32_t bg_count = ext2_superblock_get_block_group_count(fs->superblock);
+	uint32_t bpg = ext2_superblock_get_blocks_per_group(fs->superblock);
+	uint32_t block_size = ext2_superblock_get_block_size(fs->superblock);
+	uint32_t block_group = preferred_bg;
+	uint32_t free_blocks_sb;
+	uint32_t block_groups_left;
+	size_t idx;
+	ext2_block_group_ref_t *bg;
+	int rc;
+	uint32_t bb_block;
+	block_t *block;
+	size_t bb_idx;
+	size_t bb_bit;
+	
+	free_blocks_sb = ext2_superblock_get_free_block_count(fs->superblock);
+	
+	if (count > free_blocks_sb) {
+		return EIO;
+	}
+	
+	block_groups_left = bg_count;
+	
+	idx = 0;
+	
+	/* Read the block group descriptor */
+	rc = ext2_filesystem_get_block_group_ref(fs, block_group, &bg);
+	if (rc != EOK) {
+		goto failed;
+	}
+	
+	while (idx < count && block_groups_left > 0) {
+		uint16_t fb = ext2_block_group_get_free_block_count(bg->block_group);
+		if (fb == 0) {
+			block_group = (block_group + 1) % bg_count;
+			block_groups_left -= 1;
+			
+			rc = ext2_filesystem_put_block_group_ref(bg);
+			if (rc != EOK) {
+				goto failed;
+			}
+			
+			rc = ext2_filesystem_get_block_group_ref(fs, block_group, &bg);
+			if (rc != EOK) {
+				goto failed;
+			}
+			continue;
+		}
+		
+		/* We found a block group with free block, let's look at the block bitmap */
+		bb_block = ext2_block_group_get_block_bitmap_block(bg->block_group);
+		
+		rc = block_get(&block, fs->device, bb_block, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			goto failed;
+		}
+		
+		/* Use all blocks from this block group */
+		for (bb_idx = 0; bb_idx < block_size && idx < count; bb_idx++) {
+			uint8_t *data = (uint8_t *) block->data;
+			if (data[bb_idx] == 0xff) {
+				continue;
+			}
+			/* find an empty bit */
+			uint8_t mask;
+			for (mask = 1, bb_bit = 0;
+				 bb_bit < 8 && idx < count; 
+				 bb_bit++, mask = mask << 1) {
+				if ((data[bb_idx] & mask) == 0) {
+					// free block found
+					blocks[idx] = block_group * bpg + bb_idx*8 + bb_bit;
+					data[bb_idx] |= mask;
+					idx += 1;
+					fb -= 1;
+					ext2_block_group_set_free_block_count(bg->block_group, fb);
+				}
+			}
+		}
+	}
+	
+	rc = ext2_filesystem_put_block_group_ref(bg);
+	if (rc != EOK) {
+		goto failed;
+	}
+	
+	// TODO update superblock
+	
+	return EOK;
+failed:
+	// TODO deallocate already allocated blocks, if possible
+	
+	return rc;
+}
+
+/**
+ * Finalize an instance of filesystem
+ * 
+ * @param fs Pointer to ext2_filesystem_t to finalize
+ */
+void ext2_filesystem_fini(ext2_filesystem_t *fs)
+{
+	free(fs->superblock);
+	block_fini(fs->device);
+}
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_filesystem.h
===================================================================
--- uspace/lib/ext2/libext2_filesystem.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_filesystem.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_FILESYSTEM_H_
+#define LIBEXT2_LIBEXT2_FILESYSTEM_H_
+
+#include <libblock.h>
+#include "libext2_superblock.h"
+#include "libext2_block_group.h"
+#include "libext2_inode.h"
+
+typedef struct ext2_filesystem {
+	devmap_handle_t		device;
+	ext2_superblock_t *	superblock;
+} ext2_filesystem_t;
+
+// allow maximum this block size
+#define EXT2_MAX_BLOCK_SIZE			8096
+#define EXT2_REV0_FIRST_INODE		11
+#define EXT2_REV0_INODE_SIZE		128
+
+#define EXT2_FEATURE_RO_SPARSE_SUPERBLOCK	1
+#define EXT2_FEATURE_RO_LARGE_FILE			2
+#define EXT2_FEATURE_I_TYPE_IN_DIR			2
+
+#define EXT2_SUPPORTED_INCOMPATIBLE_FEATURES EXT2_FEATURE_I_TYPE_IN_DIR
+#define EXT2_SUPPORTED_READ_ONLY_FEATURES 0
+
+extern int ext2_filesystem_init(ext2_filesystem_t *, devmap_handle_t);
+extern int ext2_filesystem_check_sanity(ext2_filesystem_t *);
+extern int ext2_filesystem_check_flags(ext2_filesystem_t *, bool *);
+extern int ext2_filesystem_get_block_group_ref(ext2_filesystem_t *, uint32_t, 
+    ext2_block_group_ref_t **);
+extern int ext2_filesystem_put_block_group_ref(ext2_block_group_ref_t *);
+extern int ext2_filesystem_get_inode_ref(ext2_filesystem_t *, uint32_t,
+    ext2_inode_ref_t **);
+extern int ext2_filesystem_put_inode_ref(ext2_inode_ref_t *);
+extern int ext2_filesystem_get_inode_data_block_index(ext2_filesystem_t *, ext2_inode_t*,
+    aoff64_t, uint32_t*);
+extern int ext2_filesystem_allocate_blocks(ext2_filesystem_t *, uint32_t *, size_t, uint32_t);
+extern void ext2_filesystem_fini(ext2_filesystem_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_inode.c
===================================================================
--- uspace/lib/ext2/libext2_inode.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_inode.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include "libext2_inode.h"
+#include "libext2_superblock.h"
+#include <byteorder.h>
+#include <assert.h>
+
+/**
+ * Get mode stored in the inode
+ * 
+ * @param inode pointer to inode
+ */
+uint32_t ext2_inode_get_mode(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	if (ext2_superblock_get_os(sb) == EXT2_SUPERBLOCK_OS_HURD) {
+		return ((uint32_t)uint16_t_le2host(inode->mode_high)) << 16 |
+		    ((uint32_t)uint16_t_le2host(inode->mode));
+	}
+	return uint16_t_le2host(inode->mode);
+}
+
+/**
+ * Check whether inode is of given type
+ * 
+ * @param sb pointer to superblock structure
+ * @param inode pointer to inode
+ * @param type EXT2_INODE_MODE_TYPE_* constant to check
+ */
+bool ext2_inode_is_type(ext2_superblock_t *sb, ext2_inode_t *inode, uint32_t type)
+{
+	uint32_t mode = ext2_inode_get_mode(sb, inode);
+	return (mode & EXT2_INODE_MODE_TYPE_MASK) == type;
+}
+
+/**
+ * Get uid this inode is belonging to
+ * 
+ * @param inode pointer to inode
+ */
+uint32_t ext2_inode_get_user_id(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	uint32_t os = ext2_superblock_get_os(sb);
+	if (os == EXT2_SUPERBLOCK_OS_LINUX || os == EXT2_SUPERBLOCK_OS_HURD) {
+		return ((uint32_t)uint16_t_le2host(inode->user_id_high)) << 16 |
+		    ((uint32_t)uint16_t_le2host(inode->user_id));
+	}
+	return uint16_t_le2host(inode->user_id);
+}
+
+/**
+ * Get size of file
+ * 
+ * For regular files in revision 1 and later, the high 32 bits of
+ * file size are stored in inode->size_high and are 0 otherwise
+ * 
+ * @param inode pointer to inode
+ */
+uint64_t ext2_inode_get_size(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	uint32_t major_rev = ext2_superblock_get_rev_major(sb);
+	
+	if (major_rev > 0 && ext2_inode_is_type(sb, inode, EXT2_INODE_MODE_FILE)) {
+		return ((uint64_t)uint32_t_le2host(inode->size_high)) << 32 |
+		    ((uint64_t)uint32_t_le2host(inode->size));
+	}
+	return uint32_t_le2host(inode->size);
+}
+
+/**
+ * Get gid this inode belongs to
+ * 
+ * For Linux and Hurd, the high 16 bits are stored in OS dependent part
+ * of inode structure
+ * 
+ * @param inode pointer to inode
+ */
+uint32_t ext2_inode_get_group_id(ext2_superblock_t *sb, ext2_inode_t *inode)
+{
+	uint32_t os = ext2_superblock_get_os(sb);
+	if (os == EXT2_SUPERBLOCK_OS_LINUX || os == EXT2_SUPERBLOCK_OS_HURD) {
+		return ((uint32_t)uint16_t_le2host(inode->group_id_high)) << 16 |
+		    ((uint32_t)uint16_t_le2host(inode->group_id));
+	}
+	return uint16_t_le2host(inode->group_id);
+}
+
+/**
+ * Get usage count (i.e. hard link count)
+ * A value of 1 is common, while 0 means that the inode should be freed
+ * 
+ * @param inode pointer to inode
+ */
+uint16_t ext2_inode_get_usage_count(ext2_inode_t *inode)
+{
+	return uint16_t_le2host(inode->usage_count);
+}
+
+/**
+ * Get number of 512-byte data blocks allocated for contents of the file
+ * represented by this inode.
+ * This should be multiple of block size unless fragments are used.
+ * 
+ * @param inode pointer to inode
+ */
+uint32_t ext2_inode_get_reserved_512_blocks(ext2_inode_t *inode)
+{
+	return uint32_t_le2host(inode->reserved_512_blocks);
+}
+
+/**
+ * Get number of blocks allocated for contents of the file
+ * represented by this inode.
+ * 
+ * @param inode pointer to inode
+ */
+uint32_t ext2_inode_get_reserved_blocks(ext2_superblock_t *sb,
+    ext2_inode_t *inode)
+{
+	return ext2_inode_get_reserved_512_blocks(inode) /
+	    (ext2_superblock_get_block_size(sb) / 512);
+}
+
+/**
+ * Get inode flags
+ * 
+ * @param inode pointer to inode
+ */
+uint32_t ext2_inode_get_flags(ext2_inode_t *inode) {
+	return uint32_t_le2host(inode->flags);
+}
+
+/**
+ * Get direct block ID
+ * 
+ * @param inode pointer to inode
+ * @param idx Index to block. Valid values are 0 <= idx < 12
+ */
+uint32_t ext2_inode_get_direct_block(ext2_inode_t *inode, uint8_t idx)
+{
+	assert(idx < EXT2_INODE_DIRECT_BLOCKS);
+	return uint32_t_le2host(inode->direct_blocks[idx]);
+}
+
+/**
+ * Get indirect block ID
+ * 
+ * @param inode pointer to inode
+ * @param idx Indirection level. Valid values are 0 <= idx < 3, where 0 is
+ *            singly-indirect block and 2 is triply-indirect-block
+ */
+uint32_t ext2_inode_get_indirect_block(ext2_inode_t *inode, uint8_t idx)
+{
+	assert(idx < 3);
+	return uint32_t_le2host(inode->indirect_blocks[idx]);
+}
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_inode.h
===================================================================
--- uspace/lib/ext2/libext2_inode.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_inode.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_INODE_H_
+#define LIBEXT2_LIBEXT2_INODE_H_
+
+#include <libblock.h>
+#include "libext2_superblock.h"
+
+typedef struct ext2_inode {
+	uint16_t mode;
+	uint16_t user_id;
+	uint32_t size;
+	uint8_t unused[16];
+	uint16_t group_id;
+	uint16_t usage_count; // Hard link count, when 0 the inode is to be freed
+	uint32_t reserved_512_blocks; // Size of this inode in 512-byte blocks
+	uint32_t flags;
+	uint8_t unused2[4];
+	uint32_t direct_blocks[12]; // Direct block ids stored in this inode
+	uint32_t indirect_blocks[3];
+	uint32_t version;
+	uint32_t file_acl;
+	union {
+		uint32_t dir_acl;
+		uint32_t size_high; // For regular files in version >= 1
+	} __attribute__ ((packed));
+	uint8_t unused3[6];
+	uint16_t mode_high; // Hurd only
+	uint16_t user_id_high; // Linux/Hurd only
+	uint16_t group_id_high; // Linux/Hurd only
+} __attribute__ ((packed)) ext2_inode_t;
+
+#define EXT2_INODE_MODE_FIFO		0x1000
+#define EXT2_INODE_MODE_CHARDEV		0x2000
+#define EXT2_INODE_MODE_DIRECTORY	0x4000
+#define EXT2_INODE_MODE_BLOCKDEV	0x6000
+#define EXT2_INODE_MODE_FILE		0x8000
+#define EXT2_INODE_MODE_SOFTLINK	0xA000
+#define EXT2_INODE_MODE_SOCKET		0xC000
+#define EXT2_INODE_MODE_ACCESS_MASK	0x0FFF
+#define EXT2_INODE_MODE_TYPE_MASK	0xF000
+#define EXT2_INODE_DIRECT_BLOCKS	12
+
+#define EXT2_INODE_ROOT_INDEX		2
+
+typedef struct ext2_inode_ref {
+	block_t *block; // Reference to a block containing this inode
+	ext2_inode_t *inode;
+	uint32_t index; // Index number of this inode
+} ext2_inode_ref_t;
+
+extern uint32_t ext2_inode_get_mode(ext2_superblock_t *, ext2_inode_t *);
+extern bool ext2_inode_is_type(ext2_superblock_t *, ext2_inode_t *, uint32_t);
+extern uint32_t ext2_inode_get_user_id(ext2_superblock_t *, ext2_inode_t *);
+extern uint64_t ext2_inode_get_size(ext2_superblock_t *, ext2_inode_t *);
+extern uint32_t ext2_inode_get_group_id(ext2_superblock_t *, ext2_inode_t *);
+extern uint16_t ext2_inode_get_usage_count(ext2_inode_t *);
+extern uint32_t ext2_inode_get_reserved_512_blocks(ext2_inode_t *);
+extern uint32_t ext2_inode_get_reserved_blocks(ext2_superblock_t *, 
+    ext2_inode_t *);
+extern uint32_t ext2_inode_get_flags(ext2_inode_t *);
+extern uint32_t ext2_inode_get_direct_block(ext2_inode_t *, uint8_t);
+extern uint32_t ext2_inode_get_indirect_block(ext2_inode_t *, uint8_t level);
+
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_superblock.c
===================================================================
--- uspace/lib/ext2/libext2_superblock.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_superblock.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "libext2.h"
+#include <errno.h>
+#include <malloc.h>
+#include <libblock.h>
+#include <byteorder.h>
+
+/**
+ * Return a magic number from ext2 superblock, this should be equal to
+ * EXT_SUPERBLOCK_MAGIC for valid ext2 superblock
+ * 
+ * @param sb pointer to superblock
+ */
+uint16_t ext2_superblock_get_magic(ext2_superblock_t *sb)
+{
+	return uint16_t_le2host(sb->magic);
+}
+
+/**
+ * Get the position of first ext2 data block (i.e. the block number
+ * containing main superblock)
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_first_block(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->first_block);
+}
+
+/**
+ * Get the number of bits to shift a value of 1024 to the left necessary
+ * to get the size of a block
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_block_size_log2(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->block_size_log2);
+}
+
+/**
+ * Get the size of a block, in bytes 
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_block_size(ext2_superblock_t *sb)
+{
+	return 1024 << ext2_superblock_get_block_size_log2(sb);
+}
+
+/**
+ * Get the number of bits to shift a value of 1024 to the left necessary
+ * to get the size of a fragment (note that this is a signed integer and
+ * if negative, the value should be shifted to the right instead)
+ * 
+ * @param sb pointer to superblock
+ */
+int32_t ext2_superblock_get_fragment_size_log2(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->fragment_size_log2);
+}
+
+/**
+ * Get the size of a fragment, in bytes 
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_fragment_size(ext2_superblock_t *sb)
+{
+	int32_t log = ext2_superblock_get_fragment_size_log2(sb);
+	if (log >= 0) {
+		return 1024 << log;
+	}
+	else {
+		return 1024 >> -log;
+	}
+}
+
+/**
+ * Get number of blocks per block group
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_blocks_per_group(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->blocks_per_group);
+}
+
+/**
+ * Get number of fragments per block group
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_fragments_per_group(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->fragments_per_group);
+}
+
+/**
+ * Get filesystem state
+ * 
+ * @param sb pointer to superblock
+ */
+uint16_t ext2_superblock_get_state(ext2_superblock_t *sb)
+{
+	return uint16_t_le2host(sb->state);
+}
+
+/**
+ * Get minor revision number
+ * 
+ * @param sb pointer to superblock
+ */
+uint16_t ext2_superblock_get_rev_minor(ext2_superblock_t *sb)
+{
+	return uint16_t_le2host(sb->rev_minor);
+}
+
+/**
+ * Get major revision number
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_rev_major(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->rev_major);
+}
+
+/**
+ * Get index of first regular inode
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_first_inode(ext2_superblock_t *sb)
+{
+	if (ext2_superblock_get_rev_major(sb) == 0) {
+		return EXT2_REV0_FIRST_INODE;
+	}
+	return uint32_t_le2host(sb->first_inode);
+}
+
+/**
+ * Get size of inode
+ * 
+ * @param sb pointer to superblock
+ */
+uint16_t ext2_superblock_get_inode_size(ext2_superblock_t *sb)
+{
+	if (ext2_superblock_get_rev_major(sb) == 0) {
+		return EXT2_REV0_INODE_SIZE;
+	}
+	return uint16_t_le2host(sb->inode_size);
+}
+
+/**
+ * Get total inode count
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_total_inode_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->total_inode_count);
+}
+
+/**
+ * Get total block count
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_total_block_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->total_block_count);
+}
+
+/**
+ * Get amount of blocks reserved for the superuser
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_reserved_block_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->reserved_block_count);
+}
+
+/**
+ * Get amount of free blocks
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_free_block_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->free_block_count);
+}
+
+/**
+ * Get amount of free inodes
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_free_inode_count(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->free_inode_count);
+}
+
+/**
+ * Get id of operating system that created the filesystem
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_os(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->os);
+}
+
+/**
+ * Get count of inodes per block group
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_inodes_per_group(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->inodes_per_group);
+}
+
+/**
+ * Get compatible features flags
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_features_compatible(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->features_compatible);
+}
+
+/**
+ * Get incompatible features flags
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_features_incompatible(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->features_incompatible);
+}
+
+/**
+ * Get read-only compatible features flags
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_features_read_only(ext2_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->features_read_only);
+}
+
+/**
+ * Compute count of block groups present in the filesystem
+ * 
+ * Note: This function works only for correct filesystem,
+ *       i.e. it assumes that total block count > 0 and
+ *       blocks per group > 0
+ * 
+ * Example:
+ *   If there are 3 blocks per group, the result should be as follows:
+ *   Total blocks	Result
+ *   1				1
+ *   2				1
+ *   3				1
+ *   4				2
+ * 
+ * 
+ * @param sb pointer to superblock
+ */
+uint32_t ext2_superblock_get_block_group_count(ext2_superblock_t *sb)
+{
+	/* We add one to the result because e.g. 2/3 = 0, while to store
+	 *  2 blocks in 3-block group we need one (1) block group
+	 * 
+	 * We subtract one first because of special case that to store e.g.
+	 *  3 blocks in a 3-block group we need only one group
+	 *  (and 3/3 yields one - this is one more that we want as we
+	 *   already add one at the end)
+	 */ 
+	return ((ext2_superblock_get_total_block_count(sb)-1) / 
+	    ext2_superblock_get_blocks_per_group(sb))+1;
+}
+
+/** Read a superblock directly from device (i.e. no libblock cache)
+ * 
+ * @param devmap_handle	Device handle of the block device.
+ * @param superblock	Pointer where to store pointer to new superblock
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int ext2_superblock_read_direct(devmap_handle_t devmap_handle,
+    ext2_superblock_t **superblock)
+{
+	void *data;
+	int rc;
+	
+	data = malloc(EXT2_SUPERBLOCK_SIZE);
+	if (data == NULL) {
+		return ENOMEM;
+	}
+	
+	rc = block_read_bytes_direct(devmap_handle, EXT2_SUPERBLOCK_OFFSET,
+	    EXT2_SUPERBLOCK_SIZE, data);
+	if (rc != EOK) {
+		free(data);
+		return rc;
+	}
+	
+	(*superblock) = data;
+	return EOK;
+}
+
+/** Check a superblock for sanity
+ * 
+ * @param sb	Pointer to superblock
+ * 
+ * @return		EOK on success or negative error code on failure.
+ */
+int ext2_superblock_check_sanity(ext2_superblock_t *sb)
+{
+	if (ext2_superblock_get_magic(sb) != EXT2_SUPERBLOCK_MAGIC) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_rev_major(sb) > 1) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_total_inode_count(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_total_block_count(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_blocks_per_group(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_fragments_per_group(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	/* We don't support fragments smaller than block */
+	if (ext2_superblock_get_block_size(sb) != 
+		    ext2_superblock_get_fragment_size(sb)) {
+		return ENOTSUP;
+	}
+	if (ext2_superblock_get_blocks_per_group(sb) !=
+		    ext2_superblock_get_fragments_per_group(sb)) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_inodes_per_group(sb) == 0) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_inode_size(sb) < 128) {
+		return ENOTSUP;
+	}
+	
+	if (ext2_superblock_get_first_inode(sb) < 11) {
+		return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+
+/** @}
+ */
Index: uspace/lib/ext2/libext2_superblock.h
===================================================================
--- uspace/lib/ext2/libext2_superblock.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/ext2/libext2_superblock.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * 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 libext2
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBEXT2_LIBEXT2_SUPERBLOCK_H_
+#define LIBEXT2_LIBEXT2_SUPERBLOCK_H_
+
+#include <libblock.h>
+
+typedef struct ext2_superblock {
+	uint32_t	total_inode_count; // Total number of inodes
+	uint32_t	total_block_count; // Total number of blocks
+	uint32_t	reserved_block_count; // Total number of reserved blocks
+	uint32_t	free_block_count; // Total number of free blocks
+	uint32_t	free_inode_count; // Total number of free inodes
+	uint32_t	first_block; // Block containing the superblock (either 0 or 1)
+	uint32_t	block_size_log2; // log_2(block_size)
+	int32_t		fragment_size_log2; // log_2(fragment size)
+	uint32_t	blocks_per_group; // Number of blocks in one block group
+	uint32_t	fragments_per_group; // Number of fragments per block group
+	uint32_t	inodes_per_group; // Number of inodes per block group
+	uint8_t		unused2[12];
+	uint16_t	magic; // Magic value
+	uint16_t	state; // State (mounted/unmounted)
+	uint16_t	error_behavior; // What to do when errors are encountered
+	uint16_t	rev_minor; // Minor revision level
+	uint8_t		unused3[8];
+	uint32_t	os; // OS that created the filesystem
+	uint32_t	rev_major; // Major revision level
+	uint8_t		unused4[4];
+	
+	// Following is for ext2 revision 1 only
+	uint32_t	first_inode;
+	uint16_t	inode_size;
+	uint16_t	unused5;
+	uint32_t	features_compatible;
+	uint32_t	features_incompatible;
+	uint32_t	features_read_only;
+	uint8_t		uuid[16]; // UUID TODO: Create a library for UUIDs
+	uint8_t		volume_name[16];
+
+// TODO: add __attribute__((aligned(...)) for better performance?
+//       (it is necessary to ensure the superblock is correctly aligned then
+//        though)
+} __attribute__ ((packed)) ext2_superblock_t;
+
+#define EXT2_SUPERBLOCK_MAGIC		0xEF53
+#define EXT2_SUPERBLOCK_SIZE		1024
+#define EXT2_SUPERBLOCK_OFFSET		1024
+#define EXT2_SUPERBLOCK_LAST_BYTE	(EXT2_SUPERBLOCK_OFFSET + \
+									 EXT2_SUPERBLOCK_SIZE -1)
+#define EXT2_SUPERBLOCK_OS_LINUX	0
+#define EXT2_SUPERBLOCK_OS_HURD		1
+
+
+extern uint16_t	ext2_superblock_get_magic(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_first_block(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_block_size_log2(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_block_size(ext2_superblock_t *);
+extern int32_t	ext2_superblock_get_fragment_size_log2(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_fragment_size(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_blocks_per_group(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_fragments_per_group(ext2_superblock_t *);
+extern uint16_t	ext2_superblock_get_state(ext2_superblock_t *);
+extern uint16_t	ext2_superblock_get_rev_minor(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_rev_major(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_os(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_first_inode(ext2_superblock_t *);
+extern uint16_t	ext2_superblock_get_inode_size(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_total_inode_count(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_total_block_count(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_reserved_block_count(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_free_block_count(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_free_inode_count(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_block_group_count(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_inodes_per_group(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_features_compatible(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_features_incompatible(ext2_superblock_t *);
+extern uint32_t	ext2_superblock_get_features_read_only(ext2_superblock_t *);
+
+extern int ext2_superblock_read_direct(devmap_handle_t, ext2_superblock_t **);
+extern int ext2_superblock_check_sanity(ext2_superblock_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/fs/libfs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -67,16 +67,16 @@
  * code.
  *
- * @param vfs_phone Open phone for communication with VFS.
- * @param reg       File system registration structure. It will be
- *                  initialized by this function.
- * @param info      VFS info structure supplied by the file system
- *                  implementation.
- * @param conn      Connection fibril for handling all calls originating in
- *                  VFS.
+ * @param sess Session for communication with VFS.
+ * @param reg  File system registration structure. It will be
+ *             initialized by this function.
+ * @param info VFS info structure supplied by the file system
+ *             implementation.
+ * @param conn Connection fibril for handling all calls originating in
+ *             VFS.
  *
  * @return EOK on success or a non-zero error code on errror.
  *
  */
-int fs_register(int vfs_phone, fs_reg_t *reg, vfs_info_t *info,
+int fs_register(async_sess_t *sess, fs_reg_t *reg, vfs_info_t *info,
     async_client_conn_t conn)
 {
@@ -86,12 +86,17 @@
 	 * out-of-order, when it knows that the operation succeeded or failed.
 	 */
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
 	ipc_call_t answer;
-	aid_t req = async_send_0(vfs_phone, VFS_IN_REGISTER, &answer);
+	aid_t req = async_send_0(exch, VFS_IN_REGISTER, &answer);
 	
 	/*
 	 * Send our VFS info structure to VFS.
 	 */
-	int rc = async_data_write_start(vfs_phone, info, sizeof(*info)); 
+	int rc = async_data_write_start(exch, info, sizeof(*info));
+	
 	if (rc != EOK) {
+		async_exchange_end(exch);
 		async_wait_for(req, NULL);
 		return rc;
@@ -101,5 +106,5 @@
 	 * Ask VFS for callback connection.
 	 */
-	async_connect_to_me(vfs_phone, 0, 0, 0, conn);
+	async_connect_to_me(exch, 0, 0, 0, conn);
 	
 	/*
@@ -108,4 +113,5 @@
 	reg->plb_ro = as_get_mappable_page(PLB_SIZE);
 	if (!reg->plb_ro) {
+		async_exchange_end(exch);
 		async_wait_for(req, NULL);
 		return ENOMEM;
@@ -115,5 +121,8 @@
 	 * Request sharing the Path Lookup Buffer with VFS.
 	 */
-	rc = async_share_in_start_0_0(vfs_phone, reg->plb_ro, PLB_SIZE);
+	rc = async_share_in_start_0_0(exch, reg->plb_ro, PLB_SIZE);
+	
+	async_exchange_end(exch);
+	
 	if (rc) {
 		async_wait_for(req, NULL);
@@ -148,27 +157,15 @@
 	fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request);
 	devmap_handle_t mr_devmap_handle = (devmap_handle_t) IPC_GET_ARG4(*request);
-	int res;
-	sysarg_t rc;
-	
-	ipc_call_t call;
-	ipc_callid_t callid;
-	
-	/* Accept the phone */
-	callid = async_get_call(&call);
-	int mountee_phone = (int) IPC_GET_ARG1(call);
-	if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECTION_CLONE) ||
-	    (mountee_phone < 0)) {
-		async_answer_0(callid, EINVAL);
+	
+	async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
+	if (mountee_sess == NULL) {
 		async_answer_0(rid, EINVAL);
 		return;
 	}
 	
-	/* Acknowledge the mountee_phone */
-	async_answer_0(callid, EOK);
-	
 	fs_node_t *fn;
-	res = ops->node_get(&fn, mp_devmap_handle, mp_fs_index);
+	int res = ops->node_get(&fn, mp_devmap_handle, mp_fs_index);
 	if ((res != EOK) || (!fn)) {
-		async_hangup(mountee_phone);
+		async_hangup(mountee_sess);
 		async_data_write_void(combine_rc(res, ENOENT));
 		async_answer_0(rid, combine_rc(res, ENOENT));
@@ -177,5 +174,5 @@
 	
 	if (fn->mp_data.mp_active) {
-		async_hangup(mountee_phone);
+		async_hangup(mountee_sess);
 		(void) ops->node_put(fn);
 		async_data_write_void(EBUSY);
@@ -184,16 +181,20 @@
 	}
 	
-	rc = async_req_0_0(mountee_phone, IPC_M_CONNECT_ME);
-	if (rc != EOK) {
-		async_hangup(mountee_phone);
+	async_exch_t *exch = async_exchange_begin(mountee_sess);
+	async_sess_t *sess = async_connect_me(EXCHANGE_PARALLEL, exch);
+	
+	if (!sess) {
+		async_exchange_end(exch);
+		async_hangup(mountee_sess);
 		(void) ops->node_put(fn);
-		async_data_write_void(rc);
-		async_answer_0(rid, rc);
+		async_data_write_void(errno);
+		async_answer_0(rid, errno);
 		return;
 	}
 	
 	ipc_call_t answer;
-	rc = async_data_write_forward_1_1(mountee_phone, VFS_OUT_MOUNTED,
+	int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED,
 	    mr_devmap_handle, &answer);
+	async_exchange_end(exch);
 	
 	if (rc == EOK) {
@@ -201,5 +202,5 @@
 		fn->mp_data.fs_handle = mr_fs_handle;
 		fn->mp_data.devmap_handle = mr_devmap_handle;
-		fn->mp_data.phone = mountee_phone;
+		fn->mp_data.sess = mountee_sess;
 	}
 	
@@ -236,6 +237,7 @@
 	 * Tell the mounted file system to unmount.
 	 */
-	res = async_req_1_0(fn->mp_data.phone, VFS_OUT_UNMOUNTED,
-	    fn->mp_data.devmap_handle);
+	async_exch_t *exch = async_exchange_begin(fn->mp_data.sess);
+	res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.devmap_handle);
+	async_exchange_end(exch);
 
 	/*
@@ -243,9 +245,10 @@
 	 */
 	if (res == EOK) {
-		async_hangup(fn->mp_data.phone);
+		async_hangup(fn->mp_data.sess);
 		fn->mp_data.mp_active = false;
 		fn->mp_data.fs_handle = 0;
 		fn->mp_data.devmap_handle = 0;
-		fn->mp_data.phone = 0;
+		fn->mp_data.sess = NULL;
+		
 		/* Drop the reference created in libfs_mount(). */
 		(void) ops->node_put(fn);
@@ -293,7 +296,9 @@
 	
 	if (cur->mp_data.mp_active) {
-		async_forward_slow(rid, cur->mp_data.phone, VFS_OUT_LOOKUP,
-		    next, last, cur->mp_data.devmap_handle, lflag, index,
-		    IPC_FF_ROUTE_FROM_ME);
+		async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
+		async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
+		    cur->mp_data.devmap_handle, lflag, index, IPC_FF_ROUTE_FROM_ME);
+		async_exchange_end(exch);
+		
 		(void) ops->node_put(cur);
 		return;
@@ -351,7 +356,10 @@
 				next--;
 			
-			async_forward_slow(rid, tmp->mp_data.phone,
-			    VFS_OUT_LOOKUP, next, last, tmp->mp_data.devmap_handle,
-			    lflag, index, IPC_FF_ROUTE_FROM_ME);
+			async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
+			async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
+			    tmp->mp_data.devmap_handle, lflag, index,
+			    IPC_FF_ROUTE_FROM_ME);
+			async_exchange_end(exch);
+			
 			(void) ops->node_put(cur);
 			(void) ops->node_put(tmp);
Index: uspace/lib/fs/libfs.h
===================================================================
--- uspace/lib/fs/libfs.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/fs/libfs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,5 +44,5 @@
 typedef struct {
 	bool mp_active;
-	int phone;
+	async_sess_t *sess;
 	fs_handle_t fs_handle;
 	devmap_handle_t devmap_handle;
@@ -88,5 +88,6 @@
 } fs_reg_t;
 
-extern int fs_register(int, fs_reg_t *, vfs_info_t *, async_client_conn_t);
+extern int fs_register(async_sess_t *, fs_reg_t *, vfs_info_t *,
+    async_client_conn_t);
 
 extern void fs_node_initialize(fs_node_t *);
Index: uspace/lib/net/generic/generic.c
===================================================================
--- uspace/lib/net/generic/generic.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/generic/generic.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 #include <generic.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <ipc/services.h>
 #include <net/device.h>
@@ -56,5 +57,5 @@
     int state, services_t target)
 {
-	async_msg_3(phone, (sysarg_t) message, (sysarg_t) device_id,
+	async_obsolete_msg_3(phone, (sysarg_t) message, (sysarg_t) device_id,
 	    (sysarg_t) state, target);
 	
@@ -78,5 +79,5 @@
     int arg2, services_t service)
 {
-	return (int) async_req_3_0(phone, (sysarg_t) message,
+	return (int) async_obsolete_req_3_0(phone, (sysarg_t) message,
 	    (sysarg_t) device_id, (sysarg_t) arg2, (sysarg_t) service);
 }
@@ -107,5 +108,5 @@
 
 	/* Request the address */
-	message_id = async_send_1(phone, (sysarg_t) message,
+	message_id = async_obsolete_send_1(phone, (sysarg_t) message,
 	    (sysarg_t) device_id, NULL);
 	string = measured_strings_return(phone, address, data, 1);
@@ -145,5 +146,5 @@
 	sysarg_t suffix;
 	
-	sysarg_t result = async_req_1_4(phone, (sysarg_t) message,
+	sysarg_t result = async_obsolete_req_1_4(phone, (sysarg_t) message,
 	    (sysarg_t) device_id, &addr_len, &prefix, &content, &suffix);
 	
@@ -172,8 +173,8 @@
 {
 	if (error) {
-		async_msg_4(phone, (sysarg_t) message, (sysarg_t) device_id,
+		async_obsolete_msg_4(phone, (sysarg_t) message, (sysarg_t) device_id,
 		    (sysarg_t) packet_id, (sysarg_t) target, (sysarg_t) error);
 	} else {
-		async_msg_3(phone, (sysarg_t) message, (sysarg_t) device_id,
+		async_obsolete_msg_3(phone, (sysarg_t) message, (sysarg_t) device_id,
 		    (sysarg_t) packet_id, (sysarg_t) target);
 	}
@@ -198,8 +199,8 @@
 {
 	if (error) {
-		async_msg_4(phone, (sysarg_t) message, (sysarg_t) device_id,
+		async_obsolete_msg_4(phone, (sysarg_t) message, (sysarg_t) device_id,
 		    (sysarg_t) packet_id, (sysarg_t) sender, (sysarg_t) error);
 	} else {
-		async_msg_3(phone, (sysarg_t) message, (sysarg_t) device_id,
+		async_obsolete_msg_3(phone, (sysarg_t) message, (sysarg_t) device_id,
 		    (sysarg_t) packet_id, (sysarg_t) sender);
 	}
@@ -243,5 +244,5 @@
 
 	/* Request the translation */
-	message_id = async_send_3(phone, (sysarg_t) message,
+	message_id = async_obsolete_send_3(phone, (sysarg_t) message,
 	    (sysarg_t) device_id, (sysarg_t) count, (sysarg_t) service, NULL);
 	measured_strings_send(phone, configuration, count);
Index: uspace/lib/net/generic/packet_remote.c
===================================================================
--- uspace/lib/net/generic/packet_remote.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/generic/packet_remote.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <errno.h>
 #include <ipc/packet.h>
@@ -59,5 +60,5 @@
  * @return EOK on success.
  * @return Other error codes as defined for the pm_add() function.
- * @return Other error codes as defined for the async_share_in_start() function.
+ * @return Other error codes as defined for the async_obsolete_share_in_start() function.
  *
  */
@@ -69,8 +70,8 @@
 	int rc;
 	
-	message = async_send_1(phone, NET_PACKET_GET, packet_id, &answer);
+	message = async_obsolete_send_1(phone, NET_PACKET_GET, packet_id, &answer);
 
 	*packet = (packet_t *) as_get_mappable_page(size);
-	rc = async_share_in_start_0_0(phone, *packet, size);
+	rc = async_obsolete_share_in_start_0_0(phone, *packet, size);
 	if (rc != EOK) {
 		munmap(*packet, size);
@@ -117,5 +118,5 @@
 		sysarg_t size;
 		
-		rc = async_req_1_1(phone, NET_PACKET_GET_SIZE, packet_id,
+		rc = async_obsolete_req_1_1(phone, NET_PACKET_GET_SIZE, packet_id,
 		    &size);
 		if (rc != EOK)
@@ -154,5 +155,5 @@
 	int rc;
 	
-	rc = async_req_4_2(phone, NET_PACKET_CREATE_4, max_content, addr_len,
+	rc = async_obsolete_req_4_2(phone, NET_PACKET_CREATE_4, max_content, addr_len,
 	    max_prefix, max_suffix, &packet_id, &size);
 	if (rc != EOK)
@@ -185,5 +186,5 @@
 	int rc;
 	
-	rc = async_req_1_2(phone, NET_PACKET_CREATE_1, content, &packet_id,
+	rc = async_obsolete_req_1_2(phone, NET_PACKET_CREATE_1, content, &packet_id,
 	    &size);
 	if (rc != EOK)
@@ -212,5 +213,5 @@
 void pq_release_remote(int phone, packet_id_t packet_id)
 {
-	async_msg_1(phone, NET_PACKET_RELEASE, packet_id);
+	async_obsolete_msg_1(phone, NET_PACKET_RELEASE, packet_id);
 }
 
Index: uspace/lib/net/il/arp_remote.c
===================================================================
--- uspace/lib/net/il/arp_remote.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/il/arp_remote.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -40,4 +40,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <errno.h>
 #include <ipc/services.h>
@@ -68,5 +69,5 @@
 int arp_clean_cache_req(int arp_phone)
 {
-	return (int) async_req_0_0(arp_phone, NET_ARP_CLEAN_CACHE);
+	return (int) async_obsolete_req_0_0(arp_phone, NET_ARP_CLEAN_CACHE);
 }
 
@@ -87,5 +88,5 @@
 	sysarg_t result;
 
-	message_id = async_send_2(arp_phone, NET_ARP_CLEAR_ADDRESS,
+	message_id = async_obsolete_send_2(arp_phone, NET_ARP_CLEAR_ADDRESS,
 	    (sysarg_t) device_id, protocol, NULL);
 	measured_strings_send(arp_phone, address, 1);
@@ -104,5 +105,5 @@
 int arp_clear_device_req(int arp_phone, device_id_t device_id)
 {
-	return (int) async_req_1_0(arp_phone, NET_ARP_CLEAR_DEVICE,
+	return (int) async_obsolete_req_1_0(arp_phone, NET_ARP_CLEAR_DEVICE,
 	    (sysarg_t) device_id);
 }
@@ -137,5 +138,5 @@
 	sysarg_t result;
 
-	message_id = async_send_3(arp_phone, NET_ARP_DEVICE,
+	message_id = async_obsolete_send_3(arp_phone, NET_ARP_DEVICE,
 	    (sysarg_t) device_id, protocol, netif, NULL);
 	measured_strings_send(arp_phone, address, 1);
Index: uspace/lib/net/il/il_skel.c
===================================================================
--- uspace/lib/net/il/il_skel.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/il/il_skel.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,7 @@
 #include <net/modules.h>
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 /** Default thread for new connections.
  *
@@ -75,6 +78,5 @@
 		 * result.
 		 */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
-		    (res == EHANGUP))
+		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
 			return;
 		
Index: uspace/lib/net/il/ip_client.c
===================================================================
--- uspace/lib/net/il/ip_client.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/il/ip_client.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -181,6 +181,6 @@
 	/* Set the header */
 	header = (ip_header_t *) data;
-	header->header_length = IP_COMPUTE_HEADER_LENGTH(sizeof(ip_header_t) +
-	    ipopt_length);
+	SET_IP_HEADER_LENGTH(header,
+	    (IP_COMPUTE_HEADER_LENGTH(sizeof(ip_header_t) + ipopt_length)));
 	header->ttl = (ttl ? ttl : IPDEFTTL);
 	header->tos = tos;
@@ -188,5 +188,5 @@
 
 	if (dont_fragment)
-		header->flags = IPFLAG_DONT_FRAGMENT;
+		SET_IP_HEADER_FLAGS(header, IPFLAG_DONT_FRAGMENT);
 
 	return EOK;
@@ -227,5 +227,5 @@
 		*tos = header->tos;
 	if (dont_fragment)
-		*dont_fragment = header->flags & IPFLAG_DONT_FRAGMENT;
+		*dont_fragment = GET_IP_HEADER_FLAGS(header) & IPFLAG_DONT_FRAGMENT;
 	if (ipopt_length) {
 		*ipopt_length = IP_HEADER_LENGTH(header) - sizeof(ip_header_t);
Index: uspace/lib/net/il/ip_remote.c
===================================================================
--- uspace/lib/net/il/ip_remote.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/il/ip_remote.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,5 +44,5 @@
 #include <packet_client.h>
 #include <generic.h>
-
+#include <async_obsolete.h>
 #include <ipc/services.h>
 #include <ipc/il.h>
@@ -66,5 +66,5 @@
     in_addr_t address, in_addr_t netmask, in_addr_t gateway)
 {
-	return (int) async_req_4_0(ip_phone, NET_IP_ADD_ROUTE,
+	return (int) async_obsolete_req_4_0(ip_phone, NET_IP_ADD_ROUTE,
 	    (sysarg_t) device_id, (sysarg_t) gateway.s_addr,
 	    (sysarg_t) address.s_addr, (sysarg_t) netmask.s_addr);
@@ -150,13 +150,13 @@
 	
 	ipc_call_t answer;
-	aid_t message_id = async_send_1(ip_phone, NET_IP_GET_ROUTE,
+	aid_t message_id = async_obsolete_send_1(ip_phone, NET_IP_GET_ROUTE,
 	    (sysarg_t) protocol, &answer);
 	
-	if ((async_data_write_start(ip_phone, destination, addrlen) == EOK) &&
-	    (async_data_read_start(ip_phone, headerlen,
+	if ((async_obsolete_data_write_start(ip_phone, destination, addrlen) == EOK) &&
+	    (async_obsolete_data_read_start(ip_phone, headerlen,
 	    sizeof(*headerlen)) == EOK) && (*headerlen > 0)) {
 		*header = malloc(*headerlen);
 		if (*header) {
-			if (async_data_read_start(ip_phone, *header,
+			if (async_obsolete_data_read_start(ip_phone, *header,
 			    *headerlen) != EOK)
 				free(*header);
@@ -243,5 +243,5 @@
     in_addr_t gateway)
 {
-	return (int) async_req_2_0(ip_phone, NET_IP_SET_GATEWAY,
+	return (int) async_obsolete_req_2_0(ip_phone, NET_IP_SET_GATEWAY,
 	    (sysarg_t) device_id, (sysarg_t) gateway.s_addr);
 }
Index: uspace/lib/net/include/ip_header.h
===================================================================
--- uspace/lib/net/include/ip_header.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/include/ip_header.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -64,5 +64,5 @@
  */
 #define IP_FRAGMENT_OFFSET(header) \
-	((((header)->fragment_offset_high << 8) + \
+	(((GET_IP_HEADER_FRAGMENT_OFFSET_HIGH(header) << 8) + \
 	    (header)->fragment_offset_low) * 8U)
 
@@ -83,5 +83,5 @@
  */
 #define IP_HEADER_LENGTH(header) \
-	((header)->header_length * 4U)
+	(GET_IP_HEADER_LENGTH(header) * 4U)
 
 /** Returns the actual IP packet total length.
@@ -143,11 +143,17 @@
  */
 struct ip_header {
-#ifdef ARCH_IS_BIG_ENDIAN
-	uint8_t version : 4;
-	uint8_t header_length : 4;
-#else
-	uint8_t header_length : 4;
-	uint8_t version : 4;
-#endif
+	uint8_t vhl; /* version, header_length */
+
+#define GET_IP_HEADER_VERSION(header) \
+	(((header)->vhl & 0xf0) >> 4)
+#define SET_IP_HEADER_VERSION(header, version) \
+	((header)->vhl = \
+	 ((version & 0x0f) << 4) | ((header)->vhl & 0x0f))
+
+#define GET_IP_HEADER_LENGTH(header) \
+	((header)->vhl & 0x0f)
+#define SET_IP_HEADER_LENGTH(header, length) \
+	((header)->vhl = \
+	 (length & 0x0f) | ((header)->vhl & 0xf0))
 
 	uint8_t tos;
@@ -155,11 +161,17 @@
 	uint16_t identification;
 
-#ifdef ARCH_IS_BIG_ENDIAN
-	uint8_t flags : 3;
-	uint8_t fragment_offset_high : 5;
-#else
-	uint8_t fragment_offset_high : 5;
-	uint8_t flags : 3;
-#endif
+	uint8_t ffoh; /* flags, fragment_offset_high */
+
+#define GET_IP_HEADER_FLAGS(header) \
+	(((header)->ffoh & 0xe0) >> 5)
+#define SET_IP_HEADER_FLAGS(header, flags) \
+	((header)->ffoh = \
+	 ((flags & 0x07) << 5) | ((header)->ffoh & 0x1f))
+
+#define GET_IP_HEADER_FRAGMENT_OFFSET_HIGH(header) \
+	((header)->ffoh & 0x1f)
+#define SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(header, fragment_offset_high) \
+	((header)->ffoh = \
+	 (fragment_offset_high & 0x1f) | ((header)->ffoh & 0xe0))
 
 	uint8_t fragment_offset_low;
@@ -181,11 +193,18 @@
 	uint8_t pointer;
 
-#ifdef ARCH_IS_BIG_ENDIAN
-	uint8_t overflow : 4;
-	uint8_t flags : 4;
-#else
-	uint8_t flags : 4;
-	uint8_t overflow : 4;
-#endif
+	uint8_t of; /* overflow, flags */
+
+#define GET_IP_OPTION_OVERFLOW(option) \
+	(((option)->of & 0xf0) >> 4)
+#define SET_IP_OPTION_OVERFLOW(option, overflow) \
+	((option)->of = \
+	 ((overflow & 0x0f) << 4) | ((option)->of & 0x0f))
+
+#define GET_IP_OPTION_FLAGS(option) \
+	((option)->of & 0x0f)
+#define SET_IP_OPTION_FLAGS(option, flags) \
+	((option)->of = \
+	 (flags & 0x0f) | ((option)->of & 0xf0))
+
 } __attribute__ ((packed));
 
Index: uspace/lib/net/netif/netif_remote.c
===================================================================
--- uspace/lib/net/netif/netif_remote.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/netif/netif_remote.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 #include <packet_client.h>
 #include <generic.h>
-
+#include <async_obsolete.h>
 #include <ipc/services.h>
 #include <ipc/netif.h>
@@ -82,5 +82,5 @@
 int netif_probe_req(int netif_phone, device_id_t device_id, int irq, void *io)
 {
-	return async_req_3_0(netif_phone, NET_NETIF_PROBE, device_id, irq,
+	return async_obsolete_req_3_0(netif_phone, NET_NETIF_PROBE, device_id, irq,
 	    (sysarg_t) io);
 }
@@ -119,5 +119,5 @@
 int netif_start_req(int netif_phone, device_id_t device_id)
 {
-	return async_req_1_0(netif_phone, NET_NETIF_START, device_id);
+	return async_obsolete_req_1_0(netif_phone, NET_NETIF_START, device_id);
 }
 
@@ -136,5 +136,5 @@
 int netif_stop_req(int netif_phone, device_id_t device_id)
 {
-	return async_req_1_0(netif_phone, NET_NETIF_STOP, device_id);
+	return async_obsolete_req_1_0(netif_phone, NET_NETIF_STOP, device_id);
 }
 
@@ -154,7 +154,7 @@
 		return EBADMEM;
 	
-	aid_t message_id = async_send_1(netif_phone, NET_NETIF_STATS,
+	aid_t message_id = async_obsolete_send_1(netif_phone, NET_NETIF_STATS,
 	    (sysarg_t) device_id, NULL);
-	async_data_read_start(netif_phone, stats, sizeof(*stats));
+	async_obsolete_data_read_start(netif_phone, stats, sizeof(*stats));
 	
 	sysarg_t result;
Index: uspace/lib/net/netif/netif_skel.c
===================================================================
--- uspace/lib/net/netif/netif_skel.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/netif/netif_skel.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -54,4 +54,7 @@
 #include <nil_remote.h>
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 DEVICE_MAP_IMPLEMENT(netif_device_map, netif_device_t);
 
@@ -288,8 +291,8 @@
 	*count = 0;
 	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
-	
 	case NET_NETIF_PROBE:
 		return netif_probe_req_local(0, IPC_GET_DEVICE(*call),
@@ -385,6 +388,5 @@
 		
 		/* End if said to either by the message or the processing result */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
-		    (res == EHANGUP))
+		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
 			return;
 		
Index: uspace/lib/net/nil/nil_skel.c
===================================================================
--- uspace/lib/net/nil/nil_skel.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/nil/nil_skel.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,7 @@
 #include <net/modules.h>
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 /** Default thread for new connections.
  *
@@ -75,6 +78,5 @@
 		 * result.
 		 */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
-		    (res == EHANGUP))
+		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
 			return;
 		
Index: uspace/lib/net/tl/icmp_remote.c
===================================================================
--- uspace/lib/net/tl/icmp_remote.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/tl/icmp_remote.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,4 +41,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <errno.h>
 #include <ipc/services.h>
@@ -64,5 +65,5 @@
     icmp_param_t mtu, packet_t *packet)
 {
-	async_msg_3(icmp_phone, NET_ICMP_DEST_UNREACH, (sysarg_t) code,
+	async_obsolete_msg_3(icmp_phone, NET_ICMP_DEST_UNREACH, (sysarg_t) code,
 	    (sysarg_t) packet_get_id(packet), (sysarg_t) mtu);
 	return EOK;
@@ -83,5 +84,5 @@
 int icmp_source_quench_msg(int icmp_phone, packet_t *packet)
 {
-	async_msg_2(icmp_phone, NET_ICMP_SOURCE_QUENCH, 0,
+	async_obsolete_msg_2(icmp_phone, NET_ICMP_SOURCE_QUENCH, 0,
 	    (sysarg_t) packet_get_id(packet));
 	return EOK;
@@ -103,5 +104,5 @@
 int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t *packet)
 {
-	async_msg_2(icmp_phone, NET_ICMP_TIME_EXCEEDED, (sysarg_t) code,
+	async_obsolete_msg_2(icmp_phone, NET_ICMP_TIME_EXCEEDED, (sysarg_t) code,
 	    (sysarg_t) packet_get_id(packet));
 	return EOK;
@@ -125,5 +126,5 @@
     icmp_param_t pointer, packet_t *packet)
 {
-	async_msg_3(icmp_phone, NET_ICMP_PARAMETERPROB, (sysarg_t) code,
+	async_obsolete_msg_3(icmp_phone, NET_ICMP_PARAMETERPROB, (sysarg_t) code,
 	    (sysarg_t) packet_get_id(packet), (sysarg_t) pointer);
 	return EOK;
Index: uspace/lib/net/tl/tl_skel.c
===================================================================
--- uspace/lib/net/tl/tl_skel.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/net/tl/tl_skel.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,7 @@
 #include <net/modules.h>
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 /** Default thread for new connections.
  *
@@ -77,6 +80,5 @@
 		 * result.
 		 */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
-		    (res == EHANGUP))
+		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
 			return;
 		
Index: uspace/lib/packet/generic/packet_server.c
===================================================================
--- uspace/lib/packet/generic/packet_server.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/lib/packet/generic/packet_server.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -324,8 +324,9 @@
 
 	*answer_count = 0;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
-	
 	case NET_PACKET_CREATE_1:
 		packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2010 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusb
+EXTRA_CFLAGS += \
+	-I$(LIBDRV_PREFIX)/include \
+	-Iinclude
+
+SOURCES = \
+	src/class.c \
+	src/ddfiface.c \
+	src/debug.c \
+	src/dump.c \
+	src/hc.c \
+	src/resolve.c \
+	src/usb.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usb/include/usb/classes/classes.h
===================================================================
--- uspace/lib/usb/include/usb/classes/classes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/classes/classes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 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 libusb
+ * @{
+ */
+/** @file
+ * USB device classes (generic constants and functions).
+ */
+#ifndef LIBUSB_CLASSES_H_
+#define LIBUSB_CLASSES_H_
+
+/** USB device class. */
+typedef enum {
+	USB_CLASS_USE_INTERFACE = 0x00,
+	USB_CLASS_AUDIO = 0x01,
+	USB_CLASS_COMMUNICATIONS_CDC_CONTROL = 0x02,
+	USB_CLASS_HID = 0x03,
+	USB_CLASS_PHYSICAL = 0x05,
+	USB_CLASS_IMAGE = 0x06,
+	USB_CLASS_PRINTER = 0x07,
+	USB_CLASS_MASS_STORAGE = 0x08,
+	USB_CLASS_HUB = 0x09,
+	USB_CLASS_CDC_DATA = 0x0A,
+	USB_CLASS_SMART_CARD = 0x0B,
+	USB_CLASS_CONTENT_SECURITY = 0x0D,
+	USB_CLASS_VIDEO = 0x0E,
+	USB_CLASS_PERSONAL_HEALTHCARE = 0x0F,
+	USB_CLASS_DIAGNOSTIC = 0xDC,
+	USB_CLASS_WIRELESS_CONTROLLER = 0xE0,
+	USB_CLASS_MISCELLANEOUS = 0xEF,
+	USB_CLASS_APPLICATION_SPECIFIC = 0xFE,
+	USB_CLASS_VENDOR_SPECIFIC = 0xFF,
+	/* USB_CLASS_ = 0x, */
+} usb_class_t;
+
+const char *usb_str_class(usb_class_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * @brief USB hub related structures.
+ */
+#ifndef LIBUSB_CLASS_HUB_H_
+#define LIBUSB_CLASS_HUB_H_
+
+#include <sys/types.h>
+
+/** Hub class feature selector.
+ * @warning The constants are not unique (feature selectors are used
+ * for hub and port).
+ */
+typedef enum {
+	USB_HUB_FEATURE_HUB_LOCAL_POWER = 0,
+	USB_HUB_FEATURE_HUB_OVER_CURRENT = 1,
+	USB_HUB_FEATURE_C_HUB_LOCAL_POWER = 0,
+	USB_HUB_FEATURE_C_HUB_OVER_CURRENT = 1,
+	USB_HUB_FEATURE_PORT_CONNECTION = 0,
+	USB_HUB_FEATURE_PORT_ENABLE = 1,
+	USB_HUB_FEATURE_PORT_SUSPEND = 2,
+	USB_HUB_FEATURE_PORT_OVER_CURRENT = 3,
+	USB_HUB_FEATURE_PORT_RESET = 4,
+	USB_HUB_FEATURE_PORT_POWER = 8,
+	USB_HUB_FEATURE_PORT_LOW_SPEED = 9,
+	USB_HUB_FEATURE_C_PORT_CONNECTION = 16,
+	USB_HUB_FEATURE_C_PORT_ENABLE = 17,
+	USB_HUB_FEATURE_C_PORT_SUSPEND = 18,
+	USB_HUB_FEATURE_C_PORT_OVER_CURRENT = 19,
+	USB_HUB_FEATURE_C_PORT_RESET = 20,
+	/* USB_HUB_FEATURE_ = , */
+} usb_hub_class_feature_t;
+
+
+/** Header of standard hub descriptor without the "variadic" part. */
+typedef struct {
+	/** Descriptor length. */
+	uint8_t length;
+	/** Descriptor type (0x29). */
+	uint8_t descriptor_type;
+	/** Number of downstream ports. */
+	uint8_t port_count;
+	/** Characteristics bitmask. */
+	uint16_t characteristics;
+	/** Time from power-on to stabilization of current on the port. */
+	uint8_t power_good_time;
+	/** Maximum current requirements in mA. */
+	uint8_t max_current;
+} __attribute__ ((packed)) usb_hub_descriptor_header_t;
+
+/**
+ *	@brief usb hub descriptor
+ *
+ *	For more information see Universal Serial Bus Specification Revision 1.1 chapter 11.16.2
+ */
+typedef struct usb_hub_descriptor_type {
+    /** Number of bytes in this descriptor, including this byte */
+    //uint8_t bDescLength;
+
+    /** Descriptor Type, value: 29H for hub descriptor */
+    //uint8_t bDescriptorType;
+
+    /** Number of downstream ports that this hub supports */
+    uint8_t ports_count;
+
+    /**
+            D1...D0: Logical Power Switching Mode
+            00: Ganged power switching (all ports power at
+            once)
+            01: Individual port power switching
+            1X: Reserved. Used only on 1.0 compliant hubs
+            that implement no power switching.
+            D2: Identifies a Compound Device
+            0: Hub is not part of a compound device
+            1: Hub is part of a compound device
+            D4...D3: Over-current Protection Mode
+            00: Global Over-current Protection. The hub
+            reports over-current as a summation of all
+            ports current draw, without a breakdown of
+            individual port over-current status.
+            01: Individual Port Over-current Protection. The
+            hub reports over-current on a per-port basis.
+            Each port has an over-current indicator.
+            1X: No Over-current Protection. This option is
+            allowed only for bus-powered hubs that do not
+            implement over-current protection.
+            D15...D5:
+            Reserved
+     */
+    uint16_t hub_characteristics;
+
+    /**
+            Time (in 2ms intervals) from the time the power-on
+            sequence begins on a port until power is good on that
+            port. The USB System Software uses this value to
+            determine how long to wait before accessing a
+            powered-on port.
+     */
+    uint8_t pwr_on_2_good_time;
+
+    /**
+            Maximum current requirements of the Hub Controller
+            electronics in mA.
+     */
+    uint8_t current_requirement;
+
+    /**
+            Indicates if a port has a removable device attached.
+            This field is reported on byte-granularity. Within a
+            byte, if no port exists for a given location, the field
+            representing the port characteristics returns 0.
+            Bit value definition:
+            0B - Device is removable
+            1B - Device is non-removable
+            This is a bitmap corresponding to the individual ports
+            on the hub:
+            Bit 0: Reserved for future use
+            Bit 1: Port 1
+            Bit 2: Port 2
+            ....
+            Bit n: Port n (implementation-dependent, up to a
+            maximum of 255 ports).
+     */
+    uint8_t devices_removable[32];
+
+    /**
+            This field exists for reasons of compatibility with
+            software written for 1.0 compliant devices. All bits in
+            this field should be set to 1B. This field has one bit for
+            each port on the hub with additional pad bits, if
+            necessary, to make the number of bits in the field an
+            integer multiple of 8.
+     */
+    //uint8_t * port_pwr_ctrl_mask;
+} usb_hub_descriptor_t;
+
+
+
+/**	@brief usb hub specific request types.
+ *
+ *	For more information see Universal Serial Bus Specification Revision 1.1 chapter 11.16.2
+ */
+typedef enum {
+    /**	This request resets a value reported in the hub status.	*/
+    USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE = 0x20,
+    /** This request resets a value reported in the port status. */
+    USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE = 0x23,
+    /** This is an optional per-port diagnostic request that returns the bus state value, as sampled at the last EOF2 point. */
+    USB_HUB_REQ_TYPE_GET_STATE = 0xA3,
+    /** This request returns the hub descriptor. */
+    USB_HUB_REQ_TYPE_GET_DESCRIPTOR = 0xA0,
+    /** This request returns the current hub status and the states that have changed since the previous acknowledgment. */
+    USB_HUB_REQ_TYPE_GET_HUB_STATUS = 0xA0,
+    /** This request returns the current port status and the current value of the port status change bits. */
+    USB_HUB_REQ_TYPE_GET_PORT_STATUS = 0xA3,
+    /** This request overwrites the hub descriptor. */
+    USB_HUB_REQ_TYPE_SET_DESCRIPTOR = 0x20,
+    /** This request sets a value reported in the hub status. */
+    USB_HUB_REQ_TYPE_SET_HUB_FEATURE = 0x20,
+    /** This request sets a value reported in the port status. */
+    USB_HUB_REQ_TYPE_SET_PORT_FEATURE = 0x23
+} usb_hub_bm_request_type_t;
+
+/** @brief hub class request codes*/
+/// \TODO these are duplicit to standart descriptors
+typedef enum {
+    /**  */
+    USB_HUB_REQUEST_GET_STATUS = 0,
+    /** */
+    USB_HUB_REQUEST_CLEAR_FEATURE = 1,
+    /** */
+    USB_HUB_REQUEST_GET_STATE = 2,
+    /** */
+    USB_HUB_REQUEST_SET_FEATURE = 3,
+    /** */
+    USB_HUB_REQUEST_GET_DESCRIPTOR = 6,
+    /** */
+    USB_HUB_REQUEST_SET_DESCRIPTOR = 7
+} usb_hub_request_t;
+
+/**
+ *	Maximum size of usb hub descriptor in bytes
+ */
+extern size_t USB_HUB_MAX_DESCRIPTOR_SIZE;
+
+
+
+
+
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/massstor.h
===================================================================
--- uspace/lib/usb/include/usb/classes/massstor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/classes/massstor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,68 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * USB mass storage related functions and constants.
+ */
+#ifndef LIBUSB_CLASS_MASSSTOR_H_
+#define LIBUSB_CLASS_MASSSTOR_H_
+
+#include <sys/types.h>
+
+/** USB mass storage subclasses. */
+typedef enum {
+	USB_MASSSTOR_SUBCLASS_RBC = 0x01,
+	/** Also known as MMC-5. */
+	USB_MASSSTOR_SUBCLASS_ATAPI = 0x02,
+	USB_MASSSTOR_SUBCLASS_UFI = 0x04,
+	USB_MASSSTOR_SUBCLASS_SCSI = 0x06,
+	USB_MASSSTOR_SUBCLASS_LSDFS = 0x07,
+	USB_MASSSTOR_SUBCLASS_IEEE1667 = 0x08,
+	USB_MASSSTOR_SUBCLASS_VENDOR = 0xFF
+} usb_massstor_subclass_t;
+
+/** USB mass storage interface protocols. */
+typedef enum {
+	/** CBI transport with command completion interrupt. */
+	USB_MASSSTOR_PROTOCOL_CBI_CC = 0x00,
+	/** CBI transport with no command completion interrupt. */
+	USB_MASSSTOR_PROTOCOL_CBI = 0x01,
+	/** Bulk only transport. */
+	USB_MASSSTOR_PROTOCOL_BBB = 0x50,
+	/** USB attached SCSI. */
+	USB_MASSSTOR_PROTOCOL_UAS = 0x62,
+	USB_MASSSTOR_PROTOCOL_VENDOR = 0xFF
+} usb_massstor_protocol_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/ddfiface.h
===================================================================
--- uspace/lib/usb/include/usb/ddfiface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/ddfiface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,57 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Implementations of DDF interfaces functions.
+ */
+#ifndef LIBUSB_DDFIFACE_H_
+#define LIBUSB_DDFIFACE_H_
+
+#include <sys/types.h>
+#include <usb_iface.h>
+
+int usb_iface_get_hc_handle_hub_impl(ddf_fun_t *, devman_handle_t *);
+int usb_iface_get_address_hub_impl(ddf_fun_t *, devman_handle_t,
+    usb_address_t *);
+extern usb_iface_t usb_iface_hub_impl;
+
+int usb_iface_get_hc_handle_hub_child_impl(ddf_fun_t *, devman_handle_t *);
+int usb_iface_get_address_hub_child_impl(ddf_fun_t *, devman_handle_t,
+    usb_address_t *);
+extern usb_iface_t usb_iface_hub_child_impl;
+
+int usb_iface_get_hc_handle_hc_impl(ddf_fun_t *, devman_handle_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/debug.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2010-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 libusb
+ * @{
+ */
+/** @file
+ * Debugging related functions.
+ */
+#ifndef LIBUSB_DEBUG_H_
+#define LIBUSB_DEBUG_H_
+#include <stdio.h>
+#include <inttypes.h>
+#include <usb/usb.h>
+#include <assert.h>
+
+void usb_dump_standard_descriptor(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+
+/** Logging level. */
+typedef enum {
+	/** Fatal, unrecoverable, error.
+	 * Such error prevents the driver from working at all.
+	 */
+	USB_LOG_LEVEL_FATAL,
+
+	/** Serious but recoverable error
+	 * Shall be used for errors fatal for single device but not for
+	 * driver itself.
+	 */
+	USB_LOG_LEVEL_ERROR,
+
+	/** Warning.
+	 * Problems from which the driver is able to recover gracefully.
+	 */
+	USB_LOG_LEVEL_WARNING,
+
+	/** Information message.
+	 * This should be the last level that is printed by default to
+	 * the screen.
+	 * Typical usage is to inform that new device was found and what
+	 * are its capabilities.
+	 * Do not use for repetitive actions (such as device polling).
+	 */
+	USB_LOG_LEVEL_INFO,
+
+	/** Debugging message. */
+	USB_LOG_LEVEL_DEBUG,
+
+	/** More detailed debugging message. */
+	USB_LOG_LEVEL_DEBUG2,
+
+	/** Terminating constant for logging levels. */
+	USB_LOG_LEVEL_MAX
+} usb_log_level_t;
+
+/** Default log level. */
+#ifdef CONFIG_USB_RELEASE_BUILD
+#  define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_INFO
+#else
+#  define USB_LOG_LEVEL_DEFAULT USB_LOG_LEVEL_DEBUG
+#endif
+
+void usb_log_enable(usb_log_level_t, const char *);
+
+void usb_log_printf(usb_log_level_t, const char *, ...)
+	PRINTF_ATTRIBUTE(2, 3);
+
+/** Log fatal error. */
+#define usb_log_fatal(format, ...) \
+	usb_log_printf(USB_LOG_LEVEL_FATAL, format, ##__VA_ARGS__)
+
+/** Log normal (recoverable) error. */
+#define usb_log_error(format, ...) \
+	usb_log_printf(USB_LOG_LEVEL_ERROR, format, ##__VA_ARGS__)
+
+/** Log warning. */
+#define usb_log_warning(format, ...) \
+	usb_log_printf(USB_LOG_LEVEL_WARNING, format, ##__VA_ARGS__)
+
+/** Log informational message. */
+#define usb_log_info(format, ...) \
+	usb_log_printf(USB_LOG_LEVEL_INFO, format, ##__VA_ARGS__)
+
+/** Log debugging message. */
+#define usb_log_debug(format, ...) \
+	usb_log_printf(USB_LOG_LEVEL_DEBUG, format, ##__VA_ARGS__)
+
+/** Log verbose debugging message. */
+#define usb_log_debug2(format, ...) \
+	usb_log_printf(USB_LOG_LEVEL_DEBUG2, format, ##__VA_ARGS__)
+
+const char *usb_debug_str_buffer(const uint8_t *, size_t, size_t);
+
+
+#endif
+/**
+ * @}
+ */
+
Index: uspace/lib/usb/include/usb/descriptor.h
===================================================================
--- uspace/lib/usb/include/usb/descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/descriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2010 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 libusb
+ * @{
+ */
+/** @file
+ * Standard USB descriptors.
+ */
+#ifndef LIBUSB_DESCRIPTOR_H_
+#define LIBUSB_DESCRIPTOR_H_
+
+#include <async.h>
+
+/** Descriptor type. */
+typedef enum {
+	USB_DESCTYPE_DEVICE = 1,
+	USB_DESCTYPE_CONFIGURATION = 2,
+	USB_DESCTYPE_STRING = 3,
+	USB_DESCTYPE_INTERFACE = 4,
+	USB_DESCTYPE_ENDPOINT = 5,
+	USB_DESCTYPE_HID = 0x21,
+	USB_DESCTYPE_HID_REPORT = 0x22,
+	USB_DESCTYPE_HID_PHYSICAL = 0x23,
+	USB_DESCTYPE_HUB = 0x29,
+	/* USB_DESCTYPE_ = */
+} usb_descriptor_type_t;
+
+/** Standard USB device descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_DEVICE). */
+	uint8_t descriptor_type;
+	/** USB specification release number.
+	 * The number shall be coded as binary-coded decimal (BCD).
+	 */
+	uint16_t usb_spec_version;
+	/** Device class. */
+	uint8_t device_class;
+	/** Device sub-class. */
+	uint8_t device_subclass;
+	/** Device protocol. */
+	uint8_t device_protocol;
+	/** Maximum packet size for endpoint zero.
+	 * Valid values are only 8, 16, 32, 64).
+	 */
+	uint8_t max_packet_size;
+	/** Vendor ID. */
+	uint16_t vendor_id;
+	/** Product ID. */
+	uint16_t product_id;
+	/** Device release number (in BCD). */
+	uint16_t device_version;
+	/** Manufacturer descriptor index. */
+	uint8_t str_manufacturer;
+	/** Product descriptor index. */
+	uint8_t str_product;
+	/** Device serial number descriptor index. */
+	uint8_t str_serial_number;
+	/** Number of possible configurations. */
+	uint8_t configuration_count;
+} __attribute__ ((packed)) usb_standard_device_descriptor_t;
+
+/** Standard USB configuration descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_CONFIGURATION). */
+	uint8_t descriptor_type;
+	/** Total length of all data of this configuration.
+	 * This includes the combined length of all descriptors
+	 * (configuration, interface, endpoint, class-specific and
+	 * vendor-specific) valid for this configuration.
+	 */
+	uint16_t total_length;
+	/** Number of possible interfaces under this configuration. */
+	uint8_t interface_count;
+	/** Configuration value used when setting this configuration. */
+	uint8_t configuration_number;
+	/** String descriptor describing this configuration. */
+	uint8_t str_configuration;
+	/** Attribute bitmap. */
+	uint8_t attributes;
+	/** Maximum power consumption from the USB under this configuration.
+	 * Expressed in 2mA unit (e.g. 50 ~ 100mA).
+	 */
+	uint8_t max_power;
+} __attribute__ ((packed)) usb_standard_configuration_descriptor_t;
+
+/** Standard USB interface descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_INTERFACE). */
+	uint8_t descriptor_type;
+	/** Number of interface.
+	 * Zero-based index into array of interfaces for current configuration.
+	 */
+	uint8_t interface_number;
+	/** Alternate setting for value in interface_number. */
+	uint8_t alternate_setting;
+	/** Number of endpoints used by this interface.
+	 * This number must exclude usage of endpoint zero
+	 * (default control pipe).
+	 */
+	uint8_t endpoint_count;
+	/** Class code. */
+	uint8_t interface_class;
+	/** Subclass code. */
+	uint8_t interface_subclass;
+	/** Protocol code. */
+	uint8_t interface_protocol;
+	/** String descriptor describing this interface. */
+	uint8_t str_interface;
+} __attribute__ ((packed)) usb_standard_interface_descriptor_t;
+
+/** Standard USB endpoint descriptor.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_ENDPOINT). */
+	uint8_t descriptor_type;
+	/** Endpoint address together with data flow direction. */
+	uint8_t endpoint_address;
+	/** Endpoint attributes.
+	 * Includes transfer type (usb_transfer_type_t).
+	 */
+	uint8_t attributes;
+	/** Maximum packet size. */
+	uint16_t max_packet_size;
+	/** Polling interval in milliseconds.
+	 * Ignored for bulk and control endpoints.
+	 * Isochronous endpoints must use value 1.
+	 * Interrupt endpoints any value from 1 to 255.
+	 */
+	uint8_t poll_interval;
+} __attribute__ ((packed)) usb_standard_endpoint_descriptor_t;
+
+/** Part of standard USB HID descriptor specifying one class descriptor.
+ *
+ * (See HID Specification, p.22)
+ */
+typedef struct {
+	/** Type of class-specific descriptor (Report or Physical). */
+	uint8_t type;
+	/** Length of class-specific descriptor in bytes. */
+	uint16_t length;
+} __attribute__ ((packed)) usb_standard_hid_class_descriptor_info_t;
+
+/** Standard USB HID descriptor.
+ *
+ * (See HID Specification, p.22)
+ *
+ * It is actually only the "header" of the descriptor, it does not contain
+ * the last two mandatory fields (type and length of the first class-specific
+ * descriptor).
+ */
+typedef struct {
+	/** Total size of this descriptor in bytes.
+	 *
+	 * This includes all class-specific descriptor info - type + length
+	 * for each descriptor.
+	 */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_HID). */
+	uint8_t descriptor_type;
+	/** HID Class Specification release. */
+	uint16_t spec_release;
+	/** Country code of localized hardware. */
+	uint8_t country_code;
+	/** Total number of class-specific (i.e. Report and Physical)
+	 * descriptors.
+	 *
+	 * @note There is always only one Report descriptor.
+	 */
+	uint8_t class_desc_count;
+	/** First mandatory class descriptor (Report) info. */
+	usb_standard_hid_class_descriptor_info_t report_desc_info;
+} __attribute__ ((packed)) usb_standard_hid_descriptor_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/hc.h
===================================================================
--- uspace/lib/usb/include/usb/hc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/hc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,76 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * General communication with host controller driver.
+ */
+#ifndef LIBUSB_HC_H_
+#define LIBUSB_HC_H_
+
+#include <sys/types.h>
+#include <ipc/devman.h>
+#include <ddf/driver.h>
+#include <bool.h>
+#include <async.h>
+#include <usb/usb.h>
+
+/** Connection to the host controller driver. */
+typedef struct {
+	/** Devman handle of the host controller. */
+	devman_handle_t hc_handle;
+	/** Session to the host controller. */
+	async_sess_t *hc_sess;
+} usb_hc_connection_t;
+
+int usb_hc_connection_initialize_from_device(usb_hc_connection_t *,
+    ddf_dev_t *);
+int usb_hc_connection_initialize(usb_hc_connection_t *, devman_handle_t);
+
+int usb_hc_connection_open(usb_hc_connection_t *);
+bool usb_hc_connection_is_opened(const usb_hc_connection_t *);
+int usb_hc_connection_close(usb_hc_connection_t *);
+int usb_hc_get_handle_by_address(usb_hc_connection_t *, usb_address_t,
+    devman_handle_t *);
+
+int usb_hc_get_address_by_handle(devman_handle_t);
+
+int usb_hc_find(devman_handle_t, devman_handle_t *);
+
+int usb_resolve_device_handle(const char *, devman_handle_t *, usb_address_t *,
+    devman_handle_t *);
+
+int usb_ddf_get_hc_handle_by_class(size_t, devman_handle_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/include/usb/usb.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2010 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 libusb
+ * @{
+ */
+/** @file
+ * Common USB types and functions.
+ */
+#ifndef LIBUSB_USB_H_
+#define LIBUSB_USB_H_
+
+#include <sys/types.h>
+#include <byteorder.h>
+
+/** Convert 16bit value from native (host) endianness to USB endianness. */
+#define uint16_host2usb(n) host2uint16_t_le((n))
+
+/** Convert 32bit value from native (host) endianness to USB endianness. */
+#define uint32_host2usb(n) host2uint32_t_le((n))
+
+/** Convert 16bit value from USB endianness into native (host) one. */
+#define uint16_usb2host(n) uint16_t_le2host((n))
+
+/** Convert 32bit value from USB endianness into native (host) one. */
+#define uint32_usb2host(n) uint32_t_le2host((n))
+
+
+/** USB transfer type. */
+typedef enum {
+	USB_TRANSFER_CONTROL = 0,
+	USB_TRANSFER_ISOCHRONOUS = 1,
+	USB_TRANSFER_BULK = 2,
+	USB_TRANSFER_INTERRUPT = 3
+} usb_transfer_type_t;
+
+const char * usb_str_transfer_type(usb_transfer_type_t t);
+const char * usb_str_transfer_type_short(usb_transfer_type_t t);
+
+/** USB data transfer direction. */
+typedef enum {
+	USB_DIRECTION_IN,
+	USB_DIRECTION_OUT,
+	USB_DIRECTION_BOTH
+} usb_direction_t;
+
+/** USB speeds. */
+typedef enum {
+	/** USB 1.1 low speed (1.5Mbits/s). */
+	USB_SPEED_LOW,
+	/** USB 1.1 full speed (12Mbits/s). */
+	USB_SPEED_FULL,
+	/** USB 2.0 high speed (480Mbits/s). */
+	USB_SPEED_HIGH,
+	/** Psuedo-speed serving as a boundary. */
+	USB_SPEED_MAX
+} usb_speed_t;
+
+const char *usb_str_speed(usb_speed_t);
+
+
+/** USB request type target. */
+typedef enum {
+	USB_REQUEST_TYPE_STANDARD = 0,
+	USB_REQUEST_TYPE_CLASS = 1,
+	USB_REQUEST_TYPE_VENDOR = 2
+} usb_request_type_t;
+
+/** USB request recipient. */
+typedef enum {
+	USB_REQUEST_RECIPIENT_DEVICE = 0,
+	USB_REQUEST_RECIPIENT_INTERFACE = 1,
+	USB_REQUEST_RECIPIENT_ENDPOINT = 2,
+	USB_REQUEST_RECIPIENT_OTHER = 3
+} usb_request_recipient_t;
+
+/** USB address type.
+ * Negative values could be used to indicate error.
+ */
+typedef int usb_address_t;
+
+/** Default USB address. */
+#define USB_ADDRESS_DEFAULT 0
+/** Maximum address number in USB 1.1. */
+#define USB11_ADDRESS_MAX 128
+
+/** USB endpoint number type.
+ * Negative values could be used to indicate error.
+ */
+typedef int usb_endpoint_t;
+
+/** Maximum endpoint number in USB 1.1.
+ */
+#define USB11_ENDPOINT_MAX 16
+
+
+/** USB complete address type. 
+ * Pair address + endpoint is identification of transaction recipient.
+ */
+typedef struct {
+	usb_address_t address;
+	usb_endpoint_t endpoint;
+} usb_target_t;
+
+/** Compare USB targets (addresses and endpoints).
+ *
+ * @param a First target.
+ * @param b Second target.
+ * @return Whether @p a and @p b points to the same pipe on the same device.
+ */
+static inline int usb_target_same(usb_target_t a, usb_target_t b)
+{
+	return (a.address == b.address)
+	    && (a.endpoint == b.endpoint);
+}
+
+/** General handle type.
+ * Used by various USB functions as opaque handle.
+ */
+typedef sysarg_t usb_handle_t;
+
+/** USB packet identifier. */
+typedef enum {
+#define _MAKE_PID_NIBBLE(tag, type) \
+	((uint8_t)(((tag) << 2) | (type)))
+#define _MAKE_PID(tag, type) \
+	( \
+	    _MAKE_PID_NIBBLE(tag, type) \
+	    | ((~_MAKE_PID_NIBBLE(tag, type)) << 4) \
+	)
+	USB_PID_OUT = _MAKE_PID(0, 1),
+	USB_PID_IN = _MAKE_PID(2, 1),
+	USB_PID_SOF = _MAKE_PID(1, 1),
+	USB_PID_SETUP = _MAKE_PID(3, 1),
+
+	USB_PID_DATA0 = _MAKE_PID(0 ,3),
+	USB_PID_DATA1 = _MAKE_PID(2 ,3),
+
+	USB_PID_ACK = _MAKE_PID(0 ,2),
+	USB_PID_NAK = _MAKE_PID(2 ,2),
+	USB_PID_STALL = _MAKE_PID(3 ,2),
+
+	USB_PID_PRE = _MAKE_PID(3 ,0),
+	/* USB_PID_ = _MAKE_PID( ,), */
+#undef _MAKE_PID
+#undef _MAKE_PID_NIBBLE
+} usb_packet_id;
+
+/** Class name for USB host controllers. */
+#define USB_HC_DDF_CLASS_NAME "usbhc"
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/class.c
===================================================================
--- uspace/lib/usb/src/class.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/class.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010 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 libusb
+ * @{
+ */
+/** @file
+ * @brief Class related functions.
+ */
+#include <usb/classes/classes.h>
+#include <errno.h>
+
+/** Tell string representation of USB class.
+ *
+ * @param cls Class code.
+ * @return String representation.
+ */
+const char *usb_str_class(usb_class_t cls)
+{
+	switch (cls) {
+		case USB_CLASS_USE_INTERFACE:
+			return "use-interface";
+		case USB_CLASS_AUDIO:
+			return "audio";
+		case USB_CLASS_COMMUNICATIONS_CDC_CONTROL:
+			return "communications";
+		case USB_CLASS_HID:
+			return "HID";
+		case USB_CLASS_PHYSICAL:
+			return "physical";
+		case USB_CLASS_IMAGE:
+			return "image";
+		case USB_CLASS_PRINTER:
+			return "printer";
+		case USB_CLASS_MASS_STORAGE:
+			return "mass-storage";
+		case USB_CLASS_HUB:
+			return "hub";
+		case USB_CLASS_CDC_DATA:
+			return "CDC";
+		case USB_CLASS_SMART_CARD:
+			return "smart-card";
+		case USB_CLASS_CONTENT_SECURITY:
+			return "security";
+		case USB_CLASS_VIDEO:
+			return "video";
+		case USB_CLASS_PERSONAL_HEALTHCARE:
+			return "healthcare";
+		case USB_CLASS_DIAGNOSTIC:
+			return "diagnostic";
+		case USB_CLASS_WIRELESS_CONTROLLER:
+			return "wireless";
+		case USB_CLASS_MISCELLANEOUS:
+			return "misc";
+		case USB_CLASS_APPLICATION_SPECIFIC:
+			return "application";
+		case USB_CLASS_VENDOR_SPECIFIC:
+			return "vendor";
+		default:
+			return "unknown";
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/ddfiface.c
===================================================================
--- uspace/lib/usb/src/ddfiface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/ddfiface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,175 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Implementations of DDF interfaces functions (actual implementation).
+ */
+#include <ipc/devman.h>
+#include <devman.h>
+#include <async.h>
+#include <usb/ddfiface.h>
+#include <usb/hc.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <assert.h>
+
+/** DDF interface for USB device, implementation for typical hub. */
+usb_iface_t  usb_iface_hub_impl = {
+	.get_hc_handle = usb_iface_get_hc_handle_hub_impl,
+	.get_address = usb_iface_get_address_hub_impl
+};
+
+/** DDF interface for USB device, implementation for child of a typical hub. */
+usb_iface_t  usb_iface_hub_child_impl = {
+	.get_hc_handle = usb_iface_get_hc_handle_hub_child_impl,
+	.get_address = usb_iface_get_address_hub_child_impl
+};
+
+
+/** Get host controller handle, interface implementation for hub driver.
+ *
+ * @param[in] fun Device function the operation is running on.
+ * @param[out] handle Storage for the host controller handle.
+ * @return Error code.
+ */
+int usb_iface_get_hc_handle_hub_impl(ddf_fun_t *fun, devman_handle_t *handle)
+{
+	assert(fun);
+	return usb_hc_find(fun->handle, handle);
+}
+
+/** Get host controller handle, interface implementation for child of
+ * a hub driver.
+ *
+ * @param[in] fun Device function the operation is running on.
+ * @param[out] handle Storage for the host controller handle.
+ * @return Error code.
+ */
+int usb_iface_get_hc_handle_hub_child_impl(ddf_fun_t *fun,
+    devman_handle_t *handle)
+{
+	assert(fun != NULL);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, fun->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	
+	sysarg_t hc_handle;
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &hc_handle);
+	
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+	
+	if (rc != EOK)
+		return rc;
+	
+	*handle = hc_handle;
+	return EOK;
+}
+
+/** Get host controller handle, interface implementation for HC driver.
+ *
+ * @param[in] fun Device function the operation is running on.
+ * @param[out] handle Storage for the host controller handle.
+ * @return Always EOK.
+ */
+int usb_iface_get_hc_handle_hc_impl(ddf_fun_t *fun, devman_handle_t *handle)
+{
+	assert(fun);
+
+	if (handle != NULL) {
+		*handle = fun->handle;
+	}
+
+	return EOK;
+}
+
+/** Get USB device address, interface implementation for hub driver.
+ *
+ * @param[in] fun Device function the operation is running on.
+ * @param[in] handle Devman handle of USB device we want address of.
+ * @param[out] address Storage for USB address of device with handle @p handle.
+ * @return Error code.
+ */
+int usb_iface_get_address_hub_impl(ddf_fun_t *fun, devman_handle_t handle,
+    usb_address_t *address)
+{
+	assert(fun);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, fun->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	
+	sysarg_t addr;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_ADDRESS, handle, &addr);
+	
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+	
+	if (rc != EOK)
+		return rc;
+	
+	if (address != NULL)
+		*address = (usb_address_t) addr;
+	
+	return EOK;
+}
+
+/** Get USB device address, interface implementation for child of
+ * a hub driver.
+ *
+ * @param[in] fun Device function the operation is running on.
+ * @param[in] handle Devman handle of USB device we want address of.
+ * @param[out] address Storage for USB address of device with handle @p handle.
+ * @return Error code.
+ */
+int usb_iface_get_address_hub_child_impl(ddf_fun_t *fun,
+    devman_handle_t handle, usb_address_t *address)
+{
+	if (handle == 0) {
+		handle = fun->handle;
+	}
+	return usb_iface_get_address_hub_impl(fun, handle, address);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/debug.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2010-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 libusb
+ * @{
+ */
+/** @file
+ * Debugging and logging support.
+ */
+#include <adt/list.h>
+#include <fibril_synch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <usb/debug.h>
+
+/** Level of logging messages. */
+static usb_log_level_t log_level = USB_LOG_LEVEL_WARNING;
+
+/** Prefix for logging messages. */
+static const char *log_prefix = "usb";
+
+/** Serialization mutex for logging functions. */
+static FIBRIL_MUTEX_INITIALIZE(log_serializer);
+
+/** File where to store the log. */
+static FILE *log_stream = NULL;
+
+
+/** Enable logging.
+ *
+ * @param level Maximal enabled level (including this one).
+ * @param message_prefix Prefix for each printed message.
+ */
+void usb_log_enable(usb_log_level_t level, const char *message_prefix)
+{
+	log_prefix = message_prefix;
+	log_level = level;
+	if (log_stream == NULL) {
+		char *fname;
+		int rc = asprintf(&fname, "/log/%s", message_prefix);
+		if (rc > 0) {
+			log_stream = fopen(fname, "w");
+			free(fname);
+		}
+	}
+}
+
+/** Get log level name prefix.
+ *
+ * @param level Log level.
+ * @return String prefix for the message.
+ */
+static const char *log_level_name(usb_log_level_t level)
+{
+	switch (level) {
+		case USB_LOG_LEVEL_FATAL:
+			return " FATAL";
+		case USB_LOG_LEVEL_ERROR:
+			return " ERROR";
+		case USB_LOG_LEVEL_WARNING:
+			return " WARN";
+		case USB_LOG_LEVEL_INFO:
+			return " info";
+		default:
+			return "";
+	}
+}
+
+/** Print logging message.
+ *
+ * @param level Verbosity level of the message.
+ * @param format Formatting directive.
+ */
+void usb_log_printf(usb_log_level_t level, const char *format, ...)
+{
+	FILE *screen_stream = NULL;
+	switch (level) {
+		case USB_LOG_LEVEL_FATAL:
+		case USB_LOG_LEVEL_ERROR:
+			screen_stream = stderr;
+			break;
+		default:
+			screen_stream = stdout;
+			break;
+	}
+	assert(screen_stream != NULL);
+
+	va_list args;
+
+	/*
+	 * Serialize access to log files.
+	 * Print to screen only messages with higher level than the one
+	 * specified during logging initialization.
+	 * Print also to file, to it print one more (lower) level as well.
+	 */
+	fibril_mutex_lock(&log_serializer);
+
+	const char *level_name = log_level_name(level);
+
+	if ((log_stream != NULL) && (level <= log_level + 1)) {
+		va_start(args, format);
+
+		fprintf(log_stream, "[%s]%s: ", log_prefix, level_name);
+		vfprintf(log_stream, format, args);
+		fflush(log_stream);
+
+		va_end(args);
+	}
+
+	if (level <= log_level) {
+		va_start(args, format);
+
+		fprintf(screen_stream, "[%s]%s: ", log_prefix, level_name);
+		vfprintf(screen_stream, format, args);
+		fflush(screen_stream);
+
+		va_end(args);
+	}
+
+	fibril_mutex_unlock(&log_serializer);
+}
+
+
+#define REMAINDER_STR_FMT " (%zu)..."
+/* string + terminator + number width (enough for 4GB)*/
+#define REMAINDER_STR_LEN (5 + 1 + 10)
+
+/** How many bytes to group together. */
+#define BUFFER_DUMP_GROUP_SIZE 4
+
+/** Size of the string for buffer dumps. */
+#define BUFFER_DUMP_LEN 240 /* Ought to be enough for everybody ;-). */
+
+/** Fibril local storage for the dumped buffer. */
+static fibril_local char buffer_dump[2][BUFFER_DUMP_LEN];
+/** Fibril local storage for buffer switching. */
+static fibril_local int buffer_dump_index = 0;
+
+/** Dump buffer into string.
+ *
+ * The function dumps given buffer into hexadecimal format and stores it
+ * in a static fibril local string.
+ * That means that you do not have to deallocate the string (actually, you
+ * can not do that) and you do not have to guard it against concurrent
+ * calls to it.
+ * The only limitation is that each second call rewrites the buffer again
+ * (internally, two buffer are used in cyclic manner).
+ * Thus, it is necessary to copy the buffer elsewhere (that includes printing
+ * to screen or writing to file).
+ * Since this function is expected to be used for debugging prints only,
+ * that is not a big limitation.
+ *
+ * @warning You cannot use this function more than twice in the same printf
+ * (see detailed explanation).
+ *
+ * @param buffer Buffer to be printed (can be NULL).
+ * @param size Size of the buffer in bytes (can be zero).
+ * @param dumped_size How many bytes to actually dump (zero means all).
+ * @return Dumped buffer as a static (but fibril local) string.
+ */
+const char *usb_debug_str_buffer(const uint8_t *buffer, size_t size,
+    size_t dumped_size)
+{
+	/*
+	 * Remove previous string.
+	 */
+	bzero(buffer_dump[buffer_dump_index], BUFFER_DUMP_LEN);
+
+	if (buffer == NULL) {
+		return "(null)";
+	}
+	if (size == 0) {
+		return "(empty)";
+	}
+	if ((dumped_size == 0) || (dumped_size > size)) {
+		dumped_size = size;
+	}
+
+	/* How many bytes are available in the output buffer. */
+	size_t buffer_remaining_size = BUFFER_DUMP_LEN - 1 - REMAINDER_STR_LEN;
+	char *it = buffer_dump[buffer_dump_index];
+
+	size_t index = 0;
+
+	while (index < size) {
+		/* Determine space before the number. */
+		const char *space_before;
+		if (index == 0) {
+			space_before = "";
+		} else if ((index % BUFFER_DUMP_GROUP_SIZE) == 0) {
+			space_before = "  ";
+		} else {
+			space_before = " ";
+		}
+
+		/*
+		 * Add the byte as a hexadecimal number plus the space.
+		 * We do it into temporary buffer to ensure that always
+		 * the whole byte is printed.
+		 */
+		int val = buffer[index];
+		char current_byte[16];
+		int printed = snprintf(current_byte, 16,
+		    "%s%02x", space_before, val);
+		if (printed < 0) {
+			break;
+		}
+
+		if ((size_t) printed > buffer_remaining_size) {
+			break;
+		}
+
+		/* We can safely add 1, because space for end 0 is reserved. */
+		str_append(it, buffer_remaining_size + 1, current_byte);
+
+		buffer_remaining_size -= printed;
+		/* Point at the terminator 0. */
+		it += printed;
+		index++;
+
+		if (index >= dumped_size) {
+			break;
+		}
+	}
+
+	/* Add how many bytes were not printed. */
+	if (index < size) {
+		snprintf(it, REMAINDER_STR_LEN,
+		    REMAINDER_STR_FMT, size - index);
+	}
+
+	/* Next time, use the other buffer. */
+	buffer_dump_index = 1 - buffer_dump_index;
+
+	/* Need to take the old one due to previous line. */
+	return buffer_dump[1 - buffer_dump_index];
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/dump.c
===================================================================
--- uspace/lib/usb/src/dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,291 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Descriptor dumping.
+ */
+#include <adt/list.h>
+#include <fibril_synch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include <usb/descriptor.h>
+#include <usb/classes/classes.h>
+
+/** Mapping between descriptor id and dumping function. */
+typedef struct {
+	/** Descriptor id. */
+	int id;
+	/** Dumping function. */
+	void (*dump)(FILE *, const char *, const char *,
+	    const uint8_t *, size_t);
+} descriptor_dump_t;
+
+static void usb_dump_descriptor_device(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_configuration(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_interface(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_string(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_endpoint(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_hid(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_hub(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+static void usb_dump_descriptor_generic(FILE *, const char *, const char *,
+    const uint8_t *, size_t);
+
+/** Descriptor dumpers mapping. */
+static descriptor_dump_t descriptor_dumpers[] = {
+	{ USB_DESCTYPE_DEVICE, usb_dump_descriptor_device },
+	{ USB_DESCTYPE_CONFIGURATION, usb_dump_descriptor_configuration },
+	{ USB_DESCTYPE_STRING, usb_dump_descriptor_string },
+	{ USB_DESCTYPE_INTERFACE, usb_dump_descriptor_interface },
+	{ USB_DESCTYPE_ENDPOINT, usb_dump_descriptor_endpoint },
+	{ USB_DESCTYPE_HID, usb_dump_descriptor_hid },
+	{ USB_DESCTYPE_HUB, usb_dump_descriptor_hub },
+	{ -1, usb_dump_descriptor_generic },
+	{ -1, NULL }
+};
+
+/** Dumps standard USB descriptor.
+ * The @p line_suffix must contain the newline <code>\\n</code> character.
+ * When @p line_suffix or @p line_prefix is NULL, they are substitued with
+ * default values
+ * (<code> - </code> for prefix and line termination for suffix).
+ *
+ * @param output Output file stream to dump descriptor to.
+ * @param line_prefix Prefix for each line of output.
+ * @param line_suffix Suffix of each line of output.
+ * @param descriptor Actual descriptor.
+ * @param descriptor_length Descriptor size.
+ */
+void usb_dump_standard_descriptor(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	if (descriptor_length < 2) {
+		return;
+	}
+	int type = descriptor[1];
+
+	descriptor_dump_t *dumper = descriptor_dumpers;
+	while (dumper->dump != NULL) {
+		if ((dumper->id == type) || (dumper->id < 0)) {
+			dumper->dump(output, line_prefix, line_suffix,
+			    descriptor, descriptor_length);
+			return;
+		}
+		dumper++;
+	}
+}
+
+/** Prints single line of USB descriptor dump.
+ * @warning This macro abuses heavily the naming conventions used
+ * by all dumping functions (i.e. names for output file stream (@c output) and
+ * line prefix and suffix (@c line_prefix and @c line_suffix respectively))-
+ *
+ * @param fmt Formatting string.
+ */
+#define PRINTLINE(fmt, ...) \
+	fprintf(output, "%s" fmt "%s", \
+	    line_prefix ? line_prefix : " - ", \
+	    __VA_ARGS__, \
+	    line_suffix ? line_suffix : "\n")
+
+#define BCD_INT(a) (((unsigned int)(a)) / 256)
+#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
+
+#define BCD_FMT "%x.%x"
+#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
+
+static void usb_dump_descriptor_device(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	usb_standard_device_descriptor_t *d
+	    = (usb_standard_device_descriptor_t *) descriptor;
+	if (descriptor_length < sizeof(*d)) {
+		return;
+	}
+
+	PRINTLINE("bLength = %d", d->length);
+	PRINTLINE("bDescriptorType = 0x%02x", d->descriptor_type);
+	PRINTLINE("bcdUSB = %d (" BCD_FMT ")", d->usb_spec_version,
+	    BCD_ARGS(d->usb_spec_version));
+	PRINTLINE("bDeviceClass = 0x%02x", d->device_class);
+	PRINTLINE("bDeviceSubClass = 0x%02x", d->device_subclass);
+	PRINTLINE("bDeviceProtocol = 0x%02x", d->device_protocol);
+	PRINTLINE("bMaxPacketSize0 = %d", d->max_packet_size);
+	PRINTLINE("idVendor = 0x%04x", d->vendor_id);
+	PRINTLINE("idProduct = 0x%04x", d->product_id);
+	PRINTLINE("bcdDevice = %d", d->device_version);
+	PRINTLINE("iManufacturer = %d", d->str_manufacturer);
+	PRINTLINE("iProduct = %d", d->str_product);
+	PRINTLINE("iSerialNumber = %d", d->str_serial_number);
+	PRINTLINE("bNumConfigurations = %d", d->configuration_count);
+}
+
+static void usb_dump_descriptor_configuration(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	usb_standard_configuration_descriptor_t *d
+	    = (usb_standard_configuration_descriptor_t *) descriptor;
+	if (descriptor_length < sizeof(*d)) {
+		return;
+	}
+
+	bool self_powered = d->attributes & 64;
+	bool remote_wakeup = d->attributes & 32;
+
+	PRINTLINE("bLength = %d", d->length);
+	PRINTLINE("bDescriptorType = 0x%02x", d->descriptor_type);
+	PRINTLINE("wTotalLength = %d", d->total_length);
+	PRINTLINE("bNumInterfaces = %d", d->interface_count);
+	PRINTLINE("bConfigurationValue = %d", d->configuration_number);
+	PRINTLINE("iConfiguration = %d", d->str_configuration);
+	PRINTLINE("bmAttributes = %d [%s%s%s]", d->attributes,
+	    self_powered ? "self-powered" : "",
+	    (self_powered & remote_wakeup) ? ", " : "",
+	    remote_wakeup ? "remote-wakeup" : "");
+	PRINTLINE("MaxPower = %d (%dmA)", d->max_power,
+	    2 * d->max_power);
+}
+
+static void usb_dump_descriptor_interface(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	usb_standard_interface_descriptor_t *d
+	    = (usb_standard_interface_descriptor_t *) descriptor;
+	if (descriptor_length < sizeof(*d)) {
+		return;
+	}
+
+	PRINTLINE("bLength = %d", d->length);
+	PRINTLINE("bDescriptorType = 0x%02x", d->descriptor_type);
+	PRINTLINE("bInterfaceNumber = %d", d->interface_number);
+	PRINTLINE("bAlternateSetting = %d", d->alternate_setting);
+	PRINTLINE("bNumEndpoints = %d", d->endpoint_count);
+	PRINTLINE("bInterfaceClass = %s", d->interface_class == 0
+	    ? "reserved (0)" : usb_str_class(d->interface_class));
+	PRINTLINE("bInterfaceSubClass = %d", d->interface_subclass);
+	PRINTLINE("bInterfaceProtocol = %d", d->interface_protocol);
+	PRINTLINE("iInterface = %d", d->str_interface);
+}
+
+static void usb_dump_descriptor_string(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+}
+
+static void usb_dump_descriptor_endpoint(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	usb_standard_endpoint_descriptor_t *d
+	   = (usb_standard_endpoint_descriptor_t *) descriptor;
+	if (descriptor_length < sizeof(*d)) {
+		return;
+	}
+
+	int endpoint = d->endpoint_address & 15;
+	usb_direction_t direction = d->endpoint_address & 128
+	    ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
+	usb_transfer_type_t transfer_type = d->attributes & 3;
+
+	PRINTLINE("bLength = %d", d->length);
+	PRINTLINE("bDescriptorType = 0x%02X", d->descriptor_type);
+	PRINTLINE("bEndpointAddress = 0x%02X [%d, %s]",
+	    d->endpoint_address, endpoint,
+	    direction == USB_DIRECTION_IN ? "in" : "out");
+	PRINTLINE("bmAttributes = %d [%s]", d->attributes,
+	    usb_str_transfer_type(transfer_type));
+	PRINTLINE("wMaxPacketSize = %d", d->max_packet_size);
+	PRINTLINE("bInterval = %dms", d->poll_interval);
+}
+
+static void usb_dump_descriptor_hid(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	usb_standard_hid_descriptor_t *d
+	    = (usb_standard_hid_descriptor_t *) descriptor;
+	if (descriptor_length < sizeof(*d)) {
+		return;
+	}
+
+	PRINTLINE("bLength = %d", d->length);
+	PRINTLINE("bDescriptorType = 0x%02x", d->descriptor_type);
+	PRINTLINE("bcdHID = %d (" BCD_FMT ")", d->spec_release,
+	    BCD_ARGS(d->spec_release));
+	PRINTLINE("bCountryCode = %d", d->country_code);
+	PRINTLINE("bNumDescriptors = %d", d->class_desc_count);
+	PRINTLINE("bDescriptorType = %d", d->report_desc_info.type);
+	PRINTLINE("wDescriptorLength = %d", d->report_desc_info.length);
+
+	/* Print info about report descriptors. */
+	size_t i;
+	size_t count = (descriptor_length - sizeof(*d))
+	    / sizeof(usb_standard_hid_class_descriptor_info_t);
+	usb_standard_hid_class_descriptor_info_t *d2
+	    = (usb_standard_hid_class_descriptor_info_t *)
+	    (descriptor + sizeof(*d));
+	for (i = 0; i < count; i++, d2++) {
+		PRINTLINE("bDescriptorType = %d", d2->type);
+		PRINTLINE("wDescriptorLength = %d", d2->length);
+	}
+}
+
+static void usb_dump_descriptor_hub(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	/* TODO */
+}
+
+static void usb_dump_descriptor_generic(FILE *output,
+    const char *line_prefix, const char *line_suffix,
+    const uint8_t *descriptor, size_t descriptor_length)
+{
+	/* TODO */
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hc.c
===================================================================
--- uspace/lib/usb/src/hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,268 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * General communication with host controller driver (implementation).
+ */
+#include <devman.h>
+#include <async.h>
+#include <dev_iface.h>
+#include <usb_iface.h>
+#include <usbhc_iface.h>
+#include <usb/hc.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <assert.h>
+
+/** Initialize connection to USB host controller.
+ *
+ * @param connection Connection to be initialized.
+ * @param device Device connecting to the host controller.
+ * @return Error code.
+ */
+int usb_hc_connection_initialize_from_device(usb_hc_connection_t *connection,
+    ddf_dev_t *device)
+{
+	assert(connection);
+
+	if (device == NULL) {
+		return EBADMEM;
+	}
+
+	devman_handle_t hc_handle;
+	int rc = usb_hc_find(device->handle, &hc_handle);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_hc_connection_initialize(connection, hc_handle);
+
+	return rc;
+}
+
+/** Manually initialize connection to USB host controller.
+ *
+ * @param connection Connection to be initialized.
+ * @param hc_handle Devman handle of the host controller.
+ * @return Error code.
+ */
+int usb_hc_connection_initialize(usb_hc_connection_t *connection,
+    devman_handle_t hc_handle)
+{
+	assert(connection);
+
+	connection->hc_handle = hc_handle;
+	connection->hc_sess = NULL;
+
+	return EOK;
+}
+
+/** Open connection to host controller.
+ *
+ * @param connection Connection to the host controller.
+ * @return Error code.
+ */
+int usb_hc_connection_open(usb_hc_connection_t *connection)
+{
+	assert(connection);
+	
+	if (usb_hc_connection_is_opened(connection))
+		return EBUSY;
+	
+	async_sess_t *sess = devman_device_connect(EXCHANGE_SERIALIZE,
+	    connection->hc_handle, 0);
+	if (!sess)
+		return ENOMEM;
+	
+	connection->hc_sess = sess;
+	return EOK;
+}
+
+/** Tells whether connection to host controller is opened.
+ *
+ * @param connection Connection to the host controller.
+ * @return Whether connection is opened.
+ */
+bool usb_hc_connection_is_opened(const usb_hc_connection_t *connection)
+{
+	assert(connection);
+	return (connection->hc_sess != NULL);
+}
+
+/** Close connection to the host controller.
+ *
+ * @param connection Connection to the host controller.
+ * @return Error code.
+ */
+int usb_hc_connection_close(usb_hc_connection_t *connection)
+{
+	assert(connection);
+
+	if (!usb_hc_connection_is_opened(connection)) {
+		return ENOENT;
+	}
+
+	int rc = async_hangup(connection->hc_sess);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	connection->hc_sess = NULL;
+
+	return EOK;
+}
+
+/** Get handle of USB device with given address.
+ *
+ * @param[in] connection Opened connection to host controller.
+ * @param[in] address Address of device in question.
+ * @param[out] handle Where to write the device handle.
+ * @return Error code.
+ */
+int usb_hc_get_handle_by_address(usb_hc_connection_t *connection,
+    usb_address_t address, devman_handle_t *handle)
+{
+	if (!usb_hc_connection_is_opened(connection))
+		return ENOENT;
+	
+	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
+	
+	sysarg_t tmp;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
+	    address, &tmp);
+	
+	async_exchange_end(exch);
+	
+	if ((rc == EOK) && (handle != NULL))
+		*handle = tmp;
+	
+	return rc;
+}
+
+/** Tell USB address assigned to device with given handle.
+ *
+ * @param dev_handle Devman handle of the USB device in question.
+ * @return USB address or negative error code.
+ */
+usb_address_t usb_hc_get_address_by_handle(devman_handle_t dev_handle)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev_handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	
+	sysarg_t address;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_ADDRESS,
+	    dev_handle, &address);
+	
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (usb_address_t) address;
+}
+
+
+/** Get host controller handle by its class index.
+ *
+ * @param class_index Class index for the host controller.
+ * @param hc_handle Where to store the HC handle
+ *	(can be NULL for existence test only).
+ * @return Error code.
+ */
+int usb_ddf_get_hc_handle_by_class(size_t class_index,
+    devman_handle_t *hc_handle)
+{
+	char *class_index_str;
+	devman_handle_t hc_handle_tmp;
+	int rc;
+
+	rc = asprintf(&class_index_str, "%zu", class_index);
+	if (rc < 0) {
+		return ENOMEM;
+	}
+	rc = devman_device_get_handle_by_class("usbhc", class_index_str,
+	    &hc_handle_tmp, 0);
+	free(class_index_str);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (hc_handle != NULL) {
+		*hc_handle = hc_handle_tmp;
+	}
+
+	return EOK;
+}
+
+/** Find host controller handle that is ancestor of given device.
+ *
+ * @param[in] device_handle Device devman handle.
+ * @param[out] hc_handle Where to store handle of host controller
+ *	controlling device with @p device_handle handle.
+ * @return Error code.
+ */
+int usb_hc_find(devman_handle_t device_handle, devman_handle_t *hc_handle)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device_handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	
+	devman_handle_t h;
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
+	
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+	
+	if (rc != EOK)
+		return rc;
+	
+	if (hc_handle != NULL)
+		*hc_handle = h;
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/resolve.c
===================================================================
--- uspace/lib/usb/src/resolve.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/resolve.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,244 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ *
+ */
+#include <inttypes.h>
+#include <usb/hc.h>
+#include <devman.h>
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+
+#define MAX_DEVICE_PATH 1024
+
+static bool try_parse_bus_and_address(const char *path,
+    char **func_start,
+    devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
+{
+	size_t class_index;
+	size_t address;
+	int rc;
+	char *ptr;
+
+	rc = str_size_t(path, &ptr, 10, false, &class_index);
+	if (rc != EOK) {
+		return false;
+	}
+	if ((*ptr == ':') || (*ptr == '.')) {
+		ptr++;
+	} else {
+		return false;
+	}
+	rc = str_size_t(ptr, func_start, 10, false, &address);
+	if (rc != EOK) {
+		return false;
+	}
+	rc = usb_ddf_get_hc_handle_by_class(class_index, out_hc_handle);
+	if (rc != EOK) {
+		return false;
+	}
+	if (out_device_address != NULL) {
+		*out_device_address = (usb_address_t) address;
+	}
+	return true;
+}
+
+static int get_device_handle_by_address(devman_handle_t hc_handle, int addr,
+    devman_handle_t *dev_handle)
+{
+	int rc;
+	usb_hc_connection_t conn;
+
+	usb_hc_connection_initialize(&conn, hc_handle);
+	rc = usb_hc_connection_open(&conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
+
+	usb_hc_connection_close(&conn);
+
+	return rc;
+}
+
+/** Resolve handle and address of USB device from its path.
+ *
+ * This is a wrapper working on best effort principle.
+ * If the resolving fails, if will not give much details about what
+ * is wrong.
+ * Typically, error from this function would be reported to the user
+ * as "bad device specification" or "device does not exist".
+ *
+ * The path can be specified in following format:
+ *  - devman path (e.g. /hw/pci0/.../usb01_a5
+ *  - bus number and device address (e.g. 5.1)
+ *  - bus number, device address and device function (e.g. 2.1/HID0/keyboard)
+ *
+ * @param[in] dev_path Path to the device.
+ * @param[out] out_hc_handle Where to store handle of a parent host controller.
+ * @param[out] out_dev_addr Where to store device (USB) address.
+ * @param[out] out_dev_handle Where to store device handle.
+ * @return Error code.
+ */
+int usb_resolve_device_handle(const char *dev_path, devman_handle_t *out_hc_handle,
+    usb_address_t *out_dev_addr, devman_handle_t *out_dev_handle)
+{
+	if (dev_path == NULL) {
+		return EBADMEM;
+	}
+
+	bool found_hc = false;
+	bool found_addr = false;
+	devman_handle_t hc_handle, dev_handle;
+	usb_address_t dev_addr = -1;
+	int rc;
+	bool is_bus_addr;
+	char *func_start = NULL;
+	char *path = NULL;
+
+	/* First try the BUS.ADDR format. */
+	is_bus_addr = try_parse_bus_and_address(dev_path, &func_start,
+	    &hc_handle, &dev_addr);
+	if (is_bus_addr) {
+		found_hc = true;
+		found_addr = true;
+		/*
+		 * Now get the handle of the device. We will need that
+		 * in both cases. If there is only BUS.ADDR, it will
+		 * be the handle to be returned to the caller, otherwise
+		 * we will need it to resolve the path to which the
+		 * suffix would be appended.
+		 */
+		/* If there is nothing behind the BUS.ADDR, we will
+		 * get the device handle from the host controller.
+		 * Otherwise, we will
+		 */
+		rc = get_device_handle_by_address(hc_handle, dev_addr,
+		    &dev_handle);
+		if (rc != EOK) {
+			return rc;
+		}
+		if (str_length(func_start) > 0) {
+			char tmp_path[MAX_DEVICE_PATH ];
+			rc = devman_get_device_path(dev_handle,
+			    tmp_path, MAX_DEVICE_PATH);
+			if (rc != EOK) {
+				return rc;
+			}
+			rc = asprintf(&path, "%s%s", tmp_path, func_start);
+			if (rc < 0) {
+				return ENOMEM;
+			}
+		} else {
+			/* Everything is resolved. Get out of here. */
+			goto copy_out;
+		}
+	} else {
+		path = str_dup(dev_path);
+		if (path == NULL) {
+			return ENOMEM;
+		}
+	}
+
+	/* First try to get the device handle. */
+	rc = devman_device_get_handle(path, &dev_handle, 0);
+	if (rc != EOK) {
+		free(path);
+		/* Invalid path altogether. */
+		return rc;
+	}
+
+	/* Remove suffixes and hope that we will encounter device node. */
+	while (str_length(path) > 0) {
+		/* Get device handle first. */
+		devman_handle_t tmp_handle;
+		rc = devman_device_get_handle(path, &tmp_handle, 0);
+		if (rc != EOK) {
+			free(path);
+			return rc;
+		}
+
+		/* Try to find its host controller. */
+		if (!found_hc) {
+			rc = usb_hc_find(tmp_handle, &hc_handle);
+			if (rc == EOK) {
+				found_hc = true;
+			}
+		}
+
+		/* Try to get its address. */
+		if (!found_addr) {
+			dev_addr = usb_hc_get_address_by_handle(tmp_handle);
+			if (dev_addr >= 0) {
+				found_addr = true;
+			}
+		}
+
+		/* Speed-up. */
+		if (found_hc && found_addr) {
+			break;
+		}
+
+		/* Remove the last suffix. */
+		char *slash_pos = str_rchr(path, '/');
+		if (slash_pos != NULL) {
+			*slash_pos = 0;
+		}
+	}
+
+	free(path);
+
+	if (!found_addr || !found_hc) {
+		return ENOENT;
+	}
+
+copy_out:
+	if (out_dev_addr != NULL) {
+		*out_dev_addr = dev_addr;
+	}
+	if (out_hc_handle != NULL) {
+		*out_hc_handle = hc_handle;
+	}
+	if (out_dev_handle != NULL) {
+		*out_dev_handle = dev_handle;
+	}
+
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
+
Index: uspace/lib/usb/src/usb.c
===================================================================
--- uspace/lib/usb/src/usb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usb/src/usb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2010 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 libusb
+ * @{
+ */
+/** @file
+ * Common USB functions.
+ */
+#include <usb/usb.h>
+#include <errno.h>
+
+#define ARR_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+static const char *str_speed[] = {
+	"low",
+	"full",
+	"high"
+};
+
+static const char *str_transfer_type[] = {
+	"control",
+	"isochronous",
+	"bulk",
+	"interrupt"
+};
+
+static const char *str_transfer_type_short[] = {
+	"ctrl",
+	"iso",
+	"bulk",
+	"intr"
+};
+
+/** String representation for USB transfer type.
+ *
+ * @param t Transfer type.
+ * @return Transfer type as a string (in English).
+ */
+const char *usb_str_transfer_type(usb_transfer_type_t t)
+{
+	if (t >= ARR_SIZE(str_transfer_type)) {
+		return "invalid";
+	}
+	return str_transfer_type[t];
+}
+
+/** String representation for USB transfer type (short version).
+ *
+ * @param t Transfer type.
+ * @return Transfer type as a short string for debugging messages.
+ */
+const char *usb_str_transfer_type_short(usb_transfer_type_t t)
+{
+	if (t >= ARR_SIZE(str_transfer_type_short)) {
+		return "invl";
+	}
+	return str_transfer_type_short[t];
+}
+
+/** String representation of USB speed.
+ *
+ * @param s The speed.
+ * @return USB speed as a string (in English).
+ */
+const char *usb_str_speed(usb_speed_t s)
+{
+	if (s >= ARR_SIZE(str_speed)) {
+		return "invalid";
+	}
+	return str_speed[s];
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/Makefile
===================================================================
--- uspace/lib/usbdev/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusbdev
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include \
+	-Iinclude
+
+SOURCES = \
+	src/altiface.c \
+	src/devdrv.c \
+	src/devpoll.c \
+	src/dp.c \
+	src/hub.c \
+	src/pipepriv.c \
+	src/pipepriv.h \
+	src/pipes.c \
+	src/pipesinit.c \
+	src/pipesio.c \
+	src/recognise.c \
+	src/request.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbdev/include/usb/dev/dp.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/dp.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/dp.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,85 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB descriptor parser.
+ */
+#ifndef LIBUSBDEV_DP_H_
+#define LIBUSBDEV_DP_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+
+/** USB descriptors nesting.
+ * The nesting describes the logical tree USB descriptors form
+ * (e.g. that endpoint descriptor belongs to interface or that
+ * interface belongs to configuration).
+ *
+ * See usb_descriptor_type_t for descriptor constants.
+ */
+typedef struct {
+	/** Child descriptor id. */
+	int child;
+	/** Parent descriptor id. */
+	int parent;
+} usb_dp_descriptor_nesting_t;
+
+extern usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[];
+
+/** Descriptor parser structure. */
+typedef struct {
+	/** Used descriptor nesting. */
+	usb_dp_descriptor_nesting_t *nesting;
+} usb_dp_parser_t;
+
+/** Descriptor parser data. */
+typedef struct {
+	/** Data to be parsed. */
+	uint8_t *data;
+	/** Size of input data in bytes. */
+	size_t size;
+	/** Custom argument. */
+	void *arg;
+} usb_dp_parser_data_t;
+
+uint8_t *usb_dp_get_nested_descriptor(usb_dp_parser_t *,
+    usb_dp_parser_data_t *, uint8_t *);
+uint8_t *usb_dp_get_sibling_descriptor(usb_dp_parser_t *,
+    usb_dp_parser_data_t *, uint8_t *, uint8_t *);
+
+void usb_dp_walk_simple(uint8_t *, size_t, usb_dp_descriptor_nesting_t *,
+    void (*)(uint8_t *, size_t, void *), void *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/include/usb/dev/driver.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/driver.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/driver.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,179 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB device driver framework.
+ */
+#ifndef LIBUSBDEV_DRIVER_H_
+#define LIBUSBDEV_DRIVER_H_
+
+#include <usb/dev/pipes.h>
+
+/** Descriptors for USB device. */
+typedef struct {
+	/** Standard device descriptor. */
+	usb_standard_device_descriptor_t device;
+	/** Full configuration descriptor of current configuration. */
+	uint8_t *configuration;
+	size_t configuration_size;
+} usb_device_descriptors_t;
+
+/** Wrapper for data related to alternate interface setting.
+ * The pointers will typically point inside configuration descriptor and
+ * thus you shall not deallocate them.
+ */
+typedef struct {
+	/** Interface descriptor. */
+	usb_standard_interface_descriptor_t *interface;
+	/** Pointer to start of descriptor tree bound with this interface. */
+	uint8_t *nested_descriptors;
+	/** Size of data pointed by nested_descriptors in bytes. */
+	size_t nested_descriptors_size;
+} usb_alternate_interface_descriptors_t;
+
+/** Alternate interface settings. */
+typedef struct {
+	/** Array of alternate interfaces descriptions. */
+	usb_alternate_interface_descriptors_t *alternatives;
+	/** Size of @c alternatives array. */
+	size_t alternative_count;
+	/** Index of currently selected one. */
+	size_t current;
+} usb_alternate_interfaces_t;
+
+/** USB device structure. */
+typedef struct {
+	/** The default control pipe. */
+	usb_pipe_t ctrl_pipe;
+	/** Other endpoint pipes.
+	 * This is an array of other endpoint pipes in the same order as
+	 * in usb_driver_t.
+	 */
+	usb_endpoint_mapping_t *pipes;
+	/** Number of other endpoint pipes. */
+	size_t pipes_count;
+	/** Current interface.
+	 * Usually, drivers operate on single interface only.
+	 * This item contains the value of the interface or -1 for any.
+	 */
+	int interface_no;
+
+	/** Alternative interfaces.
+	 * Set to NULL when the driver controls whole device
+	 * (i.e. more (or any) interfaces).
+	 */
+	usb_alternate_interfaces_t *alternate_interfaces;
+
+	/** Some useful descriptors. */
+	usb_device_descriptors_t descriptors;
+
+	/** Generic DDF device backing this one. */
+	ddf_dev_t *ddf_dev;
+	/** Custom driver data.
+	 * Do not use the entry in generic device, that is already used
+	 * by the framework.
+	 */
+	void *driver_data;
+
+	/** Connection backing the pipes.
+	 * Typically, you will not need to use this attribute at all.
+	 */
+	usb_device_connection_t wire;
+} usb_device_t;
+
+/** USB driver ops. */
+typedef struct {
+	/** Callback when new device is about to be controlled by the driver. */
+	int (*add_device)(usb_device_t *);
+} usb_driver_ops_t;
+
+/** USB driver structure. */
+typedef struct {
+	/** Driver name.
+	 * This name is copied to the generic driver name and must be exactly
+	 * the same as the directory name where the driver executable resides.
+	 */
+	const char *name;
+	/** Expected endpoints description.
+	 * This description shall exclude default control endpoint (pipe zero)
+	 * and must be NULL terminated.
+	 * When only control endpoint is expected, you may set NULL directly
+	 * without creating one item array containing NULL.
+	 *
+	 * When the driver expect single interrupt in endpoint,
+	 * the initialization may look like this:
+\code
+static usb_endpoint_description_t poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HUB,
+	.interface_subclass = 0,
+	.interface_protocol = 0,
+	.flags = 0
+};
+
+static usb_endpoint_description_t *hub_endpoints[] = {
+	&poll_endpoint_description,
+	NULL
+};
+
+static usb_driver_t hub_driver = {
+	.endpoints = hub_endpoints,
+	...
+};
+\endcode
+	 */
+	usb_endpoint_description_t **endpoints;
+	/** Driver ops. */
+	usb_driver_ops_t *ops;
+} usb_driver_t;
+
+int usb_driver_main(usb_driver_t *);
+
+int usb_device_select_interface(usb_device_t *, uint8_t,
+    usb_endpoint_description_t **);
+
+int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
+int usb_device_create_pipes(ddf_dev_t *, usb_device_connection_t *,
+    usb_endpoint_description_t **, uint8_t *, size_t, int, int,
+    usb_endpoint_mapping_t **, size_t *);
+int usb_device_destroy_pipes(ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
+int usb_device_create(ddf_dev_t *, usb_endpoint_description_t **, usb_device_t **, const char **);
+void usb_device_destroy(usb_device_t *);
+
+size_t usb_interface_count_alternates(uint8_t *, size_t, uint8_t);
+int usb_alternate_interfaces_create(uint8_t *, size_t, int,
+    usb_alternate_interfaces_t **);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/include/usb/dev/hub.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/hub.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,69 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Functions needed by hub drivers.
+ *
+ * For class specific requests, see usb/classes/hub.h.
+ */
+#ifndef LIBUSBDEV_HUB_H_
+#define LIBUSBDEV_HUB_H_
+
+#include <sys/types.h>
+#include <usb/hc.h>
+
+int usb_hc_new_device_wrapper(ddf_dev_t *, usb_hc_connection_t *, usb_speed_t,
+    int (*)(int, void *), int, void *,
+    usb_address_t *, devman_handle_t *,
+    ddf_dev_ops_t *, void *, ddf_fun_t **);
+
+/** Info about device attached to host controller.
+ *
+ * This structure exists only to keep the same signature of
+ * usb_hc_register_device() when more properties of the device
+ * would have to be passed to the host controller.
+ */
+typedef struct {
+	/** Device address. */
+	usb_address_t address;
+	/** Devman handle of the device. */
+	devman_handle_t handle;
+} usb_hc_attached_device_t;
+
+usb_address_t usb_hc_request_address(usb_hc_connection_t *, usb_speed_t);
+int usb_hc_register_device(usb_hc_connection_t *,
+    const usb_hc_attached_device_t *);
+int usb_hc_unregister_device(usb_hc_connection_t *, usb_address_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/include/usb/dev/pipes.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,193 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB pipes representation.
+ */
+#ifndef LIBUSBDEV_PIPES_H_
+#define LIBUSBDEV_PIPES_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/hc.h>
+#include <usb/descriptor.h>
+#include <ipc/devman.h>
+#include <ddf/driver.h>
+#include <fibril_synch.h>
+#include <async.h>
+
+/** Abstraction of a physical connection to the device.
+ * This type is an abstraction of the USB wire that connects the host and
+ * the function (device).
+ */
+typedef struct {
+	/** Handle of the host controller device is connected to. */
+	devman_handle_t hc_handle;
+	/** Address of the device. */
+	usb_address_t address;
+} usb_device_connection_t;
+
+/** Abstraction of a logical connection to USB device endpoint.
+ * It encapsulates endpoint attributes (transfer type etc.) as well
+ * as information about currently running sessions.
+ * This endpoint must be bound with existing usb_device_connection_t
+ * (i.e. the wire to send data over).
+ *
+ * Locking order: if you want to lock both mutexes
+ * (@c guard and @c hc_sess_mutex), lock @c guard first.
+ * It is not necessary to lock @c guard if you want to lock @c hc_sess_mutex
+ * only.
+ */
+typedef struct {
+	/** Guard of the whole pipe. */
+	fibril_mutex_t guard;
+
+	/** The connection used for sending the data. */
+	usb_device_connection_t *wire;
+
+	/** Endpoint number. */
+	usb_endpoint_t endpoint_no;
+
+	/** Endpoint transfer type. */
+	usb_transfer_type_t transfer_type;
+
+	/** Endpoint direction. */
+	usb_direction_t direction;
+
+	/** Maximum packet size for the endpoint. */
+	size_t max_packet_size;
+
+	/** Session to the host controller.
+	 * NULL when no session is active.
+	 * It is an error to access this member without @c hc_sess_mutex
+	 * being locked.
+	 * If call over the phone is to be made, it must be preceeded by
+	 * call to pipe_add_ref() [internal libusb function].
+	 */
+	async_sess_t *hc_sess;
+
+	/** Guard for serialization of requests over the session. */
+	fibril_mutex_t hc_sess_mutex;
+
+	/** Number of active transfers over the pipe. */
+	int refcount;
+	/** Number of failed attempts to open the HC phone.
+	 * When user requests usb_pipe_start_long_transfer() and the operation
+	 * fails, there is no way to report this to the user.
+	 * That the soft reference counter is increased to record the attempt.
+	 * When the user then request e.g. usb_pipe_read(), it will try to
+	 * add reference as well.
+	 * If that fails, it is reported to the user. If it is okay, the
+	 * real reference counter is incremented.
+	 * The problem might arise when ending the long transfer (since
+	 * the number of references would be only 1, but logically it shall be
+	 * two).
+	 * Decrementing the soft counter first shall solve this.
+	 */
+	int refcount_soft;
+
+	/** Whether to automatically reset halt on the endpoint.
+	 * Valid only for control endpoint zero.
+	 */
+	bool auto_reset_halt;
+} usb_pipe_t;
+
+
+/** Description of endpoint characteristics. */
+typedef struct {
+	/** Transfer type (e.g. control or interrupt). */
+	usb_transfer_type_t transfer_type;
+	/** Transfer direction (to or from a device). */
+	usb_direction_t direction;
+	/** Interface class this endpoint belongs to (-1 for any). */
+	int interface_class;
+	/** Interface subclass this endpoint belongs to (-1 for any). */
+	int interface_subclass;
+	/** Interface protocol this endpoint belongs to (-1 for any). */
+	int interface_protocol;
+	/** Extra endpoint flags. */
+	unsigned int flags;
+} usb_endpoint_description_t;
+
+/** Mapping of endpoint pipes and endpoint descriptions. */
+typedef struct {
+	/** Endpoint pipe. */
+	usb_pipe_t *pipe;
+	/** Endpoint description. */
+	const usb_endpoint_description_t *description;
+	/** Interface number the endpoint must belong to (-1 for any). */
+	int interface_no;
+	/** Alternate interface setting to choose. */
+	int interface_setting;
+	/** Found descriptor fitting the description. */
+	usb_standard_endpoint_descriptor_t *descriptor;
+	/** Interface descriptor the endpoint belongs to. */
+	usb_standard_interface_descriptor_t *interface;
+	/** Whether the endpoint was actually found. */
+	bool present;
+} usb_endpoint_mapping_t;
+
+int usb_device_connection_initialize_on_default_address(
+    usb_device_connection_t *, usb_hc_connection_t *);
+int usb_device_connection_initialize_from_device(usb_device_connection_t *,
+    ddf_dev_t *);
+int usb_device_connection_initialize(usb_device_connection_t *,
+    devman_handle_t, usb_address_t);
+
+int usb_device_get_assigned_interface(ddf_dev_t *);
+
+int usb_pipe_initialize(usb_pipe_t *, usb_device_connection_t *,
+    usb_endpoint_t, usb_transfer_type_t, size_t, usb_direction_t);
+int usb_pipe_initialize_default_control(usb_pipe_t *,
+    usb_device_connection_t *);
+int usb_pipe_probe_default_control(usb_pipe_t *);
+int usb_pipe_initialize_from_configuration(usb_endpoint_mapping_t *,
+    size_t, uint8_t *, size_t, usb_device_connection_t *);
+int usb_pipe_register_with_speed(usb_pipe_t *, usb_speed_t,
+    unsigned int, usb_hc_connection_t *);
+int usb_pipe_register(usb_pipe_t *, unsigned int, usb_hc_connection_t *);
+int usb_pipe_unregister(usb_pipe_t *, usb_hc_connection_t *);
+
+void usb_pipe_start_long_transfer(usb_pipe_t *);
+void usb_pipe_end_long_transfer(usb_pipe_t *);
+
+int usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *);
+int usb_pipe_write(usb_pipe_t *, void *, size_t);
+
+int usb_pipe_control_read(usb_pipe_t *, void *, size_t,
+    void *, size_t, size_t *);
+int usb_pipe_control_write(usb_pipe_t *, void *, size_t,
+    void *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/include/usb/dev/poll.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/poll.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/poll.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,99 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB device polling functions.
+ */
+#ifndef LIBUSBDEV_POLL_H_
+#define LIBUSBDEV_POLL_H_
+
+#include <usb/dev/driver.h>
+#include <time.h>
+
+typedef struct {
+	/** Level of debugging messages from auto polling.
+	 * 0 - nothing
+	 * 1 - inform about errors and polling start/end
+	 * 2 - also dump every retrieved buffer
+	 */
+	int debug;
+	/** Maximum number of consecutive errors before polling termination. */
+	size_t max_failures;
+	/** Delay between poll requests in milliseconds.
+	 * Set to negative value to use value from endpoint descriptor.
+	 */
+	int delay;
+	/** Whether to automatically try to clear the HALT feature after
+	 * the endpoint stalls.
+	 */
+	bool auto_clear_halt;
+	/** Callback when data arrives.
+	 *
+	 * @param dev Device that was polled.
+	 * @param data Data buffer (in USB endianness).
+	 * @param data_size Size of the @p data buffer in bytes.
+	 * @param arg Custom argument.
+	 * @return Whether to continue in polling.
+	 */
+	bool (*on_data)(usb_device_t *dev, uint8_t *data, size_t data_size,
+	    void *arg);
+	/** Callback when polling is terminated.
+	 *
+	 * @param dev Device where the polling was terminated.
+	 * @param due_to_errors Whether polling stopped due to several failures.
+	 * @param arg Custom argument.
+	 */
+	void (*on_polling_end)(usb_device_t *dev, bool due_to_errors,
+	    void *arg);
+	/** Callback when error occurs.
+	 *
+	 * @param dev Device where error occurred.
+	 * @param err_code Error code (as returned from usb_pipe_read).
+	 * @param arg Custom argument.
+	 * @return Whether to continue in polling.
+	 */
+	bool (*on_error)(usb_device_t *dev, int err_code, void *arg);
+} usb_device_auto_polling_t;
+
+int usb_device_auto_polling(usb_device_t *, size_t, usb_device_auto_polling_t *,
+    size_t, void *);
+
+typedef bool (*usb_polling_callback_t)(usb_device_t *,
+    uint8_t *, size_t, void *);
+typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);
+
+int usb_device_auto_poll(usb_device_t *, size_t,
+    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/include/usb/dev/recognise.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/recognise.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/recognise.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,58 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB device recognition.
+ */
+#ifndef LIBUSBDEV_RECOGNISE_H_
+#define LIBUSBDEV_RECOGNISE_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <ipc/devman.h>
+
+int usb_device_create_match_ids_from_device_descriptor(
+    const usb_standard_device_descriptor_t *, match_id_list_t *);
+
+int usb_device_create_match_ids_from_interface(
+    const usb_standard_device_descriptor_t *,
+    const usb_standard_interface_descriptor_t *, match_id_list_t *);
+
+int usb_device_create_match_ids(usb_pipe_t *, match_id_list_t *);
+
+int usb_device_register_child_in_devman(usb_address_t, devman_handle_t,
+    ddf_dev_t *, devman_handle_t *, ddf_dev_ops_t *, void *, ddf_fun_t **);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/include/usb/dev/request.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/request.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/include/usb/dev/request.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,150 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Standard USB requests.
+ */
+#ifndef LIBUSBDEV_REQUEST_H_
+#define LIBUSBDEV_REQUEST_H_
+
+#include <sys/types.h>
+#include <l18n/langs.h>
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/descriptor.h>
+
+/** USB device status - device is self powered (opposed to bus powered). */
+#define USB_DEVICE_STATUS_SELF_POWERED ((uint16_t)(1 << 0))
+
+/** USB device status - remote wake-up signaling is enabled. */
+#define USB_DEVICE_STATUS_REMOTE_WAKEUP ((uint16_t)(1 << 1))
+
+/** USB endpoint status - endpoint is halted (stalled). */
+#define USB_ENDPOINT_STATUS_HALTED ((uint16_t)(1 << 0))
+
+/** USB feature selector - endpoint halt (stall). */
+#define USB_FEATURE_SELECTOR_ENDPOINT_HALT (0)
+
+/** USB feature selector - device remote wake-up. */
+#define USB_FEATURE_SELECTOR_REMOTE_WAKEUP (1)
+
+/** Standard device request. */
+typedef enum {
+	USB_DEVREQ_GET_STATUS = 0,
+	USB_DEVREQ_CLEAR_FEATURE = 1,
+	USB_DEVREQ_SET_FEATURE = 3,
+	USB_DEVREQ_SET_ADDRESS = 5,
+	USB_DEVREQ_GET_DESCRIPTOR = 6,
+	USB_DEVREQ_SET_DESCRIPTOR = 7,
+	USB_DEVREQ_GET_CONFIGURATION = 8,
+	USB_DEVREQ_SET_CONFIGURATION = 9,
+	USB_DEVREQ_GET_INTERFACE = 10,
+	USB_DEVREQ_SET_INTERFACE = 11,
+	USB_DEVREQ_SYNCH_FRAME = 12,
+	USB_DEVREQ_LAST_STD
+} usb_stddevreq_t;
+
+/** Device request setup packet.
+ * The setup packet describes the request.
+ */
+typedef struct {
+	/** Request type.
+	 * The type combines transfer direction, request type and
+	 * intended recipient.
+	 */
+	uint8_t request_type;
+	/** Request identification. */
+	uint8_t request;
+	/** Main parameter to the request. */
+	union {
+		uint16_t value;
+		/* FIXME: add #ifdefs according to host endianness */
+		struct {
+			uint8_t value_low;
+			uint8_t value_high;
+		};
+	};
+	/** Auxiliary parameter to the request.
+	 * Typically, it is offset to something.
+	 */
+	uint16_t index;
+	/** Length of extra data. */
+	uint16_t length;
+} __attribute__ ((packed)) usb_device_request_setup_packet_t;
+
+int usb_control_request_set(usb_pipe_t *,
+    usb_request_type_t, usb_request_recipient_t, uint8_t,
+    uint16_t, uint16_t, void *, size_t);
+
+int usb_control_request_get(usb_pipe_t *,
+    usb_request_type_t, usb_request_recipient_t, uint8_t,
+    uint16_t, uint16_t, void *, size_t, size_t *);
+
+int usb_request_get_status(usb_pipe_t *, usb_request_recipient_t,
+    uint16_t, uint16_t *);
+int usb_request_clear_feature(usb_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint16_t, uint16_t);
+int usb_request_set_feature(usb_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint16_t, uint16_t);
+int usb_request_set_address(usb_pipe_t *, usb_address_t);
+int usb_request_get_descriptor(usb_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void *, size_t, 
+    size_t *);
+int usb_request_get_descriptor_alloc(usb_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void **, size_t *);
+int usb_request_get_device_descriptor(usb_pipe_t *,
+    usb_standard_device_descriptor_t *);
+int usb_request_get_bare_configuration_descriptor(usb_pipe_t *, int,
+    usb_standard_configuration_descriptor_t *);
+int usb_request_get_full_configuration_descriptor(usb_pipe_t *, int,
+    void *, size_t, size_t *);
+int usb_request_get_full_configuration_descriptor_alloc(usb_pipe_t *,
+    int, void **, size_t *);
+int usb_request_set_descriptor(usb_pipe_t *, usb_request_type_t,
+    usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void *, size_t);
+int usb_request_get_configuration(usb_pipe_t *, uint8_t *);
+int usb_request_set_configuration(usb_pipe_t *, uint8_t);
+int usb_request_get_interface(usb_pipe_t *, uint8_t, uint8_t *);
+int usb_request_set_interface(usb_pipe_t *, uint8_t, uint8_t);
+
+int usb_request_get_supported_languages(usb_pipe_t *,
+    l18_win_locales_t **, size_t *);
+int usb_request_get_string(usb_pipe_t *, size_t, l18_win_locales_t,
+    char **);
+
+int usb_request_clear_endpoint_halt(usb_pipe_t *, uint16_t);
+int usb_pipe_clear_halt(usb_pipe_t *, usb_pipe_t *);
+int usb_request_get_endpoint_status(usb_pipe_t *, usb_pipe_t *, uint16_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/altiface.c
===================================================================
--- uspace/lib/usbdev/src/altiface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/altiface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,181 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Handling alternate interface settings.
+ */
+#include <usb/dev/driver.h>
+#include <usb/dev/request.h>
+#include <usb/debug.h>
+#include <usb/dev/dp.h>
+#include <errno.h>
+#include <str_error.h>
+#include <assert.h>
+
+/** Count number of alternate settings of a interface.
+ *
+ * @param config_descr Full configuration descriptor.
+ * @param config_descr_size Size of @p config_descr in bytes.
+ * @param interface_no Interface number.
+ * @return Number of alternate interfaces for @p interface_no interface.
+ */
+size_t usb_interface_count_alternates(uint8_t *config_descr,
+    size_t config_descr_size, uint8_t interface_no)
+{
+	assert(config_descr != NULL);
+	assert(config_descr_size > 0);
+
+	usb_dp_parser_t dp_parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = config_descr,
+		.size = config_descr_size,
+		.arg = NULL
+	};
+
+	size_t alternate_count = 0;
+
+	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, config_descr);
+	while (iface_ptr != NULL) {
+		usb_standard_interface_descriptor_t *iface
+		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
+			if (iface->interface_number == interface_no) {
+				alternate_count++;
+			}
+		}
+		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    config_descr, iface_ptr);
+	}
+
+	return alternate_count;
+}
+
+/** Create alternate interface representation structure.
+ *
+ * @param[in] config_descr Configuration descriptor.
+ * @param[in] config_descr_size Size of configuration descriptor.
+ * @param[in] interface_number Interface number.
+ * @param[out] alternates_ptr Where to store pointer to allocated structure.
+ * @return Error code.
+ */
+int usb_alternate_interfaces_create(uint8_t *config_descr,
+    size_t config_descr_size, int interface_number,
+    usb_alternate_interfaces_t **alternates_ptr)
+{
+	assert(alternates_ptr != NULL);
+	assert(config_descr != NULL);
+	assert(config_descr_size > 0);
+
+	if (interface_number < 0) {
+		alternates_ptr = NULL;
+		return EOK;
+	}
+
+	usb_alternate_interfaces_t *alternates
+	    = malloc(sizeof(usb_alternate_interfaces_t));
+
+	if (alternates == NULL) {
+		return ENOMEM;
+	}
+
+	alternates->alternative_count
+	    = usb_interface_count_alternates(config_descr, config_descr_size,
+	    interface_number);
+
+	if (alternates->alternative_count == 0) {
+		free(alternates);
+		return ENOENT;
+	}
+
+	alternates->alternatives = malloc(alternates->alternative_count
+	    * sizeof(usb_alternate_interface_descriptors_t));
+	if (alternates->alternatives == NULL) {
+		free(alternates);
+		return ENOMEM;
+	}
+
+	alternates->current = 0;
+
+	usb_dp_parser_t dp_parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = config_descr,
+		.size = config_descr_size,
+		.arg = NULL
+	};
+
+	usb_alternate_interface_descriptors_t *cur_alt_iface
+	    = &alternates->alternatives[0];
+
+	uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, dp_data.data);
+	while (iface_ptr != NULL) {
+		usb_standard_interface_descriptor_t *iface
+		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
+		    || (iface->interface_number != interface_number)) {
+			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
+			    &dp_data,
+			    dp_data.data, iface_ptr);
+			continue;
+		}
+
+		cur_alt_iface->interface = iface;
+		cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
+
+		/* Find next interface to count size of nested descriptors. */
+		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    dp_data.data, iface_ptr);
+		if (iface_ptr == NULL) {
+			uint8_t *next = dp_data.data + dp_data.size;
+			cur_alt_iface->nested_descriptors_size
+			    = next - cur_alt_iface->nested_descriptors;
+		} else {
+			cur_alt_iface->nested_descriptors_size
+			    = iface_ptr - cur_alt_iface->nested_descriptors;
+		}
+
+		cur_alt_iface++;
+	}
+
+	*alternates_ptr = alternates;
+
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/devdrv.c
===================================================================
--- uspace/lib/usbdev/src/devdrv.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/devdrv.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,563 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB device driver framework.
+ */
+#include <usb/dev/driver.h>
+#include <usb/dev/request.h>
+#include <usb/debug.h>
+#include <usb/dev/dp.h>
+#include <errno.h>
+#include <str_error.h>
+#include <assert.h>
+
+static int generic_add_device(ddf_dev_t *);
+
+static driver_ops_t generic_driver_ops = {
+	.add_device = generic_add_device
+};
+static driver_t generic_driver = {
+	.driver_ops = &generic_driver_ops
+};
+
+static usb_driver_t *driver = NULL;
+
+
+/** Main routine of USB device driver.
+ *
+ * Under normal conditions, this function never returns.
+ *
+ * @param drv USB device driver structure.
+ * @return Task exit status.
+ */
+int usb_driver_main(usb_driver_t *drv)
+{
+	assert(drv != NULL);
+
+	/* Prepare the generic driver. */
+	generic_driver.name = drv->name;
+
+	driver = drv;
+
+	return ddf_driver_main(&generic_driver);
+}
+
+/** Count number of pipes the driver expects.
+ *
+ * @param drv USB driver.
+ * @return Number of pipes (excluding default control pipe).
+ */
+static size_t count_other_pipes(usb_endpoint_description_t **endpoints)
+{
+	size_t count = 0;
+	if (endpoints == NULL) {
+		return 0;
+	}
+
+	while (endpoints[count] != NULL) {
+		count++;
+	}
+
+	return count;
+}
+
+/** Initialize endpoint pipes, excluding default control one.
+ *
+ * @param drv The device driver.
+ * @param dev Device to be initialized.
+ * @return Error code.
+ */
+static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
+    usb_device_t *dev, int alternate_setting)
+{
+	if (endpoints == NULL) {
+		dev->pipes = NULL;
+		dev->pipes_count = 0;
+		return EOK;
+	}
+
+	usb_endpoint_mapping_t *pipes;
+	size_t pipes_count;
+
+	int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints,
+	    dev->descriptors.configuration, dev->descriptors.configuration_size,
+	    dev->interface_no, alternate_setting,
+	    &pipes, &pipes_count);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	dev->pipes = pipes;
+	dev->pipes_count = pipes_count;
+
+	return EOK;
+}
+
+/** Callback when new device is supposed to be controlled by this driver.
+ *
+ * This callback is a wrapper for USB specific version of @c add_device.
+ *
+ * @param gen_dev Device structure as prepared by DDF.
+ * @return Error code.
+ */
+int generic_add_device(ddf_dev_t *gen_dev)
+{
+	assert(driver);
+	assert(driver->ops);
+	assert(driver->ops->add_device);
+
+	int rc;
+
+	usb_device_t *dev = NULL;
+	const char *err_msg = NULL;
+	rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);
+	if (rc != EOK) {
+		usb_log_error("USB device `%s' creation failed (%s): %s.\n",
+		    gen_dev->name, err_msg, str_error(rc));
+		return rc;
+	}
+
+	return driver->ops->add_device(dev);
+}
+
+/** Destroy existing pipes of a USB device.
+ *
+ * @param dev Device where to destroy the pipes.
+ * @return Error code.
+ */
+static int destroy_current_pipes(usb_device_t *dev)
+{
+	int rc = usb_device_destroy_pipes(dev->ddf_dev,
+	    dev->pipes, dev->pipes_count);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	dev->pipes = NULL;
+	dev->pipes_count = 0;
+
+	return EOK;
+}
+
+/** Change interface setting of a device.
+ * This function selects new alternate setting of an interface by issuing
+ * proper USB command to the device and also creates new USB pipes
+ * under @c dev->pipes.
+ *
+ * @warning This function is intended for drivers working at interface level.
+ * For drivers controlling the whole device, you need to change interface
+ * manually using usb_request_set_interface() and creating new pipes
+ * with usb_pipe_initialize_from_configuration().
+ *
+ * @warning This is a wrapper function that does several operations that
+ * can fail and that cannot be rollbacked easily. That means that a failure
+ * during the SET_INTERFACE request would result in having a device with
+ * no pipes at all (except the default control one). That is because the old
+ * pipes needs to be unregistered at HC first and the new ones could not
+ * be created.
+ *
+ * @param dev USB device.
+ * @param alternate_setting Alternate setting to choose.
+ * @param endpoints New endpoint descriptions.
+ * @return Error code.
+ */
+int usb_device_select_interface(usb_device_t *dev, uint8_t alternate_setting,
+    usb_endpoint_description_t **endpoints)
+{
+	if (dev->interface_no < 0) {
+		return EINVAL;
+	}
+
+	int rc;
+
+	/* Destroy existing pipes. */
+	rc = destroy_current_pipes(dev);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Change the interface itself. */
+	rc = usb_request_set_interface(&dev->ctrl_pipe, dev->interface_no,
+	    alternate_setting);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Create new pipes. */
+	rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
+
+	return rc;
+}
+
+/** Retrieve basic descriptors from the device.
+ *
+ * @param[in] ctrl_pipe Control endpoint pipe.
+ * @param[out] descriptors Where to store the descriptors.
+ * @return Error code.
+ */
+int usb_device_retrieve_descriptors(usb_pipe_t *ctrl_pipe,
+    usb_device_descriptors_t *descriptors)
+{
+	assert(descriptors != NULL);
+
+	descriptors->configuration = NULL;
+
+	int rc;
+
+	/* It is worth to start a long transfer. */
+	usb_pipe_start_long_transfer(ctrl_pipe);
+
+	/* Get the device descriptor. */
+	rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	/* Get the full configuration descriptor. */
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    ctrl_pipe, 0, (void **) &descriptors->configuration,
+	    &descriptors->configuration_size);
+
+leave:
+	usb_pipe_end_long_transfer(ctrl_pipe);
+
+	return rc;
+}
+
+/** Create pipes for a device.
+ *
+ * This is more or less a wrapper that does following actions:
+ * - allocate and initialize pipes
+ * - map endpoints to the pipes based on the descriptions
+ * - registers endpoints with the host controller
+ *
+ * @param[in] dev Generic DDF device backing the USB one.
+ * @param[in] wire Initialized backing connection to the host controller.
+ * @param[in] endpoints Endpoints description, NULL terminated.
+ * @param[in] config_descr Configuration descriptor of active configuration.
+ * @param[in] config_descr_size Size of @p config_descr in bytes.
+ * @param[in] interface_no Interface to map from.
+ * @param[in] interface_setting Interface setting (default is usually 0).
+ * @param[out] pipes_ptr Where to store array of created pipes
+ *	(not NULL terminated).
+ * @param[out] pipes_count_ptr Where to store number of pipes
+ *	(set to if you wish to ignore the count).
+ * @return Error code.
+ */
+int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,
+    usb_endpoint_description_t **endpoints,
+    uint8_t *config_descr, size_t config_descr_size,
+    int interface_no, int interface_setting,
+    usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)
+{
+	assert(dev != NULL);
+	assert(wire != NULL);
+	assert(endpoints != NULL);
+	assert(config_descr != NULL);
+	assert(config_descr_size > 0);
+	assert(pipes_ptr != NULL);
+
+	size_t i;
+	int rc;
+
+	size_t pipe_count = count_other_pipes(endpoints);
+	if (pipe_count == 0) {
+		*pipes_ptr = NULL;
+		return EOK;
+	}
+
+	usb_endpoint_mapping_t *pipes
+	    = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
+	if (pipes == NULL) {
+		return ENOMEM;
+	}
+
+	/* Initialize to NULL to allow smooth rollback. */
+	for (i = 0; i < pipe_count; i++) {
+		pipes[i].pipe = NULL;
+	}
+
+	/* Now allocate and fully initialize. */
+	for (i = 0; i < pipe_count; i++) {
+		pipes[i].pipe = malloc(sizeof(usb_pipe_t));
+		if (pipes[i].pipe == NULL) {
+			rc = ENOMEM;
+			goto rollback_free_only;
+		}
+		pipes[i].description = endpoints[i];
+		pipes[i].interface_no = interface_no;
+		pipes[i].interface_setting = interface_setting;
+	}
+
+	/* Find the mapping from configuration descriptor. */
+	rc = usb_pipe_initialize_from_configuration(pipes, pipe_count,
+	    config_descr, config_descr_size, wire);
+	if (rc != EOK) {
+		goto rollback_free_only;
+	}
+
+	/* Register the endpoints with HC. */
+	usb_hc_connection_t hc_conn;
+	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
+	if (rc != EOK) {
+		goto rollback_free_only;
+	}
+
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		goto rollback_free_only;
+	}
+
+	for (i = 0; i < pipe_count; i++) {
+		if (pipes[i].present) {
+			rc = usb_pipe_register(pipes[i].pipe,
+			    pipes[i].descriptor->poll_interval, &hc_conn);
+			if (rc != EOK) {
+				goto rollback_unregister_endpoints;
+			}
+		}
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	*pipes_ptr = pipes;
+	if (pipes_count_ptr != NULL) {
+		*pipes_count_ptr = pipe_count;
+	}
+
+	return EOK;
+
+	/*
+	 * Jump here if something went wrong after endpoints have
+	 * been registered.
+	 * This is also the target when the registration of
+	 * endpoints fails.
+	 */
+rollback_unregister_endpoints:
+	for (i = 0; i < pipe_count; i++) {
+		if (pipes[i].present) {
+			usb_pipe_unregister(pipes[i].pipe, &hc_conn);
+		}
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	/*
+	 * Jump here if something went wrong before some actual communication
+	 * with HC. Then the only thing that needs to be done is to free
+	 * allocated memory.
+	 */
+rollback_free_only:
+	for (i = 0; i < pipe_count; i++) {
+		if (pipes[i].pipe != NULL) {
+			free(pipes[i].pipe);
+		}
+	}
+	free(pipes);
+
+	return rc;
+}
+
+/** Destroy pipes previously created by usb_device_create_pipes.
+ *
+ * @param[in] dev Generic DDF device backing the USB one.
+ * @param[in] pipes Endpoint mapping to be destroyed.
+ * @param[in] pipes_count Number of endpoints.
+ */
+int usb_device_destroy_pipes(ddf_dev_t *dev,
+    usb_endpoint_mapping_t *pipes, size_t pipes_count)
+{
+	assert(dev != NULL);
+	assert(((pipes != NULL) && (pipes_count > 0))
+	    || ((pipes == NULL) && (pipes_count == 0)));
+
+	if (pipes_count == 0) {
+		return EOK;
+	}
+
+	int rc;
+
+	/* Prepare connection to HC to allow endpoint unregistering. */
+	usb_hc_connection_t hc_conn;
+	rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Destroy the pipes. */
+	size_t i;
+	for (i = 0; i < pipes_count; i++) {
+		usb_pipe_unregister(pipes[i].pipe, &hc_conn);
+		free(pipes[i].pipe);
+	}
+
+	usb_hc_connection_close(&hc_conn);
+
+	free(pipes);
+
+	return EOK;
+}
+
+/** Initialize control pipe in a device.
+ *
+ * @param dev USB device in question.
+ * @param errmsg Where to store error context.
+ * @return
+ */
+static int init_wire_and_ctrl_pipe(usb_device_t *dev, const char **errmsg)
+{
+	int rc;
+
+	rc = usb_device_connection_initialize_from_device(&dev->wire,
+	    dev->ddf_dev);
+	if (rc != EOK) {
+		*errmsg = "device connection initialization";
+		return rc;
+	}
+
+	rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
+	    &dev->wire);
+	if (rc != EOK) {
+		*errmsg = "default control pipe initialization";
+		return rc;
+	}
+
+	return EOK;
+}
+
+
+/** Create new instance of USB device.
+ *
+ * @param[in] ddf_dev Generic DDF device backing the USB one.
+ * @param[in] endpoints NULL terminated array of endpoints (NULL for none).
+ * @param[out] dev_ptr Where to store pointer to the new device.
+ * @param[out] errstr_ptr Where to store description of context
+ *	(in case error occurs).
+ * @return Error code.
+ */
+int usb_device_create(ddf_dev_t *ddf_dev,
+    usb_endpoint_description_t **endpoints,
+    usb_device_t **dev_ptr, const char **errstr_ptr)
+{
+	assert(dev_ptr != NULL);
+	assert(ddf_dev != NULL);
+
+	int rc;
+
+	usb_device_t *dev = malloc(sizeof(usb_device_t));
+	if (dev == NULL) {
+		*errstr_ptr = "structure allocation";
+		return ENOMEM;
+	}
+
+	// FIXME: proper deallocation in case of errors
+
+	dev->ddf_dev = ddf_dev;
+	dev->driver_data = NULL;
+	dev->descriptors.configuration = NULL;
+	dev->alternate_interfaces = NULL;
+
+	dev->pipes_count = 0;
+	dev->pipes = NULL;
+
+	/* Initialize backing wire and control pipe. */
+	rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Get our interface. */
+	dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
+
+	/* Retrieve standard descriptors. */
+	rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
+	    &dev->descriptors);
+	if (rc != EOK) {
+		*errstr_ptr = "descriptor retrieval";
+		return rc;
+	}
+
+	/* Create alternate interfaces. */
+	rc = usb_alternate_interfaces_create(dev->descriptors.configuration,
+	    dev->descriptors.configuration_size, dev->interface_no,
+	    &dev->alternate_interfaces);
+	if (rc != EOK) {
+		/* We will try to silently ignore this. */
+		dev->alternate_interfaces = NULL;
+	}
+
+	rc = initialize_other_pipes(endpoints, dev, 0);
+	if (rc != EOK) {
+		*errstr_ptr = "pipes initialization";
+		return rc;
+	}
+
+	*errstr_ptr = NULL;
+	*dev_ptr = dev;
+
+	return EOK;
+}
+
+/** Destroy instance of a USB device.
+ *
+ * @param dev Device to be destroyed.
+ */
+void usb_device_destroy(usb_device_t *dev)
+{
+	if (dev == NULL) {
+		return;
+	}
+
+	/* Ignore errors and hope for the best. */
+	usb_device_destroy_pipes(dev->ddf_dev, dev->pipes, dev->pipes_count);
+	if (dev->descriptors.configuration != NULL) {
+		free(dev->descriptors.configuration);
+	}
+
+	if (dev->alternate_interfaces != NULL) {
+		if (dev->alternate_interfaces->alternatives != NULL) {
+			free(dev->alternate_interfaces->alternatives);
+		}
+		free(dev->alternate_interfaces);
+	}
+
+	free(dev);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/devpoll.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,317 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB device driver framework - automatic interrupt polling.
+ */
+#include <usb/dev/poll.h>
+#include <usb/dev/request.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <assert.h>
+
+/** Maximum number of failed consecutive requests before announcing failure. */
+#define MAX_FAILED_ATTEMPTS 3
+
+/** Data needed for polling. */
+typedef struct {
+	int debug;
+	size_t max_failures;
+	useconds_t delay;
+	bool auto_clear_halt;
+	bool (*on_data)(usb_device_t *, uint8_t *, size_t, void *);
+	void (*on_polling_end)(usb_device_t *, bool, void *);
+	bool (*on_error)(usb_device_t *, int, void *);
+
+	usb_device_t *dev;
+	size_t pipe_index;
+	size_t request_size;
+	uint8_t *buffer;
+	void *custom_arg;
+} polling_data_t;
+
+
+/** Polling fibril.
+ *
+ * @param arg Pointer to polling_data_t.
+ * @return Always EOK.
+ */
+static int polling_fibril(void *arg)
+{
+	polling_data_t *polling_data = (polling_data_t *) arg;
+	assert(polling_data);
+
+	usb_pipe_t *pipe
+	    = polling_data->dev->pipes[polling_data->pipe_index].pipe;
+	
+	if (polling_data->debug > 0) {
+		usb_endpoint_mapping_t *mapping
+		    = &polling_data->dev->pipes[polling_data->pipe_index];
+		usb_log_debug("Poll%p: started polling of `%s' - " \
+		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
+		    polling_data,
+		    polling_data->dev->ddf_dev->name,
+		    (int) mapping->interface->interface_number,
+		    usb_str_class(mapping->interface->interface_class),
+		    (int) mapping->interface->interface_subclass,
+		    (int) mapping->interface->interface_protocol,
+		    polling_data->request_size, pipe->max_packet_size);
+	}
+
+	size_t failed_attempts = 0;
+	while (failed_attempts <= polling_data->max_failures) {
+		int rc;
+
+		size_t actual_size;
+		rc = usb_pipe_read(pipe, polling_data->buffer,
+		    polling_data->request_size, &actual_size);
+
+		if (polling_data->debug > 1) {
+			if (rc == EOK) {
+				usb_log_debug(
+				    "Poll%p: received: '%s' (%zuB).\n",
+				    polling_data,
+				    usb_debug_str_buffer(polling_data->buffer,
+				        actual_size, 16),
+				    actual_size);
+			} else {
+				usb_log_debug(
+				    "Poll%p: polling failed: %s.\n",
+				    polling_data, str_error(rc));
+			}
+		}
+
+		/* If the pipe stalled, we can try to reset the stall. */
+		if ((rc == ESTALL) && (polling_data->auto_clear_halt)) {
+			/*
+			 * We ignore error here as this is usually a futile
+			 * attempt anyway.
+			 */
+			usb_request_clear_endpoint_halt(
+			    &polling_data->dev->ctrl_pipe,
+			    pipe->endpoint_no);
+		}
+
+		if (rc != EOK) {
+			if (polling_data->on_error != NULL) {
+				bool cont = polling_data->on_error(
+				    polling_data->dev, rc,
+				    polling_data->custom_arg);
+				if (!cont) {
+					failed_attempts
+					    = polling_data->max_failures;
+				}
+			}
+			failed_attempts++;
+			continue;
+		}
+
+		/* We have the data, execute the callback now. */
+		bool carry_on = polling_data->on_data(polling_data->dev,
+		    polling_data->buffer, actual_size,
+		    polling_data->custom_arg);
+
+		if (!carry_on) {
+			failed_attempts = 0;
+			break;
+		}
+
+		/* Reset as something might be only a temporary problem. */
+		failed_attempts = 0;
+
+		/* Take a rest before next request. */
+		async_usleep(polling_data->delay);
+	}
+
+	if (polling_data->on_polling_end != NULL) {
+		polling_data->on_polling_end(polling_data->dev,
+		    failed_attempts > 0, polling_data->custom_arg);
+	}
+
+	if (polling_data->debug > 0) {
+		if (failed_attempts > 0) {
+			usb_log_error(
+			    "Polling of device `%s' terminated: %s.\n",
+			    polling_data->dev->ddf_dev->name,
+			    "recurring failures");
+		} else {
+			usb_log_debug(
+			    "Polling of device `%s' terminated by user.\n",
+			    polling_data->dev->ddf_dev->name
+			);
+		}
+	}
+
+	/* Free the allocated memory. */
+	free(polling_data->buffer);
+	free(polling_data);
+
+	return EOK;
+}
+
+/** Start automatic device polling over interrupt in pipe.
+ *
+ * @warning It is up to the callback to produce delays between individual
+ * requests.
+ *
+ * @warning There is no guarantee when the request to the device
+ * will be sent for the first time (it is possible that this
+ * first request would be executed prior to return from this function).
+ *
+ * @param dev Device to be periodically polled.
+ * @param pipe_index Index of the endpoint pipe used for polling.
+ * @param callback Callback when data are available.
+ * @param request_size How many bytes to ask for in each request.
+ * @param terminated_callback Callback when polling is terminated.
+ * @param arg Custom argument (passed as is to the callbacks).
+ * @return Error code.
+ * @retval EOK New fibril polling the device was already started.
+ */
+int usb_device_auto_poll(usb_device_t *dev, size_t pipe_index,
+    usb_polling_callback_t callback, size_t request_size,
+    usb_polling_terminted_callback_t terminated_callback, void *arg)
+{
+	if ((dev == NULL) || (callback == NULL)) {
+		return EBADMEM;
+	}
+	if (request_size == 0) {
+		return EINVAL;
+	}
+	if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
+	    || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
+		return EINVAL;
+	}
+
+	usb_device_auto_polling_t *auto_polling
+	    = malloc(sizeof(usb_device_auto_polling_t));
+	if (auto_polling == NULL) {
+		return ENOMEM;
+	}
+
+	auto_polling->debug = 1;
+	auto_polling->auto_clear_halt = true;
+	auto_polling->delay = 0;
+	auto_polling->max_failures = MAX_FAILED_ATTEMPTS;
+	auto_polling->on_data = callback;
+	auto_polling->on_polling_end = terminated_callback;
+	auto_polling->on_error = NULL;
+
+	int rc = usb_device_auto_polling(dev, pipe_index, auto_polling,
+	   request_size, arg);
+
+	free(auto_polling);
+
+	return rc;
+}
+
+/** Start automatic device polling over interrupt in pipe.
+ *
+ * The polling settings is copied thus it is okay to destroy the structure
+ * after this function returns.
+ *
+ * @warning There is no guarantee when the request to the device
+ * will be sent for the first time (it is possible that this
+ * first request would be executed prior to return from this function).
+ *
+ * @param dev Device to be periodically polled.
+ * @param pipe_index Index of the endpoint pipe used for polling.
+ * @param polling Polling settings.
+ * @param request_size How many bytes to ask for in each request.
+ * @param arg Custom argument (passed as is to the callbacks).
+ * @return Error code.
+ * @retval EOK New fibril polling the device was already started.
+ */
+int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
+    usb_device_auto_polling_t *polling,
+    size_t request_size, void *arg)
+{
+	if (dev == NULL) {
+		return EBADMEM;
+	}
+	if (pipe_index >= dev->pipes_count) {
+		return EINVAL;
+	}
+	if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
+	    || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
+		return EINVAL;
+	}
+	if ((polling == NULL) || (polling->on_data == NULL)) {
+		return EBADMEM;
+	}
+
+	polling_data_t *polling_data = malloc(sizeof(polling_data_t));
+	if (polling_data == NULL) {
+		return ENOMEM;
+	}
+
+	/* Fill-in the data. */
+	polling_data->buffer = malloc(sizeof(request_size));
+	if (polling_data->buffer == NULL) {
+		free(polling_data);
+		return ENOMEM;
+	}
+	polling_data->request_size = request_size;
+	polling_data->dev = dev;
+	polling_data->pipe_index = pipe_index;
+	polling_data->custom_arg = arg;
+
+	polling_data->debug = polling->debug;
+	polling_data->max_failures = polling->max_failures;
+	if (polling->delay >= 0) {
+		polling_data->delay = (useconds_t) polling->delay;
+	} else {
+		polling_data->delay = (useconds_t) dev->pipes[pipe_index]
+		    .descriptor->poll_interval;
+	}
+	polling_data->auto_clear_halt = polling->auto_clear_halt;
+
+	polling_data->on_data = polling->on_data;
+	polling_data->on_polling_end = polling->on_polling_end;
+	polling_data->on_error = polling->on_error;
+
+	fid_t fibril = fibril_create(polling_fibril, polling_data);
+	if (fibril == 0) {
+		free(polling_data->buffer);
+		free(polling_data);
+		return ENOMEM;
+	}
+	fibril_add_ready(fibril);
+
+	/* Fibril launched. That fibril will free the allocated data. */
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/dp.c
===================================================================
--- uspace/lib/usbdev/src/dp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/dp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,326 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/**
+ * @file
+ * USB descriptor parser (implementation).
+ *
+ * The descriptor parser is a generic parser for structure, where individual
+ * items are stored in single buffer and each item begins with length followed
+ * by type. These types are organized into tree hierarchy.
+ *
+ * The parser is able of only two actions: find first child and find next
+ * sibling.
+ */
+#include <stdio.h>
+#include <str_error.h>
+#include <errno.h>
+#include <assert.h>
+#include <bool.h>
+#include <usb/dev/dp.h>
+#include <usb/descriptor.h>
+
+#define NESTING(parentname, childname) \
+	{ \
+		.child = USB_DESCTYPE_##childname, \
+		.parent = USB_DESCTYPE_##parentname, \
+	}
+#define LAST_NESTING { -1, -1 }
+
+/** Nesting of standard USB descriptors. */
+usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
+	NESTING(CONFIGURATION, INTERFACE),
+	NESTING(INTERFACE, ENDPOINT),
+	NESTING(INTERFACE, HUB),
+	NESTING(INTERFACE, HID),
+	NESTING(HID, HID_REPORT),
+	LAST_NESTING
+};
+
+#undef NESTING
+#undef LAST_NESTING
+
+/** Tells whether pointer points inside descriptor data.
+ *
+ * @param data Parser data.
+ * @param ptr Pointer to be verified.
+ * @return Whether @p ptr points inside <code>data->data</code> field.
+ */
+static bool is_valid_descriptor_pointer(usb_dp_parser_data_t *data,
+    uint8_t *ptr)
+{
+	if (ptr == NULL) {
+		return false;
+	}
+
+	if (ptr < data->data) {
+		return false;
+	}
+
+	if ((size_t)(ptr - data->data) >= data->size) {
+		return false;
+	}
+
+	return true;
+}
+
+/** Get next descriptor regardless of the nesting.
+ *
+ * @param data Parser data.
+ * @param current Pointer to current descriptor.
+ * @return Pointer to start of next descriptor.
+ * @retval NULL Invalid input or no next descriptor.
+ */
+static uint8_t *get_next_descriptor(usb_dp_parser_data_t *data,
+    uint8_t *current)
+{
+	assert(is_valid_descriptor_pointer(data, current));
+
+	uint8_t current_length = *current;
+	uint8_t *next = current + current_length;
+
+	if (!is_valid_descriptor_pointer(data, next)) {
+		return NULL;
+	}
+
+	return next;
+}
+
+/** Get descriptor type.
+ *
+ * @see usb_descriptor_type_t
+ *
+ * @param data Parser data.
+ * @param start Pointer to start of the descriptor.
+ * @return Descriptor type.
+ * @retval -1 Invalid input.
+ */
+static int get_descriptor_type(usb_dp_parser_data_t *data, uint8_t *start)
+{
+	if (start == NULL) {
+		return -1;
+	}
+
+	start++;
+	if (!is_valid_descriptor_pointer(data, start)) {
+		return -1;
+	} else {
+		return (int) (*start);
+	}
+}
+
+/** Tells whether descriptors could be nested.
+ *
+ * @param parser Parser.
+ * @param child Child descriptor type.
+ * @param parent Parent descriptor type.
+ * @return Whether @p child could be child of @p parent.
+ */
+static bool is_nested_descriptor_type(usb_dp_parser_t *parser,
+    int child, int parent)
+{
+	usb_dp_descriptor_nesting_t *nesting = parser->nesting;
+	while ((nesting->child > 0) && (nesting->parent > 0)) {
+		if ((nesting->child == child) && (nesting->parent == parent)) {
+			return true;
+		}
+		nesting++;
+	}
+	return false;
+}
+
+/** Tells whether descriptors could be nested.
+ *
+ * @param parser Parser.
+ * @param data Parser data.
+ * @param child Pointer to child descriptor.
+ * @param parent Pointer to parent descriptor.
+ * @return Whether @p child could be child of @p parent.
+ */
+static bool is_nested_descriptor(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *child, uint8_t *parent)
+{
+	return is_nested_descriptor_type(parser,
+	    get_descriptor_type(data, child),
+	    get_descriptor_type(data, parent));
+}
+
+/** Find first nested descriptor of given parent.
+ *
+ * @param parser Parser.
+ * @param data Parser data.
+ * @param parent Pointer to the beginning of parent descriptor.
+ * @return Pointer to the beginning of the first nested (child) descriptor.
+ * @retval NULL No child descriptor found.
+ * @retval NULL Invalid input.
+ */
+uint8_t *usb_dp_get_nested_descriptor(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *parent)
+{
+	if (!is_valid_descriptor_pointer(data, parent)) {
+		return NULL;
+	}
+
+	uint8_t *next = get_next_descriptor(data, parent);
+	if (next == NULL) {
+		return NULL;
+	}
+
+	if (is_nested_descriptor(parser, data, next, parent)) {
+		return next;
+	} else {
+		return NULL;
+	}
+}
+
+/** Skip all nested descriptors.
+ *
+ * @param parser Parser.
+ * @param data Parser data.
+ * @param parent Pointer to the beginning of parent descriptor.
+ * @return Pointer to first non-child descriptor.
+ * @retval NULL No next descriptor.
+ * @retval NULL Invalid input.
+ */
+static uint8_t *skip_nested_descriptors(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *parent)
+{
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, parent);
+	if (child == NULL) {
+		return get_next_descriptor(data, parent);
+	}
+	uint8_t *next_child = skip_nested_descriptors(parser, data, child);
+	while (is_nested_descriptor(parser, data, next_child, parent)) {
+		next_child = skip_nested_descriptors(parser, data, next_child);
+	}
+
+	return next_child;
+}
+
+/** Get sibling descriptor.
+ *
+ * @param parser Parser.
+ * @param data Parser data.
+ * @param parent Pointer to common parent descriptor.
+ * @param sibling Left sibling.
+ * @return Pointer to first right sibling of @p sibling.
+ * @retval NULL No sibling exist.
+ * @retval NULL Invalid input.
+ */
+uint8_t *usb_dp_get_sibling_descriptor(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *parent, uint8_t *sibling)
+{
+	if (!is_valid_descriptor_pointer(data, parent)
+	    || !is_valid_descriptor_pointer(data, sibling)) {
+		return NULL;
+	}
+
+	uint8_t *possible_sibling = skip_nested_descriptors(parser, data, sibling);
+	if (possible_sibling == NULL) {
+		return NULL;
+	}
+
+	int parent_type = get_descriptor_type(data, parent);
+	int possible_sibling_type = get_descriptor_type(data, possible_sibling);
+	if (is_nested_descriptor_type(parser, possible_sibling_type, parent_type)) {
+		return possible_sibling;
+	} else {
+		return NULL;
+	}
+}
+
+/** Browser of the descriptor tree.
+ *
+ * @see usb_dp_walk_simple
+ *
+ * @param parser Descriptor parser.
+ * @param data Data for descriptor parser.
+ * @param root Pointer to current root of the tree.
+ * @param depth Current nesting depth.
+ * @param callback Callback for each found descriptor.
+ * @param arg Custom (user) argument.
+ */
+static void usb_dp_browse_simple_internal(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
+    void (*callback)(uint8_t *, size_t, void *), void *arg)
+{
+	if (root == NULL) {
+		return;
+	}
+	callback(root, depth, arg);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		usb_dp_browse_simple_internal(parser, data, child, depth + 1,
+		    callback, arg);
+		child = usb_dp_get_sibling_descriptor(parser, data,
+		    root, child);
+	} while (child != NULL);
+}
+
+/** Browse flatten descriptor tree.
+ *
+ * The callback is called with following arguments: pointer to the start
+ * of the descriptor (somewhere inside @p descriptors), depth of the nesting
+ * (starting from 0 for the first descriptor) and the custom argument.
+ * Note that the size of the descriptor is not passed because it can
+ * be read from the first byte of the descriptor.
+ *
+ * @param descriptors Descriptor data.
+ * @param descriptors_size Size of descriptor data (in bytes).
+ * @param descriptor_nesting Possible descriptor nesting.
+ * @param callback Callback for each found descriptor.
+ * @param arg Custom (user) argument.
+ */
+void usb_dp_walk_simple(uint8_t *descriptors, size_t descriptors_size,
+    usb_dp_descriptor_nesting_t *descriptor_nesting,
+    void (*callback)(uint8_t *, size_t, void *), void *arg)
+{
+	if ((descriptors == NULL) || (descriptors_size == 0)
+	    || (descriptor_nesting == NULL) || (callback == NULL)) {
+		return;
+	}
+
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = descriptors_size,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = descriptor_nesting
+	};
+
+	usb_dp_browse_simple_internal(&parser, &data, descriptors,
+	    0, callback, arg);
+}
+
+/** @}
+ */
Index: uspace/lib/usbdev/src/hub.c
===================================================================
--- uspace/lib/usbdev/src/hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/hub.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,377 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Functions needed by hub drivers.
+ */
+#include <usb/dev/hub.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/request.h>
+#include <usb/dev/recognise.h>
+#include <usbhc_iface.h>
+#include <errno.h>
+#include <assert.h>
+#include <usb/debug.h>
+#include <time.h>
+#include <async.h>
+
+/** How much time to wait between attempts to register endpoint 0:0.
+ * The value is based on typical value for port reset + some overhead.
+ */
+#define ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC (1000 * (10 + 2))
+
+/** Check that HC connection is alright.
+ *
+ * @param conn Connection to be checked.
+ */
+#define CHECK_CONNECTION(conn) \
+	do { \
+		assert((conn)); \
+		if (!usb_hc_connection_is_opened((conn))) { \
+			return ENOENT; \
+		} \
+	} while (false)
+
+/** Ask host controller for free address assignment.
+ *
+ * @param connection Opened connection to host controller.
+ * @param speed Speed of the new device (device that will be assigned
+ *    the returned address).
+ * @return Assigned USB address or negative error code.
+ */
+usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
+    usb_speed_t speed)
+{
+	CHECK_CONNECTION(connection);
+	
+	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
+	
+	sysarg_t address;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REQUEST_ADDRESS, speed,
+	    &address);
+	
+	async_exchange_end(exch);
+	
+	if (rc != EOK)
+		return (usb_address_t) rc;
+	
+	return (usb_address_t) address;
+}
+
+/** Inform host controller about new device.
+ *
+ * @param connection Opened connection to host controller.
+ * @param attached_device Information about the new device.
+ * @return Error code.
+ */
+int usb_hc_register_device(usb_hc_connection_t * connection,
+    const usb_hc_attached_device_t *attached_device)
+{
+	CHECK_CONNECTION(connection);
+	
+	if (attached_device == NULL)
+		return EBADMEM;
+	
+	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_BIND_ADDRESS,
+	    attached_device->address, attached_device->handle);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Inform host controller about device removal.
+ *
+ * @param connection Opened connection to host controller.
+ * @param address Address of the device that is being removed.
+ * @return Error code.
+ */
+int usb_hc_unregister_device(usb_hc_connection_t *connection,
+    usb_address_t address)
+{
+	CHECK_CONNECTION(connection);
+	
+	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_ADDRESS, address);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+
+static void unregister_control_endpoint_on_default_address(
+    usb_hc_connection_t *connection)
+{
+	usb_device_connection_t dev_conn;
+	int rc = usb_device_connection_initialize_on_default_address(&dev_conn,
+	    connection);
+	if (rc != EOK) {
+		return;
+	}
+
+	usb_pipe_t ctrl_pipe;
+	rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
+	if (rc != EOK) {
+		return;
+	}
+
+	usb_pipe_unregister(&ctrl_pipe, connection);
+}
+
+
+/** Wrapper for registering attached device to the hub.
+ *
+ * The @p enable_port function is expected to enable signaling on given
+ * port.
+ * The two arguments to it can have arbitrary meaning
+ * (the @p port_no is only a suggestion)
+ * and are not touched at all by this function
+ * (they are passed as is to the @p enable_port function).
+ *
+ * If the @p enable_port fails (i.e. does not return EOK), the device
+ * addition is canceled.
+ * The return value is then returned (it is good idea to use different
+ * error codes than those listed as return codes by this function itself).
+ *
+ * The @p connection representing connection with host controller does not
+ * need to be started.
+ * This function duplicates the connection to allow simultaneous calls of
+ * this function (i.e. from different fibrils).
+ *
+ * @param[in] parent Parent device (i.e. the hub device).
+ * @param[in] connection Connection to host controller.
+ * @param[in] dev_speed New device speed.
+ * @param[in] enable_port Function for enabling signaling through the port the
+ *	device is attached to.
+ * @param[in] port_no Port number (passed through to @p enable_port).
+ * @param[in] arg Any data argument to @p enable_port.
+ * @param[out] assigned_address USB address of the device.
+ * @param[out] assigned_handle Devman handle of the new device.
+ * @param[in] dev_ops Child device ops.
+ * @param[in] new_dev_data Arbitrary pointer to be stored in the child
+ *	as @c driver_data.
+ * @param[out] new_fun Storage where pointer to allocated child function
+ *	will be written.
+ * @return Error code.
+ * @retval ENOENT Connection to HC not opened.
+ * @retval EADDRNOTAVAIL Failed retrieving free address from host controller.
+ * @retval EBUSY Failed reserving default USB address.
+ * @retval ENOTCONN Problem connecting to the host controller via USB pipe.
+ * @retval ESTALL Problem communication with device (either SET_ADDRESS
+ *	request or requests for descriptors when creating match ids).
+ */
+int usb_hc_new_device_wrapper(ddf_dev_t *parent, usb_hc_connection_t *connection,
+    usb_speed_t dev_speed,
+    int (*enable_port)(int port_no, void *arg), int port_no, void *arg,
+    usb_address_t *assigned_address, devman_handle_t *assigned_handle,
+    ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
+{
+	assert(connection != NULL);
+	// FIXME: this is awful, we are accessing directly the structure.
+	usb_hc_connection_t hc_conn = {
+		.hc_handle = connection->hc_handle,
+		.hc_sess = NULL
+	};
+
+	int rc;
+	struct timeval start_time;
+
+	rc = gettimeofday(&start_time, NULL);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_hc_connection_open(&hc_conn);
+	if (rc != EOK) {
+		return rc;
+	}
+
+
+	/*
+	 * Request new address.
+	 */
+	usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
+	if (dev_addr < 0) {
+		usb_hc_connection_close(&hc_conn);
+		return EADDRNOTAVAIL;
+	}
+
+	/*
+	 * We will not register control pipe on default address.
+	 * The registration might fail. That means that someone else already
+	 * registered that endpoint. We will simply wait and try again.
+	 * (Someone else already wants to add a new device.)
+	 */
+	usb_device_connection_t dev_conn;
+	rc = usb_device_connection_initialize_on_default_address(&dev_conn,
+	    &hc_conn);
+	if (rc != EOK) {
+		rc = ENOTCONN;
+		goto leave_release_free_address;
+	}
+
+	usb_pipe_t ctrl_pipe;
+	rc = usb_pipe_initialize_default_control(&ctrl_pipe,
+	    &dev_conn);
+	if (rc != EOK) {
+		rc = ENOTCONN;
+		goto leave_release_free_address;
+	}
+
+	do {
+		rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
+		    &hc_conn);
+		if (rc != EOK) {
+			/* Do not overheat the CPU ;-). */
+			async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
+		}
+	} while (rc != EOK);
+	struct timeval end_time;
+
+	rc = gettimeofday(&end_time, NULL);
+	if (rc != EOK) {
+		goto leave_release_default_address;
+	}
+
+	/* According to the USB spec part 9.1.2 host allows 100ms time for
+	 * the insertion process to complete. According to 7.1.7.1 this is the
+	 * time between attach detected and port reset. However, the setup done
+	 * above might use much of this time so we should only wait to fill
+	 * up the 100ms quota*/
+	suseconds_t elapsed = tv_sub(&end_time, &start_time);
+	if (elapsed < 100000) {
+		async_usleep(100000 - elapsed);
+	}
+
+	/*
+	 * Endpoint is registered. We can enable the port and change
+	 * device address.
+	 */
+	rc = enable_port(port_no, arg);
+	if (rc != EOK) {
+		goto leave_release_default_address;
+	}
+	/* USB spec 7.1.7.1: The USB System Software guarantees a minimum of
+	 * 10ms for reset recovery. Device response to any bus transactions
+	 * addressed to the default device address during the reset recovery
+	 * time is undefined.
+	 */
+	async_usleep(10000);
+
+	rc = usb_pipe_probe_default_control(&ctrl_pipe);
+	if (rc != EOK) {
+		rc = ESTALL;
+		goto leave_release_default_address;
+	}
+
+	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
+	if (rc != EOK) {
+		rc = ESTALL;
+		goto leave_release_default_address;
+	}
+
+	/*
+	 * Address changed. We can release the original endpoint, thus
+	 * allowing other to access the default address.
+	 */
+	unregister_control_endpoint_on_default_address(&hc_conn);
+
+	/*
+	 * Time to register the new endpoint.
+	 */
+	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
+	if (rc != EOK) {
+		goto leave_release_free_address;
+	}
+
+	/*
+	 * It is time to register the device with devman.
+	 */
+	/* FIXME: create device_register that will get opened ctrl pipe. */
+	devman_handle_t child_handle;
+	rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle,
+	    parent, &child_handle,
+	    dev_ops, new_dev_data, new_fun);
+	if (rc != EOK) {
+		rc = ESTALL;
+		goto leave_release_free_address;
+	}
+
+	/*
+	 * And now inform the host controller about the handle.
+	 */
+	usb_hc_attached_device_t new_device = {
+		.address = dev_addr,
+		.handle = child_handle
+	};
+	rc = usb_hc_register_device(&hc_conn, &new_device);
+	if (rc != EOK) {
+		rc = EDESTADDRREQ;
+		goto leave_release_free_address;
+	}
+	
+	usb_hc_connection_close(&hc_conn);
+
+	/*
+	 * And we are done.
+	 */
+	if (assigned_address != NULL) {
+		*assigned_address = dev_addr;
+	}
+	if (assigned_handle != NULL) {
+		*assigned_handle = child_handle;
+	}
+
+	return EOK;
+
+
+
+	/*
+	 * Error handling (like nested exceptions) starts here.
+	 * Completely ignoring errors here.
+	 */
+leave_release_default_address:
+	usb_pipe_unregister(&ctrl_pipe, &hc_conn);
+
+leave_release_free_address:
+	usb_hc_unregister_device(&hc_conn, dev_addr);
+
+	usb_hc_connection_close(&hc_conn);
+
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/pipepriv.c
===================================================================
--- uspace/lib/usbdev/src/pipepriv.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/pipepriv.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,147 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Library internal functions on USB pipes (implementation).
+ */
+#include "pipepriv.h"
+#include <devman.h>
+#include <errno.h>
+#include <assert.h>
+
+/** Ensure exclusive access to the IPC phone of given pipe.
+ *
+ * @param pipe Pipe to be exclusively accessed.
+ */
+void pipe_start_transaction(usb_pipe_t *pipe)
+{
+	fibril_mutex_lock(&pipe->hc_sess_mutex);
+}
+
+/** Terminate exclusive access to the IPC phone of given pipe.
+ *
+ * @param pipe Pipe to be released from exclusive usage.
+ */
+void pipe_end_transaction(usb_pipe_t *pipe)
+{
+	fibril_mutex_unlock(&pipe->hc_sess_mutex);
+}
+
+/** Ensure exclusive access to the pipe as a whole.
+ *
+ * @param pipe Pipe to be exclusively accessed.
+ */
+void pipe_acquire(usb_pipe_t *pipe)
+{
+	fibril_mutex_lock(&pipe->guard);
+}
+
+/** Terminate exclusive access to the pipe as a whole.
+ *
+ * @param pipe Pipe to be released from exclusive usage.
+ */
+void pipe_release(usb_pipe_t *pipe)
+{
+	fibril_mutex_unlock(&pipe->guard);
+}
+
+/** Add reference of active transfers over the pipe.
+ *
+ * @param pipe The USB pipe.
+ * @param hide_failure Whether to hide failure when adding reference
+ *	(use soft refcount).
+ * @return Error code.
+ * @retval EOK Currently always.
+ */
+int pipe_add_ref(usb_pipe_t *pipe, bool hide_failure)
+{
+	pipe_acquire(pipe);
+	
+	if (pipe->refcount == 0) {
+		/* Need to open the phone by ourselves. */
+		async_sess_t *sess =
+		    devman_device_connect(EXCHANGE_SERIALIZE, pipe->wire->hc_handle, 0);
+		if (!sess) {
+			if (hide_failure) {
+				pipe->refcount_soft++;
+				pipe_release(pipe);
+				return EOK;
+			}
+			
+			pipe_release(pipe);
+			return ENOMEM;
+		}
+		
+		/*
+		 * No locking is needed, refcount is zero and whole pipe
+		 * mutex is locked.
+		 */
+		
+		pipe->hc_sess = sess;
+	}
+	
+	pipe->refcount++;
+	pipe_release(pipe);
+	
+	return EOK;
+}
+
+/** Drop active transfer reference on the pipe.
+ *
+ * @param pipe The USB pipe.
+ */
+void pipe_drop_ref(usb_pipe_t *pipe)
+{
+	pipe_acquire(pipe);
+	
+	if (pipe->refcount_soft > 0) {
+		pipe->refcount_soft--;
+		pipe_release(pipe);
+		return;
+	}
+	
+	assert(pipe->refcount > 0);
+	
+	pipe->refcount--;
+	
+	if (pipe->refcount == 0) {
+		/* We were the last users, let's hang-up. */
+		async_hangup(pipe->hc_sess);
+		pipe->hc_sess = NULL;
+	}
+	
+	pipe_release(pipe);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/pipepriv.h
===================================================================
--- uspace/lib/usbdev/src/pipepriv.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/pipepriv.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,54 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Library internal functions on USB pipes.
+ */
+#ifndef LIBUSBDEV_PIPEPRIV_H_
+#define LIBUSBDEV_PIPEPRIV_H_
+
+#include <usb/dev/pipes.h>
+#include <bool.h>
+
+void pipe_acquire(usb_pipe_t *);
+void pipe_release(usb_pipe_t *);
+
+void pipe_start_transaction(usb_pipe_t *);
+void pipe_end_transaction(usb_pipe_t *);
+
+int pipe_add_ref(usb_pipe_t *, bool);
+void pipe_drop_ref(usb_pipe_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/pipes.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,234 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * USB endpoint pipes miscellaneous functions.
+ */
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <usb/hc.h>
+#include <usbhc_iface.h>
+#include <usb_iface.h>
+#include <devman.h>
+#include <errno.h>
+#include <assert.h>
+#include "pipepriv.h"
+
+#define IPC_AGAIN_DELAY (1000 * 2) /* 2ms */
+
+/** Tell USB address assigned to given device.
+ *
+ * @param sess Session to parent device.
+ * @param dev Device in question.
+ * @return USB address or error code.
+ */
+static usb_address_t get_my_address(async_sess_t *sess, ddf_dev_t *dev)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	/*
+	 * We are sending special value as a handle - zero - to get
+	 * handle of the parent function (that handle was used
+	 * when registering our device @p dev.
+	 */
+	sysarg_t address;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_ADDRESS, 0, &address);
+	
+	async_exchange_end(exch);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (usb_address_t) address;
+}
+
+/** Tell USB interface assigned to given device.
+ *
+ * @param device Device in question.
+ * @return Interface number (negative code means any).
+ */
+int usb_device_get_assigned_interface(ddf_dev_t *device)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, device->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return -1;
+	
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	
+	sysarg_t iface_no;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_INTERFACE, device->handle, &iface_no);
+	
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+	
+	if (rc != EOK)
+		return -1;
+	
+	return (int) iface_no;
+}
+
+/** Initialize connection to USB device.
+ *
+ * @param connection Connection structure to be initialized.
+ * @param dev Generic device backing the USB device.
+ * @return Error code.
+ */
+int usb_device_connection_initialize_from_device(
+    usb_device_connection_t *connection, ddf_dev_t *dev)
+{
+	assert(connection);
+	assert(dev);
+	
+	int rc;
+	devman_handle_t hc_handle;
+	usb_address_t my_address;
+	
+	rc = usb_hc_find(dev->handle, &hc_handle);
+	if (rc != EOK)
+		return rc;
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	/*
+	 * Asking for "my" address may require several attempts.
+	 * That is because following scenario may happen:
+	 *  - parent driver (i.e. driver of parent device) announces new device
+	 *    and devman launches current driver
+	 *  - parent driver is preempted and thus does not send address-handle
+	 *    binding to HC driver
+	 *  - this driver gets here and wants the binding
+	 *  - the HC does not know the binding yet and thus it answers ENOENT
+	 *  So, we need to wait for the HC to learn the binding.
+	 */
+	
+	do {
+		my_address = get_my_address(parent_sess, dev);
+		
+		if (my_address == ENOENT) {
+			/* Be nice, let other fibrils run and try again. */
+			async_usleep(IPC_AGAIN_DELAY);
+		} else if (my_address < 0) {
+			/* Some other problem, no sense trying again. */
+			rc = my_address;
+			goto leave;
+		}
+	
+	} while (my_address < 0);
+	
+	rc = usb_device_connection_initialize(connection,
+	    hc_handle, my_address);
+	
+leave:
+	async_hangup(parent_sess);
+	return rc;
+}
+
+/** Initialize connection to USB device.
+ *
+ * @param connection Connection structure to be initialized.
+ * @param host_controller_handle Devman handle of host controller device is
+ * 	connected to.
+ * @param device_address Device USB address.
+ * @return Error code.
+ */
+int usb_device_connection_initialize(usb_device_connection_t *connection,
+    devman_handle_t host_controller_handle, usb_address_t device_address)
+{
+	assert(connection);
+
+	if ((device_address < 0) || (device_address >= USB11_ADDRESS_MAX)) {
+		return EINVAL;
+	}
+
+	connection->hc_handle = host_controller_handle;
+	connection->address = device_address;
+
+	return EOK;
+}
+
+/** Initialize connection to USB device on default address.
+ *
+ * @param dev_connection Device connection structure to be initialized.
+ * @param hc_connection Initialized connection to host controller.
+ * @return Error code.
+ */
+int usb_device_connection_initialize_on_default_address(
+    usb_device_connection_t *dev_connection,
+    usb_hc_connection_t *hc_connection)
+{
+	assert(dev_connection);
+
+	if (hc_connection == NULL) {
+		return EBADMEM;
+	}
+
+	return usb_device_connection_initialize(dev_connection,
+	    hc_connection->hc_handle, (usb_address_t) 0);
+}
+
+/** Prepare pipe for a long transfer.
+ *
+ * By a long transfer is mean transfer consisting of several
+ * requests to the HC.
+ * Calling such function is optional and it has positive effect of
+ * improved performance because IPC session is initiated only once.
+ *
+ * @param pipe Pipe over which the transfer will happen.
+ * @return Error code.
+ */
+void usb_pipe_start_long_transfer(usb_pipe_t *pipe)
+{
+	(void) pipe_add_ref(pipe, true);
+}
+
+/** Terminate a long transfer on a pipe.
+ *
+ * @see usb_pipe_start_long_transfer
+ *
+ * @param pipe Pipe where to end the long transfer.
+ */
+void usb_pipe_end_long_transfer(usb_pipe_t *pipe)
+{
+	pipe_drop_ref(pipe);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,531 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Initialization of endpoint pipes.
+ *
+ */
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/dp.h>
+#include <usb/dev/request.h>
+#include <usbhc_iface.h>
+#include <errno.h>
+#include <assert.h>
+
+#define CTRL_PIPE_MIN_PACKET_SIZE 8
+#define DEV_DESCR_MAX_PACKET_SIZE_OFFSET 7
+
+
+#define NESTING(parentname, childname) \
+	{ \
+		.child = USB_DESCTYPE_##childname, \
+		.parent = USB_DESCTYPE_##parentname, \
+	}
+#define LAST_NESTING { -1, -1 }
+
+/** Nesting pairs of standard descriptors. */
+static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
+	NESTING(CONFIGURATION, INTERFACE),
+	NESTING(INTERFACE, ENDPOINT),
+	NESTING(INTERFACE, HUB),
+	NESTING(INTERFACE, HID),
+	NESTING(HID, HID_REPORT),
+	LAST_NESTING
+};
+
+/** Tells whether given descriptor is of endpoint type.
+ *
+ * @param descriptor Descriptor in question.
+ * @return Whether the given descriptor is endpoint descriptor.
+ */
+static inline bool is_endpoint_descriptor(uint8_t *descriptor)
+{
+	return descriptor[1] == USB_DESCTYPE_ENDPOINT;
+}
+
+/** Tells whether found endpoint corresponds to endpoint described by user.
+ *
+ * @param wanted Endpoint description as entered by driver author.
+ * @param found Endpoint description obtained from endpoint descriptor.
+ * @return Whether the @p found descriptor fits the @p wanted descriptor.
+ */
+static bool endpoint_fits_description(const usb_endpoint_description_t *wanted,
+    usb_endpoint_description_t *found)
+{
+#define _SAME(fieldname) ((wanted->fieldname) == (found->fieldname))
+
+	if (!_SAME(direction)) {
+		return false;
+	}
+
+	if (!_SAME(transfer_type)) {
+		return false;
+	}
+
+	if ((wanted->interface_class >= 0) && !_SAME(interface_class)) {
+		return false;
+	}
+
+	if ((wanted->interface_subclass >= 0) && !_SAME(interface_subclass)) {
+		return false;
+	}
+
+	if ((wanted->interface_protocol >= 0) && !_SAME(interface_protocol)) {
+		return false;
+	}
+
+#undef _SAME
+
+	return true;
+}
+
+/** Find endpoint mapping for a found endpoint.
+ *
+ * @param mapping Endpoint mapping list.
+ * @param mapping_count Number of endpoint mappings in @p mapping.
+ * @param found_endpoint Description of found endpoint.
+ * @param interface_number Number of currently processed interface.
+ * @return Endpoint mapping corresponding to @p found_endpoint.
+ * @retval NULL No corresponding endpoint found.
+ */
+static usb_endpoint_mapping_t *find_endpoint_mapping(
+    usb_endpoint_mapping_t *mapping, size_t mapping_count,
+    usb_endpoint_description_t *found_endpoint,
+    int interface_number, int interface_setting)
+{
+	while (mapping_count > 0) {
+		bool interface_number_fits = (mapping->interface_no < 0)
+		    || (mapping->interface_no == interface_number);
+
+		bool interface_setting_fits = (mapping->interface_setting < 0)
+		    || (mapping->interface_setting == interface_setting);
+
+		bool endpoint_descriptions_fits = endpoint_fits_description(
+		    mapping->description, found_endpoint);
+
+		if (interface_number_fits
+		    && interface_setting_fits
+		    && endpoint_descriptions_fits) {
+			return mapping;
+		}
+
+		mapping++;
+		mapping_count--;
+	}
+	return NULL;
+}
+
+/** Process endpoint descriptor.
+ *
+ * @param mapping Endpoint mapping list.
+ * @param mapping_count Number of endpoint mappings in @p mapping.
+ * @param interface Interface descriptor under which belongs the @p endpoint.
+ * @param endpoint Endpoint descriptor.
+ * @param wire Connection backing the endpoint pipes.
+ * @return Error code.
+ */
+static int process_endpoint(
+    usb_endpoint_mapping_t *mapping, size_t mapping_count,
+    usb_standard_interface_descriptor_t *interface,
+    usb_standard_endpoint_descriptor_t *endpoint,
+    usb_device_connection_t *wire)
+{
+	usb_endpoint_description_t description;
+
+	/*
+	 * Get endpoint characteristics.
+	 */
+
+	/* Actual endpoint number is in bits 0..3 */
+	usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
+
+	/* Endpoint direction is set by bit 7 */
+	description.direction = (endpoint->endpoint_address & 128)
+	    ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
+	/* Transfer type is in bits 0..2 and the enum values corresponds 1:1 */
+	description.transfer_type = endpoint->attributes & 3;
+
+	/*
+	 * Get interface characteristics.
+	 */
+	description.interface_class = interface->interface_class;
+	description.interface_subclass = interface->interface_subclass;
+	description.interface_protocol = interface->interface_protocol;
+
+	/*
+	 * Find the most fitting mapping and initialize the pipe.
+	 */
+	usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
+	    mapping_count, &description,
+	    interface->interface_number, interface->alternate_setting);
+	if (ep_mapping == NULL) {
+		return ENOENT;
+	}
+
+	if (ep_mapping->pipe == NULL) {
+		return EBADMEM;
+	}
+	if (ep_mapping->present) {
+		return EEXISTS;
+	}
+
+	int rc = usb_pipe_initialize(ep_mapping->pipe, wire,
+	    ep_no, description.transfer_type, endpoint->max_packet_size,
+	    description.direction);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	ep_mapping->present = true;
+	ep_mapping->descriptor = endpoint;
+	ep_mapping->interface = interface;
+
+	return EOK;
+}
+
+/** Process whole USB interface.
+ *
+ * @param mapping Endpoint mapping list.
+ * @param mapping_count Number of endpoint mappings in @p mapping.
+ * @param parser Descriptor parser.
+ * @param parser_data Descriptor parser data.
+ * @param interface_descriptor Interface descriptor.
+ * @return Error code.
+ */
+static int process_interface(
+    usb_endpoint_mapping_t *mapping, size_t mapping_count,
+    usb_dp_parser_t *parser, usb_dp_parser_data_t *parser_data,
+    uint8_t *interface_descriptor)
+{
+	uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
+	    parser_data, interface_descriptor);
+
+	if (descriptor == NULL) {
+		return ENOENT;
+	}
+
+	do {
+		if (is_endpoint_descriptor(descriptor)) {
+			(void) process_endpoint(mapping, mapping_count,
+			    (usb_standard_interface_descriptor_t *)
+			        interface_descriptor,
+			    (usb_standard_endpoint_descriptor_t *)
+			        descriptor,
+			    (usb_device_connection_t *) parser_data->arg);
+		}
+
+		descriptor = usb_dp_get_sibling_descriptor(parser, parser_data,
+		    interface_descriptor, descriptor);
+	} while (descriptor != NULL);
+
+	return EOK;
+}
+
+/** Initialize endpoint pipes from configuration descriptor.
+ *
+ * The mapping array is expected to conform to following rules:
+ * - @c pipe must point to already allocated structure with uninitialized pipe
+ * - @c description must point to prepared endpoint description
+ * - @c descriptor does not need to be initialized (will be overwritten)
+ * - @c interface does not need to be initialized (will be overwritten)
+ * - @c present does not need to be initialized (will be overwritten)
+ *
+ * After processing the configuration descriptor, the mapping is updated
+ * in the following fashion:
+ * - @c present will be set to @c true when the endpoint was found in the
+ *   configuration
+ * - @c descriptor will point inside the configuration descriptor to endpoint
+ *   corresponding to given description (or NULL for not found descriptor)
+ * - @c interface will point inside the configuration descriptor to interface
+ *   descriptor the endpoint @c descriptor belongs to (or NULL for not found
+ *   descriptor)
+ * - @c pipe will be initialized when found, otherwise left untouched
+ * - @c description will be untouched under all circumstances
+ *
+ * @param mapping Endpoint mapping list.
+ * @param mapping_count Number of endpoint mappings in @p mapping.
+ * @param configuration_descriptor Full configuration descriptor (is expected
+ *	to be in USB endianness: i.e. as-is after being retrieved from
+ *	the device).
+ * @param configuration_descriptor_size Size of @p configuration_descriptor
+ *	in bytes.
+ * @param connection Connection backing the endpoint pipes.
+ * @return Error code.
+ */
+int usb_pipe_initialize_from_configuration(
+    usb_endpoint_mapping_t *mapping, size_t mapping_count,
+    uint8_t *configuration_descriptor, size_t configuration_descriptor_size,
+    usb_device_connection_t *connection)
+{
+	assert(connection);
+
+	if (configuration_descriptor == NULL) {
+		return EBADMEM;
+	}
+	if (configuration_descriptor_size
+	    < sizeof(usb_standard_configuration_descriptor_t)) {
+		return ERANGE;
+	}
+
+	/*
+	 * Go through the mapping and set all endpoints to not present.
+	 */
+	size_t i;
+	for (i = 0; i < mapping_count; i++) {
+		mapping[i].present = false;
+		mapping[i].descriptor = NULL;
+		mapping[i].interface = NULL;
+	}
+
+	/*
+	 * Prepare the descriptor parser.
+	 */
+	usb_dp_parser_t dp_parser = {
+		.nesting = descriptor_nesting
+	};
+	usb_dp_parser_data_t dp_data = {
+		.data = configuration_descriptor,
+		.size = configuration_descriptor_size,
+		.arg = connection
+	};
+
+	/*
+	 * Iterate through all interfaces.
+	 */
+	uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, configuration_descriptor);
+	if (interface == NULL) {
+		return ENOENT;
+	}
+	do {
+		(void) process_interface(mapping, mapping_count,
+		    &dp_parser, &dp_data,
+		    interface);
+		interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
+		    configuration_descriptor, interface);
+	} while (interface != NULL);
+
+	return EOK;
+}
+
+/** Initialize USB endpoint pipe.
+ *
+ * @param pipe Endpoint pipe to be initialized.
+ * @param connection Connection to the USB device backing this pipe (the wire).
+ * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15).
+ * @param transfer_type Transfer type (e.g. interrupt or bulk).
+ * @param max_packet_size Maximum packet size in bytes.
+ * @param direction Endpoint direction (in/out).
+ * @return Error code.
+ */
+int usb_pipe_initialize(usb_pipe_t *pipe,
+    usb_device_connection_t *connection, usb_endpoint_t endpoint_no,
+    usb_transfer_type_t transfer_type, size_t max_packet_size,
+    usb_direction_t direction)
+{
+	assert(pipe);
+	assert(connection);
+
+	fibril_mutex_initialize(&pipe->guard);
+	pipe->wire = connection;
+	pipe->hc_sess = NULL;
+	fibril_mutex_initialize(&pipe->hc_sess_mutex);
+	pipe->endpoint_no = endpoint_no;
+	pipe->transfer_type = transfer_type;
+	pipe->max_packet_size = max_packet_size;
+	pipe->direction = direction;
+	pipe->refcount = 0;
+	pipe->refcount_soft = 0;
+	pipe->auto_reset_halt = false;
+
+	return EOK;
+}
+
+
+/** Initialize USB endpoint pipe as the default zero control pipe.
+ *
+ * @param pipe Endpoint pipe to be initialized.
+ * @param connection Connection to the USB device backing this pipe (the wire).
+ * @return Error code.
+ */
+int usb_pipe_initialize_default_control(usb_pipe_t *pipe,
+    usb_device_connection_t *connection)
+{
+	assert(pipe);
+	assert(connection);
+
+	int rc = usb_pipe_initialize(pipe, connection,
+	    0, USB_TRANSFER_CONTROL, CTRL_PIPE_MIN_PACKET_SIZE,
+	    USB_DIRECTION_BOTH);
+
+	pipe->auto_reset_halt = true;
+
+	return rc;
+}
+
+/** Probe default control pipe for max packet size.
+ *
+ * The function tries to get the correct value of max packet size several
+ * time before giving up.
+ *
+ * The session on the pipe shall not be started.
+ *
+ * @param pipe Default control pipe.
+ * @return Error code.
+ */
+int usb_pipe_probe_default_control(usb_pipe_t *pipe)
+{
+	assert(pipe);
+	assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE);
+
+	if ((pipe->direction != USB_DIRECTION_BOTH) ||
+	    (pipe->transfer_type != USB_TRANSFER_CONTROL) ||
+	    (pipe->endpoint_no != 0)) {
+		return EINVAL;
+	}
+
+#define TRY_LOOP(attempt_var) \
+	for (attempt_var = 0; attempt_var < 3; attempt_var++)
+
+	size_t failed_attempts;
+	int rc;
+
+	usb_pipe_start_long_transfer(pipe);
+
+	uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE];
+	size_t transferred_size;
+	TRY_LOOP(failed_attempts) {
+		rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD,
+		    USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE,
+		    0, 0, dev_descr_start, CTRL_PIPE_MIN_PACKET_SIZE,
+		    &transferred_size);
+		if (rc == EOK) {
+			if (transferred_size != CTRL_PIPE_MIN_PACKET_SIZE) {
+				rc = ELIMIT;
+				continue;
+			}
+			break;
+		}
+	}
+	usb_pipe_end_long_transfer(pipe);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	pipe->max_packet_size
+	    = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET];
+
+	return EOK;
+}
+
+/** Register endpoint with the host controller.
+ *
+ * @param pipe Pipe to be registered.
+ * @param interval Polling interval.
+ * @param hc_connection Connection to the host controller (must be opened).
+ * @return Error code.
+ */
+int usb_pipe_register(usb_pipe_t *pipe,
+    unsigned int interval,
+    usb_hc_connection_t *hc_connection)
+{
+	return usb_pipe_register_with_speed(pipe, USB_SPEED_MAX + 1,
+	    interval, hc_connection);
+}
+
+/** Register endpoint with a speed at the host controller.
+ *
+ * You will rarely need to use this function because it is needed only
+ * if the registered endpoint is of address 0 and there is no other way
+ * to tell speed of the device at address 0.
+ *
+ * @param pipe Pipe to be registered.
+ * @param speed Speed of the device
+ *	(invalid speed means use previously specified one).
+ * @param interval Polling interval.
+ * @param hc_connection Connection to the host controller (must be opened).
+ * @return Error code.
+ */
+int usb_pipe_register_with_speed(usb_pipe_t *pipe, usb_speed_t speed,
+    unsigned int interval,
+    usb_hc_connection_t *hc_connection)
+{
+	assert(pipe);
+	assert(hc_connection);
+	
+	if (!usb_hc_connection_is_opened(hc_connection))
+		return EBADF;
+	
+#define _PACK2(high, low) (((high) << 16) + (low))
+#define _PACK3(high, middle, low) (((((high) << 8) + (middle)) << 8) + (low))
+	
+	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REGISTER_ENDPOINT,
+	    _PACK2(pipe->wire->address, pipe->endpoint_no),
+	    _PACK3(speed, pipe->transfer_type, pipe->direction),
+	    _PACK2(pipe->max_packet_size, interval));
+	async_exchange_end(exch);
+	
+#undef _PACK2
+#undef _PACK3
+	
+	return rc;
+}
+
+/** Revert endpoint registration with the host controller.
+ *
+ * @param pipe Pipe to be unregistered.
+ * @param hc_connection Connection to the host controller (must be opened).
+ * @return Error code.
+ */
+int usb_pipe_unregister(usb_pipe_t *pipe,
+    usb_hc_connection_t *hc_connection)
+{
+	assert(pipe);
+	assert(hc_connection);
+	
+	if (!usb_hc_connection_is_opened(hc_connection))
+		return EBADF;
+	
+	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_UNREGISTER_ENDPOINT,
+	    pipe->wire->address, pipe->endpoint_no, pipe->direction);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/pipesio.c
===================================================================
--- uspace/lib/usbdev/src/pipesio.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/pipesio.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,610 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Input and output functions (reads and writes) on endpoint pipes.
+ *
+ * Note on synchronousness of the operations: there is ABSOLUTELY NO
+ * guarantee that a call to particular function will not trigger a fibril
+ * switch.
+ *
+ * Note about the implementation: the transfer requests are always divided
+ * into two functions.
+ * The outer one does checking of input parameters (e.g. that session was
+ * already started, buffers are not NULL etc), while the inner one
+ * (with _no_checks suffix) does the actual IPC (it checks for IPC errors,
+ * obviously).
+ */
+
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <errno.h>
+#include <assert.h>
+#include <usbhc_iface.h>
+#include <usb/dev/request.h>
+#include <async.h>
+#include "pipepriv.h"
+
+/** Request an in transfer, no checking of input parameters.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[out] buffer Buffer where to store the data.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] size_transfered Number of bytes that were actually transfered.
+ * @return Error code.
+ */
+static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
+    void *buffer, size_t size, size_t *size_transfered)
+{
+	/*
+	 * Get corresponding IPC method.
+	 * In future, replace with static array of mappings
+	 * transfer type -> method.
+	 */
+	usbhc_iface_funcs_t ipc_method;
+	switch (pipe->transfer_type) {
+		case USB_TRANSFER_INTERRUPT:
+			ipc_method = IPC_M_USBHC_INTERRUPT_IN;
+			break;
+		case USB_TRANSFER_BULK:
+			ipc_method = IPC_M_USBHC_BULK_IN;
+			break;
+		default:
+			return ENOTSUP;
+	}
+	
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
+	
+	/*
+	 * Make call identifying target USB device and type of transfer.
+	 */
+	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    ipc_method, pipe->wire->address, pipe->endpoint_no, NULL);
+	
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Retrieve the data.
+	 */
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, buffer, size,
+	    &data_request_call);
+	
+	/*
+	 * Since now on, someone else might access the backing phone
+	 * without breaking the transfer IPC protocol.
+	 */
+	async_exchange_end(exch);
+	pipe_end_transaction(pipe);
+	
+	if (data_request == 0) {
+		/*
+		 * FIXME:
+		 * How to let the other side know that we want to abort?
+		 */
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Wait for the answer.
+	 */
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+	
+	*size_transfered = IPC_GET_ARG2(data_request_call);
+	
+	return EOK;
+}
+
+
+/** Request a read (in) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[out] buffer Buffer where to store the data.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] size_transfered Number of bytes that were actually transfered.
+ * @return Error code.
+ */
+int usb_pipe_read(usb_pipe_t *pipe,
+    void *buffer, size_t size, size_t *size_transfered)
+{
+	assert(pipe);
+
+	if (buffer == NULL) {
+		return EINVAL;
+	}
+
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_IN) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	int rc;
+	rc = pipe_add_ref(pipe, false);
+	if (rc != EOK) {
+		return rc;
+	}
+
+
+	size_t act_size = 0;
+
+	rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
+
+	pipe_drop_ref(pipe);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (size_transfered != NULL) {
+		*size_transfered = act_size;
+	}
+
+	return EOK;
+}
+
+
+
+
+/** Request an out transfer, no checking of input parameters.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] buffer Buffer with data to transfer.
+ * @param[in] size Size of the buffer (in bytes).
+ * @return Error code.
+ */
+static int usb_pipe_write_no_check(usb_pipe_t *pipe,
+    void *buffer, size_t size)
+{
+	/*
+	 * Get corresponding IPC method.
+	 * In future, replace with static array of mappings
+	 * transfer type -> method.
+	 */
+	usbhc_iface_funcs_t ipc_method;
+	switch (pipe->transfer_type) {
+		case USB_TRANSFER_INTERRUPT:
+			ipc_method = IPC_M_USBHC_INTERRUPT_OUT;
+			break;
+		case USB_TRANSFER_BULK:
+			ipc_method = IPC_M_USBHC_BULK_OUT;
+			break;
+		default:
+			return ENOTSUP;
+	}
+
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
+	
+	/*
+	 * Make call identifying target USB device and type of transfer.
+	 */
+	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    ipc_method, pipe->wire->address, pipe->endpoint_no, NULL);
+	
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Send the data.
+	 */
+	int rc = async_data_write_start(exch, buffer, size);
+	
+	/*
+	 * Since now on, someone else might access the backing phone
+	 * without breaking the transfer IPC protocol.
+	 */
+	async_exchange_end(exch);
+	pipe_end_transaction(pipe);
+	
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+	
+	/*
+	 * Wait for the answer.
+	 */
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	return (int) opening_request_rc;
+}
+
+/** Request a write (out) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] buffer Buffer with data to transfer.
+ * @param[in] size Size of the buffer (in bytes).
+ * @return Error code.
+ */
+int usb_pipe_write(usb_pipe_t *pipe,
+    void *buffer, size_t size)
+{
+	assert(pipe);
+
+	if (buffer == NULL) {
+		return EINVAL;
+	}
+
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_OUT) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	int rc;
+
+	rc = pipe_add_ref(pipe, false);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_pipe_write_no_check(pipe, buffer, size);
+
+	pipe_drop_ref(pipe);
+
+	return rc;
+}
+
+/** Try to clear endpoint halt of default control pipe.
+ *
+ * @param pipe Pipe for control endpoint zero.
+ */
+static void clear_self_endpoint_halt(usb_pipe_t *pipe)
+{
+	assert(pipe != NULL);
+
+	if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
+		return;
+	}
+
+
+	/* Prevent indefinite recursion. */
+	pipe->auto_reset_halt = false;
+	usb_request_clear_endpoint_halt(pipe, 0);
+	pipe->auto_reset_halt = true;
+}
+
+
+/** Request a control read transfer, no checking of input parameters.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[out] data_buffer Buffer for incoming data.
+ * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
+ * @param[out] data_transfered_size Number of bytes that were actually
+ *                                  transfered during the DATA stage.
+ * @return Error code.
+ */
+static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
+{
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+
+	/*
+	 * Make call identifying target USB device and control transfer type.
+	 */
+	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
+	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_CONTROL_READ, pipe->wire->address, pipe->endpoint_no,
+	    NULL);
+	
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Send the setup packet.
+	 */
+	int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+	
+	/*
+	 * Retrieve the data.
+	 */
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, data_buffer,
+	    data_buffer_size, &data_request_call);
+	
+	/*
+	 * Since now on, someone else might access the backing phone
+	 * without breaking the transfer IPC protocol.
+	 */
+	async_exchange_end(exch);
+	pipe_end_transaction(pipe);
+	
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+
+	/*
+	 * Wait for the answer.
+	 */
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	*data_transfered_size = IPC_GET_ARG2(data_request_call);
+
+	return EOK;
+}
+
+/** Request a control read transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[out] data_buffer Buffer for incoming data.
+ * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
+ * @param[out] data_transfered_size Number of bytes that were actually
+ *                                  transfered during the DATA stage.
+ * @return Error code.
+ */
+int usb_pipe_control_read(usb_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
+{
+	assert(pipe);
+
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((data_buffer == NULL) || (data_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
+	int rc;
+
+	rc = pipe_add_ref(pipe, false);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	size_t act_size = 0;
+	rc = usb_pipe_control_read_no_check(pipe,
+	    setup_buffer, setup_buffer_size,
+	    data_buffer, data_buffer_size, &act_size);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
+	pipe_drop_ref(pipe);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (data_transfered_size != NULL) {
+		*data_transfered_size = act_size;
+	}
+
+	return EOK;
+}
+
+
+/** Request a control write transfer, no checking of input parameters.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[in] data_buffer Buffer with data to be sent.
+ * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
+ * @return Error code.
+ */
+static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size)
+{
+	/* Ensure serialization over the phone. */
+	pipe_start_transaction(pipe);
+
+	/*
+	 * Make call identifying target USB device and control transfer type.
+	 */
+	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
+	aid_t opening_request = async_send_4(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_CONTROL_WRITE, pipe->wire->address, pipe->endpoint_no,
+	    data_buffer_size, NULL);
+	
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+		return ENOMEM;
+	}
+	
+	/*
+	 * Send the setup packet.
+	 */
+	int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+	
+	/*
+	 * Send the data (if any).
+	 */
+	if (data_buffer_size > 0) {
+		rc = async_data_write_start(exch, data_buffer, data_buffer_size);
+		
+		/* All data sent, pipe can be released. */
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+	
+		if (rc != EOK) {
+			async_wait_for(opening_request, NULL);
+			return rc;
+		}
+	} else {
+		/* No data to send, we can release the pipe for others. */
+		async_exchange_end(exch);
+		pipe_end_transaction(pipe);
+	}
+	
+	/*
+	 * Wait for the answer.
+	 */
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+
+/** Request a control write transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] setup_buffer Buffer with the setup packet.
+ * @param[in] setup_buffer_size Size of the setup packet (in bytes).
+ * @param[in] data_buffer Buffer with data to be sent.
+ * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
+ * @return Error code.
+ */
+int usb_pipe_control_write(usb_pipe_t *pipe,
+    void *setup_buffer, size_t setup_buffer_size,
+    void *data_buffer, size_t data_buffer_size)
+{
+	assert(pipe);
+
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((data_buffer == NULL) && (data_buffer_size > 0)) {
+		return EINVAL;
+	}
+
+	if ((data_buffer != NULL) && (data_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
+	int rc;
+
+	rc = pipe_add_ref(pipe, false);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_pipe_control_write_no_check(pipe,
+	    setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
+	pipe_drop_ref(pipe);
+
+	return rc;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/recognise.c
===================================================================
--- uspace/lib/usbdev/src/recognise.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/recognise.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2010 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 libusbdev
+ * @{
+ */
+/** @file
+ * Functions for recognition of attached devices.
+ */
+#include <sys/types.h>
+#include <fibril_synch.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/recognise.h>
+#include <usb/ddfiface.h>
+#include <usb/dev/request.h>
+#include <usb/classes/classes.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+
+/** Index to append after device name for uniqueness. */
+static size_t device_name_index = 0;
+/** Mutex guard for device_name_index. */
+static FIBRIL_MUTEX_INITIALIZE(device_name_index_mutex);
+
+/** DDF operations of child devices. */
+ddf_dev_ops_t child_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
+};
+
+/** Get integer part from BCD coded number. */
+#define BCD_INT(a) (((unsigned int)(a)) / 256)
+/** Get fraction part from BCD coded number (as an integer, no less). */
+#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
+
+/** Format for BCD coded number to be used in printf. */
+#define BCD_FMT "%x.%x"
+/** Arguments to printf for BCD coded number. */
+#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
+
+/* FIXME: make this dynamic */
+#define MATCH_STRING_MAX 256
+
+/** Add formatted match id.
+ *
+ * @param matches List of match ids where to add to.
+ * @param score Score of the match.
+ * @param format Printf-like format
+ * @return Error code.
+ */
+static int usb_add_match_id(match_id_list_t *matches, int score,
+    const char *format, ...)
+{
+	char *match_str = NULL;
+	match_id_t *match_id = NULL;
+	int rc;
+	
+	match_str = malloc(MATCH_STRING_MAX + 1);
+	if (match_str == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	/*
+	 * FIXME: replace with dynamic allocation of exact size
+	 */
+	va_list args;
+	va_start(args, format	);
+	vsnprintf(match_str, MATCH_STRING_MAX, format, args);
+	match_str[MATCH_STRING_MAX] = 0;
+	va_end(args);
+
+	match_id = create_match_id();
+	if (match_id == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	match_id->id = match_str;
+	match_id->score = score;
+	add_match_id(matches, match_id);
+
+	return EOK;
+	
+failure:
+	if (match_str != NULL) {
+		free(match_str);
+	}
+	if (match_id != NULL) {
+		match_id->id = NULL;
+		delete_match_id(match_id);
+	}
+	
+	return rc;
+}
+
+/** Add match id to list or return with error code.
+ *
+ * @param match_ids List of match ids.
+ * @param score Match id score.
+ * @param format Format of the matching string
+ * @param ... Arguments for the format.
+ */
+#define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
+	do { \
+		int __rc = usb_add_match_id((match_ids), (score), \
+		    format, ##__VA_ARGS__); \
+		if (__rc != EOK) { \
+			return __rc; \
+		} \
+	} while (0)
+
+/** Create device match ids based on its interface.
+ *
+ * @param[in] desc_device Device descriptor.
+ * @param[in] desc_interface Interface descriptor.
+ * @param[out] matches Initialized list of match ids.
+ * @return Error code (the two mentioned are not the only ones).
+ * @retval EINVAL Invalid input parameters (expects non NULL pointers).
+ * @retval ENOENT Device class is not "use interface".
+ */
+int usb_device_create_match_ids_from_interface(
+    const usb_standard_device_descriptor_t *desc_device,
+    const usb_standard_interface_descriptor_t *desc_interface,
+    match_id_list_t *matches)
+{
+	if (desc_interface == NULL) {
+		return EINVAL;
+	}
+	if (matches == NULL) {
+		return EINVAL;
+	}
+
+	if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
+		return ENOENT;
+	}
+
+	const char *classname = usb_str_class(desc_interface->interface_class);
+	assert(classname != NULL);
+
+#define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
+#define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
+    desc_interface->interface_protocol
+
+#define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
+#define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass
+
+#define IFACE_CLASS_FMT "interface&class=%s"
+#define IFACE_CLASS_ARGS classname
+
+#define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
+#define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
+    BCD_ARGS(desc_device->device_version)
+
+#define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
+#define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id
+
+#define VENDOR_ONLY_FMT "vendor=0x%04x"
+#define VENDOR_ONLY_ARGS desc_device->vendor_id
+
+	/*
+	 * If the vendor is specified, create match ids with vendor with
+	 * higher score.
+	 * Then the same ones without the vendor part.
+	 */
+	if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
+		/* First, interface matches with device release number. */
+		ADD_MATCHID_OR_RETURN(matches, 250,
+		    "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
+		    VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
+		ADD_MATCHID_OR_RETURN(matches, 240,
+		    "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
+		    VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
+		ADD_MATCHID_OR_RETURN(matches, 230,
+		    "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
+		    VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);
+
+		/* Next, interface matches without release number. */
+		ADD_MATCHID_OR_RETURN(matches, 220,
+		    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
+		    VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
+		ADD_MATCHID_OR_RETURN(matches, 210,
+		    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
+		    VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
+		ADD_MATCHID_OR_RETURN(matches, 200,
+		    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
+		    VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);
+
+		/* Finally, interface matches with only vendor. */
+		ADD_MATCHID_OR_RETURN(matches, 190,
+		    "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
+		    VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
+		ADD_MATCHID_OR_RETURN(matches, 180,
+		    "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
+		    VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
+		ADD_MATCHID_OR_RETURN(matches, 170,
+		    "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
+		    VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
+	}
+
+	/* Now, the same but without any vendor specification. */
+	ADD_MATCHID_OR_RETURN(matches, 160,
+	    "usb&" IFACE_PROTOCOL_FMT,
+	    IFACE_PROTOCOL_ARGS);
+	ADD_MATCHID_OR_RETURN(matches, 150,
+	    "usb&" IFACE_SUBCLASS_FMT,
+	    IFACE_SUBCLASS_ARGS);
+	ADD_MATCHID_OR_RETURN(matches, 140,
+	    "usb&" IFACE_CLASS_FMT,
+	    IFACE_CLASS_ARGS);
+
+#undef IFACE_PROTOCOL_FMT
+#undef IFACE_PROTOCOL_ARGS
+#undef IFACE_SUBCLASS_FMT
+#undef IFACE_SUBCLASS_ARGS
+#undef IFACE_CLASS_FMT
+#undef IFACE_CLASS_ARGS
+#undef VENDOR_RELEASE_FMT
+#undef VENDOR_RELEASE_ARGS
+#undef VENDOR_PRODUCT_FMT
+#undef VENDOR_PRODUCT_ARGS
+#undef VENDOR_ONLY_FMT
+#undef VENDOR_ONLY_ARGS
+
+	/* As a last resort, try fallback driver. */
+	ADD_MATCHID_OR_RETURN(matches, 10, "usb&interface&fallback");
+
+	return EOK;
+}
+
+/** Create DDF match ids from USB device descriptor.
+ *
+ * @param matches List of match ids to extend.
+ * @param device_descriptor Device descriptor returned by given device.
+ * @return Error code.
+ */
+int usb_device_create_match_ids_from_device_descriptor(
+    const usb_standard_device_descriptor_t *device_descriptor,
+    match_id_list_t *matches)
+{
+	/*
+	 * Unless the vendor id is 0, the pair idVendor-idProduct
+	 * quite uniquely describes the device.
+	 */
+	if (device_descriptor->vendor_id != 0) {
+		/* First, with release number. */
+		ADD_MATCHID_OR_RETURN(matches, 100,
+		    "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
+		    (int) device_descriptor->vendor_id,
+		    (int) device_descriptor->product_id,
+		    BCD_ARGS(device_descriptor->device_version));
+		
+		/* Next, without release number. */
+		ADD_MATCHID_OR_RETURN(matches, 90,
+		    "usb&vendor=0x%04x&product=0x%04x",
+		    (int) device_descriptor->vendor_id,
+		    (int) device_descriptor->product_id);
+	}	
+
+	/*
+	 * If the device class points to interface we skip adding
+	 * class directly but we add a multi interface device.
+	 */
+	if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
+		ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
+		    usb_str_class(device_descriptor->device_class));
+	} else {
+		ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid");
+	}
+	
+	/* As a last resort, try fallback driver. */
+	ADD_MATCHID_OR_RETURN(matches, 10, "usb&fallback");
+
+	return EOK;
+}
+
+
+/** Create match ids describing attached device.
+ *
+ * @warning The list of match ids @p matches may change even when
+ * function exits with error.
+ *
+ * @param ctrl_pipe Control pipe to given device (session must be already
+ *	started).
+ * @param matches Initialized list of match ids.
+ * @return Error code.
+ */
+int usb_device_create_match_ids(usb_pipe_t *ctrl_pipe,
+    match_id_list_t *matches)
+{
+	int rc;
+	/*
+	 * Retrieve device descriptor and add matches from it.
+	 */
+	usb_standard_device_descriptor_t device_descriptor;
+
+	rc = usb_request_get_device_descriptor(ctrl_pipe, &device_descriptor);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_device_create_match_ids_from_device_descriptor(
+	    &device_descriptor, matches);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Probe for device kind and register it in devman.
+ *
+ * @param[in] address Address of the (unknown) attached device.
+ * @param[in] hc_handle Handle of the host controller.
+ * @param[in] parent Parent device.
+ * @param[out] child_handle Handle of the child device.
+ * @param[in] dev_ops Child device ops.
+ * @param[in] dev_data Arbitrary pointer to be stored in the child
+ *	as @c driver_data.
+ * @param[out] child_fun Storage where pointer to allocated child function
+ *	will be written.
+ * @return Error code.
+ */
+int usb_device_register_child_in_devman(usb_address_t address,
+    devman_handle_t hc_handle,
+    ddf_dev_t *parent, devman_handle_t *child_handle,
+    ddf_dev_ops_t *dev_ops, void *dev_data, ddf_fun_t **child_fun)
+{
+	size_t this_device_name_index;
+
+	fibril_mutex_lock(&device_name_index_mutex);
+	this_device_name_index = device_name_index;
+	device_name_index++;
+	fibril_mutex_unlock(&device_name_index_mutex);
+
+	ddf_fun_t *child = NULL;
+	char *child_name = NULL;
+	int rc;
+	usb_device_connection_t dev_connection;
+	usb_pipe_t ctrl_pipe;
+
+	rc = usb_device_connection_initialize(&dev_connection, hc_handle, address);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	rc = usb_pipe_initialize_default_control(&ctrl_pipe,
+	    &dev_connection);
+	if (rc != EOK) {
+		goto failure;
+	}
+	rc = usb_pipe_probe_default_control(&ctrl_pipe);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	/*
+	 * TODO: Once the device driver framework support persistent
+	 * naming etc., something more descriptive could be created.
+	 */
+	rc = asprintf(&child_name, "usb%02zu_a%d",
+	    this_device_name_index, address);
+	if (rc < 0) {
+		goto failure;
+	}
+
+	child = ddf_fun_create(parent, fun_inner, child_name);
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	if (dev_ops != NULL) {
+		child->ops = dev_ops;
+	} else {
+		child->ops = &child_ops;
+	}
+
+	child->driver_data = dev_data;
+
+	rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	rc = ddf_fun_bind(child);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	if (child_handle != NULL) {
+		*child_handle = child->handle;
+	}
+
+	if (child_fun != NULL) {
+		*child_fun = child;
+	}
+
+	return EOK;
+
+failure:
+	if (child != NULL) {
+		child->name = NULL;
+		/* This takes care of match_id deallocation as well. */
+		ddf_fun_destroy(child);
+	}
+	if (child_name != NULL) {
+		free(child_name);
+	}
+
+	return rc;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/request.c
===================================================================
--- uspace/lib/usbdev/src/request.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbdev/src/request.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,930 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Standard USB requests (implementation).
+ */
+#include <usb/dev/request.h>
+#include <errno.h>
+#include <assert.h>
+#include <usb/debug.h>
+
+#define MAX_DATA_LENGTH ((size_t)(0xFFFF))
+
+/** Generic wrapper for SET requests using standard control request format.
+ *
+ * @see usb_pipe_control_write
+ *
+ * @param pipe Pipe used for the communication.
+ * @param request_type Request type (standard/class/vendor).
+ * @param recipient Request recipient (e.g. device or endpoint).
+ * @param request Actual request (e.g. GET_DESCRIPTOR).
+ * @param value Value of @c wValue field of setup packet
+ * 	(must be in USB endianness).
+ * @param index Value of @c wIndex field of setup packet
+ * 	(must be in USB endianness).
+ * @param data Data to be sent during DATA stage
+ * 	(expected to be in USB endianness).
+ * @param data_size Size of the @p data buffer (in native endianness).
+ * @return Error code.
+ * @retval EBADMEM @p pipe is NULL.
+ * @retval EBADMEM @p data is NULL and @p data_size is not zero.
+ * @retval ERANGE Data buffer too large.
+ */
+int usb_control_request_set(usb_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t request,
+    uint16_t value, uint16_t index,
+    void *data, size_t data_size)
+{
+	if (pipe == NULL) {
+		return EBADMEM;
+	}
+
+	if (data_size > MAX_DATA_LENGTH) {
+		return ERANGE;
+	}
+
+	if ((data_size > 0) && (data == NULL)) {
+		return EBADMEM;
+	}
+
+	/*
+	 * TODO: check that @p request_type and @p recipient are
+	 * within ranges.
+	 */
+
+	usb_device_request_setup_packet_t setup_packet;
+	setup_packet.request_type = (request_type << 5) | recipient;
+	setup_packet.request = request;
+	setup_packet.value = value;
+	setup_packet.index = index;
+	setup_packet.length = (uint16_t) data_size;
+
+	int rc = usb_pipe_control_write(pipe,
+	    &setup_packet, sizeof(setup_packet),
+	    data, data_size);
+
+	return rc;
+}
+
+ /** Generic wrapper for GET requests using standard control request format.
+  *
+  * @see usb_pipe_control_read
+  *
+  * @param pipe Pipe used for the communication.
+  * @param request_type Request type (standard/class/vendor).
+  * @param recipient Request recipient (e.g. device or endpoint).
+  * @param request Actual request (e.g. GET_DESCRIPTOR).
+  * @param value Value of @c wValue field of setup packet
+  * 	(must be in USB endianness).
+  * @param index Value of @c wIndex field of setup packet
+  *	(must be in USB endianness).
+  * @param data Buffer where to store data accepted during the DATA stage.
+  *	(they will come in USB endianness).
+  * @param data_size Size of the @p data buffer
+  * 	(in native endianness).
+  * @param actual_data_size Actual size of transfered data
+  * 	(in native endianness).
+  * @return Error code.
+  * @retval EBADMEM @p pipe is NULL.
+  * @retval EBADMEM @p data is NULL and @p data_size is not zero.
+  * @retval ERANGE Data buffer too large.
+  */
+int usb_control_request_get(usb_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t request,
+    uint16_t value, uint16_t index,
+    void *data, size_t data_size, size_t *actual_data_size)
+{
+	if (pipe == NULL) {
+		return EBADMEM;
+	}
+
+	if (data_size > MAX_DATA_LENGTH) {
+		return ERANGE;
+	}
+
+	if ((data_size > 0) && (data == NULL)) {
+		return EBADMEM;
+	}
+
+	/*
+	 * TODO: check that @p request_type and @p recipient are
+	 * within ranges.
+	 */
+
+	usb_device_request_setup_packet_t setup_packet;
+	setup_packet.request_type = 128 | (request_type << 5) | recipient;
+	setup_packet.request = request;
+	setup_packet.value = value;
+	setup_packet.index = index;
+	setup_packet.length = (uint16_t) data_size;
+
+	int rc = usb_pipe_control_read(pipe,
+	    &setup_packet, sizeof(setup_packet),
+	    data, data_size, actual_data_size);
+
+	return rc;
+}
+
+/** Retrieve status of a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Recipient index (in native endianness).
+ * @param[in] recipient Recipient of the GET_STATUS request.
+ * @param[out] status Recipient status (in native endianness).
+ * @return Error code.
+ */
+int usb_request_get_status(usb_pipe_t *pipe,
+    usb_request_recipient_t recipient, uint16_t index,
+    uint16_t *status)
+{
+	if ((recipient == USB_REQUEST_RECIPIENT_DEVICE) && (index != 0)) {
+		return EINVAL;
+	}
+
+	if (status == NULL) {
+		return EBADMEM;
+	}
+
+	uint16_t status_usb_endianess;
+	size_t data_transfered_size;
+	int rc = usb_control_request_get(pipe, USB_REQUEST_TYPE_STANDARD,
+	    recipient, USB_DEVREQ_GET_STATUS, 0, uint16_host2usb(index),
+	    &status_usb_endianess, 2, &data_transfered_size);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (data_transfered_size != 2) {
+		return ELIMIT;
+	}
+
+	*status = uint16_usb2host(status_usb_endianess);
+
+	return EOK;
+}
+
+/** Clear or disable specific device feature.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Recipient of the CLEAR_FEATURE request.
+ * @param[in] feature_selector Feature selector (in native endianness).
+ * @param[in] index Recipient index (in native endianness).
+ * @return Error code.
+ */
+int usb_request_clear_feature(usb_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint16_t feature_selector, uint16_t index)
+{
+	if (request_type == USB_REQUEST_TYPE_STANDARD) {
+		if ((recipient == USB_REQUEST_RECIPIENT_DEVICE)
+		    && (index != 0)) {
+			return EINVAL;
+		}
+	}
+
+	int rc = usb_control_request_set(pipe, request_type, recipient,
+	    USB_DEVREQ_CLEAR_FEATURE,
+	    uint16_host2usb(feature_selector), uint16_host2usb(index),
+	    NULL, 0);
+
+	return rc;
+}
+
+/** Set or enable specific device feature.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Recipient of the SET_FEATURE request.
+ * @param[in] feature_selector Feature selector (in native endianness).
+ * @param[in] index Recipient index (in native endianness).
+ * @return Error code.
+ */
+int usb_request_set_feature(usb_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint16_t feature_selector, uint16_t index)
+{
+	if (request_type == USB_REQUEST_TYPE_STANDARD) {
+		if ((recipient == USB_REQUEST_RECIPIENT_DEVICE)
+		    && (index != 0)) {
+			return EINVAL;
+		}
+	}
+
+	int rc = usb_control_request_set(pipe, request_type, recipient,
+	    USB_DEVREQ_SET_FEATURE,
+	    uint16_host2usb(feature_selector), uint16_host2usb(index),
+	    NULL, 0);
+
+	return rc;
+}
+
+/** Change address of connected device.
+ * This function automatically updates the backing connection to point to
+ * the new address.
+ *
+ * @param pipe Control endpoint pipe (session must be already started).
+ * @param new_address New USB address to be set (in native endianness).
+ * @return Error code.
+ */
+int usb_request_set_address(usb_pipe_t *pipe,
+    usb_address_t new_address)
+{
+	if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
+		return EINVAL;
+	}
+
+	uint16_t addr = uint16_host2usb((uint16_t)new_address);
+
+	int rc = usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_SET_ADDRESS,
+	    addr, 0,
+	    NULL, 0);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	assert(pipe->wire != NULL);
+	/* TODO: prevent other from accessing wire now. */
+	pipe->wire->address = new_address;
+
+	return EOK;
+}
+
+/** Retrieve USB descriptor of a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Request recipient (device/interface/endpoint).
+ * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
+ * @param[in] descriptor_index Descriptor index.
+ * @param[in] language Language index.
+ * @param[out] buffer Buffer where to store the retrieved descriptor.
+ * @param[in] size Size of the @p buffer.
+ * @param[out] actual_size Number of bytes actually transferred.
+ * @return Error code.
+ */
+int usb_request_get_descriptor(usb_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t descriptor_type, uint8_t descriptor_index,
+    uint16_t language,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	uint16_t wValue = descriptor_index | (descriptor_type << 8);
+
+	return usb_control_request_get(pipe,
+	    request_type, recipient,
+	    USB_DEVREQ_GET_DESCRIPTOR,
+	    wValue, language,
+	    buffer, size, actual_size);
+}
+
+/** Retrieve USB descriptor, allocate space for it.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Request recipient (device/interface/endpoint).
+ * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
+ * @param[in] descriptor_index Descriptor index.
+ * @param[in] language Language index.
+ * @param[out] buffer_ptr Where to store pointer to allocated buffer.
+ * @param[out] buffer_size Where to store the size of the descriptor.
+ * @return
+ */
+int usb_request_get_descriptor_alloc(usb_pipe_t * pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t descriptor_type, uint8_t descriptor_index,
+    uint16_t language,
+    void **buffer_ptr, size_t *buffer_size)
+{
+	if (buffer_ptr == NULL) {
+		return EBADMEM;
+	}
+
+	int rc;
+
+	/*
+	 * Get only first byte to retrieve descriptor length.
+	 */
+	uint8_t tmp_buffer[1];
+	size_t bytes_transfered;
+	rc = usb_request_get_descriptor(pipe, request_type, recipient,
+	    descriptor_type, descriptor_index, language,
+	    &tmp_buffer, 1, &bytes_transfered);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (bytes_transfered != 1) {
+		/* FIXME: some better error code? */
+		return ESTALL;
+	}
+
+	size_t size = tmp_buffer[0];
+	if (size == 0) {
+		/* FIXME: some better error code? */
+		return ESTALL;
+	}
+
+	/*
+	 * Allocate buffer and get the descriptor again.
+	 */
+	void *buffer = malloc(size);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+
+	rc = usb_request_get_descriptor(pipe, request_type, recipient,
+	    descriptor_type, descriptor_index, language,
+	    buffer, size, &bytes_transfered);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+	if (bytes_transfered != size) {
+		free(buffer);
+		/* FIXME: some better error code? */
+		return ESTALL;
+	}
+
+	*buffer_ptr = buffer;
+	if (buffer_size != NULL) {
+		*buffer_size = size;
+	}
+
+	return EOK;
+}
+
+/** Retrieve standard device descriptor of a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[out] descriptor Storage for the device descriptor.
+ * @return Error code.
+ */
+int usb_request_get_device_descriptor(usb_pipe_t *pipe,
+    usb_standard_device_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	size_t actually_transferred = 0;
+	usb_standard_device_descriptor_t descriptor_tmp;
+	int rc = usb_request_get_descriptor(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE, 
+	    USB_DESCTYPE_DEVICE, 0, 0,
+	    &descriptor_tmp, sizeof(descriptor_tmp),
+	    &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+/** Retrieve configuration descriptor of a USB device.
+ *
+ * The function does not retrieve additional data binded with configuration
+ * descriptor (such as its interface and endpoint descriptors) - use
+ * usb_request_get_full_configuration_descriptor() instead.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Descriptor index.
+ * @param[out] descriptor Storage for the device descriptor.
+ * @return Error code.
+ */
+int usb_request_get_bare_configuration_descriptor(usb_pipe_t *pipe,
+    int index, usb_standard_configuration_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	if ((index < 0) || (index > 0xFF)) {
+		return ERANGE;
+	}
+
+	size_t actually_transferred = 0;
+	usb_standard_configuration_descriptor_t descriptor_tmp;
+	int rc = usb_request_get_descriptor(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DESCTYPE_CONFIGURATION, index, 0,
+	    &descriptor_tmp, sizeof(descriptor_tmp),
+	    &actually_transferred);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+/** Retrieve full configuration descriptor of a USB device.
+ *
+ * @warning The @p buffer might be touched (i.e. its contents changed)
+ * even when error occurs.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Descriptor index.
+ * @param[out] descriptor Storage for the device descriptor.
+ * @param[in] descriptor_size Size of @p descriptor buffer.
+ * @param[out] actual_size Number of bytes actually transferred.
+ * @return Error code.
+ */
+int usb_request_get_full_configuration_descriptor(usb_pipe_t *pipe,
+    int index, void *descriptor, size_t descriptor_size, size_t *actual_size)
+{
+	if ((index < 0) || (index > 0xFF)) {
+		return ERANGE;
+	}
+
+	return usb_request_get_descriptor(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DESCTYPE_CONFIGURATION, index, 0,
+	    descriptor, descriptor_size, actual_size);
+}
+
+/** Retrieve full configuration descriptor, allocate space for it.
+ *
+ * The function takes care that full configuration descriptor is returned
+ * (i.e. the function will fail when less data then descriptor.totalLength
+ * is returned).
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Configuration index.
+ * @param[out] descriptor_ptr Where to store pointer to allocated buffer.
+ * @param[out] descriptor_size Where to store the size of the descriptor.
+ * @return Error code.
+ */
+int usb_request_get_full_configuration_descriptor_alloc(
+    usb_pipe_t *pipe, int index,
+    void **descriptor_ptr, size_t *descriptor_size)
+{
+	int rc;
+
+	if (descriptor_ptr == NULL) {
+		return EBADMEM;
+	}
+
+	usb_standard_configuration_descriptor_t bare_config;
+	rc = usb_request_get_bare_configuration_descriptor(pipe, index,
+	    &bare_config);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (bare_config.descriptor_type != USB_DESCTYPE_CONFIGURATION) {
+		return ENOENT;
+	}
+	if (bare_config.total_length < sizeof(bare_config)) {
+		return ELIMIT;
+	}
+
+	void *buffer = malloc(bare_config.total_length);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+
+	size_t transferred = 0;
+	rc = usb_request_get_full_configuration_descriptor(pipe, index,
+	    buffer, bare_config.total_length, &transferred);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+
+	if (transferred != bare_config.total_length) {
+		free(buffer);
+		return ELIMIT;
+	}
+
+	/* Everything looks okay, copy the pointers. */
+
+	*descriptor_ptr = buffer;
+
+	if (descriptor_size != NULL) {
+		*descriptor_size = bare_config.total_length;
+	}
+
+	return EOK;
+}
+
+/** Update existing or add new USB descriptor to a USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] recipient Request recipient (device/interface/endpoint).
+ * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
+ * @param[in] descriptor_index Descriptor index.
+ * @param[in] language Language index (in native endianness).
+ * @param[in] buffer Buffer with the new descriptor (in USB endianness).
+ * @param[in] size Size of the @p buffer in bytes (in native endianness).
+ * @return Error code.
+ */
+int usb_request_set_descriptor(usb_pipe_t *pipe,
+    usb_request_type_t request_type, usb_request_recipient_t recipient,
+    uint8_t descriptor_type, uint8_t descriptor_index,
+    uint16_t language,
+    void *buffer, size_t size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	/* FIXME: proper endianness. */
+	uint16_t wValue = descriptor_index | (descriptor_type << 8);
+
+	return usb_control_request_set(pipe,
+	    request_type, recipient,
+	    USB_DEVREQ_SET_DESCRIPTOR,
+	    wValue, language,
+	    buffer, size);
+}
+
+/** Get current configuration value of USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[out] configuration_value Current configuration value.
+ * @return Error code.
+ */
+int usb_request_get_configuration(usb_pipe_t *pipe,
+    uint8_t *configuration_value)
+{
+	uint8_t value;
+	size_t actual_size;
+
+	int rc = usb_control_request_get(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_GET_CONFIGURATION,
+	    0, 0,
+	    &value, 1, &actual_size);
+
+	if (rc != EOK) {
+		return rc;
+	}
+	if (actual_size != 1) {
+		return ELIMIT;
+	}
+
+	if (configuration_value != NULL) {
+		*configuration_value = value;
+	}
+
+	return EOK;
+}
+
+/** Set configuration of USB device.
+ *
+ * @param pipe Control endpoint pipe (session must be already started).
+ * @param configuration_value New configuration value.
+ * @return Error code.
+ */
+int usb_request_set_configuration(usb_pipe_t *pipe,
+    uint8_t configuration_value)
+{
+	uint16_t config_value
+	    = uint16_host2usb((uint16_t) configuration_value);
+
+	return usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_SET_CONFIGURATION, config_value, 0,
+	    NULL, 0);
+}
+
+/** Get selected alternate setting for USB interface.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] interface_index Interface index.
+ * @param[out] alternate_setting Alternate setting for the interface.
+ * @return Error code.
+ */
+int usb_request_get_interface(usb_pipe_t *pipe,
+    uint8_t interface_index, uint8_t *alternate_setting)
+{
+	uint8_t value;
+	size_t actual_size;
+
+	int rc = usb_control_request_get(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
+	    USB_DEVREQ_GET_INTERFACE,
+	    0, uint16_host2usb((uint16_t) interface_index),
+	    &value, 1, &actual_size);
+
+	if (rc != EOK) {
+		return rc;
+	}
+	if (actual_size != 1) {
+		return ELIMIT;
+	}
+
+	if (alternate_setting != NULL) {
+		*alternate_setting = value;
+	}
+
+	return EOK;
+}
+
+/** Select alternate setting for USB interface.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] interface_index Interface index.
+ * @param[in] alternate_setting Alternate setting to select.
+ * @return Error code.
+ */
+int usb_request_set_interface(usb_pipe_t *pipe,
+    uint8_t interface_index, uint8_t alternate_setting)
+{
+	return usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
+	    USB_DEVREQ_SET_INTERFACE,
+	    uint16_host2usb((uint16_t) alternate_setting),
+	    uint16_host2usb((uint16_t) interface_index),
+	    NULL, 0);
+}
+
+/** Get list of supported languages by USB device.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[out] languages_ptr Where to store pointer to allocated array of
+ *	supported languages.
+ * @param[out] languages_count Number of supported languages.
+ * @return Error code.
+ */
+int usb_request_get_supported_languages(usb_pipe_t *pipe,
+    l18_win_locales_t **languages_ptr, size_t *languages_count)
+{
+	int rc;
+
+	if (languages_ptr == NULL) {
+		return EBADMEM;
+	}
+	if (languages_count == NULL) {
+		return EBADMEM;
+	}
+
+	uint8_t *string_descriptor = NULL;
+	size_t string_descriptor_size = 0;
+	rc = usb_request_get_descriptor_alloc(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DESCTYPE_STRING, 0, 0,
+	    (void **) &string_descriptor, &string_descriptor_size);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (string_descriptor_size <= 2) {
+		free(string_descriptor);
+		return EEMPTY;
+	}
+	/* Subtract first 2 bytes (length and descriptor type). */
+	string_descriptor_size -= 2;
+
+	/* Odd number of bytes - descriptor is broken? */
+	if ((string_descriptor_size % 2) != 0) {
+		/* FIXME: shall we return with error or silently ignore? */
+		free(string_descriptor);
+		return ESTALL;
+	}
+
+	size_t langs_count = string_descriptor_size / 2;
+	l18_win_locales_t *langs
+	    = malloc(sizeof(l18_win_locales_t) * langs_count);
+	if (langs == NULL) {
+		free(string_descriptor);
+		return ENOMEM;
+	}
+
+	size_t i;
+	for (i = 0; i < langs_count; i++) {
+		/* Language code from the descriptor is in USB endianness. */
+		/* FIXME: is this really correct? */
+		uint16_t lang_code = (string_descriptor[2 + 2 * i + 1] << 8)
+		    + string_descriptor[2 + 2 * i];
+		langs[i] = uint16_usb2host(lang_code);
+	}
+
+	free(string_descriptor);
+
+	*languages_ptr = langs;
+	*languages_count =langs_count;
+
+	return EOK;
+}
+
+/** Get string (descriptor) from USB device.
+ *
+ * The string is returned in native encoding of the operating system.
+ * For HelenOS, that is UTF-8.
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index String index (in native endianness),
+ *	first index has number 1 (index from descriptors can be used directly).
+ * @param[in] lang String language (in native endianness).
+ * @param[out] string_ptr Where to store allocated string in native encoding.
+ * @return Error code.
+ */
+int usb_request_get_string(usb_pipe_t *pipe,
+    size_t index, l18_win_locales_t lang, char **string_ptr)
+{
+	if (string_ptr == NULL) {
+		return EBADMEM;
+	}
+	/*
+	 * Index is actually one byte value and zero index is used
+	 * to retrieve list of supported languages.
+	 */
+	if ((index < 1) || (index > 0xFF)) {
+		return ERANGE;
+	}
+	/* Language is actually two byte value. */
+	if (lang > 0xFFFF) {
+		return ERANGE;
+	}
+
+	int rc;
+
+	/* Prepare dynamically allocated variables. */
+	uint8_t *string = NULL;
+	wchar_t *string_chars = NULL;
+
+	/* Get the actual descriptor. */
+	size_t string_size;
+	rc = usb_request_get_descriptor_alloc(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DESCTYPE_STRING, index, uint16_host2usb(lang),
+	    (void **) &string, &string_size);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	if (string_size <= 2) {
+		rc =  EEMPTY;
+		goto leave;
+	}
+	/* Subtract first 2 bytes (length and descriptor type). */
+	string_size -= 2;
+
+	/* Odd number of bytes - descriptor is broken? */
+	if ((string_size % 2) != 0) {
+		/* FIXME: shall we return with error or silently ignore? */
+		rc = ESTALL;
+		goto leave;
+	}
+
+	size_t string_char_count = string_size / 2;
+	string_chars = malloc(sizeof(wchar_t) * (string_char_count + 1));
+	if (string_chars == NULL) {
+		rc = ENOMEM;
+		goto leave;
+	}
+
+	/*
+	 * Build a wide string.
+	 * And do not forget to set NULL terminator (string descriptors
+	 * do not have them).
+	 */
+	size_t i;
+	for (i = 0; i < string_char_count; i++) {
+		uint16_t uni_char = (string[2 + 2 * i + 1] << 8)
+		    + string[2 + 2 * i];
+		string_chars[i] = uni_char;
+	}
+	string_chars[string_char_count] = 0;
+
+
+	/* Convert to normal string. */
+	char *str = wstr_to_astr(string_chars);
+	if (str == NULL) {
+		rc = ENOMEM;
+		goto leave;
+	}
+
+	*string_ptr = str;
+	rc = EOK;
+
+leave:
+	if (string != NULL) {
+		free(string);
+	}
+	if (string_chars != NULL) {
+		free(string_chars);
+	}
+
+	return rc;
+}
+
+/** Clear halt bit of an endpoint pipe (after pipe stall).
+ *
+ * @param pipe Control pipe.
+ * @param ep_index Endpoint index (in native endianness).
+ * @return Error code.
+ */
+int usb_request_clear_endpoint_halt(usb_pipe_t *pipe, uint16_t ep_index)
+{
+	return usb_request_clear_feature(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_ENDPOINT,
+	    uint16_host2usb(USB_FEATURE_SELECTOR_ENDPOINT_HALT),
+	    uint16_host2usb(ep_index));
+}
+
+/** Clear halt bit of an endpoint pipe (after pipe stall).
+ *
+ * @param ctrl_pipe Control pipe.
+ * @param target_pipe Which pipe is halted and shall be cleared.
+ * @return Error code.
+ */
+int usb_pipe_clear_halt(usb_pipe_t *ctrl_pipe, usb_pipe_t *target_pipe)
+{
+	if ((ctrl_pipe == NULL) || (target_pipe == NULL)) {
+		return EINVAL;
+	}
+	return usb_request_clear_endpoint_halt(ctrl_pipe,
+	    target_pipe->endpoint_no);
+}
+
+/** Get endpoint status.
+ *
+ * @param[in] ctrl_pipe Control pipe.
+ * @param[in] pipe Of which pipe the status shall be received.
+ * @param[out] status Where to store pipe status (in native endianness).
+ * @return Error code.
+ */
+int usb_request_get_endpoint_status(usb_pipe_t *ctrl_pipe, usb_pipe_t *pipe,
+    uint16_t *status)
+{
+	uint16_t status_tmp;
+	uint16_t pipe_index = (uint16_t) pipe->endpoint_no;
+	int rc = usb_request_get_status(ctrl_pipe,
+	    USB_REQUEST_RECIPIENT_ENDPOINT, uint16_host2usb(pipe_index),
+	    &status_tmp);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (status != NULL) {
+		*status = uint16_usb2host(status_tmp);
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/Makefile
===================================================================
--- uspace/lib/usbhid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusbhid
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include \
+	-Iinclude
+
+SOURCES = \
+	src/hiddescriptor.c \
+	src/hidiface.c \
+	src/hidparser.c \
+	src/hidpath.c \
+	src/hidreport.c \
+	src/consumer.c \
+	src/hidreq.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbhid/include/usb/hid/hid.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hid.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2010 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 libusbhid
+ * @{
+ */
+/** @file
+ * @brief USB HID device related types.
+ */
+#ifndef LIBUSBHID_HID_H_
+#define LIBUSBHID_HID_H_
+
+#include <usb/usb.h>
+#include <usb/hid/hidparser.h>
+#include <usb/descriptor.h>
+
+/** USB/HID device requests. */
+typedef enum {
+	USB_HIDREQ_GET_REPORT = 1,
+	USB_HIDREQ_GET_IDLE = 2,
+	USB_HIDREQ_GET_PROTOCOL = 3,
+	/* Values 4 to 8 are reserved. */
+	USB_HIDREQ_SET_REPORT = 9,
+	USB_HIDREQ_SET_IDLE = 10,
+	USB_HIDREQ_SET_PROTOCOL = 11
+} usb_hid_request_t;
+
+typedef enum {
+	USB_HID_PROTOCOL_BOOT = 0,
+	USB_HID_PROTOCOL_REPORT = 1
+} usb_hid_protocol_t;
+
+/** USB/HID subclass constants. */
+typedef enum {
+	USB_HID_SUBCLASS_NONE = 0,
+	USB_HID_SUBCLASS_BOOT = 1
+} usb_hid_subclass_t;
+
+/** USB/HID interface protocols. */
+typedef enum {
+	USB_HID_PROTOCOL_NONE = 0,
+	USB_HID_PROTOCOL_KEYBOARD = 1,
+	USB_HID_PROTOCOL_MOUSE = 2
+} usb_hid_iface_protocol_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/hid_report_items.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hid_report_items.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hid_report_items.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * @brief USB HID Report descriptor item tags.
+ */
+#ifndef LIBUSB_HID_REPORT_ITEMS_H_
+#define LIBUSB_HID_REPORT_ITEMS_H_
+
+#include <stdint.h>
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Item prefix
+ */
+
+/** Returns size of item data in bytes */
+#define USB_HID_ITEM_SIZE(data) 	((uint8_t)(data & 0x3))
+
+/** Returns item tag */
+#define USB_HID_ITEM_TAG(data) 		((uint8_t)((data & 0xF0) >> 4))
+
+/** Returns class of item tag */
+#define USB_HID_ITEM_TAG_CLASS(data)	((uint8_t)((data & 0xC) >> 2))
+
+/** Returns if the item is the short item or long item. Long items are not
+ * supported. */
+#define USB_HID_ITEM_IS_LONG(data)	(data == 0xFE)
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Extended usage macros
+ */
+
+/** Recognizes if the given usage is extended (contains also usage page).  */
+#define USB_HID_IS_EXTENDED_USAGE(usage)	((usage & 0xFFFF0000) != 0)
+
+/** Cuts usage page of the extended usage. */
+#define USB_HID_EXTENDED_USAGE_PAGE(usage)	((usage & 0xFFFF0000) >> 16)
+
+/** Cuts usage of the extended usage */
+#define USB_HID_EXTENDED_USAGE(usage)		(usage & 0xFFFF)
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Input/Output/Feature Item flags
+ */
+/** 
+ * Indicates whether the item is data (0) or a constant (1) value. Data
+ * indicates the item is defining report fields that contain modifiable device
+ * data. Constant indicates the item is a static read-only field in a report
+ * and cannot be modified (written) by the host.
+ */
+#define USB_HID_ITEM_FLAG_CONSTANT(flags) 	((flags & 0x1) == 0x1)
+
+/**
+ * Indicates whether the item creates variable (1) or array (0) data fields in
+ * reports. 
+ */
+#define USB_HID_ITEM_FLAG_VARIABLE(flags) 	((flags & 0x2) == 0x2)
+
+/**
+ * Indicates whether the data is absolute (0) (based on a fixed origin) or
+ * relative (1) (indicating the change in value from the last report). Mouse
+ * devices usually provide relative data, while tablets usually provide
+ * absolute data.
+ */
+#define USB_HID_ITEM_FLAG_RELATIVE(flags) 	((flags & 0x4) == 0x4)
+
+/** Indicates whether the data “rolls over” when reaching either the extreme
+ * high or low value. For example, a dial that can spin freely 360 degrees
+ * might output values from 0 to 10. If Wrap is indicated, the next value
+ * reported after passing the 10 position in the increasing direction would be
+ * 0.
+ */
+#define USB_HID_ITEM_FLAG_WRAP(flags)		((flags & 0x8) == 0x8)
+
+/**
+ * Indicates whether the raw data from the device has been processed in some
+ * way, and no longer represents a linear relationship between what is
+ * measured and the data that is reported.
+ */
+#define USB_HID_ITEM_FLAG_LINEAR(flags)		((flags & 0x10) == 0x10)
+
+/**
+ * Indicates whether the control has a preferred state to which it will return
+ * when the user is not physically interacting with the control. Push buttons
+ * (as opposed to toggle buttons) and self- centering joysticks are examples.
+ */
+#define USB_HID_ITEM_FLAG_PREFERRED(flags)	((flags & 0x20) == 0x20)
+
+/**
+ * Indicates whether the control has a state in which it is not sending
+ * meaningful data. One possible use of the null state is for controls that
+ * require the user to physically interact with the control in order for it to
+ * report useful data.
+ */
+#define USB_HID_ITEM_FLAG_POSITION(flags)	((flags & 0x40) == 0x40)
+
+/**
+ * Indicates whether the Feature or Output control's value should be changed
+ * by the host or not.  Volatile output can change with or without host
+ * interaction. To avoid synchronization problems, volatile controls should be
+ * relative whenever possible.
+ */
+#define USB_HID_ITEM_FLAG_VOLATILE(flags)	((flags & 0x80) == 0x80)
+
+/**
+ * Indicates that the control emits a fixed-size stream of bytes. The contents
+ * of the data field are determined by the application. The contents of the
+ * buffer are not interpreted as a single numeric quantity. Report data
+ * defined by a Buffered Bytes item must be aligned on an 8-bit boundary.
+ */
+#define USB_HID_ITEM_FLAG_BUFFERED(flags)	((flags & 0x100) == 0x100)
+
+/*---------------------------------------------------------------------------*/
+
+/* MAIN ITEMS */
+
+/**
+ * Main items are used to either define or group certain types of data fields
+ * within a Report descriptor.
+ */
+#define USB_HID_TAG_CLASS_MAIN			0x0
+
+/**
+ * An Input item describes information about the data provided by one or more
+ * physical controls. An application can use this information to interpret the
+ * data provided by the device. All data fields defined in a single item share
+ * an identical data format.
+ */
+#define USB_HID_REPORT_TAG_INPUT		0x8
+
+/**
+ * The Output item is used to define an output data field in a report. This
+ * item is similar to an Input item except it describes data sent to the
+ * device—for example, LED states.
+ */
+#define USB_HID_REPORT_TAG_OUTPUT		0x9
+
+/**
+ * Feature items describe device configuration information that can be sent to
+ * the device.
+ */
+#define USB_HID_REPORT_TAG_FEATURE		0xB
+
+/**
+ * A Collection item identifies a relationship between two or more data
+ * (Input, Output, or Feature.) 
+ */
+#define USB_HID_REPORT_TAG_COLLECTION		0xA
+
+/**
+ * While the Collection item opens a collection of data, the End Collection
+ * item closes a collection.
+ */
+#define USB_HID_REPORT_TAG_END_COLLECTION	0xC
+
+/*---------------------------------------------------------------------------*/
+
+/* GLOBAL ITEMS */
+
+/**
+ * Global items describe rather than define data from a control.
+ */
+#define USB_HID_TAG_CLASS_GLOBAL		0x1
+
+/**
+ * Unsigned integer specifying the current Usage Page. Since a usage are 32
+ * bit values, Usage Page items can be used to conserve space in a report
+ * descriptor by setting the high order 16 bits of a subsequent usages. Any
+ * usage that follows which is defines 16 bits or less is interpreted as a
+ * Usage ID and concatenated with the Usage Page to form a 32 bit Usage.
+ */
+#define USB_HID_REPORT_TAG_USAGE_PAGE		0x0
+
+/** 
+ * Extent value in logical units. This is the minimum value that a variable
+ * or array item will report. For example, a mouse reporting x position values
+ * from 0 to 128 would have a Logical Minimum of 0 and a Logical Maximum of
+ * 128.
+ */
+#define USB_HID_REPORT_TAG_LOGICAL_MINIMUM	0x1
+
+/** 
+ * Extent value in logical units. This is the maximum value that a variable
+ * or array item will report.
+ */
+#define USB_HID_REPORT_TAG_LOGICAL_MAXIMUM	0x2
+
+/** 
+ * Minimum value for the physical extent of a variable item. This represents
+ * the Logical Minimum with units applied to it.
+ */
+#define USB_HID_REPORT_TAG_PHYSICAL_MINIMUM 	0x3
+
+/** 
+ * Maximum value for the physical extent of a variable item.
+ */
+#define USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM 	0x4
+
+/** 
+ * Value of the unit exponent in base 10. See the table later in this section
+ * for more information.
+ */
+#define USB_HID_REPORT_TAG_UNIT_EXPONENT	0x5
+
+/** 
+ * Unit values.
+ */
+#define USB_HID_REPORT_TAG_UNIT			0x6
+
+/** 
+ * Unsigned integer specifying the size of the report fields in bits. This
+ * allows the parser to build an item map for the report handler to use.
+ */
+#define USB_HID_REPORT_TAG_REPORT_SIZE		0x7
+
+/** 
+ * Unsigned value that specifies the Report ID. If a Report ID tag is used
+ * anywhere in Report descriptor, all data reports for the device are preceded
+ * by a single byte ID field. All items succeeding the first Report ID tag but
+ * preceding a second Report ID tag are included in a report prefixed by a
+ * 1-byte ID. All items succeeding the second but preceding a third Report ID
+ * tag are included in a second report prefixed by a second ID, and so on.
+ */
+#define USB_HID_REPORT_TAG_REPORT_ID		0x8
+
+/** 
+ * Unsigned integer specifying the number of data fields for the item;
+ * determines how many fields are included in the report for this particular
+ * item (and consequently how many bits are added to the report).
+ */
+#define USB_HID_REPORT_TAG_REPORT_COUNT		0x9
+
+/** 
+ * Places a copy of the global item state table on the stack.
+ */
+#define USB_HID_REPORT_TAG_PUSH			0xA
+
+/** 
+ * Replaces the item state table with the top structure from the stack.
+ */
+#define USB_HID_REPORT_TAG_POP			0xB
+
+/*---------------------------------------------------------------------------*/
+
+/* LOCAL ITEMS */
+
+/**
+ * Local item tags define characteristics of controls. These items do not
+ * carry over to the next Main item. If a Main item defines more than one
+ * control, it may be preceded by several similar Local item tags. For
+ * example, an Input item may have several Usage tags associated with it, one
+ * for each control.
+ */
+#define USB_HID_TAG_CLASS_LOCAL			0x2
+
+/**
+ * Usage index for an item usage; represents a suggested usage for the item or
+ * collection. In the case where an item represents multiple controls, a Usage
+ * tag may suggest a usage for every variable or element in an array.
+ */
+#define USB_HID_REPORT_TAG_USAGE		0x0
+
+/**
+ * Defines the starting usage associated with an array or bitmap.
+ */
+#define USB_HID_REPORT_TAG_USAGE_MINIMUM	0x1
+
+/**
+ * Defines the ending usage associated with an array or bitmap.
+ */
+#define USB_HID_REPORT_TAG_USAGE_MAXIMUM	0x2
+
+/**
+ * Determines the body part used for a control. Index points to a designator
+ * in the Physical descriptor.
+ */
+#define USB_HID_REPORT_TAG_DESIGNATOR_INDEX	0x3
+
+/**
+ * Defines the index of the starting designator associated with an array or
+ * bitmap.
+ */
+#define USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM	0x4
+
+/**
+ * Defines the index of the ending designator associated with an array or
+ * bitmap.
+ */
+#define USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM	0x5
+
+/**
+ * String index for a String descriptor; allows a string to be associated with
+ * a particular item or control.
+ */
+#define USB_HID_REPORT_TAG_STRING_INDEX		0x7
+
+/**
+ * Specifies the first string index when assigning a group of sequential
+ * strings to controls in an array or bitmap.
+ */
+#define USB_HID_REPORT_TAG_STRING_MINIMUM	0x8
+
+/**
+ * Specifies the last string index when assigning a group of sequential
+ * strings to controls in an array or bitmap.
+ */
+#define USB_HID_REPORT_TAG_STRING_MAXIMUM	0x9
+
+/**
+ * Defines the beginning or end of a set of local items (1 = open set, 0 =
+ * close set).
+ *
+ * Usages other than the first (most preferred) usage defined are not
+ * accessible by system software.
+ */
+#define USB_HID_REPORT_TAG_DELIMITER		0xA
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/hiddescriptor.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hiddescriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hiddescriptor.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * USB HID report descriptor and report data parser
+ */
+#ifndef LIBUSB_HIDDESCRIPTOR_H_
+#define LIBUSB_HIDDESCRIPTOR_H_
+
+#include <stdint.h>
+#include <adt/list.h>
+#include <usb/hid/hid_report_items.h>
+#include <usb/hid/hidpath.h>
+#include <usb/hid/hidtypes.h>
+
+int usb_hid_parse_report_descriptor(usb_hid_report_t *report, 
+		const uint8_t *data, size_t size);
+
+void usb_hid_free_report(usb_hid_report_t *report);
+
+void usb_hid_descriptor_print(usb_hid_report_t *report);
+
+int usb_hid_report_init(usb_hid_report_t *report);
+
+int usb_hid_report_append_fields(usb_hid_report_t *report,
+		usb_hid_report_item_t *report_item);
+
+usb_hid_report_description_t * usb_hid_report_find_description(
+		const usb_hid_report_t *report, uint8_t report_id,
+		usb_hid_report_type_t type);
+
+int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
+		size_t item_size, usb_hid_report_item_t *report_item,
+		usb_hid_report_path_t *usage_path);
+
+int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, 
+		size_t item_size, usb_hid_report_item_t *report_item,
+		usb_hid_report_path_t *usage_path);
+
+int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, 
+		size_t item_size, usb_hid_report_item_t *report_item,
+		usb_hid_report_path_t *usage_path);
+
+int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, 
+		size_t item_size, usb_hid_report_item_t *report_item,
+		usb_hid_report_path_t *usage_path);
+
+void usb_hid_descriptor_print_list(link_t *head);
+
+void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item);
+
+void usb_hid_free_report_list(link_t *head);
+
+usb_hid_report_item_t *usb_hid_report_item_clone(
+		const usb_hid_report_item_t *item);
+
+uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
+
+usb_hid_report_path_t *usb_hid_report_path_try_insert(usb_hid_report_t*report,
+		usb_hid_report_path_t *cmp_path);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/hidparser.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hidparser.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hidparser.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * USB HID report descriptor and report data parser
+ */
+#ifndef LIBUSBHID_HIDPARSER_H_
+#define LIBUSBHID_HIDPARSER_H_
+
+#include <stdint.h>
+#include <adt/list.h>
+#include <usb/hid/hid_report_items.h>
+#include <usb/hid/hidpath.h>
+#include <usb/hid/hidtypes.h>
+#include <usb/hid/hiddescriptor.h>
+
+
+/*
+ * Input report parser functions
+ */
+int usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data,
+		size_t size, uint8_t *report_id);
+
+/*
+ * Output report parser functions
+ */
+uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, 
+		uint8_t report_id);
+
+void usb_hid_report_output_free(uint8_t *output);
+
+size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id,
+		usb_hid_report_type_t type);
+
+size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id,
+		usb_hid_report_type_t type);
+
+
+int usb_hid_report_output_translate(usb_hid_report_t *report, 
+		uint8_t report_id, uint8_t *buffer, size_t size);
+
+
+/*
+ * Report descriptor structure observing functions
+ */
+usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report,
+		usb_hid_report_field_t *field, usb_hid_report_path_t *path,
+		int flags, usb_hid_report_type_t type);
+
+uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report, 
+		uint8_t report_id, usb_hid_report_type_t type);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/hidpath.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hidpath.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hidpath.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * USB HID report descriptor and report data parser
+ */
+#ifndef LIBUSB_HIDPATH_H_
+#define LIBUSB_HIDPATH_H_
+
+#include <usb/hid/hidparser.h>
+#include <stdint.h>
+#include <adt/list.h>
+
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Flags of usage paths comparison modes.
+ *
+ */
+/** Wanted usage path must be exactly the same as the searched one.  This
+ * option cannot be combined with the others. 
+ */
+#define USB_HID_PATH_COMPARE_STRICT		0
+
+/**
+ * Wanted usage path must be the suffix in the searched one.
+ */
+#define USB_HID_PATH_COMPARE_END		1
+
+/** 
+ * Only usage page are compared along the usage path.  This option can be
+ * combined with others. 
+ */
+#define USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY	2
+
+/** 
+ * Searched usage page must be prefix of the other one.
+ */
+#define USB_HID_PATH_COMPARE_BEGIN		4
+
+/** 
+ * Searched couple of usage page and usage can be anywhere in usage path.
+ * This option is deprecated.
+ */
+#define USB_HID_PATH_COMPARE_ANYWHERE		8
+
+/*----------------------------------------------------------------------------*/
+/** 
+ * Item of usage path structure. Last item of linked list describes one item
+ * in report, the others describe superior Collection tags. Usage and Usage
+ * page of report item can be changed due to data in report. 
+ */
+typedef struct {
+	/** Usage page of report item. Zero when usage page can be changed. */
+	uint32_t usage_page;
+	/** Usage of report item. Zero when usage can be changed. */	
+	uint32_t usage;
+
+	/** Attribute of Collection tag in report descriptor*/
+	uint8_t flags;
+
+	/** Linked list structure*/
+	link_t link;
+} usb_hid_report_usage_path_t;
+
+
+/*---------------------------------------------------------------------------*/
+/** 
+ * USB HID usage path structure.
+ * */
+typedef struct {
+	/** Length of usage path */	
+	int depth;	
+
+	/** Report id. Zero is reserved and means that report id is not used.
+	 * */
+	uint8_t report_id;
+	
+	/** Linked list structure. */	
+	link_t link; /* list */
+
+	/** Head of the list of usage path items. */
+	link_t head;
+
+} usb_hid_report_path_t;
+
+/*---------------------------------------------------------------------------*/
+usb_hid_report_path_t *usb_hid_report_path(void);
+
+void usb_hid_report_path_free(usb_hid_report_path_t *path);
+
+int usb_hid_report_path_set_report_id(usb_hid_report_path_t *usage_path,
+		uint8_t report_id);
+
+int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path, 
+		int32_t usage_page, int32_t usage);
+
+void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path);
+
+void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path);
+
+void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, 
+		int32_t tag, int32_t data);
+
+int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path,
+		usb_hid_report_path_t *path, int flags);
+
+usb_hid_report_path_t *usb_hid_report_path_clone(
+		usb_hid_report_path_t *usage_path);
+
+void usb_hid_print_usage_path(usb_hid_report_path_t *path);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/hidreport.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hidreport.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hidreport.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,67 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * USB HID report parser initialization from descriptors.
+ */
+
+#ifndef LIBUSBHID_HIDREPORT_H_
+#define LIBUSBHID_HIDREPORT_H_
+
+#include <usb/dev/driver.h>
+#include <usb/hid/hidparser.h>
+
+/**
+ * Retrieves the Report descriptor from the USB device and initializes the
+ * report parser.
+ *
+ * \param[in] dev USB device representing a HID device.
+ * \param[in/out] parser HID Report parser.
+ * \param[out] report_desc Place to save report descriptor into.
+ * \param[out] report_size
+ *
+ * \retval EOK if successful.
+ * \retval EINVAL if one of the parameters is not given (is NULL).
+ * \retval ENOENT if there are some descriptors missing.
+ * \retval ENOMEM if an error with allocation occured.
+ * \retval EINVAL if the Report descriptor's size does not match the size 
+ *         from the interface descriptor.
+ * \return Other value inherited from function usb_pipe_start_session(),
+ *         usb_pipe_end_session() or usb_request_get_descriptor().
+ */
+int usb_hid_process_report_descriptor(usb_device_t *dev, 
+    usb_hid_report_t *report, uint8_t **report_desc, size_t *report_size);
+
+#endif /* LIBUSB_HIDREPORT_H_ */
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/hidtypes.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hidtypes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/hidtypes.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * Basic data structures for USB HID Report descriptor and report parser.
+ */
+#ifndef LIBUSB_HIDTYPES_H_
+#define LIBUSB_HIDTYPES_H_
+
+#include <stdint.h>
+#include <adt/list.h>
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Maximum amount of specified usages for one report item
+ */
+#define USB_HID_MAX_USAGES	0xffff
+
+/**
+ * Converts integer from unsigned two's complement format format to signed
+ * one.
+ *
+ * @param x Number to convert
+ * @param size Length of the unsigned number in bites
+ * @return signed int
+ */
+#define USB_HID_UINT32_TO_INT32(x, size)	\
+	((((x) & (1 << ((size) - 1))) != 0) ?   \
+	 -(~((x) - 1) & ((1 << size) - 1)) : (x))
+
+/**
+ * Convert integer from signed format to unsigned. If number is negative the
+ * two's complement format is used.
+ *
+ * @param x Number to convert
+ * @param size Length of result number in bites
+ * @return unsigned int
+ */
+#define USB_HID_INT32_TO_UINT32(x, size)	\
+	(((x) < 0 ) ? ((1 << (size)) + (x)) : (x))
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Enum of report types
+ */
+typedef enum {
+	/** Input report. Data are sent from device to system */
+	USB_HID_REPORT_TYPE_INPUT = 1,
+
+	/** Output report. Data are sent from system to device */
+	USB_HID_REPORT_TYPE_OUTPUT = 2,
+
+	/** Feature report. Describes device configuration information that
+	 * can be sent to the device */
+	USB_HID_REPORT_TYPE_FEATURE = 3
+} usb_hid_report_type_t;
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Description of all reports described in one report descriptor.
+ */
+typedef struct {
+	/** Count of available reports. */
+	int report_count;
+
+	/** Head of linked list of description of reports. */
+	link_t reports;
+
+	/** Head of linked list of all used usage/collection paths. */
+	link_t collection_paths;
+
+	/** Length of list of usage paths. */
+	int collection_paths_count;
+
+	/** Flag whether report ids are used. */
+	int use_report_ids;
+
+	/** Report id of last parsed report. */
+	uint8_t last_report_id;
+	
+} usb_hid_report_t;
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Description of one concrete report
+ */
+typedef struct {
+	/** Report id. Zero when no report id is used. */
+	uint8_t report_id;
+
+	/** Type of report */
+	usb_hid_report_type_t type;
+
+	/** Bit length of the report */
+	size_t bit_length;
+
+	/** Number of items in report */
+	size_t item_length;
+	
+	/** Linked list of report items in report */
+	link_t report_items;
+
+	/** Linked list of descriptions. */
+	link_t link;
+} usb_hid_report_description_t;
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Description of one field/item in report 
+ */
+typedef struct {
+	/** Bit offset of the field */
+	int offset;
+
+	/** Bit size of the field */
+	size_t size;
+
+	/** Usage page. Zero when usage page can be changed. */
+	uint16_t usage_page;
+
+	/** Usage. Zero when usage can be changed. */
+	uint16_t usage;
+
+	/** Item's attributes */
+	uint8_t item_flags;
+
+	/** Usage/Collection path of the field. */
+	usb_hid_report_path_t *collection_path;
+
+	/** 
+	 * The lowest valid logical value (value with the device operates)
+	 */
+	int32_t logical_minimum;
+
+	/**
+	 * The greatest valid logical value
+	 */
+	int32_t logical_maximum;
+
+	/**
+	 * The lowest valid physical value (value with the system operates)
+	 */
+	int32_t physical_minimum;
+
+	/** The greatest valid physical value */
+	int32_t physical_maximum;
+
+	/** The lowest valid usage index */
+	int32_t usage_minimum;
+
+	/** The greatest valid usage index */
+	int32_t usage_maximum;
+	
+	/** Unit of the value */
+	uint32_t unit;
+
+	/** Unit exponent */
+	uint32_t unit_exponent;
+
+	/** Array of possible usages */
+	uint32_t *usages;
+
+	/** Size of the array of usages */
+	size_t usages_count;
+
+	/** Parsed value */
+	int32_t value;
+
+	/** List to another report items */
+	link_t link;
+} usb_hid_report_field_t;
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ * State table for report descriptor parsing
+ */
+typedef struct {
+	/** report id */	
+	int32_t id;
+	
+	/** Extended usage page */
+	uint16_t extended_usage_page;
+
+	/** Array of usages specified for this item */
+	uint32_t usages[USB_HID_MAX_USAGES];
+	
+	/** Length of usages array */
+	int usages_count;
+
+	/** Usage page*/
+	uint32_t usage_page;
+
+	/** Minimum valid usage index */	
+	int32_t usage_minimum;
+	
+	/** Maximum valid usage index */	
+	int32_t usage_maximum;
+	
+	/** Minimum valid logical value */	
+	int32_t logical_minimum;
+	
+	/** Maximum valid logical value */	
+	int32_t logical_maximum;
+
+	/** Length of the items in bits*/	
+	int32_t size;
+
+	/** COunt of items*/	
+	int32_t count;
+
+	/**  Bit offset of the item in report */	
+	size_t offset;
+
+	/** Unit exponent */	
+	int32_t unit_exponent;
+	/** Unit of the value */	
+	int32_t unit;
+
+	/** String index */
+	uint32_t string_index;
+
+	/** Minimum valid string index */	
+	uint32_t string_minimum;
+
+	/** Maximum valid string index */	
+	uint32_t string_maximum;
+
+	/** The designator index */	
+	uint32_t designator_index;
+
+	/** Minimum valid designator value*/	
+	uint32_t designator_minimum;
+
+	/** Maximum valid designator value*/	
+	uint32_t designator_maximum;
+
+	/** Minimal valid physical value*/	
+	int32_t physical_minimum;
+
+	/** Maximal valid physical value */	
+	int32_t physical_maximum;
+
+	/** Items attributes*/	
+	uint8_t item_flags;
+
+	/** Report type */
+	usb_hid_report_type_t type;
+
+	/** current collection path*/	
+	usb_hid_report_path_t *usage_path;
+
+	/** Unused*/	
+	link_t link;
+
+	int in_delimiter;
+} usb_hid_report_item_t;
+/*---------------------------------------------------------------------------*/
+/**
+ * Enum of the keyboard modifiers 
+ */
+typedef enum {
+	USB_HID_MOD_LCTRL = 0x01,
+	USB_HID_MOD_LSHIFT = 0x02,
+	USB_HID_MOD_LALT = 0x04,
+	USB_HID_MOD_LGUI = 0x08,
+	USB_HID_MOD_RCTRL = 0x10,
+	USB_HID_MOD_RSHIFT = 0x20,
+	USB_HID_MOD_RALT = 0x40,
+	USB_HID_MOD_RGUI = 0x80,
+	USB_HID_MOD_COUNT = 8
+} usb_hid_modifiers_t;
+
+static const usb_hid_modifiers_t 
+    usb_hid_modifiers_consts[USB_HID_MOD_COUNT] = {
+	USB_HID_MOD_LCTRL,
+	USB_HID_MOD_LSHIFT,
+	USB_HID_MOD_LALT,
+	USB_HID_MOD_LGUI,
+	USB_HID_MOD_RCTRL,
+	USB_HID_MOD_RSHIFT,
+	USB_HID_MOD_RALT,
+	USB_HID_MOD_RGUI
+};
+/*---------------------------------------------------------------------------*/
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/iface.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/iface.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,51 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * Client functions for accessing USB HID interface.
+ */
+#ifndef LIBUSBHID_CLASSES_HID_IFACE_H_
+#define LIBUSBHID_CLASSES_HID_IFACE_H_
+
+#include <sys/types.h>
+#include <async.h>
+
+extern int usbhid_dev_get_event_length(async_sess_t *, size_t *);
+extern int usbhid_dev_get_event(async_sess_t *, uint8_t *, size_t, size_t *,
+    int *, unsigned int);
+extern int usbhid_dev_get_report_descriptor_length(async_sess_t *, size_t *);
+extern int usbhid_dev_get_report_descriptor(async_sess_t *, uint8_t *, size_t,
+    size_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/request.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/request.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/request.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,69 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * HID class-specific requests.
+ */
+
+#ifndef USB_KBD_HIDREQ_H_
+#define USB_KBD_HIDREQ_H_
+
+#include <stdint.h>
+
+#include <usb/hid/hid.h>
+#include <usb/dev/pipes.h>
+
+/*----------------------------------------------------------------------------*/
+
+int usbhid_req_set_report(usb_pipe_t *ctrl_pipe, int iface_no,
+    usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size);
+
+int usbhid_req_set_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 
+    usb_hid_protocol_t protocol);
+
+int usbhid_req_set_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t duration);
+
+int usbhid_req_get_report(usb_pipe_t *ctrl_pipe, int iface_no, 
+    usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size, 
+    size_t *actual_size);
+
+int usbhid_req_get_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 
+    usb_hid_protocol_t *protocol);
+
+int usbhid_req_get_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t *duration);
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* USB_KBD_HIDREQ_H_ */
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/usages/consumer.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/usages/consumer.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/usages/consumer.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,45 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * USB multimedia key usage to string mapping.
+ */
+
+#ifndef LIBUSBHID_CONSUMER_H_
+#define LIBUSBHID_CONSUMER_H_
+
+const char *usbhid_multimedia_usage_to_str(int usage);
+
+#endif /* LIBUSBHID_CONSUMER_H_ */
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/usages/core.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/usages/core.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/usages/core.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 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 libusbhid
+ * @{
+ */
+/** @file
+ * @brief USB HID Usage Tables.
+ */
+#ifndef LIBUSBHID_HIDUT_H_
+#define LIBUSBHID_HIDUT_H_
+
+/** USB/HID Usage Pages. */
+typedef enum {
+	USB_HIDUT_PAGE_GENERIC_DESKTOP = 1,
+	USB_HIDUT_PAGE_SIMULATION = 2,
+	USB_HIDUT_PAGE_VR = 3,
+	USB_HIDUT_PAGE_SPORT = 4,
+	USB_HIDUT_PAGE_GAME = 5,
+	USB_HIDUT_PAGE_GENERIC_DEVICE = 6,
+	USB_HIDUT_PAGE_KEYBOARD = 7,
+	USB_HIDUT_PAGE_LED = 8,
+	USB_HIDUT_PAGE_BUTTON = 9,
+	USB_HIDUT_PAGE_ORDINAL = 0x0a,
+	USB_HIDUT_PAGE_TELEPHONY_DEVICE = 0x0b,
+	USB_HIDUT_PAGE_CONSUMER = 0x0c
+} usb_hidut_usage_page_t;
+
+/** Usages for Generic Desktop Page. */
+typedef enum {
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_POINTER = 1,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE = 2,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_JOYSTICK = 4,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_GAMEPAD = 5,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD = 6,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYPAD = 7,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_X = 0x30,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_Y = 0x31,
+	USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL = 0x38
+	/* USB_HIDUT_USAGE_GENERIC_DESKTOP_ = , */
+	
+} usb_hidut_usage_generic_desktop_t;
+
+typedef enum {
+	USB_HIDUT_USAGE_CONSUMER_CONSUMER_CONTROL = 1
+} usb_hidut_usage_consumer_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/include/usb/hid/usages/kbdgen.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/usages/kbdgen.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/usages/kbdgen.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2010 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 libusbhid
+ * @{
+ */
+/** @file
+ * @brief USB HID key codes.
+ * @details
+ * This is not a typical header as by default it is equal to empty file.
+ * However, by cleverly defining the USB_HIDUT_KBD_KEY you can use it
+ * to generate conversion tables etc.
+ *
+ * For example, this creates enum for known keys:
+ * @code
+#define USB_HIDUT_KBD_KEY(name, usage_id, l, lc, l1, l2) \
+	USB_KBD_KEY_##name = usage_id,
+typedef enum {
+	#include <usb/hidutkbd.h>
+} usb_key_code_t;
+ @endcode
+ *
+ * Maybe, it might be better that you would place such enums into separate
+ * files and create them as separate step before compiling to allow tools
+ * such as Doxygen get the definitions right.
+ *
+ * @warning This file does not include guard to prevent multiple inclusions
+ * into a single file.
+ */
+
+
+#ifndef USB_HIDUT_KBD_KEY
+/** Declare keyboard key.
+ * @param name Key name (identifier).
+ * @param usage_id Key code (see Keyboard/Keypad Page (0x07) in HUT1.12.
+ * @param letter Corresponding character (0 if not applicable).
+ * @param letter_caps Corresponding character with Caps on.
+ * @param letter_mod1 Corresponding character with modifier #1 on.
+ * @param letter_mod2 Corresponding character with modifier #2 on.
+ */
+#define USB_HIDUT_KBD_KEY(name, usage_id, letter, letter_caps, letter_mod1, letter_mod2)
+
+#endif
+
+#define __NONPRINT(name, usage_id) \
+	USB_HIDUT_KBD_KEY(name, usage_id, 0, 0, 0, 0)
+
+/* US alphabet letters */
+USB_HIDUT_KBD_KEY(A, 0x04, 'a', 'A', 0, 0)
+USB_HIDUT_KBD_KEY(B, 0x05, 'b', 'B', 0, 0)
+USB_HIDUT_KBD_KEY(C, 0x06, 'c', 'C', 0, 0)
+USB_HIDUT_KBD_KEY(D, 0x07, 'd', 'D', 0, 0)
+USB_HIDUT_KBD_KEY(E, 0x08, 'e', 'E', 0, 0)
+USB_HIDUT_KBD_KEY(F, 0x09, 'f', 'F', 0, 0)
+USB_HIDUT_KBD_KEY(G, 0x0A, 'g', 'G', 0, 0)
+USB_HIDUT_KBD_KEY(H, 0x0B, 'h', 'H', 0, 0)
+USB_HIDUT_KBD_KEY(I, 0x0C, 'i', 'I', 0, 0)
+USB_HIDUT_KBD_KEY(J, 0x0D, 'j', 'J', 0, 0)
+USB_HIDUT_KBD_KEY(K, 0x0E, 'k', 'K', 0, 0)
+USB_HIDUT_KBD_KEY(L, 0x0F, 'l', 'L', 0, 0)
+USB_HIDUT_KBD_KEY(M, 0x10, 'm', 'M', 0, 0)
+USB_HIDUT_KBD_KEY(N, 0x11, 'n', 'N', 0, 0)
+USB_HIDUT_KBD_KEY(O, 0x12, 'o', 'O', 0, 0)
+USB_HIDUT_KBD_KEY(P, 0x13, 'p', 'P', 0, 0)
+USB_HIDUT_KBD_KEY(Q, 0x14, 'q', 'Q', 0, 0)
+USB_HIDUT_KBD_KEY(R, 0x15, 'r', 'R', 0, 0)
+USB_HIDUT_KBD_KEY(S, 0x16, 's', 'S', 0, 0)
+USB_HIDUT_KBD_KEY(T, 0x17, 't', 'T', 0, 0)
+USB_HIDUT_KBD_KEY(U, 0x18, 'u', 'U', 0, 0)
+USB_HIDUT_KBD_KEY(V, 0x19, 'v', 'V', 0, 0)
+USB_HIDUT_KBD_KEY(W, 0x1A, 'w', 'W', 0, 0)
+USB_HIDUT_KBD_KEY(X, 0x1B, 'x', 'X', 0, 0)
+USB_HIDUT_KBD_KEY(Y, 0x1C, 'y', 'Y', 0, 0)
+USB_HIDUT_KBD_KEY(Z, 0x1D, 'z', 'Z', 0, 0)
+
+/* Keyboard digits */
+USB_HIDUT_KBD_KEY(1, 0x1E, '1', '!', 0, 0)
+USB_HIDUT_KBD_KEY(2, 0x1F, '2', '@', 0, 0)
+USB_HIDUT_KBD_KEY(3, 0x20, '3', '#', 0, 0)
+USB_HIDUT_KBD_KEY(4, 0x21, '4', '$', 0, 0)
+USB_HIDUT_KBD_KEY(5, 0x22, '5', '%', 0, 0)
+USB_HIDUT_KBD_KEY(6, 0x23, '6', '^', 0, 0)
+USB_HIDUT_KBD_KEY(7, 0x24, '7', '&', 0, 0)
+USB_HIDUT_KBD_KEY(8, 0x25, '8', '*', 0, 0)
+USB_HIDUT_KBD_KEY(9, 0x26, '9', '(', 0, 0)
+USB_HIDUT_KBD_KEY(0, 0x27, '0', ')', 0, 0)
+
+/* More-or-less typewriter command keys */
+USB_HIDUT_KBD_KEY(ENTER, 0x28, '\n', 0, 0, 0)
+USB_HIDUT_KBD_KEY(ESCAPE, 0x29, 0, 0, 0, 0)
+USB_HIDUT_KBD_KEY(BACKSPACE, 0x2A, '\b', 0, 0, 0)
+USB_HIDUT_KBD_KEY(TAB, 0x2B, '\t', 0, 0, 0)
+USB_HIDUT_KBD_KEY(SPACE, 0x2C, ' ', 0, 0, 0)
+
+/* Special (printable) characters */
+USB_HIDUT_KBD_KEY(DASH, 0x2D, '-', '_', 0, 0)
+USB_HIDUT_KBD_KEY(EQUALS, 0x2E, '=', '+', 0, 0)
+USB_HIDUT_KBD_KEY(LEFT_BRACKET, 0x2F, '[', '{', 0, 0)
+USB_HIDUT_KBD_KEY(RIGHT_BRACKET, 0x30, ']', '}', 0, 0)
+USB_HIDUT_KBD_KEY(BACKSLASH, 0x31, '\\', '|', 0, 0)
+USB_HIDUT_KBD_KEY(HASH, 0x32, '#', '~', 0, 0)
+USB_HIDUT_KBD_KEY(SEMICOLON, 0x33, ';', ':', 0, 0)
+USB_HIDUT_KBD_KEY(APOSTROPHE, 0x34, '\'', '"', 0, 0)
+USB_HIDUT_KBD_KEY(GRAVE_ACCENT, 0x35, '`', '~', 0, 0)
+USB_HIDUT_KBD_KEY(COMMA, 0x36, ',', '<', 0, 0)
+USB_HIDUT_KBD_KEY(PERIOD, 0x37, '.', '>', 0, 0)
+USB_HIDUT_KBD_KEY(SLASH, 0x38, '/', '?', 0, 0)
+
+USB_HIDUT_KBD_KEY(CAPS_LOCK, 0x39, 0, 0, 0, 0)
+
+/* Function keys */
+__NONPRINT( F1, 0x3A)
+__NONPRINT( F2, 0x3B)
+__NONPRINT( F3, 0x3C)
+__NONPRINT( F4, 0x3D)
+__NONPRINT( F5, 0x3E)
+__NONPRINT( F6, 0x3F)
+__NONPRINT( F7, 0x40)
+__NONPRINT( F8, 0x41)
+__NONPRINT( F9, 0x42)
+__NONPRINT(F10, 0x43)
+__NONPRINT(F11, 0x44)
+__NONPRINT(F12, 0x45)
+
+/* Cursor movement keys & co. */
+__NONPRINT(PRINT_SCREEN, 0x46)
+__NONPRINT(SCROLL_LOCK, 0x47)
+__NONPRINT(PAUSE, 0x48)
+__NONPRINT(INSERT, 0x49)
+__NONPRINT(HOME, 0x4A)
+__NONPRINT(PAGE_UP, 0x4B)
+__NONPRINT(DELETE, 0x4C)
+__NONPRINT(END, 0x4D)
+__NONPRINT(PAGE_DOWN, 0x4E)
+__NONPRINT(RIGHT_ARROW, 0x4F)
+__NONPRINT(LEFT_ARROW, 0x50)
+__NONPRINT(DOWN_ARROW, 0x51)
+__NONPRINT(UP_ARROW, 0x52)
+
+
+
+
+/* USB_HIDUT_KBD_KEY(, 0x, '', '', 0, 0) */
+
+#undef __NONPRINT
+
+/**
+ * @}
+ */
+
Index: uspace/lib/usbhid/include/usb/hid/usages/led.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/usages/led.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/include/usb/hid/usages/led.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010 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 libusbhid
+ * @{
+ */
+/** @file
+ * @brief USB HID Usage Tables - LED page.
+ */
+#ifndef LIBUSBHID_UTLED_H_
+#define LIBUSBHID_UTLED_H_
+
+typedef enum {
+	USB_HID_LED_UNDEFINED = 0,
+	USB_HID_LED_NUM_LOCK,
+	USB_HID_LED_CAPS_LOCK,
+	USB_HID_LED_SCROLL_LOCK,
+	USB_HID_LED_COMPOSE,
+	USB_HID_LED_KANA,
+	USB_HID_LED_POWER,
+	USB_HID_LED_SHIFT,
+	USB_HID_LED_DND,
+	USB_HID_LED_MUTE,
+	USB_HID_LED_TONE_ENABLE,
+	USB_HID_LED_HIGH_CUT_FILTER,
+	USB_HID_LED_LOW_CUT_FILTER,
+	USB_HID_LED_EQ_ENABLE,
+	USB_HID_LED_SOUND_FIELD_ON,
+	USB_HID_LED_SURROUND_ON,
+	USB_HID_LED_REPEAT,
+	USB_HID_LED_STEREO,
+	USB_HID_LED_SAMPLING_RATE_DETECT,
+	USB_HID_LED_SPINNING,
+	USB_HID_LED_CAV,
+	USB_HID_LED_CLV,
+	USB_HID_LED_RECORDING_FORMAT_DETECT,
+	USB_HID_LED_OFF_HOOK,
+	USB_HID_LED_RING,
+	USB_HID_LED_MESSAGE_WAITING,
+	USB_HID_LED_DATA_MODE,
+	USB_HID_LED_BATTERY_OPERATION,
+	USB_HID_LED_BATTERY_OK,
+	USB_HID_LED_BATTERY_LOW,
+	USB_HID_LED_SPEAKER,
+	USB_HID_LED_HEAD_SET,
+	USB_HID_LED_HOLD,
+	USB_HID_LED_MICRO,
+	USB_HID_LED_COVERAGE,
+	USB_HID_LED_NIGHT_MODE,
+	USB_HID_LED_SEND_CALLS,
+	USB_HID_LED_CALL_PICKUP,
+	USB_HID_LED_CONFERENCE,
+	USB_HID_LED_STAND_BY,
+	USB_HID_LED_CAMERA_ON,
+	USB_HID_LED_CAMERA_OFF,
+	USB_HID_LED_ON_LINE,
+	USB_HID_LED_OFF_LINE,
+	USB_HID_LED_BUSY,
+	USB_HID_LED_READY,
+	USB_HID_LED_PAPER_OUT,
+	USB_HID_LED_PAPER_JAM,
+	USB_HID_LED_REMOTE,
+	USB_HID_LED_FORWARD,
+	USB_HID_LED_REVERSE,
+	USB_HID_LED_STOP,
+	USB_HID_LED_REWIND,
+	USB_HID_LED_FAST_FORWARD,
+	USB_HID_LED_PLAY,
+	USB_HID_LED_PAUSE,
+	USB_HID_LED_RECORD,
+	USB_HID_LED_ERROR,
+	USB_HID_LED_USAGE_SELECTED_IND,
+	USB_HID_LED_USAGE_IN_USE_IND,
+	USB_HID_LED_USAGE_MULTI_MODE_IND,
+	USB_HID_LED_IND_ON,
+	USB_HID_LED_IND_FLASH,
+	USB_HID_LED_IND_SLOW_BLINK,
+	USB_HID_LED_IND_FAST_BLINK,
+	USB_HID_LED_IND_OFF,
+	USB_HID_LED_FLASH_ON_TIME,
+	USB_HID_LED_SLOW_BLINK_ON_TIME,
+	USB_HID_LED_SLOW_BLINK_OFF_TIME,
+	USB_HID_LED_FAST_BLINK_ON_TIME,
+	USB_HID_LED_FAST_BLINK_OFF_TIME,
+	USB_HID_LED_USAGE_IND_COLOR,
+	USB_HID_LED_IND_RED,
+	USB_HID_LED_IND_GREEN,
+	USB_HID_LED_IND_AMBER,
+	USB_HID_LED_GENERIC_IND,
+	USB_HID_LED_SYSTEM_SUSPEND,
+	USB_HID_LED_EXTERNAL_POWER
+} usb_hid_usage_led_t;
+
+#endif /* LIBUSB_UTLED_H_ */
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/consumer.c
===================================================================
--- uspace/lib/usbhid/src/consumer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/consumer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,732 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * UUSB multimedia key usage, to string mapping.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/hid/usages/consumer.h>
+
+static const char *usbhid_consumer_usage_str[0x29d] = {
+	[0x01] = "Consumer Control",
+	[0x02] = "Numeric Key Pad",
+	[0x03] = "Programmable Buttons",
+	[0x04] = "Microphone",
+	[0x05] = "Headphone",
+	[0x06] = "Graphic Equalizer",
+	[0x07] = "Reserved",
+	[0x08] = "Reserved",
+	[0x09] = "Reserved",
+	[0x0a] = "Reserved",
+	[0x0b] = "Reserved",
+	[0x0c] = "Reserved",
+	[0x0d] = "Reserved",
+	[0x0e] = "Reserved",
+	[0x0f] = "Reserved",
+	[0x10] = "Reserved",
+	[0x11] = "Reserved",
+	[0x12] = "Reserved",
+	[0x13] = "Reserved",
+	[0x14] = "Reserved",
+	[0x15] = "Reserved",
+	[0x16] = "Reserved",
+	[0x17] = "Reserved",
+	[0x18] = "Reserved",
+	[0x19] = "Reserved",
+	[0x1a] = "Reserved",
+	[0x1b] = "Reserved",
+	[0x1c] = "Reserved",
+	[0x1d] = "Reserved",
+	[0x1e] = "Reserved",
+	[0x1f] = "Reserved",
+	[0x20] = "+10",
+	[0x21] = "+100",
+	[0x22] = "AM/PM",
+	[0x23] = "Reserved",
+	[0x24] = "Reserved",
+	[0x25] = "Reserved",
+	[0x26] = "Reserved",
+	[0x27] = "Reserved",
+	[0x28] = "Reserved",
+	[0x29] = "Reserved",
+	[0x2a] = "Reserved",
+	[0x2b] = "Reserved",
+	[0x2c] = "Reserved",
+	[0x2d] = "Reserved",
+	[0x2e] = "Reserved",
+	[0x2f] = "Reserved",
+	[0x30] = "Reserved",
+	[0x31] = "Reserved",
+	[0x32] = "Reserved",
+	[0x33] = "Reserved",
+	[0x34] = "Reserved",
+	[0x35] = "Reserved",
+	[0x36] = "Reserved",
+	[0x37] = "Reserved",
+	[0x38] = "Reserved",
+	[0x39] = "Reserved",
+	[0x3a] = "Reserved",
+	[0x3b] = "Reserved",
+	[0x3c] = "Reserved",
+	[0x3d] = "Reserved",
+	[0x3e] = "Reserved",
+	[0x3f] = "Reserved",
+	[0x40] = "Menu",
+	[0x41] = "Menu Pick",
+	[0x42] = "Menu Up",
+	[0x43] = "Menu Down",
+	[0x44] = "Menu Left",
+	[0x45] = "Menu Right",
+	[0x46] = "Menu Escape",
+	[0x47] = "Menu Value Increase",
+	[0x48] = "Menu Value Decrease",
+	[0x49] = "Reserved",
+	[0x4a] = "Reserved",
+	[0x4b] = "Reserved",
+	[0x4c] = "Reserved",
+	[0x4d] = "Reserved",
+	[0x4e] = "Reserved",
+	[0x4f] = "Reserved",
+	[0x50] = "Reserved",
+	[0x51] = "Reserved",
+	[0x52] = "Reserved",
+	[0x53] = "Reserved",
+	[0x54] = "Reserved",
+	[0x55] = "Reserved",
+	[0x56] = "Reserved",
+	[0x57] = "Reserved",
+	[0x58] = "Reserved",
+	[0x59] = "Reserved",
+	[0x5a] = "Reserved",
+	[0x5b] = "Reserved",
+	[0x5c] = "Reserved",
+	[0x5d] = "Reserved",
+	[0x5e] = "Reserved",
+	[0x5f] = "Reserved",
+	[0x60] = "Data On Screen",
+	[0x61] = "Closed Caption",
+	[0x62] = "Closed Caption Select",
+	[0x63] = "VCR/TV",
+	[0x64] = "Broadcast Mode",
+	[0x65] = "Snapshot",
+	[0x66] = "Still",
+	[0x67] = "Reserved",
+	[0x68] = "Reserved",
+	[0x69] = "Reserved",
+	[0x6a] = "Reserved",
+	[0x6b] = "Reserved",
+	[0x6c] = "Reserved",
+	[0x6d] = "Reserved",
+	[0x6e] = "Reserved",
+	[0x6f] = "Reserved",
+	[0x70] = "Reserved",
+	[0x71] = "Reserved",
+	[0x72] = "Reserved",
+	[0x73] = "Reserved",
+	[0x74] = "Reserved",
+	[0x75] = "Reserved",
+	[0x76] = "Reserved",
+	[0x77] = "Reserved",
+	[0x78] = "Reserved",
+	[0x79] = "Reserved",
+	[0x7a] = "Reserved",
+	[0x7b] = "Reserved",
+	[0x7c] = "Reserved",
+	[0x7d] = "Reserved",
+	[0x7e] = "Reserved",
+	[0x7f] = "Reserved",
+	[0x80] = "Selection",
+	[0x81] = "Assign Selection",
+	[0x82] = "Mode Step",
+	[0x83] = "Recall Last",
+	[0x84] = "Enter Channel",
+	[0x85] = "Order Movie",
+	[0x86] = "Channel",
+	[0x87] = "Media Selection",
+	[0x88] = "Media Select Computer",
+	[0x89] = "Media Select TV",
+	[0x8a] = "Media Select WWW",
+	[0x8b] = "Media Select DVD",
+	[0x8c] = "Media Select Telephone",
+	[0x8d] = "Media Select Program Guide",
+	[0x8e] = "Media Select Video Phone",
+	[0x8f] = "Media Select Games",
+	[0x90] = "Media Select Messages",
+	[0x91] = "Media Select CD",
+	[0x92] = "Media Select VCR",
+	[0x93] = "Media Select Tuner",
+	[0x94] = "Quit",
+	[0x95] = "Help",
+	[0x96] = "Media Select Tape",
+	[0x97] = "Media Select Cable",
+	[0x98] = "Media Select Satellite",
+	[0x99] = "Media Select Security",
+	[0x9a] = "Media Select Home",
+	[0x9b] = "Media Select Call",
+	[0x9c] = "Channel Increment",
+	[0x9d] = "Channel Decrement",
+	[0x9e] = "Media Select SAP",
+	[0x9f] = "Reserved",
+	[0xa0] = "VCR Plus",
+	[0xa1] = "Once",
+	[0xa2] = "Daily",
+	[0xa3] = "Weekly",
+	[0xa4] = "Monthly",
+	[0xa5] = "Reserved",
+	[0xa6] = "Reserved",
+	[0xa7] = "Reserved",
+	[0xa8] = "Reserved",
+	[0xa9] = "Reserved",
+	[0xaa] = "Reserved",
+	[0xab] = "Reserved",
+	[0xac] = "Reserved",
+	[0xad] = "Reserved",
+	[0xae] = "Reserved",
+	[0xaf] = "Reserved",
+	[0xb0] = "Play",
+	[0xb1] = "Pause",
+	[0xb2] = "Record",
+	[0xb3] = "Fast Forward",
+	[0xb4] = "Rewind",
+	[0xb5] = "Scan Next Track",
+	[0xb6] = "Scan Previous Trac",
+	[0xb7] = "Stop",
+	[0xb8] = "Eject",
+	[0xb9] = "Random Play",
+	[0xba] = "Select Disc",
+	[0xbb] = "Enter Disc",
+	[0xbc] = "Repeat",
+	[0xbd] = "Tracking",
+	[0xbe] = "Track Normal",
+	[0xbf] = "Slow Tracking",
+	[0xc0] = "Frame Forward",
+	[0xc1] = "Frame Back",
+	[0xc2] = "Mark",
+	[0xc3] = "Clear Mark",
+	[0xc4] = "Repeat From Mark",
+	[0xc5] = "Return to Mark",
+	[0xc6] = "Search Mark Forward",
+	[0xc7] = "Search Mark Backwards",
+	[0xc8] = "Counter Reset",
+	[0xc9] = "Show Counter",
+	[0xca] = "Tracking Increment",
+	[0xcb] = "Tracking Decrement",
+	[0xcc] = "Stop/Eject",
+	[0xcd] = "Play/Pause",
+	[0xce] = "Play/Skip",
+	[0xcf] = "Reserved",
+	[0xd0] = "Reserved",
+	[0xd1] = "Reserved",
+	[0xd2] = "Reserved",
+	[0xd3] = "Reserved",
+	[0xd4] = "Reserved",
+	[0xd5] = "Reserved",
+	[0xd6] = "Reserved",
+	[0xd7] = "Reserved",
+	[0xd8] = "Reserved",
+	[0xd9] = "Reserved",
+	[0xda] = "Reserved",
+	[0xdb] = "Reserved",
+	[0xdc] = "Reserved",
+	[0xdd] = "Reserved",
+	[0xde] = "Reserved",
+	[0xdf] = "Reserved",
+	[0xe0] = "Volume",
+	[0xe1] = "Balance",
+	[0xe2] = "Mute",
+	[0xe3] = "Bass",
+	[0xe4] = "Treble",
+	[0xe5] = "Bass Boost",
+	[0xe6] = "Surround Mode",
+	[0xe7] = "Loudness",
+	[0xe8] = "MPX",
+	[0xe9] = "Volume Increment",
+	[0xea] = "Volume Decrement",
+	[0xeb] = "Reserved",
+	[0xec] = "Reserved",
+	[0xed] = "Reserved",
+	[0xee] = "Reserved",
+	[0xef] = "Reserved",
+	[0xf0] = "Speed Select",
+	[0xf1] = "Playback Speed",
+	[0xf2] = "Standard Play",
+	[0xf3] = "Long Play",
+	[0xf4] = "Extended Play",
+	[0xf5] = "Slow",
+	[0xf6] = "Reserved",
+	[0xf7] = "Reserved",
+	[0xf8] = "Reserved",
+	[0xf9] = "Reserved",
+	[0xfa] = "Reserved",
+	[0xfb] = "Reserved",
+	[0xfc] = "Reserved",
+	[0xfd] = "Reserved",
+	[0xfe] = "Reserved",
+	[0xff] = "Reserved",
+	[0x100] = "Fan Enable",
+	[0x101] = "Fan Speed",
+	[0x102] = "Light Enable",
+	[0x103] = "Light Illumination Level",
+	[0x104] = "Climate Control Enable",
+	[0x105] = "Room Temperature",
+	[0x106] = "Security Enable",
+	[0x107] = "Fire Alarm",
+	[0x108] = "Police Alarm",
+	[0x109] = "Proximity",
+	[0x10a] = "Motion",
+	[0x10b] = "Duress Alarm",
+	[0x10c] = "Holdup Alarm",
+	[0x10d] = "Medical Alarm",
+	[0x10e] = "Reserved",
+	[0x10f] = "Reserved",
+	[0x110] = "Reserved",
+	[0x111] = "Reserved",
+	[0x112] = "Reserved",
+	[0x113] = "Reserved",
+	[0x114] = "Reserved",
+	[0x115] = "Reserved",
+	[0x116] = "Reserved",
+	[0x117] = "Reserved",
+	[0x118] = "Reserved",
+	[0x119] = "Reserved",
+	[0x11a] = "Reserved",
+	[0x11b] = "Reserved",
+	[0x11c] = "Reserved",
+	[0x11d] = "Reserved",
+	[0x11e] = "Reserved",
+	[0x11f] = "Reserved",
+	[0x120] = "Reserved", 
+	[0x121] = "Reserved",
+	[0x122] = "Reserved",
+	[0x123] = "Reserved",
+	[0x124] = "Reserved",
+	[0x125] = "Reserved",
+	[0x126] = "Reserved",
+	[0x127] = "Reserved",
+	[0x128] = "Reserved",
+	[0x129] = "Reserved",
+	[0x12a] = "Reserved",
+	[0x12b] = "Reserved",
+	[0x12c] = "Reserved",
+	[0x12d] = "Reserved",
+	[0x12e] = "Reserved",
+	[0x12f] = "Reserved",
+	[0x130] = "Reserved", 
+	[0x131] = "Reserved",
+	[0x132] = "Reserved",
+	[0x133] = "Reserved",
+	[0x134] = "Reserved",
+	[0x135] = "Reserved",
+	[0x136] = "Reserved",
+	[0x137] = "Reserved",
+	[0x138] = "Reserved",
+	[0x139] = "Reserved",
+	[0x13a] = "Reserved",
+	[0x13b] = "Reserved",
+	[0x13c] = "Reserved",
+	[0x13d] = "Reserved",
+	[0x13e] = "Reserved",
+	[0x13f] = "Reserved",
+	[0x140] = "Reserved", 
+	[0x141] = "Reserved",
+	[0x142] = "Reserved",
+	[0x143] = "Reserved",
+	[0x144] = "Reserved",
+	[0x145] = "Reserved",
+	[0x146] = "Reserved",
+	[0x147] = "Reserved",
+	[0x148] = "Reserved",
+	[0x149] = "Reserved",
+	[0x14a] = "Reserved",
+	[0x14b] = "Reserved",
+	[0x14c] = "Reserved",
+	[0x14d] = "Reserved",
+	[0x14e] = "Reserved",
+	[0x14f] = "Reserved",
+	[0x150] = "Balance Right",
+	[0x151] = "Balance Left",
+	[0x152] = "Bass Increment",
+	[0x153] = "Bass Decrement",
+	[0x154] = "Treble Increment",
+	[0x155] = "Treble Decrement",
+	[0x156] = "Reserved",
+	[0x157] = "Reserved",
+	[0x158] = "Reserved",
+	[0x159] = "Reserved",
+	[0x15a] = "Reserved",
+	[0x15b] = "Reserved",
+	[0x15c] = "Reserved",
+	[0x15d] = "Reserved",
+	[0x15e] = "Reserved",
+	[0x15f] = "Reserved",
+	[0x160] = "Speaker System",
+	[0x161] = "Channel Left",
+	[0x162] = "Channel Right",
+	[0x163] = "Channel Center",
+	[0x164] = "Channel Front",
+	[0x165] = "Channel Center Front",
+	[0x166] = "Channel Side",
+	[0x167] = "Channel Surround",
+	[0x168] = "Channel Low Frequency Enhancement",
+	[0x169] = "Channel Top",
+	[0x16a] = "Channel Unknown",
+	[0x16b] = "Reserved",
+	[0x16c] = "Reserved",
+	[0x16d] = "Reserved",
+	[0x16e] = "Reserved",
+	[0x16f] = "Reserved",
+	[0x170] = "Sub-channel",
+	[0x171] = "Sub-channel Increment",
+	[0x172] = "Sub-channel Decrement",
+	[0x173] = "Alternate Audio Increment",
+	[0x174] = "Alternate Audio Decrement",
+	[0x175] = "Reserved",
+	[0x176] = "Reserved",
+	[0x177] = "Reserved",
+	[0x178] = "Reserved",
+	[0x179] = "Reserved",
+	[0x17a] = "Reserved",
+	[0x17b] = "Reserved",
+	[0x17c] = "Reserved",
+	[0x17d] = "Reserved",
+	[0x17e] = "Reserved",
+	[0x17f] = "Reserved",
+	[0x180] = "Application Launch Buttons",
+	[0x181] = "AL Launch Buttion Configuration Tool",
+	[0x182] = "AL Programmable Button Configuration",
+	[0x183] = "AL Consumer Control Configuration",
+	[0x184] = "AL Word Processor",
+	[0x185] = "AL Text Editor",
+	[0x186] = "AL Spreadsheet",
+	[0x187] = "AL Graphics Editor",
+	[0x188] = "AL Presentation App",
+	[0x189] = "AL Database App",
+	[0x18a] = "AL Email Reader",
+	[0x18b] = "AL Newsreader",
+	[0x18c] = "AL Voicemail",
+	[0x18d] = "AL Contacts/Address Book",
+	[0x18e] = "AL Calendar/Schedule",
+	[0x18f] = "AL Task/Project Manager",
+	[0x190] = "AL Log/Journal/Timecard",
+	[0x191] = "AL Checkbook/Finance",
+	[0x192] = "AL Calculator",
+	[0x193] = "AL A/V Capture/Playback",
+	[0x194] = "AL Local Machine Browser",
+	[0x195] = "AL LAN/WAN Browser",
+	[0x196] = "AL Internet Browser",
+	[0x197] = "AL Remote Networking/ISP Connect",
+	[0x198] = "AL Network Conference",
+	[0x199] = "AL Network Chat",
+	[0x19a] = "AL Telephony/Dialer",
+	[0x19b] = "AL Logon",
+	[0x19c] = "AL Logoff",
+	[0x19d] = "AL Logon/Logoff",
+	[0x19e] = "AL Terminal Lock/Screensaver",
+	[0x19f] = "AL Control Panel",
+	[0x1a0] = "AL Command Line Processor/Run",
+	[0x1a1] = "AL Process/Task Manager",
+	[0x1a2] = "AL Select Task/Application",
+	[0x1a3] = "AL Next Task/Application",
+	[0x1a4] = "AL Previous Task/Application",
+	[0x1a5] = "AL Preemptive Halt Task/Application",
+	[0x1a6] = "AL Integrated Help Center",
+	[0x1a7] = "AL Documents",
+	[0x1a8] = "AL Thesaurus",
+	[0x1a9] = "AL Dictionary",
+	[0x1aa] = "AL Desktop",
+	[0x1ab] = "AL Spell Check",
+	[0x1ac] = "AL Grammar Check",
+	[0x1ad] = "AL Wireless Status",
+	[0x1ae] = "AL Keyboard Layout",
+	[0x1af] = "AL Virus Protection",
+	[0x1b0] = "AL Encryption",
+	[0x1b1] = "AL Screen Saver",
+	[0x1b2] = "AL Alarms",
+	[0x1b3] = "AL Clock",
+	[0x1b4] = "AL File Browser",
+	[0x1b5] = "AL Power Status",
+	[0x1b6] = "AL Image Browser",
+	[0x1b7] = "AL Audio Browser",
+	[0x1b8] = "AL Movie Browser",
+	[0x1b9] = "AL Digital Rights Manager",
+	[0x1ba] = "AL Digital Wallet",
+	[0x1bb] = "Reserved",
+	[0x1bc] = "AL Instant Messaging",
+	[0x1bd] = "AL OEM Features Tips/Tutorial Browser",
+	[0x1be] = "AL OEM Help",
+	[0x1bf] = "AL Online Community",
+	[0x1c0] = "AL Entertainment Content Browser",
+	[0x1c1] = "AL Online Shopping Browser",
+	[0x1c2] = "AL SmartCard Information/Help",
+	[0x1c3] = "AL Market Monitor/Finance Browser",
+	[0x1c4] = "AL Customized Corporate News Browser",
+	[0x1c5] = "AL Online Activity Browser",
+	[0x1c6] = "AL Research/Search Browser",
+	[0x1c7] = "AL Audio Player",
+	[0x1c8] = "Reserved",
+	[0x1c9] = "Reserved",
+	[0x1ca] = "Reserved",
+	[0x1cb] = "Reserved",
+	[0x1cc] = "Reserved",
+	[0x1cd] = "Reserved",
+	[0x1ce] = "Reserved",
+	[0x1cf] = "Reserved",
+	[0x1d0] = "Reserved",
+	[0x1d1] = "Reserved",
+	[0x1d2] = "Reserved",
+	[0x1d3] = "Reserved",
+	[0x1d4] = "Reserved",
+	[0x1d5] = "Reserved",
+	[0x1d6] = "Reserved",
+	[0x1d7] = "Reserved",
+	[0x1d8] = "Reserved",
+	[0x1d9] = "Reserved",
+	[0x1da] = "Reserved",
+	[0x1db] = "Reserved",
+	[0x1dc] = "Reserved",
+	[0x1dd] = "Reserved",
+	[0x1de] = "Reserved",
+	[0x1df] = "Reserved",
+	[0x1e0] = "Reserved",
+	[0x1e1] = "Reserved",
+	[0x1e2] = "Reserved",
+	[0x1e3] = "Reserved",
+	[0x1e4] = "Reserved",
+	[0x1e5] = "Reserved",
+	[0x1e6] = "Reserved",
+	[0x1e7] = "Reserved",
+	[0x1e8] = "Reserved",
+	[0x1e9] = "Reserved",
+	[0x1ea] = "Reserved",
+	[0x1eb] = "Reserved",
+	[0x1ec] = "Reserved",
+	[0x1ed] = "Reserved",
+	[0x1ee] = "Reserved",
+	[0x1ef] = "Reserved",
+	[0x1f0] = "Reserved",
+	[0x1f1] = "Reserved",
+	[0x1f2] = "Reserved",
+	[0x1f3] = "Reserved",
+	[0x1f4] = "Reserved",
+	[0x1f5] = "Reserved",
+	[0x1f6] = "Reserved",
+	[0x1f7] = "Reserved",
+	[0x1f8] = "Reserved",
+	[0x1f9] = "Reserved",
+	[0x1fa] = "Reserved",
+	[0x1fb] = "Reserved",
+	[0x1fc] = "Reserved",
+	[0x1fd] = "Reserved",
+	[0x1fe] = "Reserved",
+	[0x1ff] = "Reserved",
+	[0x200] = "Generic GUI Application Controls",
+	[0x201] = "AC New",
+	[0x202] = "AC Open",
+	[0x203] = "AC Close",
+	[0x204] = "AC Exit",
+	[0x205] = "AC Maximize",
+	[0x206] = "AC Minimize",
+	[0x207] = "AC Save",
+	[0x208] = "AC Print",
+	[0x209] = "AC Properties",
+	[0x20a] = "",
+	[0x20b] = "",
+	[0x20c] = "",
+	[0x20d] = "",
+	[0x20e] = "",
+	[0x20f] = "",
+	[0x210] = "",
+	[0x211] = "",
+	[0x212] = "",
+	[0x213] = "",
+	[0x214] = "",
+	[0x215] = "",
+	[0x216] = "",
+	[0x217] = "",
+	[0x218] = "",
+	[0x219] = "",
+	[0x21a] = "AC Undo",
+	[0x21b] = "AC Copy",
+	[0x21c] = "AC Cut",
+	[0x21d] = "AC Paste",
+	[0x21e] = "AC Select All",
+	[0x21f] = "AC Find",
+	[0x220] = "AC Find and Replace",
+	[0x221] = "AC Search",
+	[0x222] = "AC Go To",
+	[0x223] = "AC Home",
+	[0x224] = "AC Back",
+	[0x225] = "AC Forward",
+	[0x226] = "AC Stop",
+	[0x227] = "AC Refresh",
+	[0x228] = "AC Previous Link",
+	[0x229] = "AC Next Link",
+	[0x22a] = "AC Bookmarks",
+	[0x22b] = "AC History",
+	[0x22c] = "AC Subscriptions",
+	[0x22d] = "AC Zoom In",
+	[0x22e] = "AC Zoom Out",
+	[0x22f] = "AC Zoom",
+	[0x230] = "AC Full Screen View",
+	[0x231] = "AC Normal View",
+	[0x232] = "AC View Toggle",
+	[0x233] = "AC Scroll Up",
+	[0x234] = "AC Scroll Down",
+	[0x235] = "AC Scroll",
+	[0x236] = "AC Pan Left",
+	[0x237] = "AC Pan Right",
+	[0x238] = "AC Pan",
+	[0x239] = "AC New Window",
+	[0x23a] = "AC Tile Horizontally",
+	[0x23b] = "AC Tile Vertically",
+	[0x23c] = "AC Format",
+	[0x23d] = "AC Edit",
+	[0x23e] = "AC Bold",
+	[0x23f] = "AC Italics",
+	[0x240] = "AC Undeline",
+	[0x241] = "AC Strikethrough",
+	[0x242] = "AC Subscript",
+	[0x243] = "AC Superscript",
+	[0x244] = "AC All Caps",
+	[0x245] = "AC Rotate",
+	[0x246] = "AC Resize",
+	[0x247] = "AC Flip Horizontal",
+	[0x248] = "AC Flip Vertical",
+	[0x249] = "AC Mirror Horizontal",
+	[0x24a] = "AC Mirror Vertical",
+	[0x24b] = "AC Font Select",
+	[0x24c] = "AC Font Color",
+	[0x24d] = "AC Font Size",
+	[0x24e] = "AC Justify Left",
+	[0x24f] = "AC Justify Center H",
+	[0x250] = "AC Justify Right",
+	[0x251] = "AC Justify Block H",
+	[0x252] = "AC Justify Top",
+	[0x253] = "AC Justify Center V",
+	[0x254] = "AC Justify Bottom",
+	[0x255] = "AC Justify Block V",
+	[0x256] = "AC Indent Decrease",
+	[0x257] = "AC Indent Increase",
+	[0x258] = "AC Numbered List",
+	[0x259] = "AC Restart Numbering",
+	[0x25a] = "AC Bulleted List",
+	[0x25b] = "AC Promote",
+	[0x25c] = "AC Demote",
+	[0x25d] = "AC Yes",
+	[0x25e] = "AC No",
+	[0x25f] = "AC Cancel",
+	[0x260] = "AC Catalog",
+	[0x261] = "AC Buy/Checkout",
+	[0x262] = "AC Add to Cart",
+	[0x263] = "AC Expand",
+	[0x264] = "AC Expand All",
+	[0x265] = "AC Collapse",
+	[0x266] = "AC Collapse All",
+	[0x267] = "AC Print Preview",
+	[0x268] = "AC Paste Special",
+	[0x269] = "AC Insert Mode",
+	[0x26a] = "AC Delete",
+	[0x26b] = "AC Lock",
+	[0x26c] = "AC Unlock",
+	[0x26d] = "AC Protect",
+	[0x26e] = "AC Unprotect",
+	[0x26f] = "AC Attach Comment",
+	[0x270] = "AC Delete Comment",
+	[0x271] = "AC View Comment",
+	[0x272] = "AC Select Word",
+	[0x273] = "AC Select Sentence",
+	[0x274] = "AC Select Paragraph",
+	[0x275] = "AC Select Column",
+	[0x276] = "AC Select Row",
+	[0x277] = "AC Select Table",
+	[0x278] = "AC Select Object",
+	[0x279] = "AC Redo/Repeat",
+	[0x27a] = "AC Sort",
+	[0x27b] = "AC Sort Ascending",
+	[0x27c] = "AC Sort Descending",
+	[0x27d] = "AC Filter",
+	[0x27e] = "AC Set Clock",
+	[0x27f] = "AC View Clock",
+	[0x280] = "AC Select Time Zone",
+	[0x281] = "AC Edit Time Zones",
+	[0x282] = "AC Set Alarm",
+	[0x283] = "AC Clear Alarm",
+	[0x284] = "AC Snooze Alarm",
+	[0x285] = "AC Reset Alarm",
+	[0x286] = "AC Synchronize",
+	[0x287] = "AC Send/Receive",
+	[0x288] = "AC Send To",
+	[0x289] = "AC Reply",
+	[0x28a] = "AC Reply All",
+	[0x28b] = "AC Forward Msg",
+	[0x28c] = "AC Send",
+	[0x28d] = "AC Attach File",
+	[0x28e] = "AC Upload",
+	[0x28f] = "AC Download (Save Target As)",
+	[0x290] = "AC Set Borders",
+	[0x291] = "AC Insert Row",
+	[0x292] = "AC Insert Column",
+	[0x293] = "AC Insert File",
+	[0x294] = "AC Insert Picture",
+	[0x295] = "AC Insert Object",
+	[0x296] = "AC Insert Symbol",
+	[0x297] = "AC Save and Close",
+	[0x298] = "AC Rename",
+	[0x299] = "AC Merge",
+	[0x29a] = "AC Split",
+	[0x29b] = "AC Distrubute Horizontally",
+	[0x29c] = "AC Distrubute Vertically"
+};
+
+/**
+ * Translates USB HID Usages from the Consumer Page into their string 
+ * representation.
+ *
+ * @param usage USB HID Consumer Page Usage number.
+ * 
+ * @retval HelenOS key code corresponding to the given USB Consumer Page Usage.
+ */
+const char *usbhid_multimedia_usage_to_str(int usage)
+{
+	size_t map_length = sizeof(usbhid_consumer_usage_str) / sizeof(char *);
+
+	if ((usage < 0) || ((size_t)usage >= map_length))
+		return "Unknown usage";
+
+	/*! @todo What if the usage is not in the table? */
+	return usbhid_consumer_usage_str[usage];
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/hiddescriptor.c
===================================================================
--- uspace/lib/usbhid/src/hiddescriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/hiddescriptor.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * HID report descriptor and report data parser implementation.
+ */
+#include <usb/hid/hidparser.h>
+#include <errno.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <mem.h>
+#include <usb/debug.h>
+#include <assert.h>
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Constants defining current parsing mode for correct parsing of the set of
+ * local tags (usage) enclosed in delimter tags.
+ */
+/**
+ * Second delimiter tag was read. The set of local items (usage) ended.
+ */
+#define OUTSIDE_DELIMITER_SET	0
+
+/**
+ * First delimiter tag was read. The set of local items (usage) started.
+ */
+#define START_DELIMITER_SET	1
+
+/**
+ * Parser is in the set of local items.
+ */
+#define INSIDE_DELIMITER_SET	2
+
+/*---------------------------------------------------------------------------*/
+	
+/** The new report item flag. Used to determine when the item is completly
+ * configured and should be added to the report structure
+ */
+#define USB_HID_NEW_REPORT_ITEM 1
+
+/** No special action after the report descriptor tag is processed should be
+ * done
+ */
+#define USB_HID_NO_ACTION	2
+
+#define USB_HID_RESET_OFFSET	3
+
+/** Unknown tag was founded in report descriptor data*/
+#define USB_HID_UNKNOWN_TAG		-99
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Checks if given collection path is already present in report structure and
+ * inserts it if not.
+ *
+ * @param report Report structure 
+ * @param cmp_path The collection path 
+ * @return Pointer to the result collection path in report structure.
+ * @retval NULL If some error occurs
+ */
+usb_hid_report_path_t *usb_hid_report_path_try_insert(
+		usb_hid_report_t *report, usb_hid_report_path_t *cmp_path) {
+	
+	link_t *path_it = report->collection_paths.prev->next;
+	usb_hid_report_path_t *path = NULL;
+	
+	if((report == NULL) || (cmp_path == NULL)) {
+		return NULL;
+	}
+	
+	while(path_it != &report->collection_paths) {
+		path = list_get_instance(path_it, usb_hid_report_path_t,
+				link);
+		
+		if(usb_hid_report_compare_usage_path(path, cmp_path,
+					USB_HID_PATH_COMPARE_STRICT) == EOK){
+			break;
+		}			
+		path_it = path_it->next;
+	}
+	if(path_it == &report->collection_paths) {
+		path = usb_hid_report_path_clone(cmp_path);
+		if(path == NULL) {
+			return NULL;
+		}
+		list_append(&path->link, &report->collection_paths);					
+		report->collection_paths_count++;
+
+		return path;
+	}
+	else {
+		return list_get_instance(path_it, usb_hid_report_path_t,
+				link); 
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Initialize the report descriptor parser structure
+ *
+ * @param parser Report descriptor parser structure
+ * @return Error code
+ * @retval EINVAL If no report structure was given
+ * @retval EOK If report structure was successfully initialized
+ */
+int usb_hid_report_init(usb_hid_report_t *report)
+{
+	if(report == NULL) {
+		return EINVAL;
+	}
+
+	memset(report, 0, sizeof(usb_hid_report_t));
+	list_initialize(&report->reports);
+	list_initialize(&report->collection_paths);
+
+	report->use_report_ids = 0;
+    return EOK;   
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ *
+ *
+ * @param report Report structure in which the new report items should be
+ * 		 stored
+ * @param report_item Current report descriptor's parsing state table 
+ * @return Error code
+ * @retval EOK If all fields were successfully append to report
+ * @retval EINVAL If invalid parameters (NULL) was given
+ * @retval ENOMEM If there is no memmory to store new report description
+ *
+ */
+int usb_hid_report_append_fields(usb_hid_report_t *report,
+		usb_hid_report_item_t *report_item) {
+
+	usb_hid_report_field_t *field;
+	int i;
+
+	uint32_t *usages;
+	int usages_used=0;
+
+	if((report == NULL) || (report_item == NULL)) {
+		return EINVAL;
+	}
+
+	if(report_item->usages_count > 0){
+		usages = malloc(sizeof(int32_t) * report_item->usages_count);
+		memcpy(usages, report_item->usages, sizeof(int32_t) *
+				report_item->usages_count); 
+	}
+	else {
+		usages = NULL;
+	}
+	
+	usb_hid_report_path_t *path = report_item->usage_path;	
+	for(i=0; i<report_item->count; i++){
+
+		field = malloc(sizeof(usb_hid_report_field_t));
+		if(field == NULL) {
+			return ENOMEM;
+		}
+
+		memset(field, 0, sizeof(usb_hid_report_field_t));
+		list_initialize(&field->link);
+
+		/* fill the attributes */		
+		field->logical_minimum = report_item->logical_minimum;
+		field->logical_maximum = report_item->logical_maximum;
+		field->physical_minimum = report_item->physical_minimum;
+		field->physical_maximum = report_item->physical_maximum;
+
+		if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0){
+			/* 
+			Store usage array. The Correct Usage Page and Usage is
+			depending on data in report and will be filled later
+			*/
+			field->usage = 0;
+			field->usage_page = 0; //report_item->usage_page;
+
+			field->usages_count = report_item->usages_count;
+			field->usages = usages;
+			usages_used = 1;
+		}
+		else {
+
+			/* Fill the correct Usage and Usage Page */
+			int32_t usage;
+			if(i < report_item->usages_count) {
+				usage = report_item->usages[i];
+			}
+			else {
+				usage = report_item->usages[
+					report_item->usages_count- 1]; 
+			}
+
+			if(USB_HID_IS_EXTENDED_USAGE(usage)){
+				field->usage = USB_HID_EXTENDED_USAGE(usage);
+				field->usage_page = 
+					USB_HID_EXTENDED_USAGE_PAGE(usage);
+			}
+			else {
+				// should not occur
+				field->usage = usage;
+				field->usage_page = report_item->usage_page;
+			}
+		}
+		
+		usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_GLOBAL,
+				field->usage_page);
+		usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_LOCAL,
+				field->usage);
+
+		field->collection_path =
+			usb_hid_report_path_try_insert(report, path);
+
+		field->size = report_item->size;
+
+		if(report_item->type == USB_HID_REPORT_TYPE_INPUT) {
+			int offset = report_item->offset + report_item->size * i;
+			int field_offset = (offset/8)*8 + (offset/8 + 1) * 8 - 
+				offset - report_item->size;
+			if(field_offset < 0) {
+				field->offset = 0;
+			}
+			else {
+				field->offset = field_offset;
+			}
+		}
+		else {
+			field->offset = report_item->offset + (i * report_item->size);
+		}
+
+
+		if(report->use_report_ids != 0) {
+			field->offset += 8;
+			report->use_report_ids = 1;
+		}
+
+		field->item_flags = report_item->item_flags;
+
+		/* find the right report list*/
+		usb_hid_report_description_t *report_des;
+		report_des = usb_hid_report_find_description(report,
+			report_item->id, report_item->type);
+		
+		if(report_des == NULL){
+			report_des = malloc(
+				sizeof(usb_hid_report_description_t));
+			if(report_des == NULL) {
+				return ENOMEM;
+			}
+
+			memset(report_des, 0,
+				sizeof(usb_hid_report_description_t));
+
+			report_des->type = report_item->type;
+			report_des->report_id = report_item->id;
+			if(report_des->report_id != 0) {
+				/* set up the bit length by report_id field */
+				report_des->bit_length = 8;
+			}
+
+			list_initialize (&report_des->link);
+			list_initialize (&report_des->report_items);
+
+			list_append(&report_des->link, &report->reports);
+			report->report_count++;
+		}
+
+		/* append this field to the end of founded report list */
+		list_append (&field->link, &report_des->report_items);
+		
+		/* update the sizes */
+		report_des->bit_length += field->size;
+		report_des->item_length++;
+
+	}
+
+	// free only when not used!!!
+	if(usages && usages_used == 0) {
+		free(usages);
+	}
+
+	return EOK;
+}
+/*---------------------------------------------------------------------------*/
+/**
+ * Finds description of report with given report_id and of given type in
+ * opaque report structure.
+ *
+ * @param report Opaque structure containing the parsed report descriptor
+ * @param report_id ReportId of report we are searching
+ * @param type Type of report we are searching
+ * @return Pointer to the particular report description
+ * @retval NULL If no description is founded
+ */
+usb_hid_report_description_t * usb_hid_report_find_description(
+		const usb_hid_report_t *report, uint8_t report_id,
+		usb_hid_report_type_t type) {
+
+	if(report == NULL) {
+		return NULL;
+	}
+
+	link_t *report_it = report->reports.next;
+	usb_hid_report_description_t *report_des = NULL;
+	
+	while(report_it != &report->reports) {
+		report_des = list_get_instance(report_it,
+				usb_hid_report_description_t, link);
+
+		// if report id not set, return the first of the type
+		if(((report_des->report_id == report_id) || (report_id == 0)) && 
+		   (report_des->type == type)) { 
+			return report_des;
+		}
+		
+		report_it = report_it->next;
+	}
+
+	return NULL;
+}
+/*---------------------------------------------------------------------------*/
+
+/** Parse HID report descriptor.
+ *
+ * @param parser Opaque HID report parser structure.
+ * @param data Data describing the report.
+ * @return Error code.
+ * @retval ENOMEM If no more memmory is available
+ * @retval EINVAL If invalid data are founded
+ * @retval EOK If report descriptor is successfully parsed
+ */
+int usb_hid_parse_report_descriptor(usb_hid_report_t *report, 
+    const uint8_t *data, size_t size)
+{
+	size_t i=0;
+	uint8_t tag=0;
+	uint8_t item_size=0;
+	int class=0;
+	int ret;
+	usb_hid_report_item_t *report_item=0;
+	usb_hid_report_item_t *new_report_item;	
+	usb_hid_report_path_t *usage_path;
+
+	size_t offset_input=0;
+	size_t offset_output=0;
+	size_t offset_feature=0;
+
+	link_t stack;
+	list_initialize(&stack);	
+
+	/* parser structure initialization*/
+	if(usb_hid_report_init(report) != EOK) {
+		return EINVAL;
+	}
+	
+	/*report item initialization*/
+	if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
+		return ENOMEM;
+	}
+	memset(report_item, 0, sizeof(usb_hid_report_item_t));
+	list_initialize(&(report_item->link));	
+
+	/* usage path context initialization */
+	if(!(usage_path=usb_hid_report_path())){
+		return ENOMEM;
+	}
+	usb_hid_report_path_append_item(usage_path, 0, 0);	
+	
+	while(i<size){	
+		if(!USB_HID_ITEM_IS_LONG(data[i])){
+
+			if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
+				return EINVAL;
+			}
+			
+			tag = USB_HID_ITEM_TAG(data[i]);
+			item_size = USB_HID_ITEM_SIZE(data[i]);
+			class = USB_HID_ITEM_TAG_CLASS(data[i]);
+			
+			ret = usb_hid_report_parse_tag(tag,class,data+i+1,
+				item_size,report_item, usage_path);
+
+			switch(ret){
+			case USB_HID_NEW_REPORT_ITEM:
+				/* store report item to report and create the
+				 * new one store current collection path
+				 */
+				report_item->usage_path = usage_path;
+					
+				usb_hid_report_path_set_report_id(
+				     report_item->usage_path, report_item->id);
+				
+				if(report_item->id != 0){
+					report->use_report_ids = 1;
+				}
+					
+				switch(tag) {
+				case USB_HID_REPORT_TAG_INPUT:
+					report_item->type = 
+					    USB_HID_REPORT_TYPE_INPUT;
+
+					report_item->offset = offset_input;
+					offset_input += report_item->count * 
+					    report_item->size;
+					break;
+	
+				case USB_HID_REPORT_TAG_OUTPUT:
+					report_item->type = 
+					    USB_HID_REPORT_TYPE_OUTPUT;
+					
+					report_item->offset = offset_output;
+					offset_output += report_item->count * 
+					    report_item->size;
+					break;
+	
+				case USB_HID_REPORT_TAG_FEATURE:
+					report_item->type = 
+					    USB_HID_REPORT_TYPE_FEATURE;
+
+					report_item->offset = offset_feature;
+					offset_feature += report_item->count * 
+						report_item->size;
+					break;
+	
+				default:
+					usb_log_debug2(
+					    "\tjump over - tag %X\n", tag);
+				    	break;
+				}
+					
+				/* 
+				 * append new fields to the report structure 					 
+				 */
+				usb_hid_report_append_fields(report, 
+				    report_item);
+
+				/* reset local items */
+				usb_hid_report_reset_local_items (report_item);
+				break;
+
+			case USB_HID_RESET_OFFSET:
+				offset_input = 0;
+				offset_output = 0;
+				offset_feature = 0;
+				usb_hid_report_path_set_report_id (usage_path, 
+				    report_item->id);
+				break;
+
+			case USB_HID_REPORT_TAG_PUSH:
+				// push current state to stack
+				new_report_item = usb_hid_report_item_clone(
+				    report_item);
+				
+				usb_hid_report_path_t *tmp_path = 
+				    usb_hid_report_path_clone(usage_path);
+
+				new_report_item->usage_path = tmp_path; 
+
+				list_prepend (&new_report_item->link, &stack);
+				break;
+			case USB_HID_REPORT_TAG_POP:
+				// restore current state from stack
+				if(list_empty (&stack)) {
+					return EINVAL;
+				}
+				free(report_item);
+						
+				report_item = list_get_instance(stack.next, 
+				    usb_hid_report_item_t, link);
+					
+				usb_hid_report_usage_path_t *tmp_usage_path;
+				tmp_usage_path = list_get_instance(
+				    report_item->usage_path->link.prev, 
+				    usb_hid_report_usage_path_t, link);
+					
+				usb_hid_report_set_last_item(usage_path, 
+				    USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
+				
+				usb_hid_report_set_last_item(usage_path, 
+				    USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
+
+				usb_hid_report_path_free(report_item->usage_path);
+				list_initialize(&report_item->usage_path->link);
+				list_remove (stack.next);
+					
+				break;
+					
+			default:
+				// nothing special to do					
+				break;
+			}
+
+			/* jump over the processed block */
+			i += 1 + USB_HID_ITEM_SIZE(data[i]);
+		}
+		else{
+			// TBD
+			i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
+		}
+		
+
+	}
+	
+	return EOK;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Parse one tag of the report descriptor
+ *
+ * @param Tag to parse
+ * @param Report descriptor buffer
+ * @param Size of data belongs to this tag
+ * @param Current report item structe
+ * @return Code of action to be done next
+ */
+int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
+	size_t item_size, usb_hid_report_item_t *report_item,
+	usb_hid_report_path_t *usage_path) {	
+	
+	int ret;
+	
+	switch(class){
+	case USB_HID_TAG_CLASS_MAIN:
+
+		if((ret=usb_hid_report_parse_main_tag(tag, data, item_size,
+			report_item, usage_path)) == EOK) {
+
+			return USB_HID_NEW_REPORT_ITEM;
+		}
+		else {
+			return ret;
+		}
+		break;
+
+	case USB_HID_TAG_CLASS_GLOBAL:	
+		return usb_hid_report_parse_global_tag(tag, data, item_size,
+			report_item, usage_path);
+		break;
+
+	case USB_HID_TAG_CLASS_LOCAL:			
+		return usb_hid_report_parse_local_tag(tag, data, item_size,
+			report_item, usage_path);
+		break;
+	
+	default:
+		return USB_HID_NO_ACTION;
+	}
+}
+
+/**
+ * Parse main tags of report descriptor
+ *
+ * @param Tag identifier
+ * @param Data buffer
+ * @param Length of data buffer
+ * @param Current state table
+ * @return Error code
+ */
+
+int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, 
+	size_t item_size, usb_hid_report_item_t *report_item,
+	usb_hid_report_path_t *usage_path)
+{
+	usb_hid_report_usage_path_t *path_item;
+	
+	switch(tag)
+	{
+	case USB_HID_REPORT_TAG_INPUT:
+	case USB_HID_REPORT_TAG_OUTPUT:
+	case USB_HID_REPORT_TAG_FEATURE:
+		report_item->item_flags = *data;			
+		return EOK;			
+		break;
+			
+	case USB_HID_REPORT_TAG_COLLECTION:
+
+		/* store collection atributes */
+		path_item = list_get_instance(usage_path->head.prev, 
+			usb_hid_report_usage_path_t, link);
+		path_item->flags = *data;	
+			
+		/* set last item */
+		usb_hid_report_set_last_item(usage_path, 
+			USB_HID_TAG_CLASS_GLOBAL, 
+			USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[
+				report_item->usages_count-1]));
+
+		usb_hid_report_set_last_item(usage_path, 
+			USB_HID_TAG_CLASS_LOCAL, 
+			USB_HID_EXTENDED_USAGE(report_item->usages[
+				report_item->usages_count-1]));
+			
+		/* append the new one which will be set by common usage/usage
+		 * page */
+		usb_hid_report_path_append_item(usage_path, 
+			report_item->usage_page, 
+			report_item->usages[report_item->usages_count-1]);
+
+		usb_hid_report_reset_local_items (report_item);
+		return USB_HID_NO_ACTION;
+		break;
+			
+	case USB_HID_REPORT_TAG_END_COLLECTION:
+		usb_hid_report_remove_last_item(usage_path);
+		return USB_HID_NO_ACTION;
+		break;
+
+	default:
+		return USB_HID_NO_ACTION;
+	}
+
+	return EOK;
+}
+
+/**
+ * Parse global tags of report descriptor
+ *
+ * @param Tag identifier
+ * @param Data buffer
+ * @param Length of data buffer
+ * @param Current state table
+ * @return Error code
+ */
+int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, 
+	size_t item_size, usb_hid_report_item_t *report_item, 
+	usb_hid_report_path_t *usage_path) { 
+	
+	switch(tag)
+	{
+	case USB_HID_REPORT_TAG_USAGE_PAGE:
+		report_item->usage_page = 
+			usb_hid_report_tag_data_uint32(data, item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
+		report_item->logical_minimum = USB_HID_UINT32_TO_INT32(
+			usb_hid_report_tag_data_uint32(data,item_size),
+		       	item_size * 8);
+		break;
+
+	case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
+		report_item->logical_maximum = USB_HID_UINT32_TO_INT32(
+			usb_hid_report_tag_data_uint32(data,item_size), 
+			item_size * 8);
+		break;
+
+	case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
+		report_item->physical_minimum = USB_HID_UINT32_TO_INT32(
+			usb_hid_report_tag_data_uint32(data,item_size), 
+			item_size * 8);
+		break;			
+
+	case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
+		report_item->physical_maximum = USB_HID_UINT32_TO_INT32(
+			usb_hid_report_tag_data_uint32(data,item_size), 
+			item_size * 8);
+		break;
+
+	case USB_HID_REPORT_TAG_UNIT_EXPONENT:
+		report_item->unit_exponent = usb_hid_report_tag_data_uint32(
+			data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_UNIT:
+		report_item->unit = usb_hid_report_tag_data_uint32(
+			data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_REPORT_SIZE:
+		report_item->size = usb_hid_report_tag_data_uint32(
+			data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_REPORT_COUNT:
+		report_item->count = usb_hid_report_tag_data_uint32(
+			data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_REPORT_ID:
+		report_item->id = usb_hid_report_tag_data_uint32(data, 
+			item_size);
+		return USB_HID_RESET_OFFSET;
+		break;
+	
+	case USB_HID_REPORT_TAG_PUSH:
+	case USB_HID_REPORT_TAG_POP:
+		/* 
+		 * stack operations are done in top level parsing
+		 * function
+		 */
+		return tag;
+		break;
+			
+	default:
+		return USB_HID_NO_ACTION;
+	}
+
+	return EOK;
+}
+
+/**
+ * Parse local tags of report descriptor
+ *
+ * @param Tag identifier
+ * @param Data buffer
+ * @param Length of data buffer
+ * @param Current state table
+ * @return Error code
+ */
+int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, 
+	size_t item_size, usb_hid_report_item_t *report_item, 
+	usb_hid_report_path_t *usage_path)
+{
+	int32_t extended_usage;
+	
+	switch(tag) {
+	case USB_HID_REPORT_TAG_USAGE:
+		switch(report_item->in_delimiter) {
+		case INSIDE_DELIMITER_SET:
+			/* nothing to do
+			 * we catch only the first one
+			 */
+			break;
+	
+		case START_DELIMITER_SET:
+			report_item->in_delimiter = INSIDE_DELIMITER_SET;
+		case OUTSIDE_DELIMITER_SET:
+			extended_usage = ((report_item->usage_page) << 16);
+			extended_usage += usb_hid_report_tag_data_uint32(
+				data,item_size);
+
+			report_item->usages[report_item->usages_count] = 
+				extended_usage;
+
+			report_item->usages_count++;
+			break;
+		}
+		break;
+		
+	case USB_HID_REPORT_TAG_USAGE_MINIMUM:			
+		if (item_size == 3) {
+			// usage extended usages
+			report_item->extended_usage_page = 
+			    USB_HID_EXTENDED_USAGE_PAGE(
+			    usb_hid_report_tag_data_uint32(data,item_size));
+			   
+
+			report_item->usage_minimum = 
+			    USB_HID_EXTENDED_USAGE(
+			    usb_hid_report_tag_data_uint32(data,item_size));
+		}
+		else {
+			report_item->usage_minimum = 
+			    usb_hid_report_tag_data_uint32(data,item_size);
+		}
+		break;
+	
+	case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
+		if (item_size == 3) {
+			if(report_item->extended_usage_page != 
+			    USB_HID_EXTENDED_USAGE_PAGE(	
+			    usb_hid_report_tag_data_uint32(data,item_size))) {
+				
+				return EINVAL;
+			}
+				
+			// usage extended usages
+			report_item->extended_usage_page = 
+				USB_HID_EXTENDED_USAGE_PAGE(
+				usb_hid_report_tag_data_uint32(data,item_size));
+
+			report_item->usage_maximum = 
+				USB_HID_EXTENDED_USAGE(
+				usb_hid_report_tag_data_uint32(data,item_size));
+		}
+		else {
+			report_item->usage_maximum = 
+				usb_hid_report_tag_data_uint32(data,item_size);
+		}
+
+		// vlozit zaznamy do pole usages
+		int32_t i;
+		for(i = report_item->usage_minimum; 
+		    i <= report_item->usage_maximum; i++) {
+
+			if(report_item->extended_usage_page) {
+			    report_item->usages[report_item->usages_count++] = 
+				(report_item->extended_usage_page << 16) + i;
+			}
+			else {			
+			    report_item->usages[report_item->usages_count++] = 
+				(report_item->usage_page << 16) + i;
+			}
+		}
+		report_item->extended_usage_page = 0;
+			
+		break;
+		
+	case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
+		report_item->designator_index = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;
+	
+	case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
+		report_item->designator_minimum = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
+		report_item->designator_maximum = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_STRING_INDEX:
+		report_item->string_index = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_STRING_MINIMUM:
+		report_item->string_minimum = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;
+
+	case USB_HID_REPORT_TAG_STRING_MAXIMUM:
+		report_item->string_maximum = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;			
+
+	case USB_HID_REPORT_TAG_DELIMITER:
+		report_item->in_delimiter = 
+			usb_hid_report_tag_data_uint32(data,item_size);
+		break;
+
+	default:
+		return USB_HID_NO_ACTION;
+	}
+
+	return EOK;
+}
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Converts raw data to uint32 (thats the maximum length of short item data)
+ *
+ * @param Data buffer
+ * @param Size of buffer
+ * @return Converted int32 number
+ */
+uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
+{
+	unsigned int i;
+	uint32_t result;
+
+	result = 0;
+	for(i=0; i<size; i++) {
+		result = (result | (data[i]) << (i*8));
+	}
+
+	return result;
+}
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Prints content of given list of report items.
+ *
+ * @param List of report items (usb_hid_report_item_t)
+ * @return void
+ */
+void usb_hid_descriptor_print_list(link_t *head)
+{
+	usb_hid_report_field_t *report_item;
+	link_t *item;
+
+
+	if(head == NULL || list_empty(head)) {
+	    usb_log_debug("\tempty\n");
+	    return;
+	}
+        
+	for(item = head->next; item != head; item = item->next) {
+                
+		report_item = list_get_instance(item, usb_hid_report_field_t, 
+				link);
+
+		usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
+		usb_log_debug("\t\tSIZE: %zu\n", report_item->size);
+		usb_log_debug("\t\tLOGMIN: %d\n", 
+			report_item->logical_minimum);
+		usb_log_debug("\t\tLOGMAX: %d\n", 
+			report_item->logical_maximum);		
+		usb_log_debug("\t\tPHYMIN: %d\n", 
+			report_item->physical_minimum);		
+		usb_log_debug("\t\tPHYMAX: %d\n", 
+			report_item->physical_maximum);				
+		usb_log_debug("\t\ttUSAGEMIN: %X\n", 
+			report_item->usage_minimum);
+		usb_log_debug("\t\tUSAGEMAX: %X\n",
+			       report_item->usage_maximum);
+		usb_log_debug("\t\tUSAGES COUNT: %zu\n", 
+			report_item->usages_count);
+
+		usb_log_debug("\t\tVALUE: %X\n", report_item->value);
+		usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
+		usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
+		
+		usb_hid_print_usage_path(report_item->collection_path);
+
+		usb_log_debug("\n");		
+
+	}
+
+}
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Prints content of given report descriptor in human readable format.
+ *
+ * @param parser Parsed descriptor to print
+ * @return void
+ */
+void usb_hid_descriptor_print(usb_hid_report_t *report)
+{
+	if(report == NULL) {
+		return;
+	}
+
+	link_t *report_it = report->reports.next;
+	usb_hid_report_description_t *report_des;
+
+	while(report_it != &report->reports) {
+		report_des = list_get_instance(report_it, 
+			usb_hid_report_description_t, link);
+		usb_log_debug("Report ID: %d\n", report_des->report_id);
+		usb_log_debug("\tType: %d\n", report_des->type);
+		usb_log_debug("\tLength: %zu\n", report_des->bit_length);		
+		usb_log_debug("\tB Size: %zu\n",
+			usb_hid_report_byte_size(report, 
+				report_des->report_id, 
+				report_des->type));
+		usb_log_debug("\tItems: %zu\n", report_des->item_length);		
+
+		usb_hid_descriptor_print_list(&report_des->report_items);
+
+		report_it = report_it->next;
+	}
+}
+/*---------------------------------------------------------------------------*/
+
+/**
+ * Releases whole linked list of report items
+ *
+ * @param head Head of list of report descriptor items (usb_hid_report_item_t)
+ * @return void
+ */
+void usb_hid_free_report_list(link_t *head)
+{
+	return; 
+	
+	usb_hid_report_item_t *report_item;
+	link_t *next;
+	
+	if(head == NULL || list_empty(head)) {		
+	    return;
+	}
+	
+	next = head->next;
+	while(next != head) {
+	
+	    report_item = list_get_instance(next, usb_hid_report_item_t, link);
+
+		while(!list_empty(&report_item->usage_path->link)) {
+		    usb_hid_report_remove_last_item(report_item->usage_path);
+		}
+
+		
+	    next = next->next;
+	    
+	    free(report_item);
+	}
+	
+	return;
+	
+}
+/*---------------------------------------------------------------------------*/
+
+/** Frees the HID report descriptor parser structure 
+ *
+ * @param parser Opaque HID report parser structure
+ * @return void
+ */
+void usb_hid_free_report(usb_hid_report_t *report)
+{
+	if(report == NULL){
+		return;
+	}
+
+	// free collection paths
+	usb_hid_report_path_t *path;
+	while(!list_empty(&report->collection_paths)) {
+		path = list_get_instance(report->collection_paths.next, 
+				usb_hid_report_path_t, link);
+
+		usb_hid_report_path_free(path);		
+	}
+	
+	// free report items
+	usb_hid_report_description_t *report_des;
+	usb_hid_report_field_t *field;
+	while(!list_empty(&report->reports)) {
+		report_des = list_get_instance(report->reports.next, 
+				usb_hid_report_description_t, link);
+
+		list_remove(&report_des->link);
+		
+		while(!list_empty(&report_des->report_items)) {
+			field = list_get_instance(
+				report_des->report_items.next, 
+				usb_hid_report_field_t, link);
+
+			list_remove(&field->link);
+
+			free(field);
+		}
+		
+		free(report_des);
+	}
+	
+	return;
+}
+/*---------------------------------------------------------------------------*/
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/hidiface.c
===================================================================
--- uspace/lib/usbhid/src/hidiface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/hidiface.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,238 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * Client functions for accessing USB HID interface (implementation).
+ */
+#include <dev_iface.h>
+#include <usbhid_iface.h>
+#include <usb/hid/iface.h>
+#include <errno.h>
+#include <str_error.h>
+#include <async.h>
+#include <assert.h>
+
+/** Ask for event array length.
+ *
+ * @param dev_sess Session to DDF device providing USB HID interface.
+ *
+ * @return Number of usages returned or negative error code.
+ *
+ */
+int usbhid_dev_get_event_length(async_sess_t *dev_sess, size_t *size)
+{
+	if (!dev_sess)
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t len;
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(USBHID_DEV_IFACE),
+	    IPC_M_USBHID_GET_EVENT_LENGTH, &len);
+	
+	async_exchange_end(exch);
+	
+	if (rc == EOK) {
+		if (size != NULL)
+			*size = (size_t) len;
+	}
+	
+	return rc;
+}
+
+/** Request for next event from HID device.
+ *
+ * @param[in]  dev_sess    Session to DDF device providing USB HID interface.
+ * @param[out] usage_pages Where to store usage pages.
+ * @param[out] usages      Where to store usages (actual data).
+ * @param[in]  usage_count Length of @p usage_pages and @p usages buffer
+ *                         (in items, not bytes).
+ * @param[out] actual_usage_count Number of usages actually returned by the
+ *                                device driver.
+ * @param[in] flags        Flags (see USBHID_IFACE_FLAG_*).
+ *
+ * @return Error code.
+ *
+ */
+int usbhid_dev_get_event(async_sess_t *dev_sess, uint8_t *buf,
+    size_t size, size_t *actual_size, int *event_nr, unsigned int flags)
+{
+	if (!dev_sess)
+		return EINVAL;
+	
+	if ((buf == NULL))
+		return ENOMEM;
+	
+	if (size == 0)
+		return EINVAL;
+	
+	size_t buffer_size =  size;
+	uint8_t *buffer = malloc(buffer_size);
+	if (buffer == NULL)
+		return ENOMEM;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	ipc_call_t opening_request_call;
+	aid_t opening_request = async_send_2(exch,
+	    DEV_IFACE_ID(USBHID_DEV_IFACE), IPC_M_USBHID_GET_EVENT,
+	    flags, &opening_request_call);
+	
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		free(buffer);
+		return ENOMEM;
+	}
+	
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, buffer, buffer_size,
+	    &data_request_call);
+	
+	async_exchange_end(exch);
+	
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		free(buffer);
+		return ENOMEM;
+	}
+	
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	if (data_request_rc != EOK) {
+		/* Prefer return code of the opening request. */
+		if (opening_request_rc != EOK)
+			return (int) opening_request_rc;
+		else
+			return (int) data_request_rc;
+	}
+	
+	if (opening_request_rc != EOK)
+		return (int) opening_request_rc;
+	
+	size_t act_size = IPC_GET_ARG2(data_request_call);
+	
+	/* Copy the individual items. */
+	memcpy(buf, buffer, act_size);
+	
+	if (actual_size != NULL)
+		*actual_size = act_size;
+	
+	if (event_nr != NULL)
+		*event_nr = IPC_GET_ARG1(opening_request_call);
+	
+	return EOK;
+}
+
+int usbhid_dev_get_report_descriptor_length(async_sess_t *dev_sess,
+    size_t *size)
+{
+	if (!dev_sess)
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t arg_size;
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(USBHID_DEV_IFACE),
+	    IPC_M_USBHID_GET_REPORT_DESCRIPTOR_LENGTH, &arg_size);
+	
+	async_exchange_end(exch);
+	
+	if (rc == EOK) {
+		if (size != NULL)
+			*size = (size_t) arg_size;
+	}
+	
+	return rc;
+}
+
+int usbhid_dev_get_report_descriptor(async_sess_t *dev_sess, uint8_t *buf,
+    size_t size, size_t *actual_size)
+{
+	if (!dev_sess)
+		return EINVAL;
+	
+	if ((buf == NULL))
+		return ENOMEM;
+	
+	if (size == 0)
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t opening_request = async_send_1(exch,
+	    DEV_IFACE_ID(USBHID_DEV_IFACE), IPC_M_USBHID_GET_REPORT_DESCRIPTOR,
+	    NULL);
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return ENOMEM;
+	}
+	
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, buf, size,
+	    &data_request_call);
+	
+	async_exchange_end(exch);
+	
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+	
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	if (data_request_rc != EOK) {
+		/* Prefer return code of the opening request. */
+		if (opening_request_rc != EOK)
+			return (int) opening_request_rc;
+		else
+			return (int) data_request_rc;
+	}
+	
+	if (opening_request_rc != EOK)
+		return (int) opening_request_rc;
+	
+	size_t act_size = IPC_GET_ARG2(data_request_call);
+	
+	if (actual_size != NULL)
+		*actual_size = act_size;
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/hidparser.c
===================================================================
--- uspace/lib/usbhid/src/hidparser.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/hidparser.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * USB HID report data parser implementation.
+ */
+#include <usb/hid/hidparser.h>
+#include <errno.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <mem.h>
+#include <usb/debug.h>
+#include <assert.h>
+
+/*---------------------------------------------------------------------------*/
+/*
+ * Data translation private functions
+ */
+uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
+
+int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data);
+
+uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 
+	int32_t value);
+
+int usb_pow(int a, int b);
+
+/*---------------------------------------------------------------------------*/
+
+// TODO: tohle ma bejt asi jinde
+int usb_pow(int a, int b)
+{
+	switch(b) {
+	case 0:
+		return 1;
+		break;
+	case 1:
+		return a;
+		break;
+	default:
+		return a * usb_pow(a, b-1);
+		break;
+	}
+}
+/*---------------------------------------------------------------------------*/
+
+/** Returns size of report of specified report id and type in items
+ *
+ * @param parser Opaque report parser structure
+ * @param report_id 
+ * @param type
+ * @return Number of items in specified report
+ */
+size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id, 
+                           usb_hid_report_type_t type)
+{
+	usb_hid_report_description_t *report_des;
+
+	if(report == NULL) {
+		return 0;
+	}
+
+	report_des = usb_hid_report_find_description (report, report_id, type);
+	if(report_des == NULL){
+		return 0;
+	}
+	else {
+		return report_des->item_length;
+	}
+}
+
+/** Returns size of report of specified report id and type in bytes
+ *
+ * @param parser Opaque report parser structure
+ * @param report_id 
+ * @param type
+ * @return Number of items in specified report
+ */
+size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id, 
+                           usb_hid_report_type_t type)
+{
+	usb_hid_report_description_t *report_des;
+
+	if(report == NULL) {
+		return 0;
+	}
+
+	report_des = usb_hid_report_find_description (report, report_id, type);
+	if(report_des == NULL){
+		return 0;
+	}
+	else {
+		return ((report_des->bit_length + 7) / 8) ;
+	}
+}
+/*---------------------------------------------------------------------------*/
+
+/** Parse and act upon a HID report.
+ *
+ * @see usb_hid_parse_report_descriptor
+ *
+ * @param parser Opaque HID report parser structure.
+ * @param data Data for the report.
+ * @return Error code.
+ */ 
+int usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data, 
+	size_t size, uint8_t *report_id)
+{
+	link_t *list_item;
+	usb_hid_report_field_t *item;
+
+	usb_hid_report_description_t *report_des;
+	usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
+	
+	if(report == NULL) {
+		return EINVAL;
+	}
+
+	if(report->use_report_ids != 0) {
+		*report_id = data[0];
+	}	
+	else {
+		*report_id = 0;
+	}
+
+
+	report_des = usb_hid_report_find_description(report, *report_id, 
+		type);
+
+	if(report_des == NULL) {
+		return EINVAL;
+	}
+
+	/* read data */
+	list_item = report_des->report_items.next;	   
+	while(list_item != &(report_des->report_items)) {
+
+		item = list_get_instance(list_item, usb_hid_report_field_t, 
+				link);
+
+		if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
+			
+			if(USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0){
+
+				// array
+				item->value = 
+					usb_hid_translate_data(item, data);
+		
+				item->usage = USB_HID_EXTENDED_USAGE(
+				    item->usages[
+				    item->value - item->physical_minimum]);
+
+				item->usage_page = 
+				    USB_HID_EXTENDED_USAGE_PAGE(
+				    item->usages[
+				    item->value - item->physical_minimum]);
+
+				usb_hid_report_set_last_item (
+				    item->collection_path, 
+				    USB_HID_TAG_CLASS_GLOBAL, 
+				    item->usage_page);
+
+				usb_hid_report_set_last_item (
+				    item->collection_path, 
+				    USB_HID_TAG_CLASS_LOCAL, item->usage);
+				
+			}
+			else {
+				// variable item
+				item->value = usb_hid_translate_data(item, 
+				    data);				
+			}			
+		}
+		list_item = list_item->next;
+	}
+	
+	return EOK;
+	
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Translate data from the report as specified in report descriptor item
+ *
+ * @param item Report descriptor item with definition of translation
+ * @param data Data to translate
+ * @return Translated data
+ */
+int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data)
+{
+	int resolution;
+	int offset;
+	int part_size;
+	
+	int32_t value=0;
+	int32_t mask=0;
+	const uint8_t *foo=0;
+
+	// now only shot tags are allowed
+	if(item->size > 32) {
+		return 0;
+	}
+
+	if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
+		item->physical_minimum = item->logical_minimum;
+		item->physical_maximum = item->logical_maximum;			
+	}
+	
+
+	if(item->physical_maximum == item->physical_minimum){
+	    resolution = 1;
+	}
+	else {
+	    resolution = (item->logical_maximum - item->logical_minimum) / 
+		((item->physical_maximum - item->physical_minimum) * 
+		(usb_pow(10,(item->unit_exponent))));
+	}
+
+	offset = item->offset;
+	// FIXME
+	if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
+		
+		part_size = 0;
+
+		size_t i=0;
+		for(i=(size_t)(offset/8); i<=(size_t)(offset+item->size-1)/8; i++){
+			if(i == (size_t)(offset/8)) {
+				// the higher one
+				part_size = 8 - (offset % 8);
+				foo = data + i;
+				mask =  ((1 << (item->size-part_size))-1);
+				value = (*foo & mask);
+			}
+			else if(i == ((offset+item->size-1)/8)){
+				// the lower one
+				foo = data + i;
+				mask = ((1 << (item->size - part_size)) - 1) 
+					<< (8 - (item->size - part_size));
+
+				value = (((*foo & mask) >> (8 - 
+				    (item->size - part_size))) << part_size ) 
+				    + value;
+			}
+			else {
+				value = (*(data + 1) << (part_size + 8)) + value;
+				part_size += 8;
+			}
+		}
+	}
+	else {		
+		foo = data+(offset/8);
+		mask =  ((1 << item->size)-1) << (8-((offset%8)+item->size));
+		value = (*foo & mask) >> (8-((offset%8)+item->size));
+	}
+
+	if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
+		value = USB_HID_UINT32_TO_INT32(value, item->size);
+	}
+
+	return (int)(((value - item->logical_minimum) / resolution) + 
+		item->physical_minimum);
+	
+}
+
+/*---------------------------------------------------------------------------*/
+/* OUTPUT API */
+
+/** 
+ * Allocates output report buffer for output report
+ *
+ * @param parser Report parsed structure
+ * @param size Size of returned buffer
+ * @param report_id Report id of created output report
+ * @return Returns allocated output buffer for specified output
+ */
+uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, 
+	uint8_t report_id)
+{
+	if(report == NULL) {
+		*size = 0;
+		return NULL;
+	}
+
+	link_t *report_it = report->reports.next;
+	usb_hid_report_description_t *report_des = NULL;
+	while(report_it != &report->reports) {
+		report_des = list_get_instance(report_it, 
+			usb_hid_report_description_t, link);
+		
+		if((report_des->report_id == report_id) && 
+			(report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
+			break;
+		}
+
+		report_it = report_it->next;
+	}
+
+	if(report_des == NULL){
+		*size = 0;
+		return NULL;
+	}
+	else {
+		*size = (report_des->bit_length + (8 - 1))/8;
+		uint8_t *ret = malloc((*size) * sizeof(uint8_t));
+		memset(ret, 0, (*size) * sizeof(uint8_t));
+		return ret;
+	}
+}
+
+
+/** Frees output report buffer
+ *
+ * @param output Output report buffer
+ * @return void
+ */
+void usb_hid_report_output_free(uint8_t *output)
+
+{
+	if(output != NULL) {
+		free (output);
+	}
+}
+
+/** Makes the output report buffer for data given in the report structure
+ *
+ * @param parser Opaque report parser structure
+ * @param path Usage path specifing which parts of output will be set
+ * @param flags Usage path structure comparison flags
+ * @param buffer Output buffer
+ * @param size Size of output buffer
+ * @return Error code
+ */
+int usb_hid_report_output_translate(usb_hid_report_t *report, 
+	uint8_t report_id, uint8_t *buffer, size_t size)
+{
+	link_t *item;	
+	int32_t value=0;
+	int offset;
+	int length;
+	int32_t tmp_value;
+	
+	if(report == NULL) {
+		return EINVAL;
+	}
+
+	if(report->use_report_ids != 0) {
+		buffer[0] = report_id;		
+	}
+
+	usb_hid_report_description_t *report_des;
+	report_des = usb_hid_report_find_description (report, report_id, 
+		USB_HID_REPORT_TYPE_OUTPUT);
+	
+	if(report_des == NULL){
+		return EINVAL;
+	}
+
+	usb_hid_report_field_t *report_item;	
+	item = report_des->report_items.next;	
+	while(item != &report_des->report_items) {
+		report_item = list_get_instance(item, usb_hid_report_field_t, link);
+
+		value = usb_hid_translate_data_reverse(report_item, 
+			report_item->value);
+
+		offset = report_des->bit_length - report_item->offset - 1;
+		length = report_item->size;
+		
+		usb_log_debug("\ttranslated value: %x\n", value);
+
+		if((offset/8) == ((offset+length-1)/8)) {
+			// je to v jednom bytu
+			if(((size_t)(offset/8) >= size) || 
+				((size_t)(offset+length-1)/8) >= size) {
+				break; // TODO ErrorCode
+			}
+			size_t shift = 8 - offset%8 - length;
+			value = value << shift;							
+			value = value & (((1 << length)-1) << shift);
+				
+			uint8_t mask = 0;
+			mask = 0xff - (((1 << length) - 1) << shift);
+			buffer[offset/8] = (buffer[offset/8] & mask) | value;
+		}
+		else {
+			int i = 0;
+			uint8_t mask = 0;
+			for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
+				if(i == (offset/8)) {
+					tmp_value = value;
+					tmp_value = tmp_value & 
+						((1 << (8-(offset%8)))-1);
+
+					tmp_value = tmp_value << (offset%8);
+	
+					mask = ~(((1 << (8-(offset%8)))-1) << 
+							(offset%8));
+
+					buffer[i] = (buffer[i] & mask) | 
+						tmp_value;
+				}
+				else if (i == ((offset + length -1)/8)) {
+					
+					value = value >> (length - 
+						((offset + length) % 8));
+
+					value = value & ((1 << (length - 
+						((offset + length) % 8))) - 1);
+				
+					mask = (1 << (length - 
+						((offset + length) % 8))) - 1;
+
+					buffer[i] = (buffer[i] & mask) | value;
+				}
+				else {
+					buffer[i] = value & (0xFF << i);
+				}
+			}
+		}
+
+		// reset value
+		report_item->value = 0;
+		
+		item = item->next;
+	}
+	
+	return EOK;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Translate given data for putting them into the outoput report
+ * @param item Report item structure
+ * @param value Value to translate
+ * @return ranslated value
+ */
+uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 
+	int value)
+{
+	int ret=0;
+	int resolution;
+
+	if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
+		ret = item->logical_minimum;
+	}
+
+	if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
+		item->physical_minimum = item->logical_minimum;
+		item->physical_maximum = item->logical_maximum;			
+	}
+	
+	// variable item
+	if(item->physical_maximum == item->physical_minimum){
+	    resolution = 1;
+	}
+	else {
+	    resolution = (item->logical_maximum - item->logical_minimum) /
+		((item->physical_maximum - item->physical_minimum) *
+		(usb_pow(10,(item->unit_exponent))));
+	}
+
+	ret = ((value - item->physical_minimum) * resolution) + 
+		item->logical_minimum;
+
+	usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), \
+		ret(%x)\n", value, resolution, item->physical_minimum, 
+		item->logical_minimum, ret);
+	
+	if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
+		return USB_HID_INT32_TO_UINT32(ret, item->size);
+	}
+	return (int32_t)0 + ret;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Clones given state table
+ *
+ * @param item State table to clone
+ * @return Pointer to the cloned item
+ */
+usb_hid_report_item_t *usb_hid_report_item_clone(
+	const usb_hid_report_item_t *item)
+{
+	usb_hid_report_item_t *new_report_item;
+	
+	if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
+		return NULL;
+	}					
+	memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
+	link_initialize(&(new_report_item->link));
+
+	return new_report_item;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Function for sequence walking through the report. Returns next field in the
+ * report or the first one when no field is given.
+ *
+ * @param report Searched report structure
+ * @param field Current field. If NULL is given, the first one in the report
+ * is returned. Otherwise the next one i nthe list is returned.
+ * @param path Usage path specifying which fields wa are interested in. 
+ * @param flags Flags defining mode of usage paths comparison
+ * @param type Type of report we search.
+ * @retval NULL if no field is founded
+ * @retval Pointer to the founded report structure when founded
+ */
+usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, 
+	usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, 
+	usb_hid_report_type_t type)
+{
+	usb_hid_report_description_t *report_des = 
+		usb_hid_report_find_description(report, path->report_id, type);
+
+	link_t *field_it;
+	
+	if(report_des == NULL){
+		return NULL;
+	}
+
+	if(field == NULL){
+		field_it = report_des->report_items.next;
+	}
+	else {
+		field_it = field->link.next;
+	}
+
+	while(field_it != &report_des->report_items) {
+		field = list_get_instance(field_it, usb_hid_report_field_t, 
+			link);
+
+		if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
+			usb_hid_report_path_append_item (
+				field->collection_path, field->usage_page, 
+				field->usage);
+
+			if(usb_hid_report_compare_usage_path(
+				field->collection_path, path, flags) == EOK){
+
+				usb_hid_report_remove_last_item(
+					field->collection_path);
+
+				return field;
+			}
+			usb_hid_report_remove_last_item (
+				field->collection_path);
+		}
+		field_it = field_it->next;
+	}
+
+	return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Returns next report_id of report of specified type. If zero is given than
+ * first report_id of specified type is returned (0 is not legal value for
+ * repotr_id)
+ *
+ * @param report_id Current report_id, 0 if there is no current report_id
+ * @param type Type of searched report
+ * @param report Report structure inwhich we search
+ * @retval 0 if report structure is null or there is no specified report
+ * @retval report_id otherwise
+ */
+uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report, 
+	uint8_t report_id, usb_hid_report_type_t type)
+{
+	if(report == NULL){
+		return 0;
+	}
+
+	usb_hid_report_description_t *report_des;
+	link_t *report_it;
+	
+	if(report_id > 0) {
+		report_des = usb_hid_report_find_description(report, report_id, 
+			type);
+		if(report_des == NULL) {
+			return 0;
+		}
+		else {
+			report_it = report_des->link.next;
+		}	
+	}
+	else {
+		report_it = report->reports.next;
+	}
+
+	while(report_it != &report->reports) {
+		report_des = list_get_instance(report_it, 
+			usb_hid_report_description_t, link);
+
+		if(report_des->type == type){
+			return report_des->report_id;
+		}
+
+		report_it = report_it->next;
+	}
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Reset all local items in given state table
+ *
+ * @param report_item State table containing current state of report
+ * descriptor parsing
+ *
+ * @return void
+ */
+void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item)
+{
+	if(report_item == NULL)	{
+		return;
+	}
+	
+	report_item->usages_count = 0;
+	memset(report_item->usages, 0, USB_HID_MAX_USAGES);
+	
+	report_item->extended_usage_page = 0;
+	report_item->usage_minimum = 0;
+	report_item->usage_maximum = 0;
+	report_item->designator_index = 0;
+	report_item->designator_minimum = 0;
+	report_item->designator_maximum = 0;
+	report_item->string_index = 0;
+	report_item->string_minimum = 0;
+	report_item->string_maximum = 0;
+
+	return;
+}
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/hidpath.c
===================================================================
--- uspace/lib/usbhid/src/hidpath.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/hidpath.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2011 Matej Klonfar
+ * 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 libusbhid
+ * @{
+ */
+/** @file
+ * HID report descriptor and report data parser implementation.
+ */
+#include <usb/hid/hidparser.h>
+#include <errno.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <mem.h>
+#include <usb/debug.h>
+#include <assert.h>
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Compares two usages if they are same or not or one of the usages is not
+ * set.
+ *
+ * @param usage1
+ * @param usage2
+ * @return boolean
+ */
+#define USB_HID_SAME_USAGE(usage1, usage2)		\
+	((usage1 == usage2) || (usage1 == 0) || (usage2 == 0))
+
+/**
+ * Compares two usage pages if they are same or not or one of them is not set.
+ *
+ * @param page1
+ * @param page2
+ * @return boolean
+ */
+#define USB_HID_SAME_USAGE_PAGE(page1, page2)	\
+	((page1 == page2) || (page1 == 0) || (page2 == 0))
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Appends one item (couple of usage_path and usage) into the usage path
+ * structure
+ *
+ * @param usage_path Usage path structure
+ * @param usage_page Usage page constant
+ * @param usage Usage constant
+ * @return Error code
+ */
+int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path, 
+                                    int32_t usage_page, int32_t usage)
+{	
+	usb_hid_report_usage_path_t *item;
+
+	if(!(item=malloc(sizeof(usb_hid_report_usage_path_t)))) {
+		return ENOMEM;
+	}
+	list_initialize(&item->link);
+
+	item->usage = usage;
+	item->usage_page = usage_page;
+	item->flags = 0;
+	
+	list_append (&item->link, &usage_path->head);
+	usage_path->depth++;
+	return EOK;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Removes last item from the usage path structure
+ * @param usage_path 
+ * @return void
+ */
+void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
+{
+	usb_hid_report_usage_path_t *item;
+	
+	if(!list_empty(&usage_path->head)){
+		item = list_get_instance(usage_path->head.prev, 
+		                         usb_hid_report_usage_path_t, link);		
+		list_remove(usage_path->head.prev);
+		usage_path->depth--;
+		free(item);
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Nulls last item of the usage path structure.
+ *
+ * @param usage_path
+ * @return void
+ */
+void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
+{
+	usb_hid_report_usage_path_t *item;
+	
+	if(!list_empty(&usage_path->head)){	
+		item = list_get_instance(usage_path->head.prev, 
+			usb_hid_report_usage_path_t, link);
+
+		memset(item, 0, sizeof(usb_hid_report_usage_path_t));
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Modifies last item of usage path structure by given usage page or usage
+ *
+ * @param usage_path Opaque usage path structure
+ * @param tag Class of currently processed tag (Usage page tag falls into Global
+ * class but Usage tag into the Local)
+ * @param data Value of the processed tag
+ * @return void
+ */
+void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, 
+                                  int32_t tag, int32_t data)
+{
+	usb_hid_report_usage_path_t *item;
+	
+	if(!list_empty(&usage_path->head)){	
+		item = list_get_instance(usage_path->head.prev, 
+		                         usb_hid_report_usage_path_t, link);
+
+		switch(tag) {
+			case USB_HID_TAG_CLASS_GLOBAL:
+				item->usage_page = data;
+				break;
+			case USB_HID_TAG_CLASS_LOCAL:
+				item->usage = data;
+				break;
+		}
+	}
+	
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ *
+ *
+ *
+ *
+ */
+void usb_hid_print_usage_path(usb_hid_report_path_t *path)
+{
+	usb_log_debug("USAGE_PATH FOR RId(%d):\n", path->report_id);
+	usb_log_debug("\tLENGTH: %d\n", path->depth);
+
+	link_t *item = path->head.next;
+	usb_hid_report_usage_path_t *path_item;
+	while(item != &path->head) {
+
+		path_item = list_get_instance(item, usb_hid_report_usage_path_t, 
+			link);
+
+		usb_log_debug("\tUSAGE_PAGE: %X\n", path_item->usage_page);
+		usb_log_debug("\tUSAGE: %X\n", path_item->usage);
+		usb_log_debug("\tFLAGS: %d\n", path_item->flags);		
+		
+       	item = item->next;
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Compares two usage paths structures
+ *
+ *
+ * @param report_path usage path structure to compare with @path 
+ * @param path usage patrh structure to compare
+ * @param flags Flags determining the mode of comparison
+ * @return EOK if both paths are identical, non zero number otherwise
+ */
+int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path, 
+                                      usb_hid_report_path_t *path,
+                                      int flags)
+{
+	usb_hid_report_usage_path_t *report_item;
+	usb_hid_report_usage_path_t *path_item;
+
+	link_t *report_link;
+	link_t *path_link;
+
+	int only_page;
+
+	if(report_path->report_id != path->report_id) {
+		if(path->report_id != 0) {
+			return 1;
+		}
+	}
+
+	// Empty path match all others
+	if(path->depth == 0){
+		return EOK;
+	}
+
+
+	if((only_page = flags & USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY) != 0){
+		flags -= USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY;
+	}
+	
+	switch(flags){
+	/* path is somewhere in report_path */
+	case USB_HID_PATH_COMPARE_ANYWHERE:
+		if(path->depth != 1){
+			return 1;
+		}
+
+		report_link = report_path->head.next;
+		path_link = path->head.next;
+		path_item = list_get_instance(path_link, 
+			usb_hid_report_usage_path_t, link);
+
+		while(report_link != &report_path->head) {
+			report_item = list_get_instance(report_link, 
+				usb_hid_report_usage_path_t, link);
+				
+			if(USB_HID_SAME_USAGE_PAGE(report_item->usage_page, 
+				path_item->usage_page)){
+					
+				if(only_page == 0){
+					if(USB_HID_SAME_USAGE(
+						report_item->usage,
+						path_item->usage)) {
+							
+						return EOK;
+					}
+				}
+				else {
+					return EOK;
+				}
+			}
+
+			report_link = report_link->next;
+		}
+
+		return 1;
+		break;
+
+	/* the paths must be identical */
+	case USB_HID_PATH_COMPARE_STRICT:
+		if(report_path->depth != path->depth){
+			return 1;
+		}
+		
+	/* path is prefix of the report_path */
+	case USB_HID_PATH_COMPARE_BEGIN:
+	
+		report_link = report_path->head.next;
+		path_link = path->head.next;
+			
+		while((report_link != &report_path->head) && 
+		      (path_link != &path->head)) {
+					  
+			report_item = list_get_instance(report_link, 
+				usb_hid_report_usage_path_t, link);
+					  
+			path_item = list_get_instance(path_link,
+       				usb_hid_report_usage_path_t, link);
+
+			if(!USB_HID_SAME_USAGE_PAGE(report_item->usage_page, 
+				path_item->usage_page) || ((only_page == 0) && 
+			    !USB_HID_SAME_USAGE(report_item->usage, 
+				path_item->usage))) {
+			
+				return 1;
+			} 
+			else {
+				report_link = report_link->next;
+				path_link = path_link->next;			
+			}
+			
+				}
+
+		if((((flags & USB_HID_PATH_COMPARE_BEGIN) != 0) && 
+			(path_link == &path->head)) || 
+		   ((report_link == &report_path->head) && 
+			(path_link == &path->head))) {
+				
+			return EOK;
+		}
+		else {
+			return 1;
+		}						
+		break;
+
+	/* path is suffix of report_path */
+	case USB_HID_PATH_COMPARE_END:
+
+		report_link = report_path->head.prev;
+		path_link = path->head.prev;
+
+		if(list_empty(&path->head)){
+			return EOK;
+		}
+			
+		while((report_link != &report_path->head) && 
+		      (path_link != &path->head)) {
+						  
+			report_item = list_get_instance(report_link, 
+				usb_hid_report_usage_path_t, link);
+
+			path_item = list_get_instance(path_link, 
+				usb_hid_report_usage_path_t, link);		
+						  
+			if(!USB_HID_SAME_USAGE_PAGE(report_item->usage_page, 
+				path_item->usage_page) || ((only_page == 0) && 
+			    !USB_HID_SAME_USAGE(report_item->usage, 
+				path_item->usage))) {
+						
+					return 1;
+			} else {
+				report_link = report_link->prev;
+				path_link = path_link->prev;			
+			}
+
+		}
+
+		if(path_link == &path->head) {
+			return EOK;
+		}
+		else {
+			return 1;
+		}						
+			
+		break;
+
+	default:
+		return EINVAL;
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Allocates and initializes new usage path structure.
+ *
+ * @return Initialized usage path structure
+ */
+usb_hid_report_path_t *usb_hid_report_path(void)
+{
+	usb_hid_report_path_t *path;
+	path = malloc(sizeof(usb_hid_report_path_t));
+	if(path == NULL){
+		return NULL;
+	}
+	else {
+		path->depth = 0;
+		path->report_id = 0;
+		list_initialize(&path->link);
+		list_initialize(&path->head);
+		return path;
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Releases given usage path structure.
+ *
+ * @param path usage path structure to release
+ * @return void
+ */
+void usb_hid_report_path_free(usb_hid_report_path_t *path)
+{
+	while(!list_empty(&path->head)){
+		usb_hid_report_remove_last_item(path);
+	}
+
+	list_remove(&path->link);
+	free(path);
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Clone content of given usage path to the new one
+ *
+ * @param usage_path Usage path structure to clone
+ * @return New copy of given usage path structure
+ */
+usb_hid_report_path_t *usb_hid_report_path_clone(
+	usb_hid_report_path_t *usage_path)
+{
+	link_t *path_link;
+	usb_hid_report_usage_path_t *path_item;
+	usb_hid_report_usage_path_t *new_path_item;
+	usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
+
+	if(new_usage_path == NULL){
+		return NULL;
+	}
+
+	new_usage_path->report_id = usage_path->report_id;
+	
+	if(list_empty(&usage_path->head)){
+		return new_usage_path;
+	}
+
+	path_link = usage_path->head.next;
+	while(path_link != &usage_path->head) {
+		path_item = list_get_instance(path_link, 
+			usb_hid_report_usage_path_t, link);
+
+		new_path_item = malloc(sizeof(usb_hid_report_usage_path_t));
+		if(new_path_item == NULL) {
+			return NULL;
+		}
+		
+		list_initialize (&new_path_item->link);		
+		new_path_item->usage_page = path_item->usage_page;
+		new_path_item->usage = path_item->usage;		
+		new_path_item->flags = path_item->flags;		
+		
+		list_append(&new_path_item->link, &new_usage_path->head);
+		new_usage_path->depth++;
+
+		path_link = path_link->next;
+	}
+
+	return new_usage_path;
+}
+
+/*---------------------------------------------------------------------------*/
+/**
+ * Sets report id in usage path structure
+ *
+ * @param path Usage path structure
+ * @param report_id Report id to set
+ * @return Error code
+ */
+int usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, 
+	uint8_t report_id)
+{
+	if(path == NULL){
+		return EINVAL;
+	}
+
+	path->report_id = report_id;
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/hidreport.c
===================================================================
--- uspace/lib/usbhid/src/hidreport.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/hidreport.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,207 @@
+/*
+ * 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 libusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard device structure and API.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/debug.h>
+#include <usb/hid/hidparser.h>
+#include <usb/dev/dp.h>
+#include <usb/dev/driver.h>
+#include <usb/dev/pipes.h>
+#include <usb/hid/hid.h>
+#include <usb/descriptor.h>
+#include <usb/dev/request.h>
+
+#include <usb/hid/hidreport.h>
+
+static int usb_hid_get_report_descriptor(usb_device_t *dev, 
+    uint8_t **report_desc, size_t *size)
+{
+	assert(report_desc != NULL);
+	assert(size != NULL);
+	
+	usb_dp_parser_t parser =  {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+	
+	usb_dp_parser_data_t parser_data = {
+		.data = dev->descriptors.configuration,
+		.size = dev->descriptors.configuration_size,
+		.arg = NULL
+	};
+	
+	/*
+	 * First nested descriptor of the configuration descriptor.
+	 */
+	uint8_t *d = 
+	    usb_dp_get_nested_descriptor(&parser, &parser_data, 
+	    dev->descriptors.configuration);
+	
+	/*
+	 * Find the interface descriptor corresponding to our interface number.
+	 */
+	int i = 0;
+	while (d != NULL && i < dev->interface_no) {
+		d = usb_dp_get_sibling_descriptor(&parser, &parser_data, 
+		    dev->descriptors.configuration, d);
+		++i;
+	}
+	
+	if (d == NULL) {
+		usb_log_error("The %d. interface descriptor not found!\n",
+		    dev->interface_no);
+		return ENOENT;
+	}
+	
+	/*
+	 * First nested descriptor of the interface descriptor.
+	 */
+	uint8_t *iface_desc = d;
+	d = usb_dp_get_nested_descriptor(&parser, &parser_data, iface_desc);
+	
+	/*
+	 * Search through siblings until the HID descriptor is found.
+	 */
+	while (d != NULL && *(d + 1) != USB_DESCTYPE_HID) {
+		d = usb_dp_get_sibling_descriptor(&parser, &parser_data, 
+		    iface_desc, d);
+	}
+	
+	if (d == NULL) {
+		usb_log_fatal("No HID descriptor found!\n");
+		return ENOENT;
+	}
+	
+	if (*d != sizeof(usb_standard_hid_descriptor_t)) {
+		usb_log_error("HID descriptor has wrong size (%u, expected %zu"
+		    ")\n", *d, sizeof(usb_standard_hid_descriptor_t));
+		return EINVAL;
+	}
+	
+	usb_standard_hid_descriptor_t *hid_desc = 
+	    (usb_standard_hid_descriptor_t *)d;
+	
+	uint16_t length =  hid_desc->report_desc_info.length;
+	size_t actual_size = 0;
+
+	/*
+	 * Allocate space for the report descriptor.
+	 */
+	*report_desc = (uint8_t *)malloc(length);
+	if (*report_desc == NULL) {
+		usb_log_error("Failed to allocate space for Report descriptor."
+		    "\n");
+		return ENOMEM;
+	}
+	
+	usb_log_debug("Getting Report descriptor, expected size: %u\n", length);
+	
+	/*
+	 * Get the descriptor from the device.
+	 */
+	int rc = usb_request_get_descriptor(&dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
+	    USB_DESCTYPE_HID_REPORT, 0, dev->interface_no,
+	    *report_desc, length, &actual_size);
+
+	if (rc != EOK) {
+		free(*report_desc);
+		*report_desc = NULL;
+		return rc;
+	}
+
+	if (actual_size != length) {
+		free(*report_desc);
+		*report_desc = NULL;
+		usb_log_error("Report descriptor has wrong size (%zu, expected "
+		    "%u)\n", actual_size, length);
+		return EINVAL;
+	}
+	
+	*size = length;
+	
+	usb_log_debug("Done.\n");
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+int usb_hid_process_report_descriptor(usb_device_t *dev, 
+    usb_hid_report_t *report, uint8_t **report_desc, size_t *report_size)
+{
+	if (dev == NULL || report == NULL) {
+		usb_log_error("Failed to process Report descriptor: wrong "
+		    "parameters given.\n");
+		return EINVAL;
+	}
+	
+//	uint8_t *report_desc = NULL;
+//	size_t report_size;
+	
+	int rc = usb_hid_get_report_descriptor(dev, report_desc, report_size);
+	
+	if (rc != EOK) {
+		usb_log_error("Problem with getting Report descriptor: %s.\n",
+		    str_error(rc));
+		if (*report_desc != NULL) {
+			free(*report_desc);
+			*report_desc = NULL;
+		}
+		return rc;
+	}
+	
+	assert(*report_desc != NULL);
+	
+	rc = usb_hid_parse_report_descriptor(report, *report_desc, *report_size);
+	if (rc != EOK) {
+		usb_log_error("Problem parsing Report descriptor: %s.\n",
+		    str_error(rc));
+		free(*report_desc);
+		*report_desc = NULL;
+		return rc;
+	}
+	
+	usb_hid_descriptor_print(report);
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbhid/src/hidreq.c
===================================================================
--- uspace/lib/usbhid/src/hidreq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhid/src/hidreq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,379 @@
+/*
+ * 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
+ * HID class-specific requests.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/hid/hid.h>
+#include <usb/debug.h>
+#include <usb/dev/request.h>
+#include <usb/dev/pipes.h>
+
+#include <usb/hid/request.h>
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 function usb_control_request_set().
+ */
+int usbhid_req_set_report(usb_pipe_t *ctrl_pipe, int iface_no,
+    usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size)
+{
+	if (ctrl_pipe == NULL) {
+		usb_log_warning("usbhid_req_set_report(): no pipe given.\n");
+		return EINVAL;
+	}
+	
+	if (iface_no < 0) {
+		usb_log_warning("usbhid_req_set_report(): no interface given."
+		    "\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc;
+	
+	uint16_t value = 0;
+	value |= (type << 8);
+
+	usb_log_debug("Sending Set_Report request to the device.\n");
+	
+	rc = usb_control_request_set(ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_SET_REPORT, value, iface_no, buffer, buf_size);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return 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 function usb_control_request_set().
+ */
+int usbhid_req_set_protocol(usb_pipe_t *ctrl_pipe, int iface_no,
+    usb_hid_protocol_t protocol)
+{
+	if (ctrl_pipe == NULL) {
+		usb_log_warning("usbhid_req_set_report(): no pipe given.\n");
+		return EINVAL;
+	}
+	
+	if (iface_no < 0) {
+		usb_log_warning("usbhid_req_set_report(): no interface given."
+		    "\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc;
+
+	usb_log_debug("Sending Set_Protocol request to the device ("
+	    "protocol: %d, iface: %d).\n", protocol, iface_no);
+	
+	rc = usb_control_request_set(ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_SET_PROTOCOL, protocol, iface_no, NULL, 0);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * 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 function usb_control_request_set().
+ */
+int usbhid_req_set_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t duration)
+{
+	if (ctrl_pipe == NULL) {
+		usb_log_warning("usbhid_req_set_report(): no pipe given.\n");
+		return EINVAL;
+	}
+	
+	if (iface_no < 0) {
+		usb_log_warning("usbhid_req_set_report(): no interface given."
+		    "\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc;
+
+	usb_log_debug("Sending Set_Idle request to the device ("
+	    "duration: %u, iface: %d).\n", duration, iface_no);
+	
+	uint16_t value = duration << 8;
+	
+	rc = usb_control_request_set(ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_SET_IDLE, value, iface_no, NULL, 0);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return 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 function usb_control_request_set().
+ */
+int usbhid_req_get_report(usb_pipe_t *ctrl_pipe, int iface_no, 
+    usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size, 
+    size_t *actual_size)
+{
+	if (ctrl_pipe == NULL) {
+		usb_log_warning("usbhid_req_set_report(): no pipe given.\n");
+		return EINVAL;
+	}
+	
+	if (iface_no < 0) {
+		usb_log_warning("usbhid_req_set_report(): no interface given."
+		    "\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc;
+
+	uint16_t value = 0;
+	value |= (type << 8);
+	
+	usb_log_debug("Sending Get_Report request to the device.\n");
+	
+	rc = usb_control_request_get(ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_GET_REPORT, value, iface_no, buffer, buf_size,
+	    actual_size);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return 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 function usb_control_request_set().
+ */
+int usbhid_req_get_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 
+    usb_hid_protocol_t *protocol)
+{
+	if (ctrl_pipe == NULL) {
+		usb_log_warning("usbhid_req_set_report(): no pipe given.\n");
+		return EINVAL;
+	}
+	
+	if (iface_no < 0) {
+		usb_log_warning("usbhid_req_set_report(): no interface given."
+		    "\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc;	
+
+	usb_log_debug("Sending Get_Protocol request to the device ("
+	    "iface: %d).\n", iface_no);
+	
+	uint8_t buffer[1];
+	size_t actual_size = 0;
+	
+	rc = usb_control_request_get(ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_GET_PROTOCOL, 0, iface_no, buffer, 1, &actual_size);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return 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_pipe_start_session(), usb_pipe_end_session(),
+ *         usb_control_request_set().
+ */
+int usbhid_req_get_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t *duration)
+{
+	if (ctrl_pipe == NULL) {
+		usb_log_warning("usbhid_req_set_report(): no pipe given.\n");
+		return EINVAL;
+	}
+	
+	if (iface_no < 0) {
+		usb_log_warning("usbhid_req_set_report(): no interface given."
+		    "\n");
+		return EINVAL;
+	}
+	
+	/*
+	 * No need for checking other parameters, as they are checked in
+	 * the called function (usb_control_request_set()).
+	 */
+	
+	int rc;
+
+	usb_log_debug("Sending Get_Idle request to the device ("
+	    "iface: %d).\n", iface_no);
+	
+	uint16_t value = 0;
+	uint8_t buffer[1];
+	size_t actual_size = 0;
+	
+	rc = usb_control_request_get(ctrl_pipe, 
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	    USB_HIDREQ_GET_IDLE, value, iface_no, buffer, 1, 
+	    &actual_size);
+
+	if (rc != EOK) {
+		usb_log_warning("Error sending output report to the keyboard: "
+		    "%s.\n", str_error(rc));
+		return 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/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusbhost
+EXTRA_CFLAGS += \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include \
+	-Iinclude
+
+SOURCES = \
+	src/batch.c \
+	src/device_keeper.c \
+	src/endpoint.c \
+	src/usb_endpoint_manager.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbhost/include/usb/host/batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/batch.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/include/usb/host/batch.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,101 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * USB transfer transaction structures.
+ */
+#ifndef LIBUSBHOST_HOST_BATCH_H
+#define LIBUSBHOST_HOST_BATCH_H
+
+#include <adt/list.h>
+
+#include <usbhc_iface.h>
+#include <usb/usb.h>
+#include <usb/host/endpoint.h>
+
+typedef struct usb_transfer_batch usb_transfer_batch_t;
+struct usb_transfer_batch {
+	endpoint_t *ep;
+	link_t link;
+	usbhc_iface_transfer_in_callback_t callback_in;
+	usbhc_iface_transfer_out_callback_t callback_out;
+	void *arg;
+	char *buffer;
+	char *data_buffer;
+	size_t buffer_size;
+	char *setup_buffer;
+	size_t setup_size;
+	size_t transfered_size;
+	void (*next_step)(usb_transfer_batch_t *);
+	int error;
+	ddf_fun_t *fun;
+	void *private_data;
+	void (*private_data_dtor)(void *p_data);
+};
+
+void usb_transfer_batch_init(
+    usb_transfer_batch_t *instance,
+    endpoint_t *ep,
+    char *buffer,
+    char *data_buffer,
+    size_t buffer_size,
+    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,
+    ddf_fun_t *fun,
+    void *private_data,
+    void (*private_data_dtor)(void *p_data)
+);
+
+void usb_transfer_batch_call_in_and_dispose(usb_transfer_batch_t *instance);
+void usb_transfer_batch_call_out_and_dispose(usb_transfer_batch_t *instance);
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance);
+void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);
+
+static inline void usb_transfer_batch_finish_error(
+    usb_transfer_batch_t *instance, int error)
+{
+	assert(instance);
+	instance->error = error;
+	usb_transfer_batch_finish(instance);
+}
+
+static inline usb_transfer_batch_t *usb_transfer_batch_from_link(link_t *l)
+{
+	assert(l);
+	return list_get_instance(l, usb_transfer_batch_t, link);
+}
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/device_keeper.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/device_keeper.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/include/usb/host/device_keeper.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,90 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * Device keeper structure and functions.
+ *
+ * Typical USB host controller needs to keep track of various settings for
+ * each device that is connected to it.
+ * State of toggle bit, device speed etc. etc.
+ * This structure shall simplify the management.
+ */
+#ifndef LIBUSBHOST_HOST_DEVICE_KEEPER_H
+#define LIBUSBHOST_HOST_DEVICE_KEEPER_H
+
+#include <adt/list.h>
+#include <devman.h>
+#include <fibril_synch.h>
+#include <usb/usb.h>
+#include <usb/host/endpoint.h>
+
+/** Number of USB address for array dimensions. */
+#define USB_ADDRESS_COUNT (USB11_ADDRESS_MAX + 1)
+
+/** Information about attached USB device. */
+struct usb_device_info {
+	usb_speed_t speed;
+	bool occupied;
+	devman_handle_t handle;
+};
+
+/** Host controller device keeper.
+ * You shall not access members directly but only using functions below.
+ */
+typedef struct {
+	struct usb_device_info devices[USB_ADDRESS_COUNT];
+	fibril_mutex_t guard;
+	usb_address_t last_address;
+} usb_device_keeper_t;
+
+void usb_device_keeper_init(usb_device_keeper_t *instance);
+
+usb_address_t device_keeper_get_free_address(usb_device_keeper_t *instance,
+    usb_speed_t speed);
+
+void usb_device_keeper_bind(usb_device_keeper_t *instance,
+    usb_address_t address, devman_handle_t handle);
+
+void usb_device_keeper_release(usb_device_keeper_t *instance,
+    usb_address_t address);
+
+usb_address_t usb_device_keeper_find(usb_device_keeper_t *instance,
+    devman_handle_t handle);
+
+bool usb_device_keeper_find_by_address(usb_device_keeper_t *instance,
+    usb_address_t address, devman_handle_t *handle);
+
+usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
+    usb_address_t address);
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,86 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ *
+ */
+#ifndef LIBUSBHOST_HOST_ENDPOINT_H
+#define LIBUSBHOST_HOST_ENDPOINT_H
+
+#include <assert.h>
+#include <bool.h>
+#include <adt/list.h>
+#include <fibril_synch.h>
+
+#include <usb/usb.h>
+
+typedef struct endpoint {
+	usb_address_t address;
+	usb_endpoint_t endpoint;
+	usb_direction_t direction;
+	usb_transfer_type_t transfer_type;
+	usb_speed_t speed;
+	size_t max_packet_size;
+	unsigned toggle:1;
+	fibril_mutex_t guard;
+	fibril_condvar_t avail;
+	volatile bool active;
+	struct {
+		void *data;
+		int (*toggle_get)(void *);
+		void (*toggle_set)(void *, int);
+	} hc_data;
+} endpoint_t;
+
+int endpoint_init(endpoint_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction,
+    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size);
+
+void endpoint_destroy(endpoint_t *instance);
+
+void endpoint_set_hc_data(endpoint_t *instance,
+    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int));
+
+void endpoint_clear_hc_data(endpoint_t *instance);
+
+void endpoint_use(endpoint_t *instance);
+
+void endpoint_release(endpoint_t *instance);
+
+int endpoint_toggle_get(endpoint_t *instance);
+
+void endpoint_toggle_set(endpoint_t *instance, int toggle);
+
+void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target);
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,106 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * Device keeper structure and functions.
+ *
+ * Typical USB host controller needs to keep track of various settings for
+ * each device that is connected to it.
+ * State of toggle bit, device speed etc. etc.
+ * This structure shall simplify the management.
+ */
+#ifndef LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
+#define LIBUSBHOST_HOST_YSB_ENDPOINT_MANAGER_H
+
+#include <stdlib.h>
+#include <adt/hash_table.h>
+#include <fibril_synch.h>
+#include <usb/usb.h>
+#include <usb/host/endpoint.h>
+
+#define BANDWIDTH_TOTAL_USB11 12000000
+#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
+
+typedef struct usb_endpoint_manager {
+	hash_table_t ep_table;
+	fibril_mutex_t guard;
+	fibril_condvar_t change;
+	size_t free_bw;
+} usb_endpoint_manager_t;
+
+size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
+    size_t size, size_t max_packet_size);
+
+int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
+    size_t available_bandwidth);
+
+void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance);
+
+int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
+    endpoint_t *ep, size_t data_size);
+
+int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t ep, usb_direction_t direction);
+
+endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t ep, usb_direction_t direction,
+    size_t *bw);
+
+void usb_endpoint_manager_reset_if_need(
+    usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
+
+static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
+    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
+    size_t data_size)
+{
+	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	if (ep == NULL)
+		return ENOMEM;
+
+	int ret = endpoint_init(ep, address, endpoint, direction, type, speed,
+	    max_packet_size);
+	if (ret != EOK) {
+		free(ep);
+		return ret;
+	}
+
+	ret = usb_endpoint_manager_register_ep(instance, ep, data_size);
+	if (ret != EOK) {
+		endpoint_destroy(ep);
+		return ret;
+	}
+	return EOK;
+}
+#endif
+/**
+ * @}
+ */
+
Index: uspace/lib/usbhost/src/batch.c
===================================================================
--- uspace/lib/usbhost/src/batch.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/src/batch.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,176 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * USB transfer transaction structures (implementation).
+ */
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+#include <usb/host/batch.h>
+
+void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
+void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
+
+void usb_transfer_batch_init(
+    usb_transfer_batch_t *instance,
+    endpoint_t *ep,
+    char *buffer,
+    char *data_buffer,
+    size_t buffer_size,
+    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,
+    ddf_fun_t *fun,
+    void *private_data,
+    void (*private_data_dtor)(void *p_data)
+    )
+{
+	assert(instance);
+	link_initialize(&instance->link);
+	instance->ep = ep;
+	instance->callback_in = func_in;
+	instance->callback_out = func_out;
+	instance->arg = arg;
+	instance->buffer = buffer;
+	instance->data_buffer = data_buffer;
+	instance->buffer_size = buffer_size;
+	instance->setup_buffer = setup_buffer;
+	instance->setup_size = setup_size;
+	instance->fun = fun;
+	instance->private_data = private_data;
+	instance->private_data_dtor = private_data_dtor;
+	instance->transfered_size = 0;
+	instance->next_step = NULL;
+	instance->error = EOK;
+	endpoint_use(instance->ep);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function, calls callback and correctly destroys batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_call_in_and_dispose(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_transfer_batch_call_in(instance);
+	usb_transfer_batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Helper function calls callback and correctly destroys batch structure.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_call_out_and_dispose(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_transfer_batch_call_out(instance);
+	usb_transfer_batch_dispose(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** Mark batch as finished and continue with next step.
+ *
+ * @param[in] instance Batch structure to use.
+ *
+ */
+void usb_transfer_batch_finish(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	assert(instance->ep);
+	endpoint_release(instance->ep);
+	instance->next_step(instance);
+}
+/*----------------------------------------------------------------------------*/
+/** 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 usb_transfer_batch_call_in(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	assert(instance->callback_in);
+	assert(instance->ep);
+
+	/* We are data in, we need data */
+	memcpy(instance->buffer, instance->data_buffer, instance->buffer_size);
+
+	usb_log_debug("Batch(%p) done (T%d.%d, %s %s in, %zuB): %s (%d).\n",
+	    instance, instance->ep->address, instance->ep->endpoint,
+	    usb_str_speed(instance->ep->speed),
+	    usb_str_transfer_type_short(instance->ep->transfer_type),
+	    instance->transfered_size, str_error(instance->error),
+	    instance->error);
+
+	instance->callback_in(instance->fun, instance->error,
+	    instance->transfered_size, instance->arg);
+}
+/*----------------------------------------------------------------------------*/
+/** Get error status and call callback out.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_call_out(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	assert(instance->callback_out);
+
+	usb_log_debug("Batch(%p) done (T%d.%d, %s %s out): %s (%d).\n",
+	    instance, instance->ep->address, instance->ep->endpoint,
+	    usb_str_speed(instance->ep->speed),
+	    usb_str_transfer_type_short(instance->ep->transfer_type),
+	    str_error(instance->error), instance->error);
+
+	instance->callback_out(instance->fun,
+	    instance->error, instance->arg);
+}
+/*----------------------------------------------------------------------------*/
+/** Correctly dispose all used data structures.
+ *
+ * @param[in] instance Batch structure to use.
+ */
+void usb_transfer_batch_dispose(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	usb_log_debug("Batch(%p) disposing.\n", instance);
+	if (instance->private_data) {
+		assert(instance->private_data_dtor);
+		instance->private_data_dtor(instance->private_data);
+	}
+	free(instance);
+}
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/device_keeper.c
===================================================================
--- uspace/lib/usbhost/src/device_keeper.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/src/device_keeper.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,208 @@
+/*
+ * 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 libusbhost
+ * @{
+ */
+/** @file
+ * Device keeper structure and functions (implementation).
+ */
+#include <assert.h>
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/host/device_keeper.h>
+
+/*----------------------------------------------------------------------------*/
+/** Initialize device keeper structure.
+ *
+ * @param[in] instance Memory place to initialize.
+ *
+ * Set all values to false/0.
+ */
+void usb_device_keeper_init(usb_device_keeper_t *instance)
+{
+	assert(instance);
+	unsigned i = 0;
+	for (; i < USB_ADDRESS_COUNT; ++i) {
+		instance->devices[i].occupied = false;
+		instance->devices[i].handle = 0;
+		instance->devices[i].speed = USB_SPEED_MAX;
+	}
+	// TODO: is this hack enough?
+	// (it is needed to allow smooth registration at default address)
+	instance->devices[0].occupied = true;
+	instance->last_address = 0;
+	fibril_mutex_initialize(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** 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_get_free_address(
+    usb_device_keeper_t *instance, usb_speed_t speed)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+
+	usb_address_t new_address = instance->last_address;
+	do {
+		++new_address;
+		if (new_address > USB11_ADDRESS_MAX)
+			new_address = 1;
+		if (new_address == instance->last_address) {
+			fibril_mutex_unlock(&instance->guard);
+			return ENOSPC;
+		}
+	} while (instance->devices[new_address].occupied);
+
+	assert(new_address != USB_ADDRESS_DEFAULT);
+	assert(instance->devices[new_address].occupied == false);
+
+	instance->devices[new_address].occupied = true;
+	instance->devices[new_address].speed = speed;
+	instance->last_address = new_address;
+
+	fibril_mutex_unlock(&instance->guard);
+	return new_address;
+}
+/*----------------------------------------------------------------------------*/
+/** 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 usb_device_keeper_bind(usb_device_keeper_t *instance,
+    usb_address_t address, devman_handle_t handle)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+
+	assert(address > 0);
+	assert(address <= USB11_ADDRESS_MAX);
+	assert(instance->devices[address].occupied);
+
+	instance->devices[address].handle = handle;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** Release used USB address.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] address Device address
+ */
+void usb_device_keeper_release(
+    usb_device_keeper_t *instance, usb_address_t address)
+{
+	assert(instance);
+	assert(address > 0);
+	assert(address <= USB11_ADDRESS_MAX);
+
+	fibril_mutex_lock(&instance->guard);
+	assert(instance->devices[address].occupied);
+
+	instance->devices[address].occupied = false;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+/** 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 usb_device_keeper_find(
+    usb_device_keeper_t *instance, devman_handle_t handle)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	usb_address_t address = 1;
+	while (address <= USB11_ADDRESS_MAX) {
+		if (instance->devices[address].handle == handle) {
+			assert(instance->devices[address].occupied);
+			fibril_mutex_unlock(&instance->guard);
+			return address;
+		}
+		++address;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	return ENOENT;
+}
+
+/** Find devman handle assigned to USB address.
+ * Intentionally refuse to find handle of default address.
+ *
+ * @param[in] instance Device keeper structure to use.
+ * @param[in] address Address the caller wants to find.
+ * @param[out] handle Where to store found handle.
+ * @return Whether such address is currently occupied.
+ */
+bool usb_device_keeper_find_by_address(usb_device_keeper_t *instance,
+    usb_address_t address, devman_handle_t *handle)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
+		fibril_mutex_unlock(&instance->guard);
+		return false;
+	}
+	if (!instance->devices[address].occupied) {
+		fibril_mutex_unlock(&instance->guard);
+		return false;
+	}
+
+	if (handle != NULL) {
+		*handle = instance->devices[address].handle;
+	}
+
+	fibril_mutex_unlock(&instance->guard);
+	return true;
+}
+
+/*----------------------------------------------------------------------------*/
+/** 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 usb_device_keeper_get_speed(
+    usb_device_keeper_t *instance, usb_address_t address)
+{
+	assert(instance);
+	assert(address >= 0);
+	assert(address <= USB11_ADDRESS_MAX);
+
+	return instance->devices[address].speed;
+}
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,130 @@
+/*
+ * 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
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <usb/host/endpoint.h>
+
+int endpoint_init(endpoint_t *instance, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction,
+    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size)
+{
+	assert(instance);
+	instance->address = address;
+	instance->endpoint = endpoint;
+	instance->direction = direction;
+	instance->transfer_type = type;
+	instance->speed = speed;
+	instance->max_packet_size = max_packet_size;
+	instance->toggle = 0;
+	instance->active = false;
+	fibril_mutex_initialize(&instance->guard);
+	fibril_condvar_initialize(&instance->avail);
+	endpoint_clear_hc_data(instance);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_destroy(endpoint_t *instance)
+{
+	assert(instance);
+	assert(!instance->active);
+	free(instance);
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_set_hc_data(endpoint_t *instance,
+    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int))
+{
+	assert(instance);
+	instance->hc_data.data = data;
+	instance->hc_data.toggle_get = toggle_get;
+	instance->hc_data.toggle_set = toggle_set;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_clear_hc_data(endpoint_t *instance)
+{
+	assert(instance);
+	instance->hc_data.data = NULL;
+	instance->hc_data.toggle_get = NULL;
+	instance->hc_data.toggle_set = NULL;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_use(endpoint_t *instance)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	while (instance->active)
+		fibril_condvar_wait(&instance->avail, &instance->guard);
+	instance->active = true;
+	fibril_mutex_unlock(&instance->guard);
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_release(endpoint_t *instance)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	instance->active = false;
+	fibril_mutex_unlock(&instance->guard);
+	fibril_condvar_signal(&instance->avail);
+}
+/*----------------------------------------------------------------------------*/
+int endpoint_toggle_get(endpoint_t *instance)
+{
+	assert(instance);
+	if (instance->hc_data.toggle_get)
+		instance->toggle =
+		    instance->hc_data.toggle_get(instance->hc_data.data);
+	return (int)instance->toggle;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_toggle_set(endpoint_t *instance, int toggle)
+{
+	assert(instance);
+	assert(toggle == 0 || toggle == 1);
+	if (instance->hc_data.toggle_set)
+		instance->hc_data.toggle_set(instance->hc_data.data, toggle);
+	instance->toggle = toggle;
+}
+/*----------------------------------------------------------------------------*/
+void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target)
+{
+	assert(instance);
+	if (instance->address == target.address &&
+	    (instance->endpoint == target.endpoint || target.endpoint == 0))
+		endpoint_toggle_set(instance, 0);
+}
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/usb_endpoint_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights eps.
+ *
+ * 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.
+ */
+
+#include <bool.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+#include <usb/host/usb_endpoint_manager.h>
+
+#define BUCKET_COUNT 7
+
+#define MAX_KEYS (3)
+typedef struct {
+	link_t link;
+	size_t bw;
+	endpoint_t *ep;
+} node_t;
+/*----------------------------------------------------------------------------*/
+static hash_index_t node_hash(unsigned long key[])
+{
+	hash_index_t hash = 0;
+	unsigned i = 0;
+	for (;i < MAX_KEYS; ++i) {
+		hash ^= key[i];
+	}
+	hash %= BUCKET_COUNT;
+	return hash;
+}
+/*----------------------------------------------------------------------------*/
+static int node_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	assert(item);
+	node_t *node = hash_table_get_instance(item, node_t, link);
+	assert(node);
+	assert(node->ep);
+	bool match = true;
+	switch (keys) {
+	case 3:
+		match = match && (key[2] == node->ep->direction);
+	case 2:
+		match = match && (key[1] == (unsigned long)node->ep->endpoint);
+	case 1:
+		match = match && (key[0] == (unsigned long)node->ep->address);
+		break;
+	default:
+		match = false;
+	}
+	return match;
+}
+/*----------------------------------------------------------------------------*/
+static void node_remove(link_t *item)
+{
+	assert(item);
+	node_t *node = hash_table_get_instance(item, node_t, link);
+	endpoint_destroy(node->ep);
+	free(node);
+}
+/*----------------------------------------------------------------------------*/
+static void node_toggle_reset_filtered(link_t *item, void *arg)
+{
+	assert(item);
+	node_t *node = hash_table_get_instance(item, node_t, link);
+	usb_target_t *target = arg;
+	endpoint_toggle_reset_filtered(node->ep, *target);
+}
+/*----------------------------------------------------------------------------*/
+static hash_table_operations_t op = {
+	.hash = node_hash,
+	.compare = node_compare,
+	.remove_callback = node_remove,
+};
+/*----------------------------------------------------------------------------*/
+size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
+    size_t size, size_t max_packet_size)
+{
+	/* We care about bandwidth only for interrupt and isochronous. */
+	if ((type != USB_TRANSFER_INTERRUPT)
+	    && (type != USB_TRANSFER_ISOCHRONOUS)) {
+		return 0;
+	}
+
+	const unsigned packet_count =
+	    (size + max_packet_size - 1) / max_packet_size;
+	/* TODO: It may be that ISO and INT transfers use only one data packet
+	 * per transaction, but I did not find text in UB spec that confirms
+	 * this */
+	/* NOTE: All data packets will be considered to be max_packet_size */
+	switch (speed)
+	{
+	case USB_SPEED_LOW:
+		assert(type == USB_TRANSFER_INTERRUPT);
+		/* Protocol overhead 13B
+		 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
+		 * CRC bytes, and a 3-byte interpacket delay)
+		 * see USB spec page 45-46. */
+		/* Speed penalty 8: low speed is 8-times slower*/
+		return packet_count * (13 + max_packet_size) * 8;
+	case USB_SPEED_FULL:
+		/* Interrupt transfer overhead see above
+		 * or page 45 of USB spec */
+		if (type == USB_TRANSFER_INTERRUPT)
+			return packet_count * (13 + max_packet_size);
+
+		assert(type == USB_TRANSFER_ISOCHRONOUS);
+		/* Protocol overhead 9B
+		 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
+		 * bytes, and a 1-byte interpacket delay)
+		 * see USB spec page 42 */
+		return packet_count * (9 + max_packet_size);
+	default:
+		return 0;
+	}
+}
+/*----------------------------------------------------------------------------*/
+int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
+    size_t available_bandwidth)
+{
+	assert(instance);
+	fibril_mutex_initialize(&instance->guard);
+	fibril_condvar_initialize(&instance->change);
+	instance->free_bw = available_bandwidth;
+	bool ht =
+	    hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
+	return ht ? EOK : ENOMEM;
+}
+/*----------------------------------------------------------------------------*/
+void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
+{
+	hash_table_destroy(&instance->ep_table);
+}
+/*----------------------------------------------------------------------------*/
+int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
+    endpoint_t *ep, size_t data_size)
+{
+	assert(ep);
+	size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type,
+	    data_size, ep->max_packet_size);
+	assert(instance);
+
+	unsigned long key[MAX_KEYS] =
+	    {ep->address, ep->endpoint, ep->direction};
+	fibril_mutex_lock(&instance->guard);
+
+	link_t *item =
+	    hash_table_find(&instance->ep_table, key);
+	if (item != NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return EEXISTS;
+	}
+
+	if (bw > instance->free_bw) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOSPC;
+	}
+
+	node_t *node = malloc(sizeof(node_t));
+	if (node == NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOMEM;
+	}
+
+	node->bw = bw;
+	node->ep = ep;
+	link_initialize(&node->link);
+
+	hash_table_insert(&instance->ep_table, key, &node->link);
+	instance->free_bw -= bw;
+	fibril_mutex_unlock(&instance->guard);
+	fibril_condvar_broadcast(&instance->change);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	unsigned long key[MAX_KEYS] = {address, endpoint, direction};
+
+	fibril_mutex_lock(&instance->guard);
+	link_t *item = hash_table_find(&instance->ep_table, key);
+	if (item == NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return EINVAL;
+	}
+
+	node_t *node = hash_table_get_instance(item, node_t, link);
+	if (node->ep->active)
+		return EBUSY;
+
+	instance->free_bw += node->bw;
+	hash_table_remove(&instance->ep_table, key, MAX_KEYS);
+
+	fibril_mutex_unlock(&instance->guard);
+	fibril_condvar_broadcast(&instance->change);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
+    size_t *bw)
+{
+	assert(instance);
+	unsigned long key[MAX_KEYS] = {address, endpoint, direction};
+
+	fibril_mutex_lock(&instance->guard);
+	link_t *item = hash_table_find(&instance->ep_table, key);
+	if (item == NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return NULL;
+	}
+	node_t *node = hash_table_get_instance(item, node_t, link);
+	if (bw)
+		*bw = node->bw;
+
+	fibril_mutex_unlock(&instance->guard);
+	return node->ep;
+}
+/*----------------------------------------------------------------------------*/
+/** 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 usb_endpoint_manager_reset_if_need(
+    usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data)
+{
+	assert(instance);
+	if (target.endpoint > 15 || target.endpoint < 0
+	    || target.address >= USB11_ADDRESS_MAX || target.address < 0) {
+		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 */
+			usb_target_t reset_target =
+			    { .address = target.address, data[4] };
+			fibril_mutex_lock(&instance->guard);
+			hash_table_apply(&instance->ep_table,
+			    node_toggle_reset_filtered, &reset_target);
+			fibril_mutex_unlock(&instance->guard);
+		}
+	break;
+
+	case 0x9: /* set configuration */
+	case 0x11: /* set interface */
+		/* target must be device */
+		if ((data[0] & 0xf) == 0) {
+			usb_target_t reset_target =
+			    { .address = target.address, 0 };
+			fibril_mutex_lock(&instance->guard);
+			hash_table_apply(&instance->ep_table,
+			    node_toggle_reset_filtered, &reset_target);
+			fibril_mutex_unlock(&instance->guard);
+		}
+	break;
+	}
+}
Index: uspace/lib/usbvirt/Makefile
===================================================================
--- uspace/lib/usbvirt/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libusbvirt
+
+EXTRA_CFLAGS = \
+	-I$(LIBDRV_PREFIX)/include \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-Iinclude
+
+SOURCES = \
+	src/ctrltransfer.c \
+	src/device.c \
+	src/ipc_dev.c \
+	src/ipc_hc.c \
+	src/stdreq.c \
+	src/transfer.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbvirt/include/usbvirt/device.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/device.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/include/usbvirt/device.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,221 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device.
+ */
+
+#ifndef LIBUSBVIRT_DEVICE_H_
+#define LIBUSBVIRT_DEVICE_H_
+
+#include <usb/usb.h>
+#include <usb/dev/request.h>
+#include <async.h>
+
+/** Maximum number of endpoints supported by virtual USB. */
+#define USBVIRT_ENDPOINT_MAX 16
+
+typedef struct usbvirt_device usbvirt_device_t;
+
+/** Callback for data to device (OUT transaction).
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param endpoint Target endpoint number.
+ * @param transfer_type Transfer type.
+ * @param buffer Data buffer.
+ * @param buffer_size Size of the buffer in bytes.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_data_to_device_t)(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
+    void *buffer, size_t buffer_size);
+
+/** Callback for data from device (IN transaction).
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param endpoint Target endpoint number.
+ * @param transfer_type Transfer type.
+ * @param buffer Data buffer to write answer to.
+ * @param buffer_size Size of the buffer in bytes.
+ * @param act_buffer_size Write here how many bytes were actually written.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_data_from_device_t)(usbvirt_device_t *dev,
+    usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
+    void *buffer, size_t buffer_size, size_t *act_buffer_size);
+
+/** Callback for control transfer on endpoint zero.
+ *
+ * Notice that size of the data buffer is expected to be read from the
+ * setup packet.
+ *
+ * @param dev Virtual device to which the transaction belongs.
+ * @param setup_packet Standard setup packet.
+ * @param data Data (might be NULL).
+ * @param act_data_size Size of returned data in bytes.
+ * @return Error code.
+ */
+typedef int (*usbvirt_on_control_t)(usbvirt_device_t *dev,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_data_size);
+
+/** Callback for control request on a virtual USB device.
+ *
+ * See usbvirt_control_reply_helper() for simple way of answering
+ * control read requests.
+ */
+typedef struct {
+	/** Request direction (in or out). */
+	usb_direction_t req_direction;
+	/** Request recipient (device, interface or endpoint). */
+	usb_request_recipient_t req_recipient;
+	/** Request type (standard, class or vendor). */
+	usb_request_type_t req_type;
+	/** Actual request code. */
+	uint8_t request;
+	/** Request handler name for debugging purposes. */
+	const char *name;
+	/** Callback to be executed on matching request. */
+	usbvirt_on_control_t callback;
+} usbvirt_control_request_handler_t;
+
+/** Extra configuration data for GET_CONFIGURATION request. */
+typedef struct {
+	/** Actual data. */
+	uint8_t *data;
+	/** Data length. */
+	size_t length;
+} usbvirt_device_configuration_extras_t;
+
+/** Single device configuration. */
+typedef struct {
+	/** Standard configuration descriptor. */
+	usb_standard_configuration_descriptor_t *descriptor;
+	/** Array of extra data. */
+	usbvirt_device_configuration_extras_t *extra;
+	/** Length of @c extra array. */
+	size_t extra_count;
+} usbvirt_device_configuration_t;
+
+/** Standard USB descriptors for virtual device. */
+typedef struct {
+	/** Standard device descriptor.
+	 * There is always only one such descriptor for the device.
+	 */
+	usb_standard_device_descriptor_t *device;
+
+	/** Configurations. */
+	usbvirt_device_configuration_t *configuration;
+	/** Number of configurations. */
+	size_t configuration_count;
+} usbvirt_descriptors_t;
+
+/** Possible states of virtual USB device.
+ * Notice that these are not 1:1 mappings to those in USB specification.
+ */
+typedef enum {
+	/** Default state, device listens at default address. */
+	USBVIRT_STATE_DEFAULT,
+	/** Device has non-default address assigned. */
+	USBVIRT_STATE_ADDRESS,
+	/** Device is configured. */
+	USBVIRT_STATE_CONFIGURED
+} usbvirt_device_state_t;
+
+/** Ops structure for virtual USB device. */
+typedef struct {
+	/** Callbacks for data to device.
+	 * Index zero is ignored.
+	 */
+	usbvirt_on_data_to_device_t data_out[USBVIRT_ENDPOINT_MAX];
+	/** Callbacks for data from device.
+	 * Index zero is ignored.
+	 */
+	usbvirt_on_data_from_device_t data_in[USBVIRT_ENDPOINT_MAX];
+	/** Array of control handlers.
+	 * Last handler is expected to have the @c callback field set to NULL
+	 */
+	usbvirt_control_request_handler_t *control;
+	/** Callback when device changes state.
+	 *
+	 * The value of @c state attribute of @p dev device is not
+	 * defined during call of this function.
+	 *
+	 * @param dev The virtual USB device.
+	 * @param old_state Old device state.
+	 * @param new_state New device state.
+	 */
+	void (*state_changed)(usbvirt_device_t *dev,
+	    usbvirt_device_state_t old_state, usbvirt_device_state_t new_state);
+} usbvirt_device_ops_t;
+
+/** Virtual USB device. */
+struct usbvirt_device {
+	/** Name for debugging purposes. */
+	const char *name;
+	/** Custom device data. */
+	void *device_data;
+	/** Device ops. */
+	usbvirt_device_ops_t *ops;
+	/** Device descriptors. */
+	usbvirt_descriptors_t *descriptors;
+	/** Current device address.
+	 * You shall treat this field as read only in your code.
+	 */
+	usb_address_t address;
+	/** Current device state.
+	 * You shall treat this field as read only in your code.
+	 */
+	usbvirt_device_state_t state;
+	/** Session to the host controller.
+	 * You shall treat this field as read only in your code.
+	 */
+	async_sess_t *vhc_sess;
+};
+
+int usbvirt_device_plug(usbvirt_device_t *, const char *);
+void usbvirt_device_unplug(usbvirt_device_t *);
+
+void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *,
+    uint8_t *, size_t *, void *, size_t);
+
+int usbvirt_control_write(usbvirt_device_t *, void *, size_t, void *, size_t);
+int usbvirt_control_read(usbvirt_device_t *, void *, size_t, void *, size_t, size_t *);
+int usbvirt_data_out(usbvirt_device_t *, usb_transfer_type_t, usb_endpoint_t,
+    void *, size_t);
+int usbvirt_data_in(usbvirt_device_t *, usb_transfer_type_t, usb_endpoint_t,
+    void *, size_t, size_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/include/usbvirt/ipc.h
===================================================================
--- uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/include/usbvirt/ipc.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,73 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers for virtual USB.
+ */
+
+#ifndef LIBUSBVIRT_IPC_H_
+#define LIBUSBVIRT_IPC_H_
+
+#include <ipc/common.h>
+#include <usb/usb.h>
+#include <bool.h>
+#include <usbvirt/device.h>
+#include <async.h>
+
+/** IPC methods communication between host controller and virtual device. */
+typedef enum {
+	IPC_M_USBVIRT_GET_NAME = IPC_FIRST_USER_METHOD + 80,
+	IPC_M_USBVIRT_CONTROL_READ,
+	IPC_M_USBVIRT_CONTROL_WRITE,
+	IPC_M_USBVIRT_INTERRUPT_IN,
+	IPC_M_USBVIRT_INTERRUPT_OUT,
+	IPC_M_USBVIRT_BULK_IN,
+	IPC_M_USBVIRT_BULK_OUT
+} usbvirt_hc_to_device_method_t;
+
+extern int usbvirt_ipc_send_control_read(async_sess_t *, void *, size_t,
+    void *, size_t, size_t *);
+extern int usbvirt_ipc_send_control_write(async_sess_t *, void *, size_t,
+    void *, size_t);
+extern int usbvirt_ipc_send_data_in(async_sess_t *, usb_endpoint_t,
+    usb_transfer_type_t, void *, size_t, size_t *);
+extern int usbvirt_ipc_send_data_out(async_sess_t *, usb_endpoint_t,
+    usb_transfer_type_t, void *, size_t);
+
+extern bool usbvirt_is_usbvirt_method(sysarg_t);
+extern bool usbvirt_ipc_handle_call(usbvirt_device_t *, ipc_callid_t,
+    ipc_call_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ctrltransfer.c
===================================================================
--- uspace/lib/usbvirt/src/ctrltransfer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/ctrltransfer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,102 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Control transfer handling.
+ */
+#include "private.h"
+#include <usb/dev/request.h>
+#include <usb/debug.h>
+#include <assert.h>
+#include <errno.h>
+
+/** Find and execute control transfer handler for virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param control_handlers Array of control request handlers.
+ * @param setup Setup packet.
+ * @param data Extra data.
+ * @param data_sent_size Size of extra data in bytes.
+ * @return Error code.
+ * @retval EFORWARD No suitable handler found.
+ */
+int process_control_transfer(usbvirt_device_t *dev,
+    usbvirt_control_request_handler_t *control_handlers,
+    usb_device_request_setup_packet_t *setup,
+    uint8_t *data, size_t *data_sent_size)
+{
+	assert(dev);
+	assert(setup);
+
+	if (control_handlers == NULL) {
+		return EFORWARD;
+	}
+
+	usb_direction_t direction = setup->request_type & 128 ?
+	    USB_DIRECTION_IN : USB_DIRECTION_OUT;
+	usb_request_recipient_t req_recipient = setup->request_type & 31;
+	usb_request_type_t req_type = (setup->request_type >> 5) & 3;
+
+	usbvirt_control_request_handler_t *handler = control_handlers;
+	while (handler->callback != NULL) {
+		if (handler->req_direction != direction) {
+			goto next;
+		}
+		if (handler->req_recipient != req_recipient) {
+			goto next;
+		}
+		if (handler->req_type != req_type) {
+			goto next;
+		}
+		if (handler->request != setup->request) {
+			goto next;
+		}
+
+		usb_log_debug("Control transfer: %s(%s)\n", handler->name,
+		    usb_debug_str_buffer((uint8_t*) setup, sizeof(*setup), 0));
+		int rc = handler->callback(dev, setup, data, data_sent_size);
+		if (rc == EFORWARD) {
+			goto next;
+		}
+
+		return rc;
+
+next:
+		handler++;
+	}
+
+	return EFORWARD;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/device.c
===================================================================
--- uspace/lib/usbvirt/src/device.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/device.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,121 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Virtual USB device main routines.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+
+#include <usb/debug.h>
+
+/** Current device. */
+static usbvirt_device_t *DEV = NULL;
+
+/** Main IPC call handling from virtual host controller.
+ *
+ * @param iid Caller identification.
+ * @param icall Initial incoming call.
+ */
+static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	assert(DEV != NULL);
+
+	async_answer_0(iid, EOK);
+
+	while (true) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+
+		callid = async_get_call(&call);
+		bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
+		if (!processed) {
+			if (!IPC_GET_IMETHOD(call)) {
+				async_answer_0(callid, EOK);
+				return;
+			} else
+				async_answer_0(callid, EINVAL);
+		}
+	}
+}
+
+/** Connect the device to the virtual host controller.
+ *
+ * @param dev The virtual device to be (virtually) plugged in.
+ * @param vhc_path Devman path to the virtual host controller.
+ * @return Error code.
+ */
+int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
+{
+	if (DEV != NULL)
+		return ELIMIT;
+	
+	devman_handle_t handle;
+	int rc = devman_device_get_handle(vhc_path, &handle, 0);
+	if (rc != EOK)
+		return rc;
+	
+	async_sess_t *hcd_sess =
+	    devman_device_connect(EXCHANGE_SERIALIZE, handle, 0);
+	if (!hcd_sess)
+		return ENOMEM;
+	
+	DEV = dev;
+	dev->vhc_sess = hcd_sess;
+	
+	async_exch_t *exch = async_exchange_begin(hcd_sess);
+	rc = async_connect_to_me(exch, 0, 0, 0, callback_connection);
+	async_exchange_end(exch);
+	
+	if (rc != EOK)
+		DEV = NULL;
+	
+	return rc;
+}
+
+/** Disconnect the device from virtual host controller.
+ *
+ * @param dev Device to be disconnected.
+ */
+void usbvirt_device_unplug(usbvirt_device_t *dev)
+{
+	async_hangup(dev->vhc_sess);
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ipc_dev.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_dev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/ipc_dev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,297 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers, device side.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include <usb/debug.h>
+
+/** Handle VHC request for device name.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_get_name(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (dev->name == NULL) {
+		async_answer_0(iid, ENOENT);
+	}
+
+	size_t size = str_size(dev->name);
+
+	ipc_callid_t callid;
+	size_t accepted_size;
+	if (!async_data_read_receive(&callid, &accepted_size)) {
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	if (accepted_size > size) {
+		accepted_size = size;
+	}
+	async_data_read_finalize(callid, dev->name, accepted_size);
+
+	async_answer_1(iid, EOK, accepted_size);
+}
+
+/** Handle VHC request for control read from the device.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_control_read(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	int rc;
+
+	void *setup_packet = NULL;
+	size_t setup_packet_len = 0;
+	size_t data_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, 1024, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EPARTY);
+		free(setup_packet);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(iid, ENOMEM);
+		free(setup_packet);
+		return;
+	}
+
+	size_t actual_len;
+	rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
+	    buffer, data_len, &actual_len);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(iid, rc);
+		free(setup_packet);
+		free(buffer);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, buffer, actual_len);
+	async_answer_0(iid, EOK);
+
+	free(setup_packet);
+	free(buffer);
+}
+
+/** Handle VHC request for control write to the device.
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_control_write(usbvirt_device_t *dev,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	size_t data_buffer_len = IPC_GET_ARG1(*icall);
+	int rc;
+
+	void *setup_packet = NULL;
+	void *data_buffer = NULL;
+	size_t setup_packet_len = 0;
+
+	rc = async_data_write_accept(&setup_packet, false,
+	    1, 0, 0, &setup_packet_len);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	if (data_buffer_len > 0) {
+		rc = async_data_write_accept(&data_buffer, false,
+		    1, 0, 0, &data_buffer_len);
+		if (rc != EOK) {
+			async_answer_0(iid, rc);
+			free(setup_packet);
+			return;
+		}
+	}
+
+	rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
+	    data_buffer, data_buffer_len);
+
+	async_answer_0(iid, rc);
+
+	free(setup_packet);
+	if (data_buffer != NULL) {
+		free(data_buffer);
+	}
+}
+
+/** Handle VHC request for data read from the device (in transfer).
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_data_in(usbvirt_device_t *dev,
+    usb_transfer_type_t transfer_type,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
+
+	int rc;
+
+	size_t data_len = 0;
+	ipc_callid_t data_callid;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EPARTY);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	size_t actual_len;
+	rc = usbvirt_data_in(dev, transfer_type, endpoint,
+	    buffer, data_len, &actual_len);
+
+	if (rc != EOK) {
+		async_answer_0(data_callid, rc);
+		async_answer_0(iid, rc);
+		free(buffer);
+		return;
+	}
+
+	async_data_read_finalize(data_callid, buffer, actual_len);
+	async_answer_0(iid, EOK);
+
+	free(buffer);
+}
+
+/** Handle VHC request for data write to the device (out transfer).
+ *
+ * @param dev Target virtual device.
+ * @param iid Caller id.
+ * @param icall The call with the request.
+ */
+static void ipc_data_out(usbvirt_device_t *dev,
+    usb_transfer_type_t transfer_type,
+    ipc_callid_t iid, ipc_call_t *icall)
+{
+	usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
+
+	void *data_buffer = NULL;
+	size_t data_buffer_size = 0;
+
+	int rc = async_data_write_accept(&data_buffer, false,
+	    1, 0, 0, &data_buffer_size);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = usbvirt_data_out(dev, transfer_type, endpoint,
+	    data_buffer, data_buffer_size);
+
+	async_answer_0(iid, rc);
+
+	free(data_buffer);
+}
+
+/** Handle incoming IPC call for virtual USB device.
+ *
+ * @param dev Target USB device.
+ * @param callid Caller id.
+ * @param call Incoming call.
+ * @return Whether the call was handled.
+ */
+bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	switch (IPC_GET_IMETHOD(*call)) {
+	case IPC_M_USBVIRT_GET_NAME:
+		ipc_get_name(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_CONTROL_READ:
+		ipc_control_read(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_CONTROL_WRITE:
+		ipc_control_write(dev, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_INTERRUPT_IN:
+		ipc_data_in(dev, USB_TRANSFER_INTERRUPT, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_BULK_IN:
+		ipc_data_in(dev, USB_TRANSFER_BULK, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_INTERRUPT_OUT:
+		ipc_data_out(dev, USB_TRANSFER_INTERRUPT, callid, call);
+		break;
+
+	case IPC_M_USBVIRT_BULK_OUT:
+		ipc_data_out(dev, USB_TRANSFER_BULK, callid, call);
+		break;
+
+
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/ipc_hc.c
===================================================================
--- uspace/lib/usbvirt/src/ipc_hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/ipc_hc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,316 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * IPC wrappers, host controller side.
+ */
+#include <errno.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <async.h>
+#include <devman.h>
+#include <usbvirt/device.h>
+#include <usbvirt/ipc.h>
+#include <usb/debug.h>
+
+/** Send control read transfer to virtual USB device.
+ *
+ * @param sess Session to the virtual device.
+ * @param ep Target endpoint number.
+ * @param setup_buffer Setup buffer.
+ * @param setup_buffer_size Setup buffer size in bytes.
+ * @param data_buffer Data buffer (DATA stage of control transfer).
+ * @param data_buffer_size Size of data buffer in bytes.
+ * @param data_transfered_size Number of actually transferred bytes.
+ *
+ * @return Error code.
+ *
+ */
+int usbvirt_ipc_send_control_read(async_sess_t *sess, void *setup_buffer,
+    size_t setup_buffer_size, void *data_buffer, size_t data_buffer_size,
+    size_t *data_transfered_size)
+{
+	if (!sess)
+		return EINVAL;
+	
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0))
+		return EINVAL;
+	
+	if ((data_buffer == NULL) || (data_buffer_size == 0))
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t opening_request = async_send_0(exch, IPC_M_USBVIRT_CONTROL_READ,
+	    NULL);
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return ENOMEM;
+	}
+	
+	int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+	
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, data_buffer, data_buffer_size,
+	    &data_request_call);
+	
+	async_exchange_end(exch);
+	
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+	
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK)
+			return (int) opening_request_rc;
+		else
+			return (int) data_request_rc;
+	}
+	
+	if (opening_request_rc != EOK)
+		return (int) opening_request_rc;
+	
+	if (data_transfered_size != NULL)
+		*data_transfered_size = IPC_GET_ARG2(data_request_call);
+	
+	return EOK;
+}
+
+/** Send control write transfer to virtual USB device.
+ *
+ * @param sess Session to the virtual device.
+ * @param ep Target endpoint number.
+ * @param setup_buffer Setup buffer.
+ * @param setup_buffer_size Setup buffer size in bytes.
+ * @param data_buffer Data buffer (DATA stage of control transfer).
+ * @param data_buffer_size Size of data buffer in bytes.
+ *
+ * @return Error code.
+ *
+ */
+int usbvirt_ipc_send_control_write(async_sess_t *sess, void *setup_buffer,
+    size_t setup_buffer_size, void *data_buffer, size_t data_buffer_size)
+{
+	if (!sess)
+		return EINVAL;
+	
+	if ((setup_buffer == NULL) || (setup_buffer_size == 0))
+		return EINVAL;
+	
+	if ((data_buffer_size > 0) && (data_buffer == NULL))
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t opening_request = async_send_1(exch, IPC_M_USBVIRT_CONTROL_WRITE,
+	    data_buffer_size, NULL);
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return ENOMEM;
+	}
+	
+	int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+	
+	if (data_buffer_size > 0) {
+		rc = async_data_write_start(exch, data_buffer, data_buffer_size);
+		if (rc != EOK) {
+			async_exchange_end(exch);
+			async_wait_for(opening_request, NULL);
+			return rc;
+		}
+	}
+	
+	async_exchange_end(exch);
+	
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	return (int) opening_request_rc;
+}
+
+/** Request data transfer from virtual USB device.
+ *
+ * @param sess Session to the virtual device.
+ * @param ep Target endpoint number.
+ * @param tr_type Transfer type (interrupt or bulk).
+ * @param data Data buffer.
+ * @param data_size Size of the data buffer in bytes.
+ * @param act_size Number of actually returned bytes.
+ *
+ * @return Error code.
+ *
+ */
+int usbvirt_ipc_send_data_in(async_sess_t *sess, usb_endpoint_t ep,
+    usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
+{
+	if (!sess)
+		return EINVAL;
+	
+	usbvirt_hc_to_device_method_t method;
+	
+	switch (tr_type) {
+	case USB_TRANSFER_INTERRUPT:
+		method = IPC_M_USBVIRT_INTERRUPT_IN;
+		break;
+	case USB_TRANSFER_BULK:
+		method = IPC_M_USBVIRT_BULK_IN;
+		break;
+	default:
+		return EINVAL;
+	}
+	
+	if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX))
+		return EINVAL;
+	
+	if ((data == NULL) || (data_size == 0))
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t opening_request = async_send_2(exch, method, ep, tr_type, NULL);
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return ENOMEM;
+	}
+	
+	ipc_call_t data_request_call;
+	aid_t data_request = async_data_read(exch, data, data_size,
+	    &data_request_call);
+	
+	async_exchange_end(exch);
+	
+	if (data_request == 0) {
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+	
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK)
+			return (int) opening_request_rc;
+		else
+			return (int) data_request_rc;
+	}
+	
+	if (opening_request_rc != EOK)
+		return (int) opening_request_rc;
+	
+	if (act_size != NULL)
+		*act_size = IPC_GET_ARG2(data_request_call);
+	
+	return EOK;
+}
+
+/** Send data to virtual USB device.
+ *
+ * @param sess Session to the virtual device.
+ * @param ep Target endpoint number.
+ * @param tr_type Transfer type (interrupt or bulk).
+ * @param data Data buffer.
+ * @param data_size Size of the data buffer in bytes.
+ *
+ * @return Error code.
+ *
+ */
+int usbvirt_ipc_send_data_out(async_sess_t *sess, usb_endpoint_t ep,
+    usb_transfer_type_t tr_type, void *data, size_t data_size)
+{
+	if (!sess)
+		return EINVAL;
+	
+	usbvirt_hc_to_device_method_t method;
+	
+	switch (tr_type) {
+	case USB_TRANSFER_INTERRUPT:
+		method = IPC_M_USBVIRT_INTERRUPT_OUT;
+		break;
+	case USB_TRANSFER_BULK:
+		method = IPC_M_USBVIRT_BULK_OUT;
+		break;
+	default:
+		return EINVAL;
+	}
+	
+	if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX))
+		return EINVAL;
+	
+	if ((data == NULL) || (data_size == 0))
+		return EINVAL;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t opening_request = async_send_1(exch, method, ep, NULL);
+	if (opening_request == 0) {
+		async_exchange_end(exch);
+		return ENOMEM;
+	}
+	
+	int rc = async_data_write_start(exch, data, data_size);
+	
+	async_exchange_end(exch);
+	
+	if (rc != EOK) {
+		async_wait_for(opening_request, NULL);
+		return rc;
+	}
+	
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+	
+	return (int) opening_request_rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/private.h
===================================================================
--- uspace/lib/usbvirt/src/private.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/private.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,50 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Private definitions.
+ */
+#ifndef USBVIRT_PRIVATE_H_
+#define USBVIRT_PRIVATE_H_
+
+#include <usbvirt/device.h>
+
+int process_control_transfer(usbvirt_device_t *,
+    usbvirt_control_request_handler_t *,
+    usb_device_request_setup_packet_t *,
+    uint8_t *, size_t *);
+
+extern usbvirt_control_request_handler_t library_handlers[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/stdreq.c
===================================================================
--- uspace/lib/usbvirt/src/stdreq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/stdreq.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,223 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Standard control request handlers.
+ */
+#include "private.h"
+#include <usb/dev/request.h>
+#include <assert.h>
+#include <errno.h>
+
+/** Helper for replying to control read transfer from virtual USB device.
+ *
+ * This function takes care of copying data to answer buffer taking care
+ * of buffer sizes properly.
+ *
+ * @param setup_packet The setup packet.
+ * @param data Data buffer to write to.
+ * @param act_size Where to write actual size of returned data.
+ * @param actual_data Data to be returned.
+ * @param actual_data_size Size of answer data (@p actual_data) in bytes.
+ */
+void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size,
+    void *actual_data, size_t actual_data_size)
+{
+	size_t expected_size = setup_packet->length;
+	if (expected_size < actual_data_size) {
+		actual_data_size = expected_size;
+	}
+
+	memcpy(data, actual_data, actual_data_size);
+
+	if (act_size != NULL) {
+		*act_size = actual_data_size;
+	}
+}
+
+/** GET_DESCRIPTOR handler. */
+static int req_get_descriptor(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
+{
+	uint8_t type = setup_packet->value_high;
+	uint8_t index = setup_packet->value_low;
+
+	/*
+	 * Standard device descriptor.
+	 */
+	if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
+		if (device->descriptors && device->descriptors->device) {
+			usbvirt_control_reply_helper(setup_packet, data, act_size,
+			    device->descriptors->device,
+			    device->descriptors->device->length);
+			return EOK;
+		} else {
+			return EFORWARD;
+		}
+	}
+
+	/*
+	 * Configuration descriptor together with interface, endpoint and
+	 * class-specific descriptors.
+	 */
+	if (type == USB_DESCTYPE_CONFIGURATION) {
+		if (!device->descriptors) {
+			return EFORWARD;
+		}
+		if (index >= device->descriptors->configuration_count) {
+			return EFORWARD;
+		}
+		/* Copy the data. */
+		usbvirt_device_configuration_t *config = &device->descriptors
+		    ->configuration[index];
+		uint8_t *all_data = malloc(config->descriptor->total_length);
+		if (all_data == NULL) {
+			return ENOMEM;
+		}
+
+		uint8_t *ptr = all_data;
+		memcpy(ptr, config->descriptor, config->descriptor->length);
+		ptr += config->descriptor->length;
+		size_t i;
+		for (i = 0; i < config->extra_count; i++) {
+			usbvirt_device_configuration_extras_t *extra
+			    = &config->extra[i];
+			memcpy(ptr, extra->data, extra->length);
+			ptr += extra->length;
+		}
+
+		usbvirt_control_reply_helper(setup_packet, data, act_size,
+		    all_data, config->descriptor->total_length);
+
+		free(all_data);
+
+		return EOK;
+	}
+
+	return EFORWARD;
+}
+
+static int req_set_address(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
+{
+	uint16_t new_address = setup_packet->value;
+	uint16_t zero1 = setup_packet->index;
+	uint16_t zero2 = setup_packet->length;
+
+	if ((zero1 != 0) || (zero2 != 0)) {
+		return EINVAL;
+	}
+
+	if (new_address > 127) {
+		return EINVAL;
+	}
+
+	device->address = new_address;
+
+	return EOK;
+}
+
+static int req_set_configuration(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
+{
+	uint16_t configuration_value = setup_packet->value;
+	uint16_t zero1 = setup_packet->index;
+	uint16_t zero2 = setup_packet->length;
+
+	if ((zero1 != 0) || (zero2 != 0)) {
+		return EINVAL;
+	}
+
+	/*
+	 * Configuration value is 1 byte information.
+	 */
+	if (configuration_value > 255) {
+		return EINVAL;
+	}
+
+	/*
+	 * Do nothing when in default state. According to specification,
+	 * this is not specified.
+	 */
+	if (device->state == USBVIRT_STATE_DEFAULT) {
+		return EOK;
+	}
+
+	usbvirt_device_state_t new_state;
+	if (configuration_value == 0) {
+		new_state = USBVIRT_STATE_ADDRESS;
+	} else {
+		// FIXME: check that this configuration exists
+		new_state = USBVIRT_STATE_CONFIGURED;
+	}
+
+	if (device->ops && device->ops->state_changed) {
+		device->ops->state_changed(device, device->state, new_state);
+	}
+	device->state = new_state;
+
+	return EOK;
+}
+
+/** Standard request handlers. */
+usbvirt_control_request_handler_t library_handlers[] = {
+	{
+		.req_direction = USB_DIRECTION_OUT,
+		.req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
+		.req_type = USB_REQUEST_TYPE_STANDARD,
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.name = "SetAddress",
+		.callback = req_set_address
+	},
+	{
+		.req_direction = USB_DIRECTION_IN,
+		.req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
+		.req_type = USB_REQUEST_TYPE_STANDARD,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "GetDescriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		.req_direction = USB_DIRECTION_OUT,
+		.req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
+		.req_type = USB_REQUEST_TYPE_STANDARD,
+		.request = USB_DEVREQ_SET_CONFIGURATION,
+		.name = "SetConfiguration",
+		.callback = req_set_configuration
+	},
+
+	{ .callback = NULL }
+};
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/transfer.c
===================================================================
--- uspace/lib/usbvirt/src/transfer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/lib/usbvirt/src/transfer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,190 @@
+/*
+ * 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 libusbvirt
+ * @{
+ */
+/** @file
+ * Transfer handling.
+ */
+#include <usbvirt/device.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <assert.h>
+#include "private.h"
+
+/** Process a control transfer to the virtual USB device.
+ *
+ * @param dev Target device.
+ * @param setup Setup packet data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data in bytes.
+ * @param data_size_sent Number of actually send bytes during the transfer
+ *	(only used for READ transfers).
+ * @return Error code.
+ */
+static int usbvirt_control_transfer(usbvirt_device_t *dev,
+    void *setup, size_t setup_size,
+    void *data, size_t data_size, size_t *data_size_sent)
+{
+	assert(dev);
+	assert(dev->ops);
+
+	if (setup_size != sizeof(usb_device_request_setup_packet_t)) {
+		return ESTALL;
+	}
+	usb_device_request_setup_packet_t *setup_packet = setup;
+	if (data_size != setup_packet->length) {
+		return ESTALL;
+	}
+
+	int rc;
+
+	/* Run user handler first. */
+	rc = process_control_transfer(dev, dev->ops->control,
+	    setup_packet, data, data_size_sent);
+	if (rc != EFORWARD) {
+		return rc;
+	}
+
+	/* Run the library handlers afterwards. */
+	rc = process_control_transfer(dev, library_handlers,
+	    setup_packet, data, data_size_sent);
+
+	if (rc == EFORWARD) {
+		usb_log_warning("Control transfer {%s (%s)} not handled.\n",
+		    usb_debug_str_buffer(setup, setup_size, 10),
+		    setup_packet->request_type & 0x80
+		    ? "IN" : usb_debug_str_buffer(data, data_size, 10));
+		rc = EBADCHECKSUM;
+	}
+
+	return rc;
+}
+
+/** Issue a control write transfer to virtual USB device.
+ *
+ * @see usbvirt_control_transfer
+ *
+ * @param dev Target virtual device.
+ * @param setup Setup data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data buffer in bytes.
+ * @return Error code.
+ */
+int usbvirt_control_write(usbvirt_device_t *dev, void *setup, size_t setup_size,
+    void *data, size_t data_size)
+{
+	return usbvirt_control_transfer(dev, setup, setup_size,
+	    data, data_size, NULL);
+}
+
+/** Issue a control read transfer to virtual USB device.
+ *
+ * @see usbvirt_control_transfer
+ *
+ * @param dev Target virtual device.
+ * @param setup Setup data.
+ * @param setup_size Size of setup packet.
+ * @param data Extra data (DATA stage).
+ * @param data_size Size of extra data buffer in bytes.
+ * @param data_size_sent Number of actually send bytes during the transfer.
+ * @return Error code.
+ */
+int usbvirt_control_read(usbvirt_device_t *dev, void *setup, size_t setup_size,
+    void *data, size_t data_size, size_t *data_size_sent)
+{
+	return usbvirt_control_transfer(dev, setup, setup_size,
+	    data, data_size, data_size_sent);
+}
+
+/** Send data to virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param transf_type Transfer type (interrupt, bulk).
+ * @param endpoint Endpoint number.
+ * @param data Data sent from the driver to the device.
+ * @param data_size Size of the @p data buffer in bytes.
+ * @return Error code.
+ */
+int usbvirt_data_out(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
+    usb_endpoint_t endpoint, void *data, size_t data_size)
+{
+	if ((endpoint <= 0) || (endpoint >= USBVIRT_ENDPOINT_MAX)) {
+		return ERANGE;
+	}
+	if ((dev->ops == NULL) || (dev->ops->data_out[endpoint] == NULL)) {
+		return ENOTSUP;
+	}
+
+	int rc = dev->ops->data_out[endpoint](dev, endpoint, transf_type,
+	    data, data_size);
+
+	return rc;
+}
+
+/** Request data from virtual USB device.
+ *
+ * @param dev Target virtual device.
+ * @param transf_type Transfer type (interrupt, bulk).
+ * @param endpoint Endpoint number.
+ * @param data Where to stored data the device returns to the driver.
+ * @param data_size Size of the @p data buffer in bytes.
+ * @param data_size_sent Number of actually written bytes.
+ * @return Error code.
+ */
+int usbvirt_data_in(usbvirt_device_t *dev, usb_transfer_type_t transf_type,
+    usb_endpoint_t endpoint, void *data, size_t data_size, size_t *data_size_sent)
+{
+	if ((endpoint <= 0) || (endpoint >= USBVIRT_ENDPOINT_MAX)) {
+		return ERANGE;
+	}
+	if ((dev->ops == NULL) || (dev->ops->data_in[endpoint] == NULL)) {
+		return ENOTSUP;
+	}
+
+	size_t data_size_sent_tmp;
+	int rc = dev->ops->data_in[endpoint](dev, endpoint, transf_type,
+	    data, data_size, &data_size_sent_tmp);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (data_size_sent != NULL) {
+		*data_size_sent = data_size_sent_tmp;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -317,12 +317,15 @@
 	(void) async_share_out_finalize(callid, fs_va);
 
-	while (1) {
+	while (true) {
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -198,12 +198,15 @@
 	(void) async_share_out_finalize(callid, fs_va);
 
-	while (1) {
+	while (true) {
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -201,12 +201,15 @@
 	(void) async_share_out_finalize(callid, fs_va);
 
-	while (1) {
+	while (true) {
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
Index: uspace/srv/bd/part/guid_part/guid_part.c
===================================================================
--- uspace/srv/bd/part/guid_part/guid_part.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/bd/part/guid_part/guid_part.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -139,5 +139,5 @@
 	}
 
-	rc = block_init(indev_handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, indev_handle, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": could not init libblock.\n");
@@ -356,12 +356,15 @@
 	(void) async_share_out_finalize(callid, fs_va);
 
-	while (1) {
+	while (true) {
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
Index: uspace/srv/bd/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -190,5 +190,5 @@
 	}
 
-	rc = block_init(indev_handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, indev_handle, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": could not init libblock.\n");
@@ -437,9 +437,12 @@
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/bd/rd/rd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -123,12 +123,15 @@
 	while (true) {
 		callid = async_get_call(&call);
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!IPC_GET_IMETHOD(call)) {
 			/*
 			 * The other side has hung up.
-			 * Answer the message and exit the fibril.
+			 * Exit the fibril.
 			 */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
@@ -243,5 +246,5 @@
 		return false;
 	}
-
+	
 	fibril_rwlock_initialize(&rd_lock);
 	
@@ -258,5 +261,5 @@
 	printf("%s: Accepting connections\n", NAME);
 	async_manager();
-
+	
 	/* Never reached */
 	return 0;
Index: uspace/srv/clip/clip.c
===================================================================
--- uspace/srv/clip/clip.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/clip/clip.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -30,5 +30,5 @@
 #include <bool.h>
 #include <async.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <ipc/services.h>
 #include <ipc/clipboard.h>
@@ -153,13 +153,12 @@
 	async_answer_0(iid, EOK);
 	
-	bool cont = true;
-	while (cont) {
+	while (true) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			cont = false;
-			continue;
 		case CLIPBOARD_PUT_DATA:
 			clip_put_data(callid, &call);
@@ -179,5 +178,5 @@
 int main(int argc, char *argv[])
 {
-	printf(NAME ": HelenOS clipboard service\n");
+	printf("%s: HelenOS clipboard service\n", NAME);
 	
 	async_set_client_connection(clip_connection);
@@ -186,5 +185,6 @@
 		return -1;
 	
-	printf(NAME ": Accepting connections\n");
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
 	async_manager();
 	
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/devman/devman.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -564,5 +564,4 @@
 	dev_node_t *dev;
 	link_t *link;
-	int phone;
 
 	log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
@@ -570,8 +569,11 @@
 
 	fibril_mutex_lock(&driver->driver_mutex);
-
-	phone = async_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);
-
-	if (phone < 0) {
+	
+	async_exch_t *exch = async_exchange_begin(driver->sess);
+	async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
+	    DRIVER_DEVMAN, 0, 0);
+	async_exchange_end(exch);
+
+	if (!sess) {
 		fibril_mutex_unlock(&driver->driver_mutex);
 		return;
@@ -602,5 +604,5 @@
 		fibril_mutex_unlock(&driver->driver_mutex);
 
-		add_device(phone, driver, dev, tree);
+		add_device(sess, driver, dev, tree);
 
 		/*
@@ -623,5 +625,5 @@
 	}
 
-	async_hangup(phone);
+	async_hangup(sess);
 
 	/*
@@ -673,5 +675,5 @@
 	list_initialize(&drv->devices);
 	fibril_mutex_initialize(&drv->driver_mutex);
-	drv->phone = -1;
+	drv->sess = NULL;
 }
 
@@ -737,5 +739,6 @@
  * @param node		The device's node in the device tree.
  */
-void add_device(int phone, driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
+void add_device(async_sess_t *sess, driver_t *drv, dev_node_t *dev,
+    dev_tree_t *tree)
 {
 	/*
@@ -746,7 +749,4 @@
 	    drv->name, dev->pfun->name);
 	
-	sysarg_t rc;
-	ipc_call_t answer;
-	
 	/* Send the device to the driver. */
 	devman_handle_t parent_handle;
@@ -756,11 +756,17 @@
 		parent_handle = 0;
 	}
-
-	aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, dev->handle,
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
 	    parent_handle, &answer);
 	
-	/* Send the device's name to the driver. */
-	rc = async_data_write_start(phone, dev->pfun->name,
+	/* Send the device name to the driver. */
+	sysarg_t rc = async_data_write_start(exch, dev->pfun->name,
 	    str_size(dev->pfun->name) + 1);
+	
+	async_exchange_end(exch);
+	
 	if (rc != EOK) {
 		/* TODO handle error */
@@ -823,8 +829,12 @@
 	if (is_running) {
 		/* Notify the driver about the new device. */
-		int phone = async_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
-		if (phone >= 0) {
-			add_device(phone, drv, dev, tree);
-			async_hangup(phone);
+		async_exch_t *exch = async_exchange_begin(drv->sess);
+		async_sess_t *sess = async_connect_me_to(EXCHANGE_SERIALIZE, exch,
+		    DRIVER_DEVMAN, 0, 0);
+		async_exchange_end(exch);
+		
+		if (sess) {
+			add_device(sess, drv, dev, tree);
+			async_hangup(sess);
 		}
 	}
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/devman/devman.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,4 +44,5 @@
 #include <fibril_synch.h>
 #include <atomic.h>
+#include <async.h>
 
 #include "util.h"
@@ -87,6 +88,6 @@
 	int state;
 	
-	/** Phone asociated with this driver. */
-	int phone;
+	/** Session asociated with this driver. */
+	async_sess_t *sess;
 	/** Name of the device driver. */
 	char *name;
@@ -99,5 +100,5 @@
 	
 	/**
-	 * Fibril mutex for this driver - driver state, list of devices, phone.
+	 * Fibril mutex for this driver - driver state, list of devices, session.
 	 */
 	fibril_mutex_t driver_mutex;
@@ -312,5 +313,5 @@
 extern void add_driver(driver_list_t *, driver_t *);
 extern void attach_driver(dev_node_t *, driver_t *);
-extern void add_device(int, driver_t *, dev_node_t *, dev_tree_t *);
+extern void add_device(async_sess_t *, driver_t *, dev_node_t *, dev_tree_t *);
 extern bool start_driver(driver_t *);
 
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/devman/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,5 +39,5 @@
 #include <assert.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <stdio.h>
@@ -108,5 +108,5 @@
 	fibril_mutex_lock(&driver->driver_mutex);
 	
-	if (driver->phone >= 0) {
+	if (driver->sess) {
 		/* We already have a connection to the driver. */
 		log_msg(LVL_ERROR, "Driver '%s' already started.\n",
@@ -128,5 +128,5 @@
 		break;
 	case DRIVER_RUNNING:
-		/* Should not happen since we do not have a connected phone */
+		/* Should not happen since we do not have a connected session */
 		assert(false);
 	}
@@ -135,23 +135,17 @@
 	log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
 	    driver->name);
-	ipc_call_t call;
-	ipc_callid_t callid = async_get_call(&call);
-	if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
+	driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (!driver->sess) {
 		fibril_mutex_unlock(&driver->driver_mutex);
-		async_answer_0(callid, ENOTSUP);
 		async_answer_0(iid, ENOTSUP);
 		return NULL;
 	}
 	
-	/* Remember driver's phone. */
-	driver->phone = IPC_GET_ARG5(call);
-	
 	fibril_mutex_unlock(&driver->driver_mutex);
 	
-	log_msg(LVL_NOTE, 
+	log_msg(LVL_NOTE,
 	    "The `%s' driver was successfully registered as running.",
 	    driver->name);
 	
-	async_answer_0(callid, EOK);
 	async_answer_0(iid, EOK);
 	
@@ -434,14 +428,12 @@
 	fibril_add_ready(fid);
 	
-	ipc_callid_t callid;
-	ipc_call_t call;
-	bool cont = true;
-	while (cont) {
-		callid = async_get_call(&call);
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
 		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			cont = false;
-			continue;
 		case DEVMAN_ADD_FUNCTION:
 			devman_add_function(callid, &call);
@@ -515,4 +507,41 @@
 }
 
+/** Find device path by its handle. */
+static void devman_get_device_path_by_handle(ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	devman_handle_t handle = IPC_GET_ARG1(*icall);
+
+	fun_node_t *fun = find_fun_node(&device_tree, handle);
+	if (fun == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	ipc_callid_t data_callid;
+	size_t data_len;
+	if (!async_data_read_receive(&data_callid, &data_len)) {
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+
+	void *buffer = malloc(data_len);
+	if (buffer == NULL) {
+		async_answer_0(data_callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	size_t sent_length = str_size(fun->pathname);
+	if (sent_length > data_len) {
+		sent_length = data_len;
+	}
+
+	async_data_read_finalize(data_callid, fun->pathname, sent_length);
+	async_answer_0(iid, EOK);
+
+	free(buffer);
+}
+
 
 /** Function for handling connections from a client to the device manager. */
@@ -522,13 +551,12 @@
 	async_answer_0(iid, EOK);
 	
-	bool cont = true;
-	while (cont) {
+	while (true) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			cont = false;
-			continue;
 		case DEVMAN_DEVICE_GET_HANDLE:
 			devman_function_get_handle(callid, &call);
@@ -536,4 +564,7 @@
 		case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
 			devman_function_get_handle_by_class(callid, &call);
+			break;
+		case DEVMAN_DEVICE_GET_DEVICE_PATH:
+			devman_get_device_path_by_handle(callid, &call);
 			break;
 		default:
@@ -606,8 +637,7 @@
 		method = DRIVER_CLIENT;
 	
-	if (driver->phone < 0) {
-		log_msg(LVL_ERROR, 
-		    "Could not forward to driver `%s' (phone is %d).",
-		    driver->name, (int) driver->phone);
+	if (!driver->sess) {
+		log_msg(LVL_ERROR,
+		    "Could not forward to driver `%s'.", driver->name);
 		async_answer_0(iid, EINVAL);
 		return;
@@ -623,6 +653,8 @@
 		    dev->pfun->pathname, driver->name);
 	}
-
-	async_forward_fast(iid, driver->phone, method, fwd_h, 0, IPC_FF_NONE);
+	
+	async_exch_t *exch = async_exchange_begin(driver->sess);
+	async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
+	async_exchange_end(exch);
 }
 
@@ -646,12 +678,15 @@
 	dev = fun->dev;
 	
-	if (dev->state != DEVICE_USABLE || dev->drv->phone < 0) {
+	if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) {
 		async_answer_0(iid, EINVAL);
 		return;
 	}
 	
-	async_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, fun->handle, 0,
+	async_exch_t *exch = async_exchange_begin(dev->drv->sess);
+	async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0,
 	    IPC_FF_NONE);
-	log_msg(LVL_DEBUG, 
+	async_exchange_end(exch);
+	
+	log_msg(LVL_DEBUG,
 	    "Forwarding devmapper request for `%s' function to driver `%s'.",
 	    fun->pathname, dev->drv->name);
@@ -745,4 +780,5 @@
 
 	printf(NAME ": Accepting connections.\n");
+	task_retval(0);
 	async_manager();
 
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/devmap/devmap.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,5 +37,5 @@
 
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <stdio.h>
@@ -59,10 +59,14 @@
 	/** Pointers to previous and next drivers in linked list */
 	link_t drivers;
+	
 	/** Pointer to the linked list of devices controlled by this driver */
 	link_t devices;
-	/** Phone asociated with this driver */
-	sysarg_t phone;
+	
+	/** Session asociated with this driver */
+	async_sess_t *sess;
+	
 	/** Device driver name */
 	char *name;
+	
 	/** Fibril mutex for list of devices owned by this driver */
 	fibril_mutex_t devices_mutex;
@@ -75,8 +79,11 @@
 	/** Pointer to the previous and next device in the list of all namespaces */
 	link_t namespaces;
+	
 	/** Unique namespace identifier */
 	devmap_handle_t handle;
+	
 	/** Namespace name */
 	char *name;
+	
 	/** Reference count */
 	size_t refcnt;
@@ -405,17 +412,11 @@
 	 * Create connection to the driver
 	 */
-	ipc_call_t call;
-	ipc_callid_t callid = async_get_call(&call);
-	
-	if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
+	driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (!driver->sess) {
 		free(driver->name);
 		free(driver);
-		async_answer_0(callid, ENOTSUP);
 		async_answer_0(iid, ENOTSUP);
 		return NULL;
 	}
-	
-	driver->phone = IPC_GET_ARG5(call);
-	async_answer_0(callid, EOK);
 	
 	/*
@@ -462,6 +463,6 @@
 	fibril_mutex_lock(&drivers_list_mutex);
 	
-	if (driver->phone != 0)
-		async_hangup(driver->phone);
+	if (driver->sess)
+		async_hangup(driver->sess);
 	
 	/* Remove it from list of drivers */
@@ -607,5 +608,5 @@
 	devmap_device_t *dev = devmap_device_find_handle(handle);
 	
-	if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
+	if ((dev == NULL) || (dev->driver == NULL) || (!dev->driver->sess)) {
 		fibril_mutex_unlock(&devices_list_mutex);
 		async_answer_0(callid, ENOENT);
@@ -613,13 +614,13 @@
 	}
 	
-	if (dev->forward_interface == 0) {
-		async_forward_fast(callid, dev->driver->phone,
-		    dev->handle, 0, 0,
-		    IPC_FF_NONE);
-	} else {
-		async_forward_fast(callid, dev->driver->phone,
-		    dev->forward_interface, dev->handle, 0,
-		    IPC_FF_NONE);
-	}
+	async_exch_t *exch = async_exchange_begin(dev->driver->sess);
+	
+	if (dev->forward_interface == 0)
+		async_forward_fast(callid, exch, dev->handle, 0, 0, IPC_FF_NONE);
+	else
+		async_forward_fast(callid, exch, dev->forward_interface,
+		    dev->handle, 0, IPC_FF_NONE);
+	
+	async_exchange_end(exch);
 	
 	fibril_mutex_unlock(&devices_list_mutex);
@@ -1029,13 +1030,12 @@
 		return;
 	
-	bool cont = true;
-	while (cont) {
+	while (true) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			cont = false;
-			continue;
 		case DEVMAP_DRIVER_UNREGISTER:
 			if (NULL == driver)
@@ -1080,13 +1080,12 @@
 	async_answer_0(iid, EOK);
 	
-	bool cont = true;
-	while (cont) {
+	while (true) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			cont = false;
-			continue;
 		case DEVMAP_DEVICE_GET_HANDLE:
 			devmap_device_get_handle(callid, &call);
Index: uspace/srv/fs/devfs/devfs.c
===================================================================
--- uspace/srv/fs/devfs/devfs.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/fs/devfs/devfs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,5 +41,5 @@
 #include <stdio.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <errno.h>
@@ -68,7 +68,8 @@
 		ipc_callid_t callid = async_get_call(&call);
 		
-		switch  (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		if (!IPC_GET_IMETHOD(call))
 			return;
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case VFS_OUT_MOUNTED:
 			devfs_mounted(callid, &call);
@@ -119,25 +120,26 @@
 int main(int argc, char *argv[])
 {
-	printf(NAME ": HelenOS Device Filesystem\n");
+	printf("%s: HelenOS Device Filesystem\n", NAME);
 	
 	if (!devfs_init()) {
-		printf(NAME ": failed to initialize devfs\n");
+		printf("%s: failed to initialize devfs\n", NAME);
 		return -1;
 	}
 	
-	int vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
-	if (vfs_phone < EOK) {
-		printf(NAME ": Unable to connect to VFS\n");
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		printf("%s: Unable to connect to VFS\n", NAME);
 		return -1;
 	}
 	
-	int rc = fs_register(vfs_phone, &devfs_reg, &devfs_vfs_info,
+	int rc = fs_register(vfs_sess, &devfs_reg, &devfs_vfs_info,
 	    devfs_connection);
 	if (rc != EOK) {
-		printf(NAME ": Failed to register file system (%d)\n", rc);
+		printf("%s: Failed to register file system (%d)\n", NAME, rc);
 		return rc;
 	}
 	
-	printf(NAME ": Accepting connections\n");
+	printf("%s: Accepting connections\n", NAME);
 	task_retval(0);
 	async_manager();
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -59,8 +59,8 @@
 typedef struct {
 	devmap_handle_t handle;
-	int phone;		/**< When < 0, the structure is incomplete. */
+	async_sess_t *sess;       /**< If NULL, the structure is incomplete. */
 	size_t refcount;
 	link_t link;
-	fibril_condvar_t cv;	/**< Broadcast when completed. */
+	fibril_condvar_t cv;      /**< Broadcast when completed. */
 } device_t;
 
@@ -232,5 +232,5 @@
 		};
 		link_t *lnk;
-
+		
 		fibril_mutex_lock(&devices_mutex);
 restart:
@@ -244,8 +244,10 @@
 			
 			dev->handle = node->handle;
-			dev->phone = -1;	/* mark as incomplete */
+			
+			/* Mark as incomplete */
+			dev->sess = NULL;
 			dev->refcount = 1;
 			fibril_condvar_initialize(&dev->cv);
-
+			
 			/*
 			 * Insert the incomplete device structure so that other
@@ -254,14 +256,15 @@
 			 */
 			hash_table_insert(&devices, key, &dev->link);
-
+			
 			/*
 			 * Drop the mutex to allow recursive devfs requests.
 			 */
 			fibril_mutex_unlock(&devices_mutex);
-
-			int phone = devmap_device_connect(node->handle, 0);
-
+			
+			async_sess_t *sess = devmap_device_connect(EXCHANGE_SERIALIZE,
+			    node->handle, 0);
+			
 			fibril_mutex_lock(&devices_mutex);
-
+			
 			/*
 			 * Notify possible waiters about this device structure
@@ -269,6 +272,6 @@
 			 */
 			fibril_condvar_broadcast(&dev->cv);
-
-			if (phone < 0) {
+			
+			if (!sess) {
 				/*
 				 * Connecting failed, need to remove the
@@ -277,14 +280,14 @@
 				hash_table_remove(&devices, key, DEVICES_KEYS);
 				fibril_mutex_unlock(&devices_mutex);
-
+				
 				return ENOENT;
 			}
 			
-			/* Set the correct phone. */
-			dev->phone = phone;
+			/* Set the correct session. */
+			dev->sess = sess;
 		} else {
 			device_t *dev = hash_table_get_instance(lnk, device_t, link);
-
-			if (dev->phone < 0) {
+			
+			if (!dev->sess) {
 				/*
 				 * Wait until the device structure is completed
@@ -608,5 +611,5 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->phone >= 0);
+		assert(dev->sess);
 		
 		ipc_callid_t callid;
@@ -619,11 +622,16 @@
 		
 		/* Make a request at the driver */
+		async_exch_t *exch = async_exchange_begin(dev->sess);
+		
 		ipc_call_t answer;
-		aid_t msg = async_send_3(dev->phone, IPC_GET_IMETHOD(*request),
+		aid_t msg = async_send_3(exch, IPC_GET_IMETHOD(*request),
 		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
 		    IPC_GET_ARG3(*request), &answer);
 		
 		/* Forward the IPC_M_DATA_READ request to the driver */
-		async_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		
+		async_exchange_end(exch);
+		
 		fibril_mutex_unlock(&devices_mutex);
 		
@@ -672,5 +680,5 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->phone >= 0);
+		assert(dev->sess);
 		
 		ipc_callid_t callid;
@@ -683,11 +691,15 @@
 		
 		/* Make a request at the driver */
+		async_exch_t *exch = async_exchange_begin(dev->sess);
+		
 		ipc_call_t answer;
-		aid_t msg = async_send_3(dev->phone, IPC_GET_IMETHOD(*request),
+		aid_t msg = async_send_3(exch, IPC_GET_IMETHOD(*request),
 		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
 		    IPC_GET_ARG3(*request), &answer);
 		
 		/* Forward the IPC_M_DATA_WRITE request to the driver */
-		async_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		
+		async_exchange_end(exch);
 		
 		fibril_mutex_unlock(&devices_mutex);
@@ -742,9 +754,9 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->phone >= 0);
+		assert(dev->sess);
 		dev->refcount--;
 		
 		if (dev->refcount == 0) {
-			async_hangup(dev->phone);
+			async_hangup(dev->sess);
 			hash_table_remove(&devices, key, DEVICES_KEYS);
 		}
@@ -790,10 +802,14 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->phone >= 0);
+		assert(dev->sess);
 		
 		/* Make a request at the driver */
+		async_exch_t *exch = async_exchange_begin(dev->sess);
+		
 		ipc_call_t answer;
-		aid_t msg = async_send_2(dev->phone, IPC_GET_IMETHOD(*request),
+		aid_t msg = async_send_2(exch, IPC_GET_IMETHOD(*request),
 		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
+		
+		async_exchange_end(exch);
 		
 		fibril_mutex_unlock(&devices_mutex);
Index: uspace/srv/fs/ext2fs/Makefile
===================================================================
--- uspace/srv/fs/ext2fs/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/srv/fs/ext2fs/Makefile	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2010 Martin Sucha
+# 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 = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT2_PREFIX)
+BINARY = ext2fs
+
+SOURCES = \
+	ext2fs.c \
+	ext2fs_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/ext2fs/ext2fs.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/srv/fs/ext2fs/ext2fs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Martin Sucha
+ * 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 fs
+ * @{
+ */ 
+
+/**
+ * @file	ext2.c
+ * @brief	EXT2 file system driver for HelenOS.
+ */
+
+#include "ext2fs.h"
+#include <ipc/services.h>
+#include <ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <stdio.h>
+#include <libfs.h>
+#include "../../vfs/vfs.h"
+
+#define NAME	"ext2fs"
+
+vfs_info_t ext2fs_vfs_info = {
+	.name = NAME,
+};
+
+fs_reg_t ext2fs_reg;
+
+/**
+ * This connection fibril processes VFS requests from VFS.
+ *
+ * In order to support simultaneous VFS requests, our design is as follows.
+ * The connection fibril accepts VFS requests from VFS. If there is only one
+ * instance of the fibril, VFS will need to serialize all VFS requests it sends
+ * to EXT2FS. To overcome this bottleneck, VFS can send EXT2FS the IPC_M_CONNECT_ME_TO
+ * call. In that case, a new connection fibril will be created, which in turn
+ * will accept the call. Thus, a new phone will be opened for VFS.
+ *
+ * There are few issues with this arrangement. First, VFS can run out of
+ * available phones. In that case, VFS can close some other phones or use one
+ * phone for more serialized requests. Similarily, EXT2FS can refuse to duplicate
+ * the connection. VFS should then just make use of already existing phones and
+ * route its requests through them. To avoid paying the fibril creation price 
+ * upon each request, EXT2FS might want to keep the connections open after the
+ * request has been completed.
+ */
+static void ext2fs_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	dprintf(NAME ": connection opened\n");
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			return;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case VFS_OUT_MOUNTED:
+			ext2fs_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			ext2fs_mount(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			ext2fs_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			ext2fs_unmount(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			ext2fs_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			ext2fs_read(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			ext2fs_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			ext2fs_truncate(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			ext2fs_stat(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			ext2fs_close(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			ext2fs_destroy(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			ext2fs_open_node(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			ext2fs_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	printf(NAME ": HelenOS EXT2 file system server\n");
+	
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		printf(NAME ": failed to connect to VFS\n");
+		return -1;
+	}
+
+	int rc = ext2fs_global_init();
+	if (rc != EOK) {
+		printf(NAME ": Failed global initialization\n");
+		return 1;
+	}	
+		
+	rc = fs_register(vfs_sess, &ext2fs_reg, &ext2fs_vfs_info, ext2fs_connection);
+	if (rc != EOK) {
+		fprintf(stdout, NAME ": Failed to register fs (%d)\n", rc);
+		return 1;
+	}
+	
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+	/* not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */ 
Index: uspace/srv/fs/ext2fs/ext2fs.h
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/srv/fs/ext2fs/ext2fs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Martin Sucha
+ * 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 fs
+ * @{
+ */ 
+
+#ifndef EXT2FS_EXT2FS_H_
+#define EXT2FS_EXT2FS_H_
+
+#include <libext2.h>
+#include <fibril_synch.h>
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include "../../vfs/vfs.h"
+
+#ifndef dprintf
+#define dprintf(...)	printf(__VA_ARGS__)
+#endif
+
+#define min(a, b)		((a) < (b) ? (a) : (b))
+
+extern fs_reg_t ext2fs_reg;
+
+extern int ext2fs_global_init(void);
+extern int ext2fs_global_fini(void);
+extern void ext2fs_mounted(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_mount(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_unmounted(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_unmount(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_lookup(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_read(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_write(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_truncate(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_stat(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_close(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_destroy(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_open_node(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_stat(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_sync(ipc_callid_t, ipc_call_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Martin Sucha
+ * 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 fs
+ * @{
+ */ 
+
+/**
+ * @file	ext2fs_ops.c
+ * @brief	Implementation of VFS operations for the EXT2 file system server.
+ */
+
+#include "ext2fs.h"
+#include "../../vfs/vfs.h"
+#include <libfs.h>
+#include <libblock.h>
+#include <libext2.h>
+#include <ipc/services.h>
+#include <ipc/devmap.h>
+#include <macros.h>
+#include <async.h>
+#include <errno.h>
+#include <str.h>
+#include <byteorder.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <sys/mman.h>
+#include <align.h>
+#include <adt/hash_table.h>
+#include <sys/typefmt.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#define EXT2FS_NODE(node)	((node) ? (ext2fs_node_t *) (node)->data : NULL)
+#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
+#define OPEN_NODES_KEYS 2
+#define OPEN_NODES_DEV_HANDLE_KEY 0
+#define OPEN_NODES_INODE_KEY 1
+#define OPEN_NODES_BUCKETS 256
+
+typedef struct ext2fs_instance {
+	link_t link;
+	devmap_handle_t devmap_handle;
+	ext2_filesystem_t *filesystem;
+	unsigned int open_nodes_count;
+} ext2fs_instance_t;
+
+typedef struct ext2fs_node {
+	ext2fs_instance_t *instance;
+	ext2_inode_ref_t *inode_ref;
+	fs_node_t *fs_node;
+	link_t link;
+	unsigned int references;
+} ext2fs_node_t;
+
+/*
+ * Forward declarations of auxiliary functions
+ */
+static int ext2fs_instance_get(devmap_handle_t, ext2fs_instance_t **);
+static void ext2fs_read_directory(ipc_callid_t, ipc_callid_t, aoff64_t,
+	size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
+static void ext2fs_read_file(ipc_callid_t, ipc_callid_t, aoff64_t,
+	size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
+static bool ext2fs_is_dots(const uint8_t *, size_t);
+static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
+static int ext2fs_node_put_core(ext2fs_node_t *);
+
+/*
+ * Forward declarations of EXT2 libfs operations.
+ */
+static int ext2fs_root_get(fs_node_t **, devmap_handle_t);
+static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
+static int ext2fs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int ext2fs_node_open(fs_node_t *);
+static int ext2fs_node_put(fs_node_t *);
+static int ext2fs_create_node(fs_node_t **, devmap_handle_t, int);
+static int ext2fs_destroy_node(fs_node_t *);
+static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
+static int ext2fs_unlink(fs_node_t *, fs_node_t *, const char *);
+static int ext2fs_has_children(bool *, fs_node_t *);
+static fs_index_t ext2fs_index_get(fs_node_t *);
+static aoff64_t ext2fs_size_get(fs_node_t *);
+static unsigned ext2fs_lnkcnt_get(fs_node_t *);
+static char ext2fs_plb_get_char(unsigned);
+static bool ext2fs_is_directory(fs_node_t *);
+static bool ext2fs_is_file(fs_node_t *node);
+static devmap_handle_t ext2fs_device_get(fs_node_t *node);
+
+/*
+ * Static variables
+ */
+static LIST_INITIALIZE(instance_list);
+static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
+static hash_table_t open_nodes;
+static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
+
+/* Hash table interface for open nodes hash table */
+static hash_index_t open_nodes_hash(unsigned long key[])
+{
+	/* TODO: This is very simple and probably can be improved */
+	return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
+}
+
+static int open_nodes_compare(unsigned long key[], hash_count_t keys, 
+    link_t *item)
+{
+	ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
+	assert(keys > 0);
+	if (enode->instance->devmap_handle !=
+	    ((devmap_handle_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
+		return false;
+	}
+	if (keys == 1) {
+		return true;
+	}
+	assert(keys == 2);
+	return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
+}
+
+static void open_nodes_remove_cb(link_t *link)
+{
+	/* We don't use remove callback for this hash table */
+}
+
+static hash_table_operations_t open_nodes_ops = {
+	.hash = open_nodes_hash,
+	.compare = open_nodes_compare,
+	.remove_callback = open_nodes_remove_cb,
+};
+
+/**
+ * 
+ */
+int ext2fs_global_init(void)
+{
+	if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
+	    OPEN_NODES_KEYS, &open_nodes_ops)) {
+		return ENOMEM;
+	}
+	return EOK;
+}
+
+int ext2fs_global_fini(void)
+{
+	hash_table_destroy(&open_nodes);
+	return EOK;
+}
+
+
+/*
+ * EXT2 libfs operations.
+ */
+
+/**
+ * Find an instance of filesystem for the given devmap_handle
+ */
+int ext2fs_instance_get(devmap_handle_t devmap_handle, ext2fs_instance_t **inst)
+{
+	EXT2FS_DBG("(%" PRIun ", -)", devmap_handle);
+	link_t *link;
+	ext2fs_instance_t *tmp;
+	
+	fibril_mutex_lock(&instance_list_mutex);
+
+	if (list_empty(&instance_list)) {
+		EXT2FS_DBG("list empty");
+		fibril_mutex_unlock(&instance_list_mutex);
+		return EINVAL;
+	}
+
+	for (link = instance_list.next; link != &instance_list; link = link->next) {
+		tmp = list_get_instance(link, ext2fs_instance_t, link);
+		
+		if (tmp->devmap_handle == devmap_handle) {
+			*inst = tmp;
+			fibril_mutex_unlock(&instance_list_mutex);
+			return EOK;
+		}
+	}
+	
+	EXT2FS_DBG("not found");
+	
+	fibril_mutex_unlock(&instance_list_mutex);
+	return EINVAL;
+}
+
+
+
+int ext2fs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
+{
+	EXT2FS_DBG("(-, %" PRIun ")", devmap_handle);
+	return ext2fs_node_get(rfn, devmap_handle, EXT2_INODE_ROOT_INDEX);
+}
+
+int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	EXT2FS_DBG("(-,-,%s)", component);
+	ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
+	ext2_filesystem_t *fs;
+	ext2_directory_iterator_t it;
+	int rc;
+	size_t name_size;
+	size_t component_size;
+	bool found = false;
+	uint32_t inode;
+	
+	fs = eparent->instance->filesystem;
+	
+	if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		return ENOTDIR;
+	}
+	
+	rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Find length of component in bytes
+	 * TODO: check for library function call that does this
+	 */
+	component_size = 0;
+	while (*(component+component_size) != 0) {
+		component_size++;
+	}
+	
+	while (it.current != NULL) {
+		inode = ext2_directory_entry_ll_get_inode(it.current);
+		
+		/* ignore empty directory entries */
+		if (inode != 0) {
+			name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+				it.current);
+
+			if (name_size == component_size && bcmp(component, &it.current->name,
+				    name_size) == 0) {
+				rc = ext2fs_node_get_core(rfn, eparent->instance,
+					inode);
+				if (rc != EOK) {
+					ext2_directory_iterator_fini(&it);
+					return rc;
+				}
+				found = true;
+				break;
+			}
+		}
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			return rc;
+		}
+	}
+	
+	ext2_directory_iterator_fini(&it);
+	
+	if (!found) {
+		return ENOENT;
+	}
+	
+	return EOK;
+}
+
+/** Instantiate a EXT2 in-core node. */
+int ext2fs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
+{
+	EXT2FS_DBG("(-,%" PRIun ",%u)", devmap_handle, index);
+	
+	ext2fs_instance_t *inst = NULL;
+	int rc;
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	return ext2fs_node_get_core(rfn, inst, index);
+}
+
+int ext2fs_node_get_core(fs_node_t **rfn, ext2fs_instance_t *inst,
+		fs_index_t index)
+{
+	int rc;
+	fs_node_t *node = NULL;
+	ext2fs_node_t *enode = NULL;
+	
+	ext2_inode_ref_t *inode_ref = NULL;
+
+	fibril_mutex_lock(&open_nodes_lock);
+	
+	/* Check if the node is not already open */
+	unsigned long key[] = {
+		[OPEN_NODES_DEV_HANDLE_KEY] = inst->devmap_handle,
+		[OPEN_NODES_INODE_KEY] = index,
+	};
+	link_t *already_open = hash_table_find(&open_nodes, key);
+
+	if (already_open) {
+		enode = hash_table_get_instance(already_open, ext2fs_node_t, link);
+		*rfn = enode->fs_node;
+		enode->references++;
+
+		fibril_mutex_unlock(&open_nodes_lock);
+		return EOK;
+	}
+
+	enode = malloc(sizeof(ext2fs_node_t));
+	if (enode == NULL) {
+		fibril_mutex_unlock(&open_nodes_lock);
+		return ENOMEM;
+	}
+
+	node = malloc(sizeof(fs_node_t));
+	if (node == NULL) {
+		free(enode);
+		fibril_mutex_unlock(&open_nodes_lock);
+		return ENOMEM;
+	}	
+	fs_node_initialize(node);
+
+	rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
+	if (rc != EOK) {
+		free(enode);
+		free(node);
+		fibril_mutex_unlock(&open_nodes_lock);
+		return rc;
+	}
+	
+	enode->inode_ref = inode_ref;
+	enode->instance = inst;
+	enode->references = 1;
+	enode->fs_node = node;
+	link_initialize(&enode->link);
+	
+	node->data = enode;
+	*rfn = node;
+	
+	hash_table_insert(&open_nodes, key, &enode->link);
+	inst->open_nodes_count++;
+	
+	EXT2FS_DBG("inode: %u", inode_ref->index);
+	
+	EXT2FS_DBG("EOK");
+
+	fibril_mutex_unlock(&open_nodes_lock);
+	return EOK;
+}
+
+int ext2fs_node_open(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	/*
+	 * Opening a file is stateless, nothing
+	 * to be done here.
+	 */
+	return EOK;
+}
+
+int ext2fs_node_put(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	int rc;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	
+	fibril_mutex_lock(&open_nodes_lock);
+
+	assert(enode->references > 0);
+	enode->references--;
+	if (enode->references == 0) {
+		rc = ext2fs_node_put_core(enode);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&open_nodes_lock);
+			return rc;
+		}
+	}
+
+	fibril_mutex_unlock(&open_nodes_lock);
+	
+	return EOK;
+}
+
+int ext2fs_node_put_core(ext2fs_node_t *enode)
+{
+	int rc;
+
+	unsigned long key[] = {
+		[OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->devmap_handle,
+		[OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
+	};
+	hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
+	assert(enode->instance->open_nodes_count > 0);
+	enode->instance->open_nodes_count--;
+
+	rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
+	if (rc != EOK) {
+		EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
+		return rc;
+	}
+
+	free(enode->fs_node);
+	free(enode);
+	return EOK;
+}
+
+int ext2fs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_destroy_node(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_has_children(bool *has_children, fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	ext2_directory_iterator_t it;
+	ext2_filesystem_t *fs;
+	int rc;
+	bool found = false;
+	size_t name_size;
+
+	fs = enode->instance->filesystem;
+
+	if (!ext2_inode_is_type(fs->superblock, enode->inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		*has_children = false;
+		EXT2FS_DBG("EOK - false");
+		return EOK;
+	}
+	
+	rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref);
+	if (rc != EOK) {
+		EXT2FS_DBG("error %u", rc);
+		return rc;
+	}
+	
+	/* Find a non-empty directory entry */
+	while (it.current != NULL) {
+		if (it.current->inode != 0) {
+			name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+				it.current);
+			if (!ext2fs_is_dots(&it.current->name, name_size)) {
+				found = true;
+				break;
+			}
+		}
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			EXT2FS_DBG("error %u", rc);
+			return rc;
+		}
+	}
+	
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		EXT2FS_DBG("error %u", rc);
+		return rc;
+	}
+
+	*has_children = found;
+	EXT2FS_DBG("EOK");
+	
+	return EOK;
+}
+
+
+fs_index_t ext2fs_index_get(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	EXT2FS_DBG("%u", enode->inode_ref->index);
+	return enode->inode_ref->index;
+}
+
+aoff64_t ext2fs_size_get(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	aoff64_t size = ext2_inode_get_size(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode);
+	EXT2FS_DBG("%" PRIu64, size);
+	return size;
+}
+
+unsigned ext2fs_lnkcnt_get(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	unsigned count = ext2_inode_get_usage_count(enode->inode_ref->inode);
+	EXT2FS_DBG("%u", count);
+	return count;
+}
+
+char ext2fs_plb_get_char(unsigned pos)
+{
+	return ext2fs_reg.plb_ro[pos % PLB_SIZE];
+}
+
+bool ext2fs_is_directory(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	bool is_dir = ext2_inode_is_type(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode, EXT2_INODE_MODE_DIRECTORY);
+	EXT2FS_DBG("%s", is_dir ? "true" : "false");
+	EXT2FS_DBG("%u", enode->inode_ref->index);
+	return is_dir;
+}
+
+bool ext2fs_is_file(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	bool is_file = ext2_inode_is_type(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode, EXT2_INODE_MODE_FILE);
+	EXT2FS_DBG("%s", is_file ? "true" : "false");
+	return is_file;
+}
+
+devmap_handle_t ext2fs_device_get(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	return enode->instance->devmap_handle;
+}
+
+/** libfs operations */
+libfs_ops_t ext2fs_libfs_ops = {
+	.root_get = ext2fs_root_get,
+	.match = ext2fs_match,
+	.node_get = ext2fs_node_get,
+	.node_open = ext2fs_node_open,
+	.node_put = ext2fs_node_put,
+	.create = ext2fs_create_node,
+	.destroy = ext2fs_destroy_node,
+	.link = ext2fs_link,
+	.unlink = ext2fs_unlink,
+	.has_children = ext2fs_has_children,
+	.index_get = ext2fs_index_get,
+	.size_get = ext2fs_size_get,
+	.lnkcnt_get = ext2fs_lnkcnt_get,
+	.plb_get_char = ext2fs_plb_get_char,
+	.is_directory = ext2fs_is_directory,
+	.is_file = ext2fs_is_file,
+	.device_get = ext2fs_device_get
+};
+
+/*
+ * VFS operations.
+ */
+
+void ext2fs_mounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	int rc;
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	ext2_filesystem_t *fs;
+	ext2fs_instance_t *inst;
+	bool read_only;
+	
+	/* Accept the mount options */
+	char *opts;
+	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
+	
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	free(opts);
+	
+	/* Allocate libext2 filesystem structure */
+	fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
+	if (fs == NULL) {
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+	
+	/* Allocate instance structure */
+	inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
+	if (inst == NULL) {
+		free(fs);
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+	
+	/* Initialize the filesystem  */
+	rc = ext2_filesystem_init(fs, devmap_handle);
+	if (rc != EOK) {
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Do some sanity checking */
+	rc = ext2_filesystem_check_sanity(fs);
+	if (rc != EOK) {
+		ext2_filesystem_fini(fs);
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Check flags */
+	rc = ext2_filesystem_check_flags(fs, &read_only);
+	if (rc != EOK) {
+		ext2_filesystem_fini(fs);
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Initialize instance */
+	link_initialize(&inst->link);
+	inst->devmap_handle = devmap_handle;
+	inst->filesystem = fs;
+	inst->open_nodes_count = 0;
+	
+	/* Read root node */
+	fs_node_t *root_node;
+	rc = ext2fs_node_get_core(&root_node, inst, EXT2_INODE_ROOT_INDEX);
+	if (rc != EOK) {
+		ext2_filesystem_fini(fs);
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	ext2fs_node_t *enode = EXT2FS_NODE(root_node);
+		
+	/* Add instance to the list */
+	fibril_mutex_lock(&instance_list_mutex);
+	list_append(&inst->link, &instance_list);
+	fibril_mutex_unlock(&instance_list_mutex);
+	
+	async_answer_3(rid, EOK,
+	    EXT2_INODE_ROOT_INDEX,
+	    0,
+	    ext2_inode_get_usage_count(enode->inode_ref->inode));
+	
+	ext2fs_node_put(root_node);
+}
+
+void ext2fs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_mount(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	ext2fs_instance_t *inst;
+	int rc;
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	fibril_mutex_lock(&open_nodes_lock);
+
+	EXT2FS_DBG("open_nodes_count = %d", inst->open_nodes_count)
+	if (inst->open_nodes_count != 0) {
+		fibril_mutex_unlock(&open_nodes_lock);
+		async_answer_0(rid, EBUSY);
+		return;
+	}
+	
+	/* Remove the instance from the list */
+	fibril_mutex_lock(&instance_list_mutex);
+	list_remove(&inst->link);
+	fibril_mutex_unlock(&instance_list_mutex);
+
+	fibril_mutex_unlock(&open_nodes_lock);
+	
+	ext2_filesystem_fini(inst->filesystem);
+	
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_unmount(&ext2fs_libfs_ops, rid, request);
+}
+
+void ext2fs_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_lookup(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	ext2fs_instance_t *inst;
+	ext2_inode_ref_t *inode_ref;
+	int rc;
+	
+	/*
+	 * Receive the read request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
+		    EXT2_INODE_MODE_FILE)) {
+		ext2fs_read_file(rid, callid, pos, size, inst, inode_ref);
+	}
+	else if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
+		    EXT2_INODE_MODE_DIRECTORY)) {
+		ext2fs_read_directory(rid, callid, pos, size, inst, inode_ref);
+	}
+	else {
+		/* Other inode types not supported */
+		async_answer_0(callid, ENOTSUP);
+		async_answer_0(rid, ENOTSUP);
+	}
+	
+	ext2_filesystem_put_inode_ref(inode_ref);
+	
+}
+
+/**
+ * Determine whether given directory entry name is . or ..
+ */
+bool ext2fs_is_dots(const uint8_t *name, size_t name_size) {
+	if (name_size == 1 && name[0] == '.') {
+		return true;
+	}
+	
+	if (name_size == 2 && name[0] == '.' && name[1] == '.') {
+		return true;
+	}
+	
+	return false;
+}
+
+void ext2fs_read_directory(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
+	size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
+{
+	ext2_directory_iterator_t it;
+	aoff64_t cur;
+	uint8_t *buf;
+	size_t name_size;
+	int rc;
+	bool found = false;
+	
+	rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Find the index we want to read
+	 * Note that we need to iterate and count as
+	 * the underlying structure is a linked list
+	 * Moreover, we want to skip . and .. entries
+	 * as these are not used in HelenOS
+	 */
+	cur = 0;
+	while (it.current != NULL) {
+		if (it.current->inode == 0) {
+			goto skip;
+		}
+		
+		name_size = ext2_directory_entry_ll_get_name_length(
+			inst->filesystem->superblock, it.current);
+		
+		/* skip . and .. */
+		if (ext2fs_is_dots(&it.current->name, name_size)) {
+			goto skip;
+		}
+		
+		/* Is this the dir entry we want to read? */
+		if (cur == pos) {
+			/* The on-disk entry does not contain \0 at the end
+			 * end of entry name, so we copy it to new buffer
+			 * and add the \0 at the end
+			 */
+			buf = malloc(name_size+1);
+			if (buf == NULL) {
+				ext2_directory_iterator_fini(&it);
+				async_answer_0(callid, ENOMEM);
+				async_answer_0(rid, ENOMEM);
+				return;
+			}
+			memcpy(buf, &it.current->name, name_size);
+			*(buf+name_size) = 0;
+			found = true;
+			(void) async_data_read_finalize(callid, buf, name_size+1);
+			free(buf);
+			break;
+		}
+		cur++;
+		
+skip:
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			async_answer_0(callid, rc);
+			async_answer_0(rid, rc);
+			return;
+		}
+	}
+	
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	if (found) {
+		async_answer_1(rid, EOK, 1);
+	}
+	else {
+		async_answer_0(callid, ENOENT);
+		async_answer_0(rid, ENOENT);
+	}
+}
+
+void ext2fs_read_file(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
+	size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
+{
+	int rc;
+	uint32_t block_size;
+	aoff64_t file_block;
+	uint64_t file_size;
+	uint32_t fs_block;
+	size_t offset_in_block;
+	size_t bytes;
+	block_t *block;
+	uint8_t *buffer;
+	
+	file_size = ext2_inode_get_size(inst->filesystem->superblock,
+		inode_ref->inode);
+	
+	if (pos >= file_size) {
+		/* Read 0 bytes successfully */
+		async_data_read_finalize(callid, NULL, 0);
+		async_answer_1(rid, EOK, 0);
+		return;
+	}
+	
+	/* For now, we only read data from one block at a time */
+	block_size = ext2_superblock_get_block_size(inst->filesystem->superblock);
+	file_block = pos / block_size;
+	offset_in_block = pos % block_size;
+	bytes = min(block_size - offset_in_block, size);
+	
+	/* Handle end of file */
+	if (pos + bytes > file_size) {
+		bytes = file_size - pos;
+	}
+	
+	/* Get the real block number */
+	rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
+		inode_ref->inode, file_block, &fs_block);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Check for sparse file
+	 * If ext2_filesystem_get_inode_data_block_index returned
+	 * fs_block == 0, it means that the given block is not allocated for the 
+	 * file and we need to return a buffer of zeros
+	 */
+	if (fs_block == 0) {
+		buffer = malloc(bytes);
+		if (buffer == NULL) {
+			async_answer_0(callid, ENOMEM);
+			async_answer_0(rid, ENOMEM);
+			return;
+		}
+		
+		memset(buffer, 0, bytes);
+		
+		async_data_read_finalize(callid, buffer, bytes);
+		async_answer_1(rid, EOK, bytes);
+		
+		free(buffer);
+		
+		return;
+	}
+	
+	/* Usual case - we need to read a block from device */
+	rc = block_get(&block, inst->devmap_handle, fs_block, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	assert(offset_in_block + bytes <= block_size);
+	async_data_read_finalize(callid, block->data + offset_in_block, bytes);
+	
+	rc = block_put(block);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+		
+	async_answer_1(rid, EOK, bytes);
+}
+
+void ext2fs_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t pos =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2fs_truncate(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t size =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2fs_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_destroy(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2fs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_open_node(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_stat(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/fat/fat.c
===================================================================
--- uspace/srv/fs/fat/fat.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/fs/fat/fat.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,5 +39,5 @@
 #include "fat.h"
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <errno.h>
@@ -88,12 +88,13 @@
 	
 	dprintf(NAME ": connection opened\n");
-	while (1) {
-		ipc_callid_t callid;
+	
+	while (true) {
 		ipc_call_t call;
-	
-		callid = async_get_call(&call);
-		switch  (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
 			return;
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case VFS_OUT_MOUNTED:
 			fat_mounted(callid, &call);
@@ -144,20 +145,18 @@
 int main(int argc, char **argv)
 {
-	int vfs_phone;
-	int rc;
-
 	printf(NAME ": HelenOS FAT file system server\n");
-
-	rc = fat_idx_init();
+	
+	int rc = fat_idx_init();
 	if (rc != EOK)
 		goto err;
-
-	vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
-	if (vfs_phone < EOK) {
+	
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
 		printf(NAME ": failed to connect to VFS\n");
 		return -1;
 	}
 	
-	rc = fs_register(vfs_phone, &fat_reg, &fat_vfs_info, fat_connection);
+	rc = fs_register(vfs_sess, &fat_reg, &fat_vfs_info, fat_connection);
 	if (rc != EOK) {
 		fat_idx_fini();
@@ -168,7 +167,8 @@
 	task_retval(0);
 	async_manager();
-	/* not reached */
+	
+	/* Not reached */
 	return 0;
-
+	
 err:
 	printf(NAME ": Failed to register file system (%d)\n", rc);
@@ -178,3 +178,3 @@
 /**
  * @}
- */ 
+ */
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -970,5 +970,5 @@
 
 	/* initialize libblock */
-	rc = block_init(devmap_handle, BS_SIZE);
+	rc = block_init(EXCHANGE_SERIALIZE, devmap_handle, BS_SIZE);
 	if (rc != EOK) {
 		async_answer_0(rid, rc);
Index: uspace/srv/fs/tmpfs/tmpfs.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -30,5 +30,5 @@
 /** @addtogroup fs
  * @{
- */ 
+ */
 
 /**
@@ -43,5 +43,5 @@
 #include "tmpfs.h"
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <errno.h>
@@ -94,12 +94,13 @@
 	
 	dprintf(NAME ": connection opened\n");
-	while (1) {
-		ipc_callid_t callid;
+	
+	while (true) {
 		ipc_call_t call;
-	
-		callid = async_get_call(&call);
-		switch  (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
 			return;
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case VFS_OUT_MOUNTED:
 			tmpfs_mounted(callid, &call);
@@ -151,17 +152,18 @@
 {
 	printf(NAME ": HelenOS TMPFS file system server\n");
-
+	
 	if (!tmpfs_init()) {
 		printf(NAME ": failed to initialize TMPFS\n");
 		return -1;
 	}
-
-	int vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
-	if (vfs_phone < EOK) {
+	
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
 		printf(NAME ": Unable to connect to VFS\n");
 		return -1;
 	}
-
-	int rc = fs_register(vfs_phone, &tmpfs_reg, &tmpfs_vfs_info,
+	
+	int rc = fs_register(vfs_sess, &tmpfs_reg, &tmpfs_vfs_info,
 	    tmpfs_connection);
 	if (rc != EOK) {
@@ -169,9 +171,10 @@
 		return rc;
 	}
-
+	
 	printf(NAME ": Accepting connections\n");
 	task_retval(0);
 	async_manager();
-	/* not reached */
+	
+	/* Not reached */
 	return 0;
 }
@@ -179,3 +182,3 @@
 /**
  * @}
- */ 
+ */
Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -167,5 +167,5 @@
 	int rc;
 
-	rc = block_init(dev, TMPFS_COMM_SIZE);
+	rc = block_init(EXCHANGE_SERIALIZE, dev, TMPFS_COMM_SIZE);
 	if (rc != EOK)
 		return false; 
Index: uspace/srv/hid/adb_mouse/adb_dev.c
===================================================================
--- uspace/srv/hid/adb_mouse/adb_dev.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/adb_mouse/adb_dev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,4 +39,9 @@
 #include <fcntl.h>
 #include <errno.h>
+#include <devmap.h>
+#include <devmap_obsolete.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <kernel/ipc/ipc_methods.h>
 
 #include "adb_mouse.h"
@@ -45,27 +50,23 @@
 static void adb_dev_events(ipc_callid_t iid, ipc_call_t *icall);
 
-static int dev_phone;
-
 int adb_dev_init(void)
 {
-	const char *input = "/dev/adb/mouse";
-	int input_fd;
-
-	printf(NAME ": open %s\n", input);
-
-	input_fd = open(input, O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s (%d)\n", input, input_fd);
-		return false;
+	devmap_handle_t handle;
+	int rc = devmap_device_get_handle("adb/mouse", &handle,
+	    IPC_FLAG_BLOCKING);
+	
+	if (rc != EOK) {
+		printf("%s: Failed resolving ADB\n", NAME);
+		return rc;
 	}
-
-	dev_phone = fd_phone(input_fd);
+	
+	int dev_phone = devmap_obsolete_device_connect(handle, IPC_FLAG_BLOCKING);
 	if (dev_phone < 0) {
-		printf(NAME ": Failed to connect to device\n");
-		return false;
+		printf("%s: Failed connecting to ADB\n", NAME);
+		return ENOENT;
 	}
-
+	
 	/* NB: The callback connection is slotted for removal */
-	if (async_connect_to_me(dev_phone, 0, 0, 0, adb_dev_events) != 0) {
+	if (async_obsolete_connect_to_me(dev_phone, 0, 0, 0, adb_dev_events) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return false;
@@ -84,9 +85,11 @@
 
 		int retval;
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
 
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			/* TODO: Handle hangup */
-			return;
 		case IPC_FIRST_USER_METHOD:
 			mouse_handle_data(IPC_GET_ARG1(call));
Index: uspace/srv/hid/adb_mouse/adb_mouse.c
===================================================================
--- uspace/srv/hid/adb_mouse/adb_mouse.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/adb_mouse/adb_mouse.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -43,9 +43,12 @@
 #include <stdlib.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <errno.h>
 #include <devmap.h>
-
 #include "adb_mouse.h"
 #include "adb_dev.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 static void client_connection(ipc_callid_t iid, ipc_call_t *icall);
@@ -101,8 +104,8 @@
 	while (1) {
 		callid = async_get_call(&call);
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!IPC_GET_IMETHOD(call)) {
 			if (client_phone != -1) {
-				async_hangup(client_phone);
+				async_obsolete_hangup(client_phone);
 				client_phone = -1;
 			}
@@ -110,4 +113,7 @@
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case IPC_M_CONNECT_TO_ME:
 			if (client_phone != -1) {
@@ -158,5 +164,5 @@
 {
 	if (client_phone != -1) {
-		async_msg_2(client_phone, MEVENT_BUTTON, button, press);
+		async_obsolete_msg_2(client_phone, MEVENT_BUTTON, button, press);
 	}
 }
@@ -165,5 +171,5 @@
 {
 	if (client_phone != -1)
-		async_msg_2(client_phone, MEVENT_MOVE, dx, dy);
+		async_obsolete_msg_2(client_phone, MEVENT_MOVE, dx, dy);
 }
 
Index: uspace/srv/hid/char_mouse/char_mouse.c
===================================================================
--- uspace/srv/hid/char_mouse/char_mouse.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/char_mouse/char_mouse.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -43,10 +43,13 @@
 #include <stdlib.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <errno.h>
 #include <devmap.h>
-
 #include <char_mouse.h>
 #include <mouse_port.h>
 #include <mouse_proto.h>
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME       "mouse"
@@ -65,5 +68,5 @@
 /*	printf("ev_btn: button %d, press %d\n", button, press);*/
 	if (client_phone != -1) {
-		async_msg_2(client_phone, MEVENT_BUTTON, button, press);
+		async_obsolete_msg_2(client_phone, MEVENT_BUTTON, button, press);
 	}
 }
@@ -73,5 +76,5 @@
 /*	printf("ev_move: dx %d, dy %d\n", dx, dy);*/
 	if (client_phone != -1)
-		async_msg_2(client_phone, MEVENT_MOVE, dx, dy);
+		async_obsolete_msg_2(client_phone, MEVENT_MOVE, dx, dy);
 }
 
@@ -86,8 +89,8 @@
 	while (1) {
 		callid = async_get_call(&call);
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!IPC_GET_IMETHOD(call)) {
 			if (client_phone != -1) {
-				async_hangup(client_phone);
+				async_obsolete_hangup(client_phone);
 				client_phone = -1;
 			}
@@ -95,4 +98,7 @@
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case IPC_M_CONNECT_TO_ME:
 			if (client_phone != -1) {
Index: uspace/srv/hid/char_mouse/chardev.c
===================================================================
--- uspace/srv/hid/char_mouse/chardev.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/char_mouse/chardev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -36,8 +36,10 @@
 #include <ipc/char.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <vfs/vfs.h>
 #include <fcntl.h>
 #include <errno.h>
-
+#include <devmap.h>
+#include <devmap_obsolete.h>
 #include <char_mouse.h>
 #include <mouse_port.h>
@@ -51,27 +53,25 @@
 int mouse_port_init(void)
 {
-	const char *input = "/dev/char/ps2b";
-	int input_fd;
-
-	printf(NAME ": open %s\n", input);
-
-	input_fd = open(input, O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s (%d)\n", input, input_fd);
-		return false;
+	devmap_handle_t handle;
+	int rc = devmap_device_get_handle("char/ps2b", &handle,
+	    IPC_FLAG_BLOCKING);
+	
+	if (rc != EOK) {
+		printf("%s: Failed resolving PS/2\n", NAME);
+		return rc;
 	}
-
-	dev_phone = fd_phone(input_fd);
+	
+	dev_phone = devmap_obsolete_device_connect(handle, IPC_FLAG_BLOCKING);
 	if (dev_phone < 0) {
-		printf(NAME ": Failed to connect to device\n");
-		return false;
+		printf("%s: Failed connecting to PS/2\n", NAME);
+		return ENOENT;
 	}
-
+	
 	/* NB: The callback connection is slotted for removal */
-	if (async_connect_to_me(dev_phone, 0, 0, 0, chardev_events) != 0) {
+	if (async_obsolete_connect_to_me(dev_phone, 0, 0, 0, chardev_events) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return false;
 	}
-
+	
 	return 0;
 }
@@ -87,5 +87,5 @@
 void mouse_port_write(uint8_t data)
 {
-	async_msg_1(dev_phone, CHAR_WRITE_BYTE, data);
+	async_obsolete_msg_1(dev_phone, CHAR_WRITE_BYTE, data);
 }
 
@@ -99,9 +99,11 @@
 
 		int retval;
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
 
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			/* TODO: Handle hangup */
-			return;
 		case IPC_FIRST_USER_METHOD:
 			mouse_handle_byte(IPC_GET_ARG1(call));
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/console/console.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,9 +39,12 @@
 #include <ipc/fb.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
+#include <ns_obsolete.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ipc/console.h>
 #include <unistd.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <adt/fifo.h>
 #include <sys/mman.h>
@@ -51,4 +54,5 @@
 #include <event.h>
 #include <devmap.h>
+#include <devmap_obsolete.h>
 #include <fcntl.h>
 #include <vfs/vfs.h>
@@ -56,4 +60,5 @@
 #include <io/style.h>
 #include <io/screenbuffer.h>
+#include <inttypes.h>
 
 #include "console.h"
@@ -61,7 +66,18 @@
 #include "keybuffer.h"
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME       "console"
 #define NAMESPACE  "term"
+
+/** Interval for checking for new keyboard (1/4s). */
+#define HOTPLUG_WATCH_INTERVAL (1000 * 250)
+
+/* Kernel defines 32 but does not export it. */
+#define MAX_IPC_OUTGOING_PHONES 128
+
+/** To allow proper phone closing. */
+static ipc_callid_t driver_phones[MAX_IPC_OUTGOING_PHONES] = { 0 };
 
 /** Phone to the keyboard driver. */
@@ -111,55 +127,55 @@
 static void curs_visibility(bool visible)
 {
-	async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible); 
+	async_obsolete_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible); 
 }
 
 static void curs_hide_sync(void)
 {
-	async_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false); 
+	async_obsolete_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false); 
 }
 
 static void curs_goto(sysarg_t x, sysarg_t y)
 {
-	async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
+	async_obsolete_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
 }
 
 static void screen_clear(void)
 {
-	async_msg_0(fb_info.phone, FB_CLEAR);
+	async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
 }
 
 static void screen_yield(void)
 {
-	async_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
+	async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
 }
 
 static void screen_reclaim(void)
 {
-	async_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
+	async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
 }
 
 static void kbd_yield(void)
 {
-	async_req_0_0(kbd_phone, KBD_YIELD);
+	async_obsolete_req_0_0(kbd_phone, KBD_YIELD);
 }
 
 static void kbd_reclaim(void)
 {
-	async_req_0_0(kbd_phone, KBD_RECLAIM);
+	async_obsolete_req_0_0(kbd_phone, KBD_RECLAIM);
 }
 
 static void set_style(uint8_t style)
 {
-	async_msg_1(fb_info.phone, FB_SET_STYLE, style);
+	async_obsolete_msg_1(fb_info.phone, FB_SET_STYLE, style);
 }
 
 static void set_color(uint8_t fgcolor, uint8_t bgcolor, uint8_t flags)
 {
-	async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
+	async_obsolete_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
 }
 
 static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
 {
-	async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor); 
+	async_obsolete_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor); 
 }
 
@@ -216,5 +232,5 @@
 		}
 		
-		async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
+		async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
 		    x0, y0, width, height);
 	}
@@ -257,5 +273,5 @@
 static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row)
 {
-	async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
+	async_obsolete_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
 }
 
@@ -306,5 +322,5 @@
 		
 		if (cons == active_console)
-			async_msg_1(fb_info.phone, FB_SCROLL, 1);
+			async_obsolete_msg_1(fb_info.phone, FB_SCROLL, 1);
 	}
 	
@@ -323,10 +339,10 @@
 	
 	if (cons == kernel_console) {
-		async_serialize_start();
+		async_obsolete_serialize_start();
 		curs_hide_sync();
 		gcons_in_kernel();
 		screen_yield();
 		kbd_yield();
-		async_serialize_end();
+		async_obsolete_serialize_end();
 		
 		if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
@@ -338,5 +354,5 @@
 	
 	if (cons != kernel_console) {
-		async_serialize_start();
+		async_obsolete_serialize_start();
 		
 		if (active_console == kernel_console) {
@@ -365,5 +381,5 @@
 			
 			/* This call can preempt, but we are already at the end */
-			rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
+			rc = async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
 			    0, 0, cons->scr.size_x,
 			    cons->scr.size_y);
@@ -393,5 +409,18 @@
 		curs_visibility(cons->scr.is_cursor_visible);
 		
-		async_serialize_end();
+		async_obsolete_serialize_end();
+	}
+}
+
+static void close_driver_phone(ipc_callid_t hash)
+{
+	int i;
+	for (i = 0; i < MAX_IPC_OUTGOING_PHONES; i++) {
+		if (driver_phones[i] == hash) {
+			printf("Device %" PRIxn " gone.\n", hash);
+			driver_phones[i] = 0;
+			async_obsolete_hangup(i);
+			return;
+		}
 	}
 }
@@ -406,10 +435,13 @@
 		
 		int retval;
-		console_event_t ev;
+		kbd_event_t ev;
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			close_driver_phone(iid);
+			return;
+		}
 		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			/* TODO: Handle hangup */
-			return;
 		case KBD_EVENT:
 			/* Got event from keyboard driver. */
@@ -451,8 +483,11 @@
 		int retval;
 		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			close_driver_phone(iid);
+			return;
+		}
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			/* TODO: Handle hangup */
-			return;
 		case MEVENT_BUTTON:
 			if (IPC_GET_ARG1(call) == 1) {
@@ -487,5 +522,5 @@
 	}
 	
-	async_serialize_start();
+	async_obsolete_serialize_start();
 	
 	size_t off = 0;
@@ -495,5 +530,5 @@
 	}
 	
-	async_serialize_end();
+	async_obsolete_serialize_end();
 	
 	gcons_notify_char(cons->index);
@@ -521,5 +556,5 @@
 	
 	size_t pos = 0;
-	console_event_t ev;
+	kbd_event_t ev;
 	fibril_mutex_lock(&input_mutex);
 	
@@ -546,5 +581,5 @@
 static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	
 	fibril_mutex_lock(&input_mutex);
@@ -590,5 +625,5 @@
 	int rc;
 	
-	async_serialize_start();
+	async_obsolete_serialize_start();
 	if (cons->refcount == 0)
 		gcons_notify_connect(cons->index);
@@ -600,7 +635,7 @@
 	
 	while (true) {
-		async_serialize_end();
+		async_obsolete_serialize_end();
 		callid = async_get_call(&call);
-		async_serialize_start();
+		async_obsolete_serialize_start();
 		
 		arg1 = 0;
@@ -608,24 +643,26 @@
 		arg3 = 0;
 		
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		if (!IPC_GET_IMETHOD(call)) {
 			cons->refcount--;
 			if (cons->refcount == 0)
 				gcons_notify_disconnect(cons->index);
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case VFS_OUT_READ:
-			async_serialize_end();
+			async_obsolete_serialize_end();
 			cons_read(cons, callid, &call);
-			async_serialize_start();
+			async_obsolete_serialize_start();
 			continue;
 		case VFS_OUT_WRITE:
-			async_serialize_end();
+			async_obsolete_serialize_end();
 			cons_write(cons, callid, &call);
-			async_serialize_start();
+			async_obsolete_serialize_start();
 			continue;
 		case VFS_OUT_SYNC:
 			fb_pending_flush();
 			if (cons == active_console) {
-				async_req_0_0(fb_info.phone, FB_FLUSH);
+				async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
 				curs_goto(cons->scr.position_x, cons->scr.position_y);
 			}
@@ -634,5 +671,5 @@
 			/* Send message to fb */
 			if (cons == active_console)
-				async_msg_0(fb_info.phone, FB_CLEAR);
+				async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
 			
 			screenbuffer_clear(&cons->scr);
@@ -693,7 +730,7 @@
 			break;
 		case CONSOLE_GET_EVENT:
-			async_serialize_end();
+			async_obsolete_serialize_end();
 			cons_get_event(cons, callid, &call);
-			async_serialize_start();
+			async_obsolete_serialize_start();
 			continue;
 		case CONSOLE_KCON_ENABLE:
@@ -710,55 +747,153 @@
 }
 
-static bool console_init(char *input)
+static int async_connect_to_me_hack(int phone, sysarg_t arg1, sysarg_t arg2,
+    sysarg_t arg3, async_client_conn_t client_receiver, ipc_callid_t *hash)
+{
+	sysarg_t task_hash;
+	sysarg_t phone_hash;
+	int rc = async_obsolete_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
+	    NULL, NULL, NULL, &task_hash, &phone_hash);
+	if (rc != EOK)
+		return rc;
+	
+	if (client_receiver != NULL)
+		async_new_connection(task_hash, phone_hash, phone_hash, NULL,
+		    client_receiver);
+	
+	if (hash != NULL)
+		*hash = phone_hash;
+	
+	return EOK;
+}
+
+static int connect_keyboard_or_mouse(const char *devname,
+    async_client_conn_t handler, const char *dev)
+{
+	int phone;
+	devmap_handle_t handle;
+	
+	int rc = devmap_device_get_handle(dev, &handle, 0);
+	if (rc == EOK) {
+		phone = devmap_obsolete_device_connect(handle, 0);
+		if (phone < 0) {
+			printf("%s: Failed to connect to input device\n", NAME);
+			return phone;
+		}
+	} else
+		return rc;
+	
+	/* NB: The callback connection is slotted for removal */
+	ipc_callid_t hash;
+	rc = async_connect_to_me_hack(phone, SERVICE_CONSOLE, 0, phone,
+	    handler, &hash);
+	if (rc != EOK) {
+		async_obsolete_hangup(phone);
+		printf("%s: Failed to create callback from input device (%s).\n",
+		    NAME, str_error(rc));
+		return rc;
+	}
+	
+	driver_phones[phone] = hash;
+	printf("%s: found %s \"%s\" (%" PRIxn ").\n", NAME, devname, dev, hash);
+	return phone;
+}
+
+static int connect_keyboard(const char *dev)
+{
+	return connect_keyboard_or_mouse("keyboard", keyboard_events, dev);
+}
+
+static int connect_mouse(const char *dev)
+{
+	return connect_keyboard_or_mouse("mouse", mouse_events, dev);
+}
+
+struct hid_class_info {
+	char *classname;
+	int (*connection_func)(const char *);
+};
+
+/** Periodically check for new keyboards in /dev/class/.
+ *
+ * @param arg Class name.
+ *
+ * @return This function should never exit.
+ *
+ */
+static int check_new_device_fibril(void *arg)
+{
+	struct hid_class_info *dev_info = (struct hid_class_info *) arg;
+	
+	size_t index = 1;
+	
+	while (true) {
+		async_usleep(HOTPLUG_WATCH_INTERVAL);
+		
+		char *dev;
+		int rc = asprintf(&dev, "class/%s\\%zu",
+		    dev_info->classname, index);
+		if (rc < 0)
+			continue;
+		
+		rc = dev_info->connection_func(dev);
+		if (rc > 0) {
+			/* We do not allow unplug. */
+			index++;
+		}
+		
+		free(dev);
+	}
+	
+	return EOK;
+}
+
+/** Start a fibril monitoring hot-plugged keyboards.
+ */
+static void check_new_devices_in_background(int (*connection_func)(const char *),
+    const char *classname)
+{
+	struct hid_class_info *dev_info = malloc(sizeof(struct hid_class_info));
+	if (dev_info == NULL) {
+		printf("%s: Out of memory, no hot-plug support.\n", NAME);
+		return;
+	}
+	
+	int rc = asprintf(&dev_info->classname, "%s", classname);
+	if (rc < 0) {
+		printf("%s: Failed to format classname: %s.\n", NAME,
+		    str_error(rc));
+		return;
+	}
+	
+	dev_info->connection_func = connection_func;
+	
+	fid_t fid = fibril_create(check_new_device_fibril, (void *) dev_info);
+	if (!fid) {
+		printf("%s: Failed to create hot-plug fibril for %s.\n", NAME,
+		    classname);
+		return;
+	}
+	
+	fibril_add_ready(fid);
+}
+
+static bool console_srv_init(char *kdev)
 {
 	/* Connect to input device */
-	int input_fd = open(input, O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s\n", input);
+	kbd_phone = connect_keyboard(kdev);
+	if (kbd_phone < 0)
 		return false;
-	}
-	
-	kbd_phone = fd_phone(input_fd);
-	if (kbd_phone < 0) {
-		printf(NAME ": Failed to connect to input device\n");
+	
+	mouse_phone = connect_mouse("hid_in/mouse");
+	if (mouse_phone < 0) {
+		printf("%s: Failed to connect to mouse device %s\n", NAME,
+		    str_error(mouse_phone));
+	}
+	
+	/* Connect to framebuffer driver */
+	fb_info.phone = service_obsolete_connect_blocking(SERVICE_VIDEO, 0, 0);
+	if (fb_info.phone < 0) {
+		printf("%s: Failed to connect to video service\n", NAME);
 		return false;
-	}
-	
-	/* NB: The callback connection is slotted for removal */
-	if (async_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, keyboard_events)
-	    != 0) {
-		printf(NAME ": Failed to create callback from input device\n");
-		return false;
-	}
-	
-	/* Connect to mouse device */
-	mouse_phone = -1;
-	int mouse_fd = open("/dev/hid_in/mouse", O_RDONLY);
-	
-	if (mouse_fd < 0) {
-		printf(NAME ": Notice - failed opening %s\n", "/dev/hid_in/mouse");
-		goto skip_mouse;
-	}
-	
-	mouse_phone = fd_phone(mouse_fd);
-	if (mouse_phone < 0) {
-		printf(NAME ": Failed to connect to mouse device\n");
-		goto skip_mouse;
-	}
-	
-	if (async_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, mouse_events)
-	    != 0) {
-		printf(NAME ": Failed to create callback from mouse device\n");
-		mouse_phone = -1;
-		goto skip_mouse;
-	}
-	
-skip_mouse:
-	
-	/* Connect to framebuffer driver */
-	fb_info.phone = service_connect_blocking(SERVICE_VIDEO, 0, 0);
-	if (fb_info.phone < 0) {
-		printf(NAME ": Failed to connect to video service\n");
-		return -1;
 	}
 	
@@ -766,5 +901,5 @@
 	int rc = devmap_driver_register(NAME, client_connection);
 	if (rc < 0) {
-		printf(NAME ": Unable to register driver (%d)\n", rc);
+		printf("%s: Unable to register driver (%d)\n", NAME, rc);
 		return false;
 	}
@@ -774,7 +909,7 @@
 	
 	/* Synchronize, the gcons could put something in queue */
-	async_req_0_0(fb_info.phone, FB_FLUSH);
-	async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
-	async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
+	async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
+	async_obsolete_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
+	async_obsolete_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
 	
 	/* Set up shared memory buffer. */
@@ -787,5 +922,5 @@
 	
 	if (interbuffer) {
-		if (async_share_out_start(fb_info.phone, interbuffer,
+		if (async_obsolete_share_out_start(fb_info.phone, interbuffer,
 		    AS_AREA_READ) != EOK) {
 			as_area_destroy(interbuffer);
@@ -802,5 +937,5 @@
 			if (screenbuffer_init(&consoles[i].scr,
 			    fb_info.cols, fb_info.rows) == NULL) {
-				printf(NAME ": Unable to allocate screen buffer %zu\n", i);
+				printf("%s: Unable to allocate screen buffer %zu\n", NAME, i);
 				return false;
 			}
@@ -814,5 +949,5 @@
 			
 			if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
-				printf(NAME ": Unable to register device %s\n", vc);
+				printf("%s: Unable to register device %s\n", NAME, vc);
 				return false;
 			}
@@ -824,5 +959,5 @@
 	
 	/* Initialize the screen */
-	async_serialize_start();
+	async_obsolete_serialize_start();
 	gcons_redraw_console();
 	set_style(STYLE_NORMAL);
@@ -830,10 +965,14 @@
 	curs_goto(0, 0);
 	curs_visibility(active_console->scr.is_cursor_visible);
-	async_serialize_end();
+	async_obsolete_serialize_end();
 	
 	/* Receive kernel notifications */
 	async_set_interrupt_received(interrupt_received);
 	if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
-		printf(NAME ": Error registering kconsole notifications\n");
+		printf("%s: Error registering kconsole notifications\n", NAME);
+	
+	/* Start fibril for checking on hot-plugged keyboards. */
+	check_new_devices_in_background(connect_keyboard, "keyboard");
+	check_new_devices_in_background(connect_mouse, "mouse");
 	
 	return true;
@@ -854,5 +993,5 @@
 	printf(NAME ": HelenOS Console service\n");
 	
-	if (!console_init(argv[1]))
+	if (!console_srv_init(argv[1]))
 		return -1;
 	
Index: uspace/srv/hid/console/gcons.c
===================================================================
--- uspace/srv/hid/console/gcons.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/console/gcons.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -35,4 +35,5 @@
 #include <ipc/fb.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <stdio.h>
 #include <sys/mman.h>
@@ -115,5 +116,5 @@
 static void vp_switch(int vp)
 {
-	async_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
+	async_obsolete_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
 }
 
@@ -121,5 +122,5 @@
 static int vp_create(sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
 {
-	return async_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y,
+	return async_obsolete_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y,
 	    (width << 16) | height);
 }
@@ -127,10 +128,10 @@
 static void clear(void)
 {
-	async_msg_0(fbphone, FB_CLEAR);
+	async_obsolete_msg_0(fbphone, FB_CLEAR);
 }
 
 static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
 {
-	async_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
+	async_obsolete_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
 }
 
@@ -138,5 +139,5 @@
 static void tran_putch(wchar_t ch, sysarg_t col, sysarg_t row)
 {
-	async_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
+	async_obsolete_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
 }
 
@@ -149,5 +150,5 @@
 	
 	if (ic_pixmaps[state] != -1)
-		async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
+		async_obsolete_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
 		    ic_pixmaps[state]);
 	
@@ -177,5 +178,5 @@
 		
 		if (animation != -1)
-			async_msg_1(fbphone, FB_ANIM_START, animation);
+			async_obsolete_msg_1(fbphone, FB_ANIM_START, animation);
 	} else {
 		if (console_state[active_console] == CONS_DISCONNECTED_SEL)
@@ -258,5 +259,5 @@
 {
 	if (animation != -1)
-		async_msg_1(fbphone, FB_ANIM_STOP, animation);
+		async_obsolete_msg_1(fbphone, FB_ANIM_STOP, animation);
 	
 	active_console = KERNEL_CONSOLE;
@@ -294,5 +295,5 @@
 	
 	if (active_console != KERNEL_CONSOLE)
-		async_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
+		async_obsolete_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
 }
 
@@ -374,18 +375,18 @@
 	
 	/* Send area */
-	int rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
+	int rc = async_obsolete_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
 	if (rc)
 		goto exit;
 	
-	rc = async_share_out_start(fbphone, shm, PROTO_READ);
+	rc = async_obsolete_share_out_start(fbphone, shm, PROTO_READ);
 	if (rc)
 		goto drop;
 	
 	/* Draw logo */
-	async_msg_2(fbphone, FB_DRAW_PPM, x, y);
+	async_obsolete_msg_2(fbphone, FB_DRAW_PPM, x, y);
 	
 drop:
 	/* Drop area */
-	async_msg_0(fbphone, FB_DROP_SHM);
+	async_obsolete_msg_0(fbphone, FB_DROP_SHM);
 	
 exit:
@@ -436,14 +437,14 @@
 	
 	/* Send area */
-	int rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
+	int rc = async_obsolete_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
 	if (rc)
 		goto exit;
 	
-	rc = async_share_out_start(fbphone, shm, PROTO_READ);
+	rc = async_obsolete_share_out_start(fbphone, shm, PROTO_READ);
 	if (rc)
 		goto drop;
 	
 	/* Obtain pixmap */
-	rc = async_req_0_0(fbphone, FB_SHM2PIXMAP);
+	rc = async_obsolete_req_0_0(fbphone, FB_SHM2PIXMAP);
 	if (rc < 0)
 		goto drop;
@@ -453,5 +454,5 @@
 drop:
 	/* Drop area */
-	async_msg_0(fbphone, FB_DROP_SHM);
+	async_obsolete_msg_0(fbphone, FB_DROP_SHM);
 	
 exit:
@@ -464,5 +465,5 @@
 static void make_anim(void)
 {
-	int an = async_req_1_0(fbphone, FB_ANIM_CREATE,
+	int an = async_obsolete_req_1_0(fbphone, FB_ANIM_CREATE,
 	    cstatus_vp[KERNEL_CONSOLE]);
 	if (an < 0)
@@ -471,19 +472,19 @@
 	int pm = make_pixmap(_binary_gfx_anim_1_ppm_start,
 	    (size_t) &_binary_gfx_anim_1_ppm_size);
-	async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
+	async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
 	
 	pm = make_pixmap(_binary_gfx_anim_2_ppm_start,
 	    (size_t) &_binary_gfx_anim_2_ppm_size);
-	async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
+	async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
 	
 	pm = make_pixmap(_binary_gfx_anim_3_ppm_start,
 	    (size_t) &_binary_gfx_anim_3_ppm_size);
-	async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
+	async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
 	
 	pm = make_pixmap(_binary_gfx_anim_4_ppm_start,
 	    (size_t) &_binary_gfx_anim_4_ppm_size);
-	async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
-	
-	async_msg_1(fbphone, FB_ANIM_START, an);
+	async_obsolete_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
+	
+	async_obsolete_msg_1(fbphone, FB_ANIM_START, an);
 	
 	animation = an;
@@ -495,5 +496,5 @@
 	fbphone = phone;
 	
-	int rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
+	int rc = async_obsolete_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
 	if (rc)
 		return;
Index: uspace/srv/hid/console/keybuffer.c
===================================================================
--- uspace/srv/hid/console/keybuffer.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/console/keybuffer.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -90,5 +90,5 @@
  *
  */
-void keybuffer_push(keybuffer_t *keybuffer, const console_event_t *ev)
+void keybuffer_push(keybuffer_t *keybuffer, const kbd_event_t *ev)
 {
 	futex_down(&keybuffer_futex);
@@ -110,5 +110,5 @@
  *
  */
-bool keybuffer_pop(keybuffer_t *keybuffer, console_event_t *edst)
+bool keybuffer_pop(keybuffer_t *keybuffer, kbd_event_t *edst)
 {
 	futex_down(&keybuffer_futex);
Index: uspace/srv/hid/console/keybuffer.h
===================================================================
--- uspace/srv/hid/console/keybuffer.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/console/keybuffer.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -46,5 +46,5 @@
 
 typedef struct {
-	console_event_t fifo[KEYBUFFER_SIZE];
+	kbd_event_t fifo[KEYBUFFER_SIZE];
 	size_t head;
 	size_t tail;
@@ -56,6 +56,6 @@
 extern size_t keybuffer_available(keybuffer_t *);
 extern bool keybuffer_empty(keybuffer_t *);
-extern void keybuffer_push(keybuffer_t *, const console_event_t *);
-extern bool keybuffer_pop(keybuffer_t *, console_event_t *);
+extern void keybuffer_push(keybuffer_t *, const kbd_event_t *);
+extern bool keybuffer_pop(keybuffer_t *, kbd_event_t *);
 
 #endif
Index: uspace/srv/hid/fb/ega.c
===================================================================
--- uspace/srv/hid/fb/ega.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/fb/ega.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -52,7 +52,9 @@
 #include <io/screenbuffer.h>
 #include <sys/types.h>
-
 #include "ega.h"
 #include "main.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define MAX_SAVED_SCREENS  256
@@ -291,6 +293,5 @@
 		int retval;
 		
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		if (!IPC_GET_IMETHOD(call)) {
 			client_connected = 0;
 			async_answer_0(callid, EOK);
@@ -298,4 +299,7 @@
 			/* Exit thread */
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case IPC_M_SHARE_OUT:
 			/* We accept one area for data interchange */
Index: uspace/srv/hid/fb/fb.c
===================================================================
--- uspace/srv/hid/fb/fb.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/fb/fb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -59,12 +59,13 @@
 #include <byteorder.h>
 #include <io/screenbuffer.h>
-
 #include "font-8x16.h"
 #include "fb.h"
 #include "main.h"
 #include "ppm.h"
-
 #include "pointer.xbm"
 #include "pointer_mask.xbm"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define DEFAULT_BGCOLOR  0xf0f0f0
@@ -1620,6 +1621,5 @@
 			continue;
 		
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		if (!IPC_GET_IMETHOD(call)) {
 			client_connected = false;
 			
@@ -1630,5 +1630,7 @@
 			/* Exit thread */
 			return;
+		}
 		
+		switch (IPC_GET_IMETHOD(call)) {
 		case FB_PUTCHAR:
 			ch = IPC_GET_ARG1(call);
Index: uspace/srv/hid/fb/main.c
===================================================================
--- uspace/srv/hid/fb/main.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/fb/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -28,5 +28,5 @@
 
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <sysinfo.h>
 #include <async.h>
Index: uspace/srv/hid/fb/serial_console.c
===================================================================
--- uspace/srv/hid/fb/serial_console.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/fb/serial_console.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -52,4 +52,7 @@
 #include "serial_console.h"
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 #define MAX_CONTROL 20
 
@@ -344,6 +347,5 @@
 		int retval;
 		
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		if (!IPC_GET_IMETHOD(call)) {
 			client_connected = 0;
 			async_answer_0(callid, EOK);
@@ -351,4 +353,7 @@
 			/* Exit thread */
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case IPC_M_SHARE_OUT:
 			/* We accept one area for data interchange */
Index: uspace/srv/hid/kbd/ctl/apple.c
===================================================================
--- uspace/srv/hid/kbd/ctl/apple.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/ctl/apple.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -52,5 +52,5 @@
 void kbd_ctl_parse_scancode(int scancode)
 {
-	console_ev_type_t type;
+	kbd_event_type_t type;
 	unsigned int key;
 
Index: uspace/srv/hid/kbd/ctl/pc.c
===================================================================
--- uspace/srv/hid/kbd/ctl/pc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/ctl/pc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -205,5 +205,5 @@
 void kbd_ctl_parse_scancode(int scancode)
 {
-	console_ev_type_t type;
+	kbd_event_type_t type;
 	unsigned int key;
 	int *map;
Index: uspace/srv/hid/kbd/ctl/sun.c
===================================================================
--- uspace/srv/hid/kbd/ctl/sun.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/ctl/sun.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -53,5 +53,5 @@
 void kbd_ctl_parse_scancode(int scancode)
 {
-	console_ev_type_t type;
+	kbd_event_type_t type;
 	unsigned int key;
 
Index: uspace/srv/hid/kbd/generic/kbd.c
===================================================================
--- uspace/srv/hid/kbd/generic/kbd.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/generic/kbd.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -43,6 +43,8 @@
 #include <stdlib.h>
 #include <stdio.h>
-#include <ipc/ns.h>
+#include <ns.h>
+#include <ns_obsolete.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <errno.h>
 #include <adt/fifo.h>
@@ -50,9 +52,11 @@
 #include <io/keycode.h>
 #include <devmap.h>
-
 #include <kbd.h>
 #include <kbd_port.h>
 #include <kbd_ctl.h>
 #include <layout.h>
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME       "kbd"
@@ -88,5 +92,5 @@
 void kbd_push_ev(int type, unsigned int key)
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	unsigned mod_mask;
 
@@ -163,5 +167,5 @@
 	ev.c = layout[active_layout]->parse_ev(&ev);
 
-	async_msg_4(client_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
+	async_obsolete_msg_4(client_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
 }
 
@@ -174,10 +178,10 @@
 	async_answer_0(iid, EOK);
 
-	while (1) {
+	while (true) {
 		callid = async_get_call(&call);
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!IPC_GET_IMETHOD(call)) {
 			if (client_phone != -1) {
-				async_hangup(client_phone);
+				async_obsolete_hangup(client_phone);
 				client_phone = -1;
 			}
@@ -185,4 +189,7 @@
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case IPC_M_CONNECT_TO_ME:
 			if (client_phone != -1) {
@@ -222,5 +229,5 @@
 	if (irc_service) {
 		while (irc_phone < 0)
-			irc_phone = service_connect_blocking(SERVICE_IRC, 0, 0);
+			irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
 	}
 	
Index: uspace/srv/hid/kbd/include/layout.h
===================================================================
--- uspace/srv/hid/kbd/include/layout.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/include/layout.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -43,5 +43,5 @@
 typedef struct {
 	void (*reset)(void);
-	wchar_t (*parse_ev)(console_event_t *);
+	wchar_t (*parse_ev)(kbd_event_t *);
 } layout_op_t;
 
Index: uspace/srv/hid/kbd/layout/cz.c
===================================================================
--- uspace/srv/hid/kbd/layout/cz.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/layout/cz.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,5 +39,5 @@
 
 static void layout_reset(void);
-static wchar_t layout_parse_ev(console_event_t *ev);
+static wchar_t layout_parse_ev(kbd_event_t *ev);
 
 enum m_state {
@@ -273,5 +273,5 @@
 }
 
-static wchar_t parse_ms_hacek(console_event_t *ev)
+static wchar_t parse_ms_hacek(kbd_event_t *ev)
 {
 	wchar_t c;
@@ -291,5 +291,5 @@
 }
 
-static wchar_t parse_ms_carka(console_event_t *ev)
+static wchar_t parse_ms_carka(kbd_event_t *ev)
 {
 	wchar_t c;
@@ -309,5 +309,5 @@
 }
 
-static wchar_t parse_ms_start(console_event_t *ev)
+static wchar_t parse_ms_start(kbd_event_t *ev)
 {
 	wchar_t c;
@@ -384,5 +384,5 @@
 }
 
-static wchar_t layout_parse_ev(console_event_t *ev)
+static wchar_t layout_parse_ev(kbd_event_t *ev)
 {
 	if (ev->type != KEY_PRESS)
Index: uspace/srv/hid/kbd/layout/us_dvorak.c
===================================================================
--- uspace/srv/hid/kbd/layout/us_dvorak.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/layout/us_dvorak.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 
 static void layout_reset(void);
-static wchar_t layout_parse_ev(console_event_t *ev);
+static wchar_t layout_parse_ev(kbd_event_t *ev);
 
 layout_op_t us_dvorak_op = {
@@ -210,5 +210,5 @@
 }
 
-static wchar_t layout_parse_ev(console_event_t *ev)
+static wchar_t layout_parse_ev(kbd_event_t *ev)
 {
 	wchar_t c;
Index: uspace/srv/hid/kbd/layout/us_qwerty.c
===================================================================
--- uspace/srv/hid/kbd/layout/us_qwerty.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/layout/us_qwerty.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 
 static void layout_reset(void);
-static wchar_t layout_parse_ev(console_event_t *ev);
+static wchar_t layout_parse_ev(kbd_event_t *ev);
 
 layout_op_t us_qwerty_op = {
@@ -204,5 +204,5 @@
 }
 
-static wchar_t layout_parse_ev(console_event_t *ev)
+static wchar_t layout_parse_ev(kbd_event_t *ev)
 {
 	wchar_t c;
Index: uspace/srv/hid/kbd/port/adb.c
===================================================================
--- uspace/srv/hid/kbd/port/adb.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/port/adb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -30,5 +30,5 @@
  * @ingroup kbd
  * @{
- */ 
+ */
 /** @file
  * @brief ADB keyboard port driver.
@@ -37,4 +37,5 @@
 #include <ipc/adb.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <kbd_port.h>
 #include <kbd.h>
@@ -42,4 +43,6 @@
 #include <fcntl.h>
 #include <errno.h>
+#include <devmap.h>
+#include <devmap_obsolete.h>
 
 static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall);
@@ -52,28 +55,25 @@
 int kbd_port_init(void)
 {
-	const char *input = "/dev/adb/kbd";
-	int input_fd;
-
-	printf(NAME ": open %s\n", input);
-
-	input_fd = open(input, O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s (%d)\n", input, input_fd);
-		return false;
+	const char *dev = "adb/kbd";
+	devmap_handle_t handle;
+	
+	int rc = devmap_device_get_handle(dev, &handle, 0);
+	if (rc == EOK) {
+		dev_phone = devmap_obsolete_device_connect(handle, 0);
+		if (dev_phone < 0) {
+			printf("%s: Failed to connect to device\n", NAME);
+			return dev_phone;
+		}
+	} else
+		return rc;
+	
+	/* NB: The callback connection is slotted for removal */
+	rc = async_obsolete_connect_to_me(dev_phone, 0, 0, 0, kbd_port_events);
+	if (rc != EOK) {
+		printf(NAME ": Failed to create callback from device\n");
+		return rc;
 	}
-
-	dev_phone = fd_phone(input_fd);
-	if (dev_phone < 0) {
-		printf(NAME ": Failed to connect to device\n");
-		return false;
-	}
-
-	/* NB: The callback connection is slotted for removal */
-	if (async_connect_to_me(dev_phone, 0, 0, 0, kbd_port_events) != 0) {
-		printf(NAME ": Failed to create callback from device\n");
-		return false;
-	}
-
-	return 0;
+	
+	return EOK;
 }
 
@@ -100,9 +100,11 @@
 
 		int retval;
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!IPC_GET_IMETHOD(call)) {
 			/* TODO: Handle hangup */
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case ADB_REG_NOTIF:
 			adb_kbd_reg0_data(IPC_GET_ARG1(call));
Index: uspace/srv/hid/kbd/port/chardev.c
===================================================================
--- uspace/srv/hid/kbd/port/chardev.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/port/chardev.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -30,5 +30,5 @@
  * @ingroup kbd
  * @{
- */ 
+ */
 /** @file
  * @brief Chardev keyboard port driver.
@@ -37,10 +37,13 @@
 #include <ipc/char.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <kbd_port.h>
 #include <kbd.h>
-#include <vfs/vfs.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <devmap.h>
+#include <devmap_obsolete.h>
 #include <errno.h>
+#include <stdio.h>
+
+#define NAME  "kbd/chardev"
 
 static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall);
@@ -48,47 +51,37 @@
 static int dev_phone;
 
-#define NAME "kbd"
-
 /** List of devices to try connecting to. */
 static const char *in_devs[] = {
-	"/dev/char/ps2a",
-	"/dev/char/s3c24ser"
+	"char/ps2a",
+	"char/s3c24ser"
 };
 
-static const int num_devs = sizeof(in_devs) / sizeof(in_devs[0]);
+static const unsigned int num_devs = sizeof(in_devs) / sizeof(in_devs[0]);
 
 int kbd_port_init(void)
 {
-	int input_fd;
-	int i;
-
-	input_fd = -1;
+	devmap_handle_t handle;
+	unsigned int i;
+	int rc;
+	
 	for (i = 0; i < num_devs; i++) {
-		struct stat s;
-
-		if (stat(in_devs[i], &s) == EOK)
+		rc = devmap_device_get_handle(in_devs[i], &handle, 0);
+		if (rc == EOK)
 			break;
 	}
-
+	
 	if (i >= num_devs) {
-		printf(NAME ": Could not find any suitable input device.\n");
+		printf("%s: Could not find any suitable input device\n", NAME);
 		return -1;
 	}
-
-	input_fd = open(in_devs[i], O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": failed opening device %s (%d).\n", in_devs[i],
-		    input_fd);
-		return -1;
+	
+	dev_phone = devmap_obsolete_device_connect(handle, IPC_FLAG_BLOCKING);
+	if (dev_phone < 0) {
+		printf("%s: Failed connecting to device\n", NAME);
+		return ENOENT;
 	}
-
-	dev_phone = fd_phone(input_fd);
-	if (dev_phone < 0) {
-		printf(NAME ": Failed connecting to device\n");
-		return -1;
-	}
-
+	
 	/* NB: The callback connection is slotted for removal */
-	if (async_connect_to_me(dev_phone, 0, 0, 0, kbd_port_events) != 0) {
+	if (async_obsolete_connect_to_me(dev_phone, 0, 0, 0, kbd_port_events) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
 		return -1;
@@ -108,5 +101,5 @@
 void kbd_port_write(uint8_t data)
 {
-	async_msg_1(dev_phone, CHAR_WRITE_BYTE, data);
+	async_obsolete_msg_1(dev_phone, CHAR_WRITE_BYTE, data);
 }
 
@@ -118,11 +111,13 @@
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
 
 		int retval;
 
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			/* TODO: Handle hangup */
-			return;
 		case CHAR_NOTIF_BYTE:
 			kbd_push_scancode(IPC_GET_ARG1(call));
Index: uspace/srv/hid/kbd/port/ns16550.c
===================================================================
--- uspace/srv/hid/kbd/port/ns16550.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/port/ns16550.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 #include <ipc/irc.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <sysinfo.h>
 #include <kbd.h>
@@ -121,5 +122,5 @@
 	
 	if (irc_service)
-		async_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
+		async_obsolete_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
 		    IPC_GET_IMETHOD(*call));
 }
Index: uspace/srv/hid/kbd/port/z8530.c
===================================================================
--- uspace/srv/hid/kbd/port/z8530.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/kbd/port/z8530.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 #include <ipc/irc.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <sysinfo.h>
 #include <kbd.h>
@@ -109,5 +110,5 @@
 	
 	if (irc_service)
-		async_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
+		async_obsolete_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
 		    IPC_GET_IMETHOD(*call));
 }
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,4 +44,5 @@
 #include <ipc/mouse.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -50,6 +51,8 @@
 #include <errno.h>
 #include <inttypes.h>
-
 #include "s3c24xx_ts.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME "s3c24ser"
@@ -280,5 +283,5 @@
 	button = 1;
 	press = 0;
-	async_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
+	async_obsolete_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
 
 	s3c24xx_ts_wait_for_int_mode(ts, updn_down);
@@ -321,6 +324,6 @@
 
 	/* Send notifications to client. */
-	async_msg_2(ts->client_phone, MEVENT_MOVE, dx, dy);
-	async_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
+	async_obsolete_msg_2(ts->client_phone, MEVENT_MOVE, dx, dy);
+	async_obsolete_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
 
 	ts->last_x = x_pos;
@@ -380,8 +383,8 @@
 	while (1) {
 		callid = async_get_call(&call);
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!IPC_GET_IMETHOD(call)) {
 			if (ts->client_phone != -1) {
-				async_hangup(ts->client_phone);
+				async_obsolete_hangup(ts->client_phone);
 				ts->client_phone = -1;
 			}
@@ -389,4 +392,7 @@
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (IPC_GET_IMETHOD(call)) {
 		case IPC_M_CONNECT_TO_ME:
 			if (ts->client_phone != -1) {
Index: uspace/srv/hw/bus/cuda_adb/cuda_adb.c
===================================================================
--- uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -48,6 +48,10 @@
 #include <ipc/adb.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <assert.h>
 #include "cuda_adb.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME "cuda_adb"
@@ -219,9 +223,12 @@
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case IPC_M_CONNECT_TO_ME:
 			if (adb_dev[dev_addr].client_phone != -1) {
@@ -479,5 +486,5 @@
 		return;
 
-	async_msg_1(adb_dev[dev_addr].client_phone, ADB_REG_NOTIF, reg_val);
+	async_obsolete_msg_1(adb_dev[dev_addr].client_phone, ADB_REG_NOTIF, reg_val);
 }
 
Index: uspace/srv/hw/char/i8042/i8042.c
===================================================================
--- uspace/srv/hw/char/i8042/i8042.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/char/i8042/i8042.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,4 +41,5 @@
 #include <devmap.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <unistd.h>
 #include <sysinfo.h>
@@ -46,6 +47,8 @@
 #include <errno.h>
 #include <inttypes.h>
-
 #include "i8042.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME "i8042"
@@ -247,9 +250,12 @@
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case IPC_M_CONNECT_TO_ME:
 			printf(NAME ": creating callback connection\n");
@@ -300,5 +306,5 @@
 
 	if (i8042_port[devid].client_phone != -1) {
-		async_msg_1(i8042_port[devid].client_phone,
+		async_obsolete_msg_1(i8042_port[devid].client_phone,
 		    IPC_FIRST_USER_METHOD, data);
 	}
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -42,4 +42,5 @@
 #include <ipc/char.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -48,6 +49,8 @@
 #include <errno.h>
 #include <inttypes.h>
-
 #include "s3c24xx_uart.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #define NAME "s3c24ser"
@@ -123,9 +126,12 @@
 		callid = async_get_call(&call);
 		method = IPC_GET_IMETHOD(call);
-		switch (method) {
-		case IPC_M_PHONE_HUNGUP:
+		
+		if (!method) {
 			/* The other side has hung up. */
 			async_answer_0(callid, EOK);
 			return;
+		}
+		
+		switch (method) {
 		case IPC_M_CONNECT_TO_ME:
 			printf(NAME ": creating callback connection\n");
@@ -156,5 +162,5 @@
 
 		if (uart->client_phone != -1) {
-			async_msg_1(uart->client_phone, CHAR_NOTIF_BYTE,
+			async_obsolete_msg_1(uart->client_phone, CHAR_NOTIF_BYTE,
 			    data);
 		}
Index: uspace/srv/hw/irc/apic/apic.c
===================================================================
--- uspace/srv/hw/irc/apic/apic.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/irc/apic/apic.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 #include <ipc/services.h>
 #include <ipc/irc.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <sysinfo.h>
 #include <as.h>
@@ -79,4 +79,10 @@
 		callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* The other side has hung up. */
+			async_answer_0(callid, EOK);
+			return;
+		}
+		
 		switch (IPC_GET_IMETHOD(call)) {
 		case IRC_ENABLE_INTERRUPT:
@@ -102,5 +108,5 @@
 	
 	if ((sysinfo_get_value("apic", &apic) != EOK) || (!apic)) {
-		printf(NAME ": No APIC found\n");
+		printf("%s: No APIC found\n", NAME);
 		return false;
 	}
@@ -114,10 +120,11 @@
 int main(int argc, char **argv)
 {
-	printf(NAME ": HelenOS APIC driver\n");
+	printf("%s: HelenOS APIC driver\n", NAME);
 	
 	if (!apic_init())
 		return -1;
 	
-	printf(NAME ": Accepting connections\n");
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
 	async_manager();
 	
Index: uspace/srv/hw/irc/fhc/fhc.c
===================================================================
--- uspace/srv/hw/irc/fhc/fhc.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/irc/fhc/fhc.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 #include <ipc/services.h>
 #include <ipc/irc.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <sysinfo.h>
 #include <as.h>
@@ -53,5 +53,5 @@
 #define NAME "fhc"
 
-#define FHC_UART_INR	0x39	
+#define FHC_UART_INR	0x39
 
 #define FHC_UART_IMAP	0x0
@@ -128,10 +128,10 @@
 	
 	if (retval < 0) {
-		printf(NAME ": Error mapping FHC UART registers\n");
+		printf("%s: Error mapping FHC UART registers\n", NAME);
 		return false;
 	}
 	
-	printf(NAME ": FHC UART registers at %p, %zu bytes\n", fhc_uart_phys,
-	    fhc_uart_size);
+	printf("%s: FHC UART registers at %p, %zu bytes\n", NAME,
+	    fhc_uart_phys, fhc_uart_size);
 	
 	async_set_client_connection(fhc_connection);
@@ -143,12 +143,13 @@
 int main(int argc, char **argv)
 {
-	printf(NAME ": HelenOS FHC bus controller driver\n");
+	printf("%s: HelenOS FHC bus controller driver\n", NAME);
 	
 	if (!fhc_init())
 		return -1;
 	
-	printf(NAME ": Accepting connections\n");
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
 	async_manager();
-
+	
 	/* Never reached */
 	return 0;
@@ -157,3 +158,3 @@
 /**
  * @}
- */ 
+ */
Index: uspace/srv/hw/irc/i8259/i8259.c
===================================================================
--- uspace/srv/hw/irc/i8259/i8259.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/irc/i8259/i8259.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,5 +38,5 @@
 #include <ipc/services.h>
 #include <ipc/irc.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <sysinfo.h>
 #include <as.h>
@@ -113,4 +113,10 @@
 		callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* The other side has hung up. */
+			async_answer_0(callid, EOK);
+			return;
+		}
+		
 		switch (IPC_GET_IMETHOD(call)) {
 		case IRC_ENABLE_INTERRUPT:
@@ -136,5 +142,5 @@
 	
 	if ((sysinfo_get_value("i8259", &i8259) != EOK) || (!i8259)) {
-		printf(NAME ": No i8259 found\n");
+		printf("%s: No i8259 found\n", NAME);
 		return false;
 	}
@@ -144,5 +150,5 @@
 	    (pio_enable((void *) IO_RANGE1_START, IO_RANGE1_SIZE,
 	    (void **) &io_range1) != EOK)) {
-		printf(NAME ": i8259 not accessible\n");
+		printf("%s: i8259 not accessible\n", NAME);
 		return false;
 	}
@@ -156,10 +162,11 @@
 int main(int argc, char **argv)
 {
-	printf(NAME ": HelenOS i8259 driver\n");
+	printf("%s: HelenOS i8259 driver\n", NAME);
 	
 	if (!i8259_init())
 		return -1;
 	
-	printf(NAME ": Accepting connections\n");
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
 	async_manager();
 	
Index: uspace/srv/hw/irc/obio/obio.c
===================================================================
--- uspace/srv/hw/irc/obio/obio.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/irc/obio/obio.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -44,5 +44,5 @@
 #include <ipc/services.h>
 #include <ipc/irc.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <sysinfo.h>
 #include <as.h>
@@ -118,5 +118,5 @@
 	
 	if (sysinfo_get_value("obio.base.physical", &paddr) != EOK) {
-		printf(NAME ": no OBIO registers found\n");
+		printf("%s: No OBIO registers found\n", NAME);
 		return false;
 	}
@@ -130,9 +130,9 @@
 	
 	if (retval < 0) {
-		printf(NAME ": Error mapping OBIO registers\n");
+		printf("%s: Error mapping OBIO registers\n", NAME);
 		return false;
 	}
 	
-	printf(NAME ": OBIO registers with base at %p\n", base_phys);
+	printf("%s: OBIO registers with base at %p\n", NAME, base_phys);
 	
 	async_set_client_connection(obio_connection);
@@ -144,12 +144,13 @@
 int main(int argc, char **argv)
 {
-	printf(NAME ": HelenOS OBIO driver\n");
+	printf("%s: HelenOS OBIO driver\n", NAME);
 	
 	if (!obio_init())
 		return -1;
 	
-	printf(NAME ": Accepting connections\n");
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
 	async_manager();
-
+	
 	/* Never reached */
 	return 0;
@@ -158,3 +159,3 @@
 /**
  * @}
- */ 
+ */
Index: uspace/srv/hw/netif/ne2000/ne2000.c
===================================================================
--- uspace/srv/hw/netif/ne2000/ne2000.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/hw/netif/ne2000/ne2000.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,4 +38,5 @@
 #include <assert.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <ddi.h>
 #include <errno.h>
@@ -44,5 +45,6 @@
 #include <sysinfo.h>
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
+#include <ns_obsolete.h>
 #include <ipc/irc.h>
 #include <net/modules.h>
@@ -330,5 +332,5 @@
 		
 		if (irc_service)
-			async_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
+			async_obsolete_msg_1(irc_phone, IRC_ENABLE_INTERRUPT, ne2k->irq);
 	}
 	
@@ -389,10 +391,10 @@
 	if (irc_service) {
 		while (irc_phone < 0)
-			irc_phone = service_connect_blocking(SERVICE_IRC, 0, 0);
+			irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
 	}
 	
 	async_set_interrupt_received(irq_handler);
 	
-	return async_connect_to_me(PHONE_NS, SERVICE_NE2000, 0, 0, NULL);
+	return service_register(SERVICE_NE2000);
 }
 
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/loader/main.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -52,6 +52,5 @@
 #include <ipc/services.h>
 #include <ipc/loader.h>
-#include <ipc/ns.h>
-#include <macros.h>
+#include <ns.h>
 #include <loader/pcb.h>
 #include <entry_point.h>
@@ -60,5 +59,4 @@
 #include <str.h>
 #include <as.h>
-
 #include <elf.h>
 #include <elf_load.h>
@@ -414,8 +412,4 @@
 static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
-	ipc_callid_t callid;
-	ipc_call_t call;
-	int retval;
-	
 	/* Already have a connection? */
 	if (connected) {
@@ -430,13 +424,15 @@
 	
 	/* Ignore parameters, the connection is already open */
-	(void) iid;
 	(void) icall;
 	
-	while (1) {
-		callid = async_get_call(&call);
+	while (true) {
+		int retval;
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			exit(0);
 		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			exit(0);
 		case LOADER_GET_TASKID:
 			ldr_get_taskid(callid, &call);
@@ -465,6 +461,5 @@
 		}
 		
-		if (IPC_GET_IMETHOD(call) != IPC_M_PHONE_HUNGUP)
-			async_answer_0(callid, retval);
+		async_answer_0(callid, retval);
 	}
 }
@@ -479,5 +474,5 @@
 	/* Introduce this task to the NS (give it our task ID). */
 	task_id_t id = task_get_id();
-	int rc = async_req_2_0(PHONE_NS, NS_ID_INTRO, LOWER32(id), UPPER32(id));
+	int rc = ns_intro(id);
 	if (rc != EOK)
 		return -1;
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/il/arp/arp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -845,8 +845,9 @@
 	
 	*count = 0;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
-	
 	case NET_ARP_DEVICE:
 		rc = measured_strings_receive(&address, &data, 1);
Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/il/ip/ip.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -77,4 +77,7 @@
 #include <il_skel.h>
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 /** IP module name. */
 #define NAME			"ip"
@@ -201,5 +204,5 @@
 
 	/* Set the destination address */
-	switch (header->version) {
+	switch (GET_IP_HEADER_VERSION(header)) {
 	case IPVERSION:
 		addrlen = sizeof(dest_in);
@@ -635,5 +638,5 @@
 
 	/* Process all IP options */
-	while (next < first->header_length) {
+	while (next < GET_IP_HEADER_LENGTH(first)) {
 		option = (ip_option_t *) (((uint8_t *) first) + next);
 		/* Skip end or noop */
@@ -656,7 +659,7 @@
 	if (length % 4) {
 		bzero(((uint8_t *) last) + length, 4 - (length % 4));
-		last->header_length = length / 4 + 1;
+		SET_IP_HEADER_LENGTH(last, (length / 4 + 1));
 	} else {
-		last->header_length = length / 4;
+		SET_IP_HEADER_LENGTH(last, (length / 4));
 	}
 
@@ -706,6 +709,6 @@
 		return rc;
 	
-	header->version = IPV4;
-	header->fragment_offset_high = 0;
+	SET_IP_HEADER_VERSION(header, IPV4);
+	SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(header, 0);
 	header->fragment_offset_low = 0;
 	header->header_checksum = 0;
@@ -735,9 +738,10 @@
 			memcpy(middle_header, last_header,
 			    IP_HEADER_LENGTH(last_header));
-			header->flags |= IPFLAG_MORE_FRAGMENTS;
+			SET_IP_HEADER_FLAGS(header,
+			    (GET_IP_HEADER_FLAGS(header) | IPFLAG_MORE_FRAGMENTS));
 			middle_header->total_length =
 			    htons(packet_get_data_length(next));
-			middle_header->fragment_offset_high =
-			    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
+			SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(middle_header,
+			    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length));
 			middle_header->fragment_offset_low =
 			    IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
@@ -768,6 +772,6 @@
 		middle_header->total_length =
 		    htons(packet_get_data_length(next));
-		middle_header->fragment_offset_high =
-		    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
+		SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(middle_header,
+		    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length));
 		middle_header->fragment_offset_low =
 		    IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
@@ -785,5 +789,6 @@
 		length += packet_get_data_length(next);
 		free(last_header);
-		header->flags |= IPFLAG_MORE_FRAGMENTS;
+		SET_IP_HEADER_FLAGS(header,
+		    (GET_IP_HEADER_FLAGS(header) | IPFLAG_MORE_FRAGMENTS));
 	}
 
@@ -834,6 +839,6 @@
 	new_header->total_length = htons(IP_HEADER_LENGTH(new_header) + length);
 	offset = IP_FRAGMENT_OFFSET(header) + IP_HEADER_DATA_LENGTH(header);
-	new_header->fragment_offset_high =
-	    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(offset);
+	SET_IP_HEADER_FRAGMENT_OFFSET_HIGH(new_header,
+	    IP_COMPUTE_FRAGMENT_OFFSET_HIGH(offset));
 	new_header->fragment_offset_low =
 	    IP_COMPUTE_FRAGMENT_OFFSET_LOW(offset);
@@ -865,5 +870,6 @@
 		return NULL;
 	memcpy(middle, last, IP_HEADER_LENGTH(last));
-	middle->flags |= IPFLAG_MORE_FRAGMENTS;
+	SET_IP_HEADER_FLAGS(middle,
+	    (GET_IP_HEADER_FLAGS(middle) | IPFLAG_MORE_FRAGMENTS));
 	return middle;
 }
@@ -922,5 +928,5 @@
 
 	/* Fragmentation forbidden? */
-	if(header->flags & IPFLAG_DONT_FRAGMENT)
+	if(GET_IP_HEADER_FLAGS(header) & IPFLAG_DONT_FRAGMENT)
 		return EPERM;
 
@@ -958,5 +964,6 @@
 
 	/* Mark the first as fragmented */
-	header->flags |= IPFLAG_MORE_FRAGMENTS;
+	SET_IP_HEADER_FLAGS(header,
+	    (GET_IP_HEADER_FLAGS(header) | IPFLAG_MORE_FRAGMENTS));
 
 	/* Create middle fragments */
@@ -1319,5 +1326,5 @@
 	int rc;
 
-	if ((header->flags & IPFLAG_MORE_FRAGMENTS) ||
+	if ((GET_IP_HEADER_FLAGS(header) & IPFLAG_MORE_FRAGMENTS) ||
 	    IP_FRAGMENT_OFFSET(header)) {
 		// TODO fragmented
@@ -1325,5 +1332,5 @@
 	}
 	
-	switch (header->version) {
+	switch (GET_IP_HEADER_VERSION(header)) {
 	case IPVERSION:
 		addrlen = sizeof(src_in);
@@ -1447,5 +1454,5 @@
 
 	/* Set the destination address */
-	switch (header->version) {
+	switch (GET_IP_HEADER_VERSION(header)) {
 	case IPVERSION:
 		addrlen = sizeof(addr_in);
@@ -1909,8 +1916,9 @@
 	
 	*answer_count = 0;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
-	
 	case IPC_M_CONNECT_TO_ME:
 		return ip_register(IL_GET_PROTO(*call), IL_GET_SERVICE(*call),
Index: uspace/srv/net/net/net.c
===================================================================
--- uspace/srv/net/net/net.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/net/net.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -41,4 +41,5 @@
 #include <ctype.h>
 #include <ddi.h>
+#include <ns.h>
 #include <errno.h>
 #include <malloc.h>
@@ -339,5 +340,5 @@
 		goto out;
 	
-	rc = async_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, NULL);
+	rc = service_register(SERVICE_NETWORKING);
 	if (rc != EOK)
 		goto out;
@@ -638,7 +639,9 @@
 	
 	*answer_count = 0;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
 	case NET_NET_GET_DEVICE_CONF:
 		rc = measured_strings_receive(&strings, &data,
@@ -703,5 +706,5 @@
 		
 		/* End if told to either by the message or the processing result */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP))
+		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
 			return;
 		
Index: uspace/srv/net/netif/lo/lo.c
===================================================================
--- uspace/srv/net/netif/lo/lo.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/netif/lo/lo.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -39,4 +39,5 @@
 #include <stdio.h>
 #include <str.h>
+#include <ns.h>
 #include <ipc/services.h>
 #include <ipc/nil.h>
@@ -164,5 +165,5 @@
 int netif_initialize(void)
 {
-	return async_connect_to_me(PHONE_NS, SERVICE_LO, 0, 0, NULL);
+	return service_register(SERVICE_LO);
 }
 
Index: uspace/srv/net/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/nil/eth/eth.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -59,4 +59,7 @@
 #include <packet_remote.h>
 #include <nil_skel.h>
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 #include "eth.h"
@@ -846,8 +849,9 @@
 	
 	*answer_count = 0;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
-	
 	case NET_NIL_DEVICE:
 		return eth_device_message(IPC_GET_DEVICE(*call),
Index: uspace/srv/net/nil/nildummy/nildummy.c
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/nil/nildummy/nildummy.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -54,4 +54,7 @@
 #include <nil_skel.h>
 
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
+
 #include "nildummy.h"
 
@@ -393,8 +396,9 @@
 	
 	*answer_count = 0;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_PHONE_HUNGUP:
-		return EOK;
-	
 	case NET_NIL_DEVICE:
 		return nildummy_device_message(IPC_GET_DEVICE(*call),
Index: uspace/srv/net/tl/icmp/icmp.c
===================================================================
--- uspace/srv/net/tl/icmp/icmp.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/tl/icmp/icmp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -612,9 +612,11 @@
 static void icmp_receiver(ipc_callid_t iid, ipc_call_t *icall)
 {
-	bool loop = true;
 	packet_t *packet;
 	int rc;
 	
-	while (loop) {
+	while (true) {
+		if (!IPC_GET_IMETHOD(*icall))
+			break;
+		
 		switch (IPC_GET_IMETHOD(*icall)) {
 		case NET_TL_RECEIVED:
@@ -629,7 +631,4 @@
 			async_answer_0(iid, (sysarg_t) rc);
 			break;
-		case IPC_M_PHONE_HUNGUP:
-			loop = false;
-			continue;
 		default:
 			async_answer_0(iid, (sysarg_t) ENOTSUP);
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -38,4 +38,5 @@
 #include <assert.h>
 #include <async.h>
+#include <async_obsolete.h>
 #include <fibril_synch.h>
 #include <malloc.h>
@@ -72,4 +73,7 @@
 #include "tcp.h"
 #include "tcp_header.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 /** TCP module name. */
@@ -476,5 +480,5 @@
 	old_incoming = socket_data->next_incoming;
 
-	if (header->finalize) {
+	if (GET_TCP_HEADER_FINALIZE(header)) {
 		socket_data->fin_incoming = new_sequence_number +
 		    total_length - TCP_HEADER_LENGTH(header);
@@ -799,5 +803,5 @@
 
 	/* Notify the destination socket */
-	async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
+	async_obsolete_msg_5(socket->phone, NET_SOCKET_RECEIVED,
 	    (sysarg_t) socket->socket_id,
 	    ((packet_dimension->content < socket_data->data_fragment_size) ?
@@ -820,5 +824,5 @@
 
 	/* Notify the destination socket */
-	async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
+	async_obsolete_msg_5(socket->phone, NET_SOCKET_RECEIVED,
 	    (sysarg_t) socket->socket_id,
 	    0, 0, 0,
@@ -838,5 +842,5 @@
 	assert(packet);
 
-	if (!header->synchronize)
+	if (!GET_TCP_HEADER_SYNCHRONIZE(header))
 		return tcp_release_and_return(packet, EINVAL);
 	
@@ -903,5 +907,5 @@
 	assert(packet);
 
-	if (!header->synchronize)
+	if (!GET_TCP_HEADER_SYNCHRONIZE(header))
 		return tcp_release_and_return(packet, EINVAL);
 
@@ -1057,5 +1061,5 @@
 	assert(packet);
 
-	if (!header->acknowledge)
+	if (!GET_TCP_HEADER_ACKNOWLEDGE(header))
 		return tcp_release_and_return(packet, EINVAL);
 
@@ -1078,5 +1082,5 @@
 		if (rc == EOK) {
 			/* Notify the destination socket */
-			async_msg_5(socket->phone, NET_SOCKET_ACCEPTED,
+			async_obsolete_msg_5(socket->phone, NET_SOCKET_ACCEPTED,
 			    (sysarg_t) listening_socket->socket_id,
 			    socket_data->data_fragment_size, TCP_HEADER_SIZE,
@@ -1126,5 +1130,5 @@
 	assert(header);
 
-	if (!header->acknowledge)
+	if (!GET_TCP_HEADER_ACKNOWLEDGE(header))
 		return;
 
@@ -1269,5 +1273,4 @@
 {
 	int res;
-	bool keep_on_going = true;
 	socket_cores_t local_sockets;
 	int app_phone = IPC_GET_PHONE(call);
@@ -1293,5 +1296,5 @@
 	fibril_rwlock_initialize(&lock);
 
-	while (keep_on_going) {
+	while (true) {
 
 		/* Answer the call */
@@ -1301,12 +1304,12 @@
 		/* Get the next call */
 		callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			res = EHANGUP;
+			break;
+		}
 
 		/* Process the call */
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			keep_on_going = false;
-			res = EHANGUP;
-			break;
-
 		case NET_SOCKET:
 			socket_data =
@@ -1506,5 +1509,5 @@
 
 	/* Release the application phone */
-	async_hangup(app_phone);
+	async_obsolete_hangup(app_phone);
 
 	printf("release\n");
@@ -1833,5 +1836,5 @@
 
 	/* Remember the outgoing FIN */
-	if (header->finalize) 
+	if (GET_TCP_HEADER_FINALIZE(header))
 		socket_data->fin_outgoing = socket_data->next_outgoing;
 	
@@ -1952,5 +1955,5 @@
 		header->acknowledgement_number =
 		    htonl(socket_data->next_incoming);
-		header->acknowledge = 1;
+		SET_TCP_HEADER_ACKNOWLEDGE(header, 1);
 	}
 	header->window = htons(socket_data->window);
@@ -2024,7 +2027,8 @@
 	header->source_port = htons(socket->port);
 	header->source_port = htons(socket_data->dest_port);
-	header->header_length = TCP_COMPUTE_HEADER_LENGTH(sizeof(*header));
-	header->synchronize = synchronize;
-	header->finalize = finalize;
+	SET_TCP_HEADER_LENGTH(header,
+	    TCP_COMPUTE_HEADER_LENGTH(sizeof(*header)));
+	SET_TCP_HEADER_SYNCHRONIZE(header, synchronize);
+	SET_TCP_HEADER_FINALIZE(header, finalize);
 }
 
Index: uspace/srv/net/tl/tcp/tcp_header.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_header.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/tl/tcp/tcp_header.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -47,5 +47,5 @@
  * @param[in] header The TCP packet header.
  */
-#define TCP_HEADER_LENGTH(header)		((header)->header_length * 4U)
+#define TCP_HEADER_LENGTH(header)		(GET_TCP_HEADER_LENGTH(header) * 4U)
 
 /** Returns the TCP header length.
@@ -73,30 +73,63 @@
 	uint32_t sequence_number;
 	uint32_t acknowledgement_number;
-	
-#ifdef ARCH_IS_BIG_ENDIAN
-	uint8_t header_length:4;
-	uint8_t reserved1:4;
-#else
-	uint8_t reserved1:4;
-	uint8_t header_length:4;
-#endif
 
-#ifdef ARCH_IS_BIG_ENDIAN
-	uint8_t reserved2:2;
-	uint8_t urgent:1;
-	uint8_t acknowledge:1;
-	uint8_t push:1;
-	uint8_t reset:1;
-	uint8_t synchronize:1;
-	uint8_t finalize:1;
-#else
-	uint8_t finalize:1;
-	uint8_t synchronize:1;
-	uint8_t reset:1;
-	uint8_t push:1;
-	uint8_t acknowledge:1;
-	uint8_t urgent:1;
-	uint8_t reserved2:2;
-#endif
+	uint8_t hlr; /* header length, reserved1 */
+
+#define GET_TCP_HEADER_LENGTH(header) \
+	(((header)->hlr & 0xf0) >> 4)
+#define SET_TCP_HEADER_LENGTH(header, length) \
+	((header)->hlr = \
+	 ((length & 0x0f) << 4) | ((header)->hlr & 0x0f))
+
+#define GET_TCP_HEADER_RESERVED1(header) \
+	((header)->hlr & 0x0f)
+#define SET_TCP_HEADER_RESERVED1(header, reserved1) \
+	((header)->hlr = \
+	 (reserved1 & 0x0f) | ((header)->hlr & 0xf0))
+
+	/* reserved2, urgent, acknowledge, push, reset, synchronize, finalize */
+	uint8_t ruaprsf;  
+
+#define GET_TCP_HEADER_RESERVED2(header) \
+	(((header)->ruaprsf & 0xc0) >> 6)
+#define SET_TCP_HEADER_RESERVED2(header, reserved2) \
+	((header)->ruaprsf = \
+	 ((reserved2 & 0x03) << 6) | ((header)->ruaprsf & 0x3f))
+
+#define GET_TCP_HEADER_URGENT(header) \
+	(((header)->ruaprsf & 0x20) >> 5)
+#define SET_TCP_HEADER_URGENT(header, urgent) \
+	((header)->ruaprsf = \
+	 ((urgent & 0x01) << 5) | ((header)->ruaprsf & 0xdf))
+
+#define GET_TCP_HEADER_ACKNOWLEDGE(header) \
+	(((header)->ruaprsf & 0x10) >> 4)
+#define SET_TCP_HEADER_ACKNOWLEDGE(header, acknowledge) \
+	((header)->ruaprsf = \
+	 ((acknowledge & 0x01) << 4) | ((header)->ruaprsf & 0xef))
+
+#define GET_TCP_HEADER_PUSH(header) \
+	(((header)->ruaprsf & 0x08) >> 3)
+#define SET_TCP_HEADER_PUSH(header, push) \
+	((header)->ruaprsf = \
+	 ((push & 0x01) << 3) | ((header)->ruaprsf & 0xf7))
+
+#define GET_TCP_HEADER_RESET(header) \
+	(((header)->ruaprsf & 0x04) >> 2)
+#define SET_TCP_HEADER_RESET(header, reset) \
+	((header)->ruaprsf = \
+	 ((reset & 0x01) << 2) | ((header)->ruaprsf & 0xfb))
+
+#define GET_TCP_HEADER_SYNCHRONIZE(header) \
+	(((header)->ruaprsf & 0x02) >> 1)
+#define SET_TCP_HEADER_SYNCHRONIZE(header, synchronize) \
+	((header)->ruaprsf = \
+	 ((synchronize & 0x01) << 1) | ((header)->ruaprsf & 0xfd))
+
+#define GET_TCP_HEADER_FINALIZE(header) \
+	((header)->ruaprsf & 0x01)
+#define SET_TCP_HEADER_FINALIZE(header, finalize) \
+	((header)->ruaprsf = \
+	 (finalize & 0x01) | ((header)->ruaprsf & 0xfe))
 
 	uint16_t window;
Index: uspace/srv/net/tl/udp/udp.c
===================================================================
--- uspace/srv/net/tl/udp/udp.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/net/tl/udp/udp.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,4 +37,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <fibril_synch.h>
 #include <malloc.h>
@@ -69,4 +70,7 @@
 #include "udp.h"
 #include "udp_header.h"
+
+// FIXME: remove this header
+#include <kernel/ipc/ipc_methods.h>
 
 /** UDP module name. */
@@ -299,5 +303,5 @@
 	/* Notify the destination socket */
 	fibril_rwlock_write_unlock(&udp_globals.lock);
-	async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
+	async_obsolete_msg_5(socket->phone, NET_SOCKET_RECEIVED,
 	    (sysarg_t) socket->socket_id, packet_dimension->content, 0, 0,
 	    (sysarg_t) fragments);
@@ -748,5 +752,4 @@
 {
 	int res;
-	bool keep_on_going = true;
 	socket_cores_t local_sockets;
 	int app_phone = IPC_GET_PHONE(call);
@@ -773,5 +776,5 @@
 	socket_cores_initialize(&local_sockets);
 
-	while (keep_on_going) {
+	while (true) {
 
 		/* Answer the call */
@@ -783,12 +786,12 @@
 		/* Get the next call */
 		callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			res = EHANGUP;
+			break;
+		}
 
 		/* Process the call */
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			keep_on_going = false;
-			res = EHANGUP;
-			break;
-
 		case NET_SOCKET:
 			socket_id = SOCKET_GET_SOCKET_ID(call);
@@ -880,5 +883,5 @@
 
 	/* Release the application phone */
-	async_hangup(app_phone);
+	async_obsolete_hangup(app_phone);
 
 	/* Release all local sockets */
Index: uspace/srv/taskmon/taskmon.c
===================================================================
--- uspace/srv/taskmon/taskmon.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/taskmon/taskmon.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -92,14 +92,15 @@
 int main(int argc, char *argv[])
 {
-	printf(NAME ": Task Monitoring Service\n");
-
+	printf("%s: Task Monitoring Service\n", NAME);
+	
 	if (event_subscribe(EVENT_FAULT, 0) != EOK) {
-		printf(NAME ": Error registering fault notifications.\n");
+		printf("%s: Error registering fault notifications.\n", NAME);
 		return -1;
 	}
-
+	
 	async_set_interrupt_received(fault_event);
+	task_retval(0);
 	async_manager();
-
+	
 	return 0;
 }
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -37,5 +37,5 @@
 
 #include <ipc/services.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <errno.h>
@@ -51,6 +51,6 @@
 static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
-	bool keep_on_going = true;
-
+	bool cont = true;
+	
 	/*
 	 * The connection was opened via the IPC_CONNECT_ME_TO call.
@@ -59,15 +59,15 @@
 	async_answer_0(iid, EOK);
 	
-	while (keep_on_going) {
+	while (cont) {
 		ipc_call_t call;
 		ipc_callid_t callid = async_get_call(&call);
 		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
 		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			keep_on_going = false;
-			break;
 		case VFS_IN_REGISTER:
 			vfs_register(callid, &call);
-			keep_on_going = false;
+			cont = false;
 			break;
 		case VFS_IN_MOUNT:
@@ -123,5 +123,5 @@
 		}
 	}
-
+	
 	/*
 	 * Open files for this client will be cleaned up when its last
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs.h	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -53,5 +53,5 @@
 	vfs_info_t vfs_info;
 	fs_handle_t fs_handle;
-	async_sess_t session;
+	async_sess_t *sess;
 } fs_info_t;
 
@@ -167,6 +167,6 @@
 extern fibril_rwlock_t namespace_rwlock;
 
-extern int vfs_grab_phone(fs_handle_t);
-extern void vfs_release_phone(fs_handle_t, int);
+extern async_exch_t *vfs_exchange_grab(fs_handle_t);
+extern void vfs_exchange_release(async_exch_t *);
 
 extern fs_handle_t fs_name_to_handle(char *, bool);
@@ -176,5 +176,4 @@
     vfs_pair_t *, ...);
 extern int vfs_open_node_internal(vfs_lookup_res_t *);
-extern int vfs_close_internal(vfs_file_t *);
 
 extern bool vfs_nodes_init(void);
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs_file.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -45,5 +45,5 @@
 #include "vfs.h"
 
-#define VFS_DATA	((vfs_client_data_t *) async_client_data_get())
+#define VFS_DATA	((vfs_client_data_t *) async_get_client_data())
 #define FILES		(VFS_DATA->files)
 
@@ -79,5 +79,4 @@
 	for (i = 0; i < MAX_OPEN_FILES; i++) {
 		if (FILES[i]) {
-			(void) vfs_close_internal(FILES[i]);
 			(void) vfs_fd_free(i);
 		}
@@ -108,4 +107,23 @@
 }
 
+/** Close the file in the endpoint FS server. */
+static int vfs_file_close_remote(vfs_file_t *file)
+{
+	assert(!file->refcnt);
+	
+	async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
+	
+	ipc_call_t answer;
+	aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->devmap_handle,
+	    file->node->index, &answer);
+	
+	vfs_exchange_release(exch);
+	
+	sysarg_t rc;
+	async_wait_for(msg, &rc);
+	
+	return IPC_GET_ARG1(answer);
+}
+
 /** Increment reference count of VFS file structure.
  *
@@ -125,16 +143,21 @@
  *			decremented.
  */
-static void vfs_file_delref(vfs_file_t *file)
-{
+static int vfs_file_delref(vfs_file_t *file)
+{
+	int rc = EOK;
+
 	assert(fibril_mutex_is_locked(&VFS_DATA->lock));
 
 	if (file->refcnt-- == 1) {
 		/*
-		 * Lost the last reference to a file, need to drop our reference
-		 * to the underlying VFS node.
+		 * Lost the last reference to a file, need to close it in the
+		 * endpoint FS and drop our reference to the underlying VFS node.
 		 */
+		rc = vfs_file_close_remote(file);
 		vfs_node_delref(file->node);
 		free(file);
 	}
+
+	return rc;
 }
 
@@ -201,4 +224,6 @@
 int vfs_fd_free(int fd)
 {
+	int rc;
+
 	if (!vfs_files_init())
 		return ENOMEM;
@@ -210,9 +235,9 @@
 	}
 	
-	vfs_file_delref(FILES[fd]);
+	rc = vfs_file_delref(FILES[fd]);
 	FILES[fd] = NULL;
 	fibril_mutex_unlock(&VFS_DATA->lock);
 	
-	return EOK;
+	return rc;
 }
 
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -159,6 +159,6 @@
 
 	ipc_call_t answer;
-	int phone = vfs_grab_phone(root->fs_handle);
-	aid_t req = async_send_5(phone, VFS_OUT_LOOKUP, (sysarg_t) first,
+	async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
+	aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
 	    (sysarg_t) (first + len - 1) % PLB_SIZE,
 	    (sysarg_t) root->devmap_handle, (sysarg_t) lflag, (sysarg_t) index,
@@ -167,5 +167,5 @@
 	sysarg_t rc;
 	async_wait_for(req, &rc);
-	vfs_release_phone(root->fs_handle, phone);
+	vfs_exchange_release(exch);
 	
 	fibril_mutex_lock(&plb_mutex);
@@ -208,8 +208,8 @@
 int vfs_open_node_internal(vfs_lookup_res_t *result)
 {
-	int phone = vfs_grab_phone(result->triplet.fs_handle);
+	async_exch_t *exch = vfs_exchange_grab(result->triplet.fs_handle);
 	
 	ipc_call_t answer;
-	aid_t req = async_send_2(phone, VFS_OUT_OPEN_NODE,
+	aid_t req = async_send_2(exch, VFS_OUT_OPEN_NODE,
 	    (sysarg_t) result->triplet.devmap_handle,
 	    (sysarg_t) result->triplet.index, &answer);
@@ -217,5 +217,5 @@
 	sysarg_t rc;
 	async_wait_for(req, &rc);
-	vfs_release_phone(result->triplet.fs_handle, phone);
+	vfs_exchange_release(exch);
 	
 	if (rc == EOK) {
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs_node.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -104,11 +104,14 @@
 	bool free_vfs_node = false;
 	bool free_fs_node = false;
-
-	fibril_mutex_lock(&nodes_mutex);
+	
+	fibril_mutex_lock(&nodes_mutex);
+	
 	if (node->refcnt-- == 1) {
+		
 		/*
 		 * We are dropping the last reference to this node.
 		 * Remove it from the VFS node hash table.
 		 */
+		
 		unsigned long key[] = {
 			[KEY_FS_HANDLE] = node->fs_handle,
@@ -116,23 +119,29 @@
 			[KEY_INDEX] = node->index
 		};
+		
 		hash_table_remove(&nodes, key, 3);
 		free_vfs_node = true;
+		
 		if (!node->lnkcnt)
 			free_fs_node = true;
 	}
-	fibril_mutex_unlock(&nodes_mutex);
-
+	
+	fibril_mutex_unlock(&nodes_mutex);
+	
 	if (free_fs_node) {
-		/* 
+		
+		/*
 		 * The node is not visible in the file system namespace.
 		 * Free up its resources.
 		 */
-		int phone = vfs_grab_phone(node->fs_handle);
-		sysarg_t rc;
-		rc = async_req_2_0(phone, VFS_OUT_DESTROY,
-		    (sysarg_t)node->devmap_handle, (sysarg_t)node->index);
+		
+		async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
+		sysarg_t rc = async_req_2_0(exch, VFS_OUT_DESTROY,
+		    (sysarg_t) node->devmap_handle, (sysarg_t)node->index);
+		
 		assert(rc == EOK);
-		vfs_release_phone(node->fs_handle, phone);
+		vfs_exchange_release(exch);
 	}
+	
 	if (free_vfs_node)
 		free(node);
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs_ops.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -78,6 +78,6 @@
 	size_t rsize;
 	unsigned rlnkcnt;
+	async_exch_t *exch;
 	sysarg_t rc;
-	int phone;
 	aid_t msg;
 	ipc_call_t answer;
@@ -123,13 +123,14 @@
 			
 			/* Tell the mountee that it is being mounted. */
-			phone = vfs_grab_phone(fs_handle);
-			msg = async_send_1(phone, VFS_OUT_MOUNTED,
+			exch = vfs_exchange_grab(fs_handle);
+			msg = async_send_1(exch, VFS_OUT_MOUNTED,
 			    (sysarg_t) devmap_handle, &answer);
-			/* send the mount options */
-			rc = async_data_write_start(phone, (void *)opts,
+			/* Send the mount options */
+			rc = async_data_write_start(exch, (void *)opts,
 			    str_size(opts));
+			vfs_exchange_release(exch);
+			
 			if (rc != EOK) {
 				async_wait_for(msg, NULL);
-				vfs_release_phone(fs_handle, phone);
 				fibril_rwlock_write_unlock(&namespace_rwlock);
 				async_answer_0(rid, rc);
@@ -137,5 +138,4 @@
 			}
 			async_wait_for(msg, &rc);
-			vfs_release_phone(fs_handle, phone);
 			
 			if (rc != EOK) {
@@ -182,9 +182,9 @@
 	 */
 	
-	int mountee_phone = vfs_grab_phone(fs_handle);
-	assert(mountee_phone >= 0);
-
-	phone = vfs_grab_phone(mp_res.triplet.fs_handle);
-	msg = async_send_4(phone, VFS_OUT_MOUNT,
+	async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle);
+	assert(mountee_exch);
+	
+	exch = vfs_exchange_grab(mp_res.triplet.fs_handle);
+	msg = async_send_4(exch, VFS_OUT_MOUNT,
 	    (sysarg_t) mp_res.triplet.devmap_handle,
 	    (sysarg_t) mp_res.triplet.index,
@@ -192,34 +192,38 @@
 	    (sysarg_t) devmap_handle, &answer);
 	
-	/* send connection */
-	rc = async_req_1_0(phone, IPC_M_CONNECTION_CLONE, mountee_phone);
-	if (rc != EOK) {
+	/* Send connection */
+	rc = async_exchange_clone(exch, mountee_exch);
+	vfs_exchange_release(mountee_exch);
+	
+	if (rc != EOK) {
+		vfs_exchange_release(exch);
 		async_wait_for(msg, NULL);
-		vfs_release_phone(fs_handle, mountee_phone);
-		vfs_release_phone(mp_res.triplet.fs_handle, phone);
+		
 		/* Mount failed, drop reference to mp_node. */
 		if (mp_node)
 			vfs_node_put(mp_node);
-		async_answer_0(rid, rc);
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		return;
-	}
-
-	vfs_release_phone(fs_handle, mountee_phone);
+		
+		async_answer_0(rid, rc);
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		return;
+	}
 	
 	/* send the mount options */
-	rc = async_data_write_start(phone, (void *)opts, str_size(opts));
-	if (rc != EOK) {
+	rc = async_data_write_start(exch, (void *) opts, str_size(opts));
+	if (rc != EOK) {
+		vfs_exchange_release(exch);
 		async_wait_for(msg, NULL);
-		vfs_release_phone(mp_res.triplet.fs_handle, phone);
+		
 		/* Mount failed, drop reference to mp_node. */
 		if (mp_node)
 			vfs_node_put(mp_node);
-		fibril_rwlock_write_unlock(&namespace_rwlock);
-		async_answer_0(rid, rc);
-		return;
-	}
+		
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	vfs_exchange_release(exch);
 	async_wait_for(msg, &rc);
-	vfs_release_phone(mp_res.triplet.fs_handle, phone);
 	
 	if (rc == EOK) {
@@ -227,5 +231,5 @@
 		rsize = (size_t) IPC_GET_ARG2(answer);
 		rlnkcnt = (unsigned) IPC_GET_ARG3(answer);
-	
+		
 		mr_res.triplet.fs_handle = fs_handle;
 		mr_res.triplet.devmap_handle = devmap_handle;
@@ -234,5 +238,5 @@
 		mr_res.lnkcnt = rlnkcnt;
 		mr_res.type = VFS_NODE_DIRECTORY;
-	
+		
 		/* Add reference to the mounted root. */
 		mr_node = vfs_node_get(&mr_res); 
@@ -243,5 +247,5 @@
 			vfs_node_put(mp_node);
 	}
-
+	
 	async_answer_0(rid, rc);
 	fibril_rwlock_write_unlock(&namespace_rwlock);
@@ -303,10 +307,10 @@
 	
 	/*
-	 * Wait for IPC_M_PING so that we can return an error if we don't know
+	 * Wait for VFS_IN_PING so that we can return an error if we don't know
 	 * fs_name.
 	 */
 	ipc_call_t data;
 	ipc_callid_t callid = async_get_call(&data);
-	if (IPC_GET_IMETHOD(data) != IPC_M_PING) {
+	if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
 		async_answer_0(callid, ENOTSUP);
 		async_answer_0(rid, ENOTSUP);
@@ -358,6 +362,6 @@
 	vfs_lookup_res_t mr_res;
 	vfs_node_t *mr_node;
-	int phone;
-
+	async_exch_t *exch;
+	
 	/*
 	 * Receive the mount point path.
@@ -367,5 +371,5 @@
 	if (rc != EOK)
 		async_answer_0(rid, rc);
-
+	
 	/*
 	 * Taking the namespace lock will do two things for us. First, it will
@@ -395,5 +399,5 @@
 		return;
 	}
-
+	
 	/*
 	 * Count the total number of references for the mounted file system. We
@@ -411,7 +415,7 @@
 		return;
 	}
-
+	
 	if (str_cmp(mp, "/") == 0) {
-
+		
 		/*
 		 * Unmounting the root file system.
@@ -420,10 +424,12 @@
 		 * VFS_OUT_UNMOUNTED directly to the mounted file system.
 		 */
-
+		
 		free(mp);
-		phone = vfs_grab_phone(mr_node->fs_handle);
-		rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,
+		
+		exch = vfs_exchange_grab(mr_node->fs_handle);
+		rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
 		    mr_node->devmap_handle);
-		vfs_release_phone(mr_node->fs_handle, phone);
+		vfs_exchange_release(exch);
+		
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
@@ -432,8 +438,9 @@
 			return;
 		}
+		
 		rootfs.fs_handle = 0;
 		rootfs.devmap_handle = 0;
 	} else {
-
+		
 		/*
 		 * Unmounting a non-root file system.
@@ -442,5 +449,5 @@
 		 * file system, so we delegate the operation to it.
 		 */
-
+		
 		rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
 		free(mp);
@@ -451,4 +458,5 @@
 			return;
 		}
+		
 		vfs_node_t *mp_node = vfs_node_get(&mp_res);
 		if (!mp_node) {
@@ -458,9 +466,10 @@
 			return;
 		}
-
-		phone = vfs_grab_phone(mp_node->fs_handle);
-		rc = async_req_2_0(phone, VFS_OUT_UNMOUNT,
+		
+		exch = vfs_exchange_grab(mp_node->fs_handle);
+		rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,
 		    mp_node->devmap_handle, mp_node->index);
-		vfs_release_phone(mp_node->fs_handle, phone);
+		vfs_exchange_release(exch);
+		
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
@@ -470,5 +479,5 @@
 			return;
 		}
-
+		
 		/* Drop the reference we got above. */
 		vfs_node_put(mp_node);
@@ -476,6 +485,5 @@
 		vfs_node_put(mp_node);
 	}
-
-
+	
 	/*
 	 * All went well, the mounted file system was successfully unmounted.
@@ -483,5 +491,5 @@
 	 */
 	vfs_node_forget(mr_node);
-
+	
 	fibril_rwlock_write_unlock(&namespace_rwlock);
 	async_answer_0(rid, EOK);
@@ -698,75 +706,28 @@
 	 */
 	fibril_mutex_lock(&file->lock);
-	int fs_phone = vfs_grab_phone(file->node->fs_handle);
+	async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
 	
 	/* Make a VFS_OUT_SYMC request at the destination FS server. */
 	aid_t msg;
 	ipc_call_t answer;
-	msg = async_send_2(fs_phone, VFS_OUT_SYNC, file->node->devmap_handle,
+	msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->devmap_handle,
 	    file->node->index, &answer);
-
+	
+	vfs_exchange_release(fs_exch);
+	
 	/* Wait for reply from the FS server. */
 	sysarg_t rc;
 	async_wait_for(msg, &rc);
 	
-	vfs_release_phone(file->node->fs_handle, fs_phone);
 	fibril_mutex_unlock(&file->lock);
-
+	
 	vfs_file_put(file);
 	async_answer_0(rid, rc);
 }
 
-int vfs_close_internal(vfs_file_t *file)
-{
-	/*
-	 * Lock the open file structure so that no other thread can manipulate
-	 * the same open file at a time.
-	 */
-	fibril_mutex_lock(&file->lock);
-	
-	if (file->refcnt <= 1) {
-		/* Only close the file on the destination FS server
-		   if there are no more file descriptors (except the
-		   present one) pointing to this file. */
-		
-		int fs_phone = vfs_grab_phone(file->node->fs_handle);
-		
-		/* Make a VFS_OUT_CLOSE request at the destination FS server. */
-		aid_t msg;
-		ipc_call_t answer;
-		msg = async_send_2(fs_phone, VFS_OUT_CLOSE,
-		    file->node->devmap_handle, file->node->index, &answer);
-		
-		/* Wait for reply from the FS server. */
-		sysarg_t rc;
-		async_wait_for(msg, &rc);
-		
-		vfs_release_phone(file->node->fs_handle, fs_phone);
-		fibril_mutex_unlock(&file->lock);
-		
-		return IPC_GET_ARG1(answer);
-	}
-	
-	fibril_mutex_unlock(&file->lock);
-	return EOK;
-}
-
 void vfs_close(ipc_callid_t rid, ipc_call_t *request)
 {
 	int fd = IPC_GET_ARG1(*request);
-	
-	/* Lookup the file structure corresponding to the file descriptor. */
-	vfs_file_t *file = vfs_file_get(fd);
-	if (!file) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-	
-	int ret = vfs_close_internal(file);
-	if (ret != EOK)
-		async_answer_0(rid, ret);
-	
-	vfs_file_put(file);
-	ret = vfs_fd_free(fd);
+	int ret = vfs_fd_free(fd);
 	async_answer_0(rid, ret);
 }
@@ -774,6 +735,4 @@
 static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
 {
-	vfs_info_t *vi;
-
 	/*
 	 * The following code strongly depends on the fact that the files data
@@ -785,5 +744,5 @@
 	 * open files supports parallel access!
 	 */
-
+	
 	int fd = IPC_GET_ARG1(*request);
 	
@@ -800,8 +759,8 @@
 	 */
 	fibril_mutex_lock(&file->lock);
-
-	vi = fs_handle_to_info(file->node->fs_handle);
-	assert(vi);
-
+	
+	vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
+	assert(fs_info);
+	
 	/*
 	 * Lock the file's node so that no other client can read/write to it at
@@ -809,9 +768,10 @@
 	 * write implementation does not modify the file size.
 	 */
-	if (read || (vi->concurrent_read_write && vi->write_retains_size))
+	if ((read) ||
+	    ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
 		fibril_rwlock_read_lock(&file->node->contents_rwlock);
 	else
 		fibril_rwlock_write_lock(&file->node->contents_rwlock);
-
+	
 	if (file->node->type == VFS_NODE_DIRECTORY) {
 		/*
@@ -823,5 +783,5 @@
 	}
 	
-	int fs_phone = vfs_grab_phone(file->node->fs_handle);
+	async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
 	
 	/*
@@ -835,5 +795,5 @@
 	ipc_call_t answer;
 	if (read) {
-		rc = async_data_read_forward_3_1(fs_phone, VFS_OUT_READ,
+		rc = async_data_read_forward_3_1(fs_exch, VFS_OUT_READ,
 		    file->node->devmap_handle, file->node->index, file->pos,
 		    &answer);
@@ -842,10 +802,10 @@
 			file->pos = file->node->size;
 		
-		rc = async_data_write_forward_3_1(fs_phone, VFS_OUT_WRITE,
+		rc = async_data_write_forward_3_1(fs_exch, VFS_OUT_WRITE,
 		    file->node->devmap_handle, file->node->index, file->pos,
 		    &answer);
 	}
 	
-	vfs_release_phone(file->node->fs_handle, fs_phone);
+	vfs_exchange_release(fs_exch);
 	
 	size_t bytes = IPC_GET_ARG1(answer);
@@ -855,5 +815,6 @@
 	
 	/* Unlock the VFS node. */
-	if (read || (vi->concurrent_read_write && vi->write_retains_size))
+	if ((read) ||
+	    ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
 		fibril_rwlock_read_unlock(&file->node->contents_rwlock);
 	else {
@@ -975,12 +936,11 @@
     fs_index_t index, aoff64_t size)
 {
-	sysarg_t rc;
-	int fs_phone;
-	
-	fs_phone = vfs_grab_phone(fs_handle);
-	rc = async_req_4_0(fs_phone, VFS_OUT_TRUNCATE, (sysarg_t) devmap_handle,
-	    (sysarg_t) index, LOWER32(size), UPPER32(size));
-	vfs_release_phone(fs_handle, fs_phone);
-	return (int)rc;
+	async_exch_t *exch = vfs_exchange_grab(fs_handle);
+	sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
+	    (sysarg_t) devmap_handle, (sysarg_t) index, LOWER32(size),
+	    UPPER32(size));
+	vfs_exchange_release(exch);
+	
+	return (int) rc;
 }
 
@@ -1032,13 +992,15 @@
 	fibril_mutex_lock(&file->lock);
 
-	int fs_phone = vfs_grab_phone(file->node->fs_handle);
+	async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
 	
 	aid_t msg;
-	msg = async_send_3(fs_phone, VFS_OUT_STAT, file->node->devmap_handle,
+	msg = async_send_3(exch, VFS_OUT_STAT, file->node->devmap_handle,
 	    file->node->index, true, NULL);
-	async_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+	
+	vfs_exchange_release(exch);
+	
 	async_wait_for(msg, &rc);
-	vfs_release_phone(file->node->fs_handle, fs_phone);
-
+	
 	fibril_mutex_unlock(&file->lock);
 	vfs_file_put(file);
@@ -1083,13 +1045,15 @@
 	fibril_rwlock_read_unlock(&namespace_rwlock);
 
-	int fs_phone = vfs_grab_phone(node->fs_handle);
+	async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
+	
 	aid_t msg;
-	msg = async_send_3(fs_phone, VFS_OUT_STAT, node->devmap_handle,
+	msg = async_send_3(exch, VFS_OUT_STAT, node->devmap_handle,
 	    node->index, false, NULL);
-	async_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+	
+	vfs_exchange_release(exch);
 	
 	sysarg_t rv;
 	async_wait_for(msg, &rv);
-	vfs_release_phone(node->fs_handle, fs_phone);
 
 	async_answer_0(rid, rv);
@@ -1369,27 +1333,6 @@
 	fibril_mutex_lock(&oldfile->lock);
 	
-	/* Lookup an open file structure possibly corresponding to newfd. */
-	vfs_file_t *newfile = vfs_file_get(newfd);
-	if (newfile) {
-		/* Close the originally opened file. */
-		int ret = vfs_close_internal(newfile);
-		if (ret != EOK) {
-			fibril_mutex_unlock(&oldfile->lock);
-			vfs_file_put(oldfile);
-			vfs_file_put(newfile);
-			async_answer_0(rid, ret);
-			return;
-		}
-		
-		ret = vfs_fd_free(newfd);
-		if (ret != EOK) {
-			fibril_mutex_unlock(&oldfile->lock);
-			vfs_file_put(oldfile);
-			vfs_file_put(newfile);
-			async_answer_0(rid, ret);
-			return;
-		}
-		vfs_file_put(newfile);
-	}
+	/* Make sure newfd is closed. */
+	(void) vfs_fd_free(newfd);
 	
 	/* Assign the old file to newfd. */
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision 9536e6ec91688bf386cf5f5e8f86fd2fb06546e2)
+++ uspace/srv/vfs/vfs_register.c	(revision 41811af3f30a71c0fd211463ca7ddf34b1da9041)
@@ -62,12 +62,13 @@
 /** Verify the VFS info structure.
  *
- * @param info		Info structure to be verified.
- *
- * @return		Non-zero if the info structure is sane, zero otherwise.
+ * @param info Info structure to be verified.
+ *
+ * @return Non-zero if the info structure is sane, zero otherwise.
+ *
  */
 static bool vfs_info_sane(vfs_info_t *info)
 {
 	int i;
-
+	
 	/*
 	 * Check if the name is non-empty and is composed solely of ASCII
@@ -78,4 +79,5 @@
 		return false;
 	}
+	
 	for (i = 1; i < FS_NAME_MAXLEN; i++) {
 		if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
@@ -90,4 +92,5 @@
 		}
 	}
+	
 	/*
 	 * This check is not redundant. It ensures that the name is
@@ -104,11 +107,10 @@
 /** VFS_REGISTER protocol function.
  *
- * @param rid		Hash of the call with the request.
- * @param request	Call structure with the request.
+ * @param rid     Hash of the call with the request.
+ * @param request Call structure with the request.
+ *
  */
 void vfs_register(ipc_callid_t rid, ipc_call_t *request)
 {
-	int phone;
-	
 	dprintf("Processing VFS_REGISTER request received from %p.\n",
 	    request->in_phone_hash);
@@ -174,20 +176,14 @@
 	 * which to forward VFS requests to it.
 	 */
-	ipc_call_t call;
-	ipc_callid_t callid = async_get_call(&call);
-	if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
-		dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call));
+	fs_info->sess = async_callback_receive(EXCHANGE_PARALLEL);
+	if (!fs_info->sess) {
+		dprintf("Callback connection expected\n");
 		list_remove(&fs_info->fs_link);
 		fibril_mutex_unlock(&fs_head_lock);
 		free(fs_info);
-		async_answer_0(callid, EINVAL);
 		async_answer_0(rid, EINVAL);
 		return;
 	}
 	
-	phone = IPC_GET_ARG5(call);
-	async_session_create(&fs_info->session, phone, 0);
-	async_answer_0(callid, EOK);
-	
 	dprintf("Callback connection to FS created.\n");
 	
@@ -197,10 +193,10 @@
 	
 	size_t size;
+	ipc_callid_t callid;
 	if (!async_share_in_receive(&callid, &size)) {
 		dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call));
 		list_remove(&fs_info->fs_link);
 		fibril_mutex_unlock(&fs_head_lock);
-		async_session_destroy(&fs_info->session);
-		async_hangup(phone);
+		async_hangup(fs_info->sess);
 		free(fs_info);
 		async_answer_0(callid, EINVAL);
@@ -216,6 +212,5 @@
 		list_remove(&fs_info->fs_link);
 		fibril_mutex_unlock(&fs_head_lock);
-		async_session_destroy(&fs_info->session);
-		async_hangup(phone);
+		async_hangup(fs_info->sess);
 		free(fs_info);
 		async_answer_0(callid, EINVAL);
@@ -247,69 +242,59 @@
 }
 
-/** For a given file system handle, implement policy for allocating a phone.
- *
- * @param handle	File system handle.
- *
- * @return		Phone over which a multi-call request can be safely
- *			sent. Return 0 if no phone was found.
- */
-int vfs_grab_phone(fs_handle_t handle)
-{
+/** Begin an exchange for a given file system handle
+ *
+ * @param handle File system handle.
+ *
+ * @return Exchange for a multi-call request.
+ * @return NULL if no such file exists.
+ *
+ */
+async_exch_t *vfs_exchange_grab(fs_handle_t handle)
+{
+	/*
+	 * For now, we don't try to be very clever and very fast.
+	 * We simply lookup the session in the fs_head list and
+	 * begin an exchange.
+	 */
+	fibril_mutex_lock(&fs_head_lock);
+	
 	link_t *cur;
-	fs_info_t *fs;
-	int phone;
-
-	/*
-	 * For now, we don't try to be very clever and very fast.  We simply
-	 * lookup the phone in the fs_head list and duplicate it.  The duplicate
-	 * phone will be returned to the client and the client will use it for
-	 * communication.  In the future, we should cache the connections so
-	 * that they do not have to be reestablished over and over again.
-	 */
-	fibril_mutex_lock(&fs_head_lock);
 	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
-		fs = list_get_instance(cur, fs_info_t, fs_link);
+		fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
+		
 		if (fs->fs_handle == handle) {
 			fibril_mutex_unlock(&fs_head_lock);
-			phone = async_exchange_begin(&fs->session);
-
-			assert(phone > 0);
-			return phone;
+			
+			assert(fs->sess);
+			async_exch_t *exch = async_exchange_begin(fs->sess);
+			
+			assert(exch);
+			return exch;
 		}
 	}
+	
 	fibril_mutex_unlock(&fs_head_lock);
-	return 0;
-}
-
-/** Tell VFS that the phone is not needed anymore.
- *
- * @param phone		Phone to FS task.
- */
-void vfs_release_phone(fs_handle_t handle, int phone)
-{
-	link_t *cur;
-	fs_info_t *fs;
-
-	fibril_mutex_lock(&fs_head_lock);
-	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
-		fs = list_get_instance(cur, fs_info_t, fs_link);
-		if (fs->fs_handle == handle) {
-			fibril_mutex_unlock(&fs_head_lock);
-			async_exchange_end(&fs->session, phone);
-			return;
-		}
-	}
-	/* should not really get here */
-	abort();
-	fibril_mutex_unlock(&fs_head_lock);
+	
+	return NULL;
+}
+
+/** End VFS server exchange.
+ *
+ * @param exch   VFS server exchange.
+ *
+ */
+void vfs_exchange_release(async_exch_t *exch)
+{
+	async_exchange_end(exch);
 }
 
 /** Convert file system name to its handle.
  *
- * @param name		File system name.
- * @param lock		If true, the function will lock and unlock the
- * 			fs_head_lock.
- *
- * @return		File system handle or zero if file system not found.
+ * @param name File system name.
+ * @param lock If true, the function will lock and unlock the
+ *             fs_head_lock.
+ *
+ * @return File system handle or zero if file system not found.
+ *
  */
 fs_handle_t fs_name_to_handle(char *name, bool lock)
@@ -319,4 +304,5 @@
 	if (lock)
 		fibril_mutex_lock(&fs_head_lock);
+	
 	link_t *cur;
 	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
@@ -327,6 +313,8 @@
 		}
 	}
+	
 	if (lock)
 		fibril_mutex_unlock(&fs_head_lock);
+	
 	return handle;
 }
@@ -334,6 +322,8 @@
 /** Find the VFS info structure.
  *
- * @param handle	FS handle for which the VFS info structure is sought.
- * @return		VFS info structure on success or NULL otherwise.
+ * @param handle FS handle for which the VFS info structure is sought.
+ *
+ * @return VFS info structure on success or NULL otherwise.
+ *
  */
 vfs_info_t *fs_handle_to_info(fs_handle_t handle)
@@ -341,5 +331,5 @@
 	vfs_info_t *info = NULL;
 	link_t *cur;
-
+	
 	fibril_mutex_lock(&fs_head_lock);
 	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
@@ -351,5 +341,5 @@
 	}
 	fibril_mutex_unlock(&fs_head_lock);
-
+	
 	return info;
 }
@@ -357,3 +347,3 @@
 /**
  * @}
- */ 
+ */
