Index: abi/include/ddi/arg.h
===================================================================
--- abi/include/ddi/arg.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ abi/include/ddi/arg.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -36,4 +36,6 @@
 #define ABI_DDI_ARG_H_
 
+#define DMAMEM_FLAGS_ANONYMOUS  0x01
+
 /** Structure encapsulating arguments for SYS_PHYSMEM_MAP syscall. */
 typedef struct {
Index: abi/include/ipc/methods.h
===================================================================
--- abi/include/ipc/methods.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ abi/include/ipc/methods.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -127,5 +127,8 @@
  *
  * on answer, the recipient must set:
- * - ARG1 - dst as_area base adress
+ *
+ * - ARG1 - dst as_area lower bound
+ * - ARG2 - dst as_area base adress pointer
+ *          (filled automatically by the kernel)
  *
  */
@@ -133,7 +136,6 @@
 
 /** Receive as_area over IPC.
- * - ARG1 - destination as_area base address
- * - ARG2 - destination as_area size
- * - ARG3 - user defined argument
+ * - ARG1 - destination as_area size
+ * - ARG2 - user defined argument
  *
  * on answer, the recipient must set:
@@ -141,4 +143,6 @@
  * - ARG1 - source as_area base address
  * - ARG2 - flags that will be used for sharing
+ * - ARG3 - dst as_area lower bound
+ * - ARG4 - dst as_area base address (filled automatically by kernel)
  *
  */
Index: abi/include/syscall.h
===================================================================
--- abi/include/syscall.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ abi/include/syscall.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -60,5 +60,4 @@
 	SYS_AS_AREA_CHANGE_FLAGS,
 	SYS_AS_AREA_DESTROY,
-	SYS_AS_GET_UNMAPPED_AREA,
 	
 	SYS_PAGE_FIND_MAPPING,
@@ -85,7 +84,11 @@
 	SYS_DEVICE_ASSIGN_DEVNO,
 	SYS_PHYSMEM_MAP,
+	SYS_PHYSMEM_UNMAP,
+	SYS_DMAMEM_MAP,
+	SYS_DMAMEM_UNMAP,
 	SYS_IOSPACE_ENABLE,
-	SYS_REGISTER_IRQ,
-	SYS_UNREGISTER_IRQ,
+	SYS_IOSPACE_DISABLE,
+	SYS_IRQ_REGISTER,
+	SYS_IRQ_UNREGISTER,
 	
 	SYS_SYSINFO_GET_VAL_TYPE,
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ boot/Makefile.common	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -123,5 +123,6 @@
 	test/test3 \
 	nic/lo \
-	nic/ne2k
+	nic/ne2k \
+	nic/e1k
 
 RD_DRV_CFG =
@@ -174,4 +175,5 @@
 	$(USPACE_PATH)/app/nettest1/nettest1 \
 	$(USPACE_PATH)/app/nettest2/nettest2 \
+	$(USPACE_PATH)/app/nettest3/nettest3 \
 	$(USPACE_PATH)/app/netecho/netecho \
 	$(USPACE_PATH)/app/ping/ping \
@@ -202,5 +204,6 @@
 	$(USPACE_PATH)/srv/net/cfg/general \
 	$(USPACE_PATH)/srv/net/cfg/lo.nic \
-	$(USPACE_PATH)/srv/net/cfg/ne2k.nic
+	$(USPACE_PATH)/srv/net/cfg/ne2k.nic \
+	$(USPACE_PATH)/srv/net/cfg/e1k.nic
 endif
 
Index: contrib/conf/net-qe.sh
===================================================================
--- contrib/conf/net-qe.sh	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ contrib/conf/net-qe.sh	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,12 +1,14 @@
 #!/bin/sh
 
-# Obsolete versions of QEMU
-#
-#   QEMU 0.10.2 and later 0.10.*
-#    qemu $@ -no-kqemu -vga std -M isapc -net nic,model=ne2k_isa -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
-#
-#   QEMU 0.11.* and 0.12.*
-#    qemu $@ -vga std -M isapc -net nic,model=ne2k_isa -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
-
-# QEMU 0.13 and later
-qemu $@ -device ne2k_isa,irq=5,vlan=0 -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
+case "$1" in
+	ne2k)
+		shift
+		qemu $@ -device ne2k_isa,irq=5,vlan=0 -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
+		;;
+	e1k)
+		shift
+		qemu $@ -device e1000,vlan=0 -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
+		;;
+	*)
+		echo "Usage: $0 {ne2k|e1k}"
+esac
Index: kernel/arch/abs32le/src/abs32le.c
===================================================================
--- kernel/arch/abs32le/src/abs32le.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/abs32le/src/abs32le.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -86,5 +86,5 @@
 }
 
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	return EOK;
Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/amd64/src/amd64.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,39 +34,29 @@
 
 #include <arch.h>
-
 #include <typedefs.h>
-
-#include <config.h>
-
-#include <proc/thread.h>
+#include <errno.h>
+#include <memstr.h>
+#include <interrupt.h>
+#include <console/console.h>
+#include <syscall/syscall.h>
+#include <sysinfo/sysinfo.h>
+#include <arch/bios/bios.h>
+#include <arch/boot/boot.h>
+#include <arch/debugger.h>
+#include <arch/drivers/i8254.h>
+#include <arch/drivers/i8259.h>
+#include <arch/syscall.h>
+#include <genarch/acpi/acpi.h>
+#include <genarch/drivers/ega/ega.h>
+#include <genarch/drivers/i8042/i8042.h>
+#include <genarch/drivers/legacy/ia32/io.h>
+#include <genarch/fb/bfb.h>
+#include <genarch/kbrd/kbrd.h>
 #include <genarch/multiboot/multiboot.h>
 #include <genarch/multiboot/multiboot2.h>
-#include <genarch/drivers/legacy/ia32/io.h>
-#include <genarch/drivers/ega/ega.h>
-#include <genarch/fb/bfb.h>
-#include <genarch/drivers/i8042/i8042.h>
-#include <genarch/kbrd/kbrd.h>
-#include <arch/drivers/i8254.h>
-#include <arch/drivers/i8259.h>
-#include <arch/boot/boot.h>
 
 #ifdef CONFIG_SMP
 #include <arch/smp/apic.h>
 #endif
-
-#include <arch/bios/bios.h>
-#include <arch/cpu.h>
-#include <print.h>
-#include <arch/cpuid.h>
-#include <genarch/acpi/acpi.h>
-#include <panic.h>
-#include <interrupt.h>
-#include <arch/syscall.h>
-#include <arch/debugger.h>
-#include <syscall/syscall.h>
-#include <console/console.h>
-#include <ddi/irq.h>
-#include <sysinfo/sysinfo.h>
-#include <memstr.h>
 
 /** Disable I/O on non-privileged levels
@@ -264,10 +254,10 @@
  * we need not to go to CPL0 to read it.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	THREAD->arch.tls = addr;
 	write_msr(AMD_MSR_FS, addr);
 	
-	return 0;
+	return EOK;
 }
 
Index: kernel/arch/ia32/src/boot/vesa_real.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_real.inc	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/ia32/src/boot/vesa_real.inc	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -374,5 +374,5 @@
 		xor %ebx, %ebx
 		xor %edx, %edx
-		mov $0xffffffff, %edi
+		xor %edi, %edi
 		
 		jz vesa_leave_real  /* force relative jump */
Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/ia32/src/ia32.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -36,38 +36,24 @@
 
 #include <arch.h>
-
 #include <typedefs.h>
-
-#include <arch/pm.h>
-
+#include <errno.h>
+#include <memstr.h>
+#include <interrupt.h>
+#include <console/console.h>
+#include <syscall/syscall.h>
+#include <sysinfo/sysinfo.h>
+#include <arch/bios/bios.h>
+#include <arch/boot/boot.h>
+#include <arch/debugger.h>
+#include <arch/drivers/i8254.h>
+#include <arch/drivers/i8259.h>
+#include <genarch/acpi/acpi.h>
+#include <genarch/drivers/ega/ega.h>
+#include <genarch/drivers/i8042/i8042.h>
+#include <genarch/drivers/legacy/ia32/io.h>
+#include <genarch/fb/bfb.h>
+#include <genarch/kbrd/kbrd.h>
 #include <genarch/multiboot/multiboot.h>
 #include <genarch/multiboot/multiboot2.h>
-#include <genarch/drivers/legacy/ia32/io.h>
-#include <genarch/drivers/ega/ega.h>
-#include <genarch/fb/bfb.h>
-#include <genarch/drivers/i8042/i8042.h>
-#include <genarch/kbrd/kbrd.h>
-#include <arch/drivers/i8254.h>
-#include <arch/drivers/i8259.h>
-
-#include <arch/context.h>
-
-#include <config.h>
-
-#include <arch/interrupt.h>
-#include <arch/asm.h>
-#include <genarch/acpi/acpi.h>
-
-#include <arch/bios/bios.h>
-
-#include <interrupt.h>
-#include <ddi/irq.h>
-#include <arch/debugger.h>
-#include <proc/thread.h>
-#include <syscall/syscall.h>
-#include <console/console.h>
-#include <sysinfo/sysinfo.h>
-#include <arch/boot/boot.h>
-#include <memstr.h>
 
 #ifdef CONFIG_SMP
@@ -219,10 +205,10 @@
  * selector, and the descriptor->base is the correct address.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	THREAD->arch.tls = addr;
 	set_tls_desc(addr);
 	
-	return 0;
+	return EOK;
 }
 
Index: kernel/arch/ia64/include/asm.h
===================================================================
--- kernel/arch/ia64/include/asm.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/ia64/include/asm.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -38,5 +38,4 @@
 #include <config.h>
 #include <typedefs.h>
-#include <typedefs.h>
 #include <arch/register.h>
 #include <trace.h>
Index: kernel/arch/ia64/src/ia64.c
===================================================================
--- kernel/arch/ia64/src/ia64.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/ia64/src/ia64.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,38 +34,21 @@
 
 #include <arch.h>
-#include <arch/drivers/ski.h>
-#include <arch/drivers/it.h>
-#include <arch/interrupt.h>
-#include <arch/barrier.h>
-#include <arch/asm.h>
-#include <arch/register.h>
 #include <typedefs.h>
-#include <arch/context.h>
-#include <arch/stack.h>
-#include <arch/mm/page.h>
+#include <errno.h>
 #include <interrupt.h>
-#include <mm/as.h>
-#include <config.h>
 #include <macros.h>
+#include <str.h>
 #include <userspace.h>
 #include <console/console.h>
-#include <abi/proc/uarg.h>
 #include <syscall/syscall.h>
-#include <ddi/irq.h>
-#include <arch/bootinfo.h>
+#include <sysinfo/sysinfo.h>
+#include <arch/drivers/it.h>
+#include <arch/drivers/kbd.h>
+#include <genarch/drivers/ega/ega.h>
+#include <genarch/drivers/i8042/i8042.h>
+#include <genarch/drivers/ns16550/ns16550.h>
 #include <genarch/drivers/legacy/ia32/io.h>
-#include <genarch/drivers/ega/ega.h>
 #include <genarch/kbrd/kbrd.h>
 #include <genarch/srln/srln.h>
-#include <genarch/drivers/i8042/i8042.h>
-#include <genarch/drivers/ns16550/ns16550.h>
-#include <arch/drivers/kbd.h>
-#include <smp/smp.h>
-#include <smp/ipi.h>
-#include <arch/atomic.h>
-#include <panic.h>
-#include <print.h>
-#include <sysinfo/sysinfo.h>
-#include <str.h>
 
 /* NS16550 as a COM 1 */
@@ -262,7 +245,7 @@
  * We use r13 (a.k.a. tp) for this purpose.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
-{
-	return 0;
+sysarg_t sys_tls_set(uintptr_t addr)
+{
+	return EOK;
 }
 
@@ -270,6 +253,5 @@
 {
 	pio_write_8((ioport8_t *)0x64, 0xfe);
-	while (1)
-		;
+	while (1);
 }
 
Index: kernel/arch/ia64/src/start.S
===================================================================
--- kernel/arch/ia64/src/start.S	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/ia64/src/start.S	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -174,5 +174,5 @@
 	mov ar.bspstore = r8
 	loadrs
-
+	
 	#
 	# Initialize memory stack to some sane value and allocate a scratch area
@@ -196,5 +196,5 @@
 	srlz.i
 	srlz.d ;;
-
+	
 	br.call.sptk.many b0 = arch_pre_main
 0:
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/mips32/src/mips32.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,31 +34,21 @@
 
 #include <arch.h>
-#include <arch/cp0.h>
-#include <arch/exception.h>
-#include <arch/debug.h>
-#include <mm/as.h>
+#include <typedefs.h>
+#include <errno.h>
+#include <interrupt.h>
+#include <macros.h>
+#include <str.h>
+#include <memstr.h>
 #include <userspace.h>
-#include <memstr.h>
-#include <proc/thread.h>
-#include <abi/proc/uarg.h>
-#include <print.h>
 #include <console/console.h>
 #include <syscall/syscall.h>
 #include <sysinfo/sysinfo.h>
-#include <arch/interrupt.h>
-#include <interrupt.h>
-#include <console/chardev.h>
-#include <arch/barrier.h>
+#include <arch/debug.h>
 #include <arch/debugger.h>
+#include <arch/drivers/msim.h>
 #include <genarch/fb/fb.h>
-#include <abi/fb/visuals.h>
 #include <genarch/drivers/dsrln/dsrlnin.h>
 #include <genarch/drivers/dsrln/dsrlnout.h>
 #include <genarch/srln/srln.h>
-#include <macros.h>
-#include <config.h>
-#include <str.h>
-#include <arch/drivers/msim.h>
-#include <arch/asm/regname.h>
 
 /* Size of the code jumping to the exception handler code
@@ -248,7 +238,7 @@
  * possible to have it separately in the future.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
-{
-	return 0;
+sysarg_t sys_tls_set(uintptr_t addr)
+{
+	return EOK;
 }
 
Index: kernel/arch/mips64/src/mips64.c
===================================================================
--- kernel/arch/mips64/src/mips64.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/arch/mips64/src/mips64.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,31 +34,21 @@
 
 #include <arch.h>
-#include <arch/cp0.h>
-#include <arch/exception.h>
-#include <arch/debug.h>
-#include <mm/as.h>
+#include <typedefs.h>
+#include <errno.h>
+#include <interrupt.h>
+#include <macros.h>
+#include <str.h>
+#include <memstr.h>
 #include <userspace.h>
-#include <memstr.h>
-#include <proc/thread.h>
-#include <abi/proc/uarg.h>
-#include <print.h>
 #include <console/console.h>
 #include <syscall/syscall.h>
 #include <sysinfo/sysinfo.h>
-#include <arch/interrupt.h>
-#include <interrupt.h>
-#include <console/chardev.h>
-#include <arch/barrier.h>
+#include <arch/debug.h>
 #include <arch/debugger.h>
+#include <arch/drivers/msim.h>
 #include <genarch/fb/fb.h>
-#include <abi/fb/visuals.h>
 #include <genarch/drivers/dsrln/dsrlnin.h>
 #include <genarch/drivers/dsrln/dsrlnout.h>
 #include <genarch/srln/srln.h>
-#include <macros.h>
-#include <config.h>
-#include <str.h>
-#include <arch/drivers/msim.h>
-#include <arch/asm/regname.h>
 
 /* Size of the code jumping to the exception handler code
@@ -226,7 +216,7 @@
  * possible to have it separately in the future.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
-{
-	return 0;
+sysarg_t sys_tls_set(uintptr_t addr)
+{
+	return EOK;
 }
 
Index: kernel/generic/include/ddi/ddi.h
===================================================================
--- kernel/generic/include/ddi/ddi.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/include/ddi/ddi.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -55,6 +55,14 @@
 extern void ddi_parea_register(parea_t *);
 
-extern sysarg_t sys_physmem_map(sysarg_t, sysarg_t, sysarg_t, sysarg_t);
+extern sysarg_t sys_physmem_map(uintptr_t, size_t, unsigned int, void *,
+    uintptr_t);
+extern sysarg_t sys_physmem_unmap(uintptr_t);
+
+extern sysarg_t sys_dmamem_map(size_t, unsigned int, unsigned int, void *,
+    void *, uintptr_t);
+extern sysarg_t sys_dmamem_unmap(uintptr_t, size_t, unsigned int);
+
 extern sysarg_t sys_iospace_enable(ddi_ioarg_t *);
+extern sysarg_t sys_iospace_disable(ddi_ioarg_t *);
 
 /*
Index: kernel/generic/include/ipc/sysipc.h
===================================================================
--- kernel/generic/include/ipc/sysipc.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/include/ipc/sysipc.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -56,6 +56,6 @@
     unsigned int);
 extern sysarg_t sys_ipc_hangup(sysarg_t);
-extern sysarg_t sys_register_irq(inr_t, devno_t, sysarg_t, irq_code_t *);
-extern sysarg_t sys_unregister_irq(inr_t, devno_t);
+extern sysarg_t sys_irq_register(inr_t, devno_t, sysarg_t, irq_code_t *);
+extern sysarg_t sys_irq_unregister(inr_t, devno_t);
 
 #ifdef __32_BITS__
Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/include/mm/as.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -242,10 +242,10 @@
 extern int as_page_fault(uintptr_t, pf_access_t, istate_t *);
 
-extern as_area_t *as_area_create(as_t *, unsigned int, size_t, uintptr_t,
-    unsigned int, mem_backend_t *, mem_backend_data_t *);
+extern as_area_t *as_area_create(as_t *, unsigned int, size_t, unsigned int,
+    mem_backend_t *, mem_backend_data_t *, uintptr_t *, uintptr_t);
 extern int as_area_destroy(as_t *, uintptr_t);
 extern int as_area_resize(as_t *, uintptr_t, size_t, unsigned int);
-extern int as_area_share(as_t *, uintptr_t, size_t, as_t *, uintptr_t,
-    unsigned int);
+extern int as_area_share(as_t *, uintptr_t, size_t, as_t *, unsigned int,
+    uintptr_t *, uintptr_t);
 extern int as_area_change_flags(as_t *, unsigned int, uintptr_t);
 
@@ -284,9 +284,8 @@
 
 /* Address space area related syscalls. */
-extern sysarg_t sys_as_area_create(uintptr_t, size_t, unsigned int);
+extern sysarg_t sys_as_area_create(uintptr_t, size_t, unsigned int, uintptr_t);
 extern sysarg_t sys_as_area_resize(uintptr_t, size_t, unsigned int);
 extern sysarg_t sys_as_area_change_flags(uintptr_t, unsigned int);
 extern sysarg_t sys_as_area_destroy(uintptr_t);
-extern sysarg_t sys_as_get_unmapped_area(uintptr_t, size_t);
 
 /* Introspection functions. */
Index: kernel/generic/include/mm/page.h
===================================================================
--- kernel/generic/include/mm/page.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/include/mm/page.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -66,5 +66,6 @@
 extern uintptr_t hw_map(uintptr_t, size_t);
 
-extern sysarg_t sys_page_find_mapping(uintptr_t, uintptr_t *);
+extern int page_find_mapping(uintptr_t, void **);
+extern sysarg_t sys_page_find_mapping(uintptr_t, void *);
 
 #endif
Index: kernel/generic/include/synch/smc.h
===================================================================
--- kernel/generic/include/synch/smc.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/include/synch/smc.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -36,5 +36,5 @@
 #define KERN_SMC_H_
 
-extern sysarg_t sys_smc_coherence(uintptr_t va, size_t size);
+extern sysarg_t sys_smc_coherence(uintptr_t, size_t);
 
 #endif
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/include/syscall/syscall.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -45,5 +45,5 @@
 extern sysarg_t syscall_handler(sysarg_t, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, sysarg_t);
-extern sysarg_t sys_tls_set(sysarg_t);
+extern sysarg_t sys_tls_set(uintptr_t);
 
 #endif
Index: kernel/generic/src/ddi/ddi.c
===================================================================
--- kernel/generic/src/ddi/ddi.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/ddi/ddi.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -45,4 +45,5 @@
 #include <mm/frame.h>
 #include <mm/as.h>
+#include <mm/page.h>
 #include <synch/mutex.h>
 #include <syscall/copy.h>
@@ -52,4 +53,5 @@
 #include <errno.h>
 #include <trace.h>
+#include <bitops.h>
 
 /** This lock protects the parea_btree. */
@@ -87,25 +89,24 @@
 /** Map piece of physical memory into virtual address space of current task.
  *
- * @param pf    Physical address of the starting frame.
- * @param vp    Virtual address of the starting page.
+ * @param phys  Physical address of the starting frame.
  * @param pages Number of pages to map.
  * @param flags Address space area flags for the mapping.
- *
- * @return 0 on success, EPERM if the caller lacks capabilities to use this
- *         syscall, EBADMEM if pf or vf is not page aligned, ENOENT if there
- *         is no task matching the specified ID or the physical address space
- *         is not enabled for mapping and ENOMEM if there was a problem in
- *         creating address space area.
- *
- */
-NO_TRACE static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, size_t pages,
-    unsigned int flags)
+ * @param virt  Virtual address of the starting page.
+ * @param bound Lowest virtual address bound.
+ *
+ * @return EOK on success.
+ * @return EPERM if the caller lacks capabilities to use this syscall.
+ * @return EBADMEM if phys is not page aligned.
+ * @return ENOENT if there is no task matching the specified ID or
+ *         the physical address space is not enabled for mapping.
+ * @return ENOMEM if there was a problem in creating address space area.
+ *
+ */
+NO_TRACE static int physmem_map(uintptr_t phys, size_t pages,
+    unsigned int flags, uintptr_t *virt, uintptr_t bound)
 {
 	ASSERT(TASK);
 	
-	if ((pf % FRAME_SIZE) != 0)
-		return EBADMEM;
-	
-	if ((vp % PAGE_SIZE) != 0)
+	if ((phys % FRAME_SIZE) != 0)
 		return EBADMEM;
 	
@@ -118,5 +119,5 @@
 	
 	mem_backend_data_t backend_data;
-	backend_data.base = pf;
+	backend_data.base = phys;
 	backend_data.frames = pages;
 	
@@ -129,5 +130,5 @@
 	btree_node_t *nodep;
 	parea_t *parea = (parea_t *) btree_search(&parea_btree,
-	    (btree_key_t) pf, &nodep);
+	    (btree_key_t) phys, &nodep);
 	
 	if ((parea != NULL) && (parea->frames >= pages)) {
@@ -149,5 +150,5 @@
 	
 	irq_spinlock_lock(&zones.lock, true);
-	size_t znum = find_zone(ADDR2PFN(pf), pages, 0);
+	size_t znum = find_zone(ADDR2PFN(phys), pages, 0);
 	
 	if (znum == (size_t) -1) {
@@ -182,6 +183,6 @@
 	
 map:
-	if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp,
-	    AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
+	if (!as_area_create(TASK->as, flags, FRAMES2SIZE(pages),
+	    AS_AREA_ATTR_NONE, &phys_backend, &backend_data, virt, bound)) {
 		/*
 		 * The address space area was not created.
@@ -207,4 +208,44 @@
 }
 
+NO_TRACE static int physmem_unmap(uintptr_t virt)
+{
+	// TODO: implement unmap
+	return EOK;
+}
+
+/** Wrapper for SYS_PHYSMEM_MAP syscall.
+ *
+ * @param phys     Physical base address to map
+ * @param pages    Number of pages
+ * @param flags    Flags of newly mapped pages
+ * @param virt_ptr Destination virtual address
+ * @param bound    Lowest virtual address bound.
+ *
+ * @return 0 on success, otherwise it returns error code found in errno.h
+ *
+ */
+sysarg_t sys_physmem_map(uintptr_t phys, size_t pages, unsigned int flags,
+    void *virt_ptr, uintptr_t bound)
+{
+	uintptr_t virt = (uintptr_t) -1;
+	int rc = physmem_map(ALIGN_DOWN(phys, FRAME_SIZE), pages, flags,
+	    &virt, bound);
+	if (rc != EOK)
+		return rc;
+	
+	rc = copy_to_uspace(virt_ptr, &virt, sizeof(virt));
+	if (rc != EOK) {
+		physmem_unmap((uintptr_t) virt);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+sysarg_t sys_physmem_unmap(uintptr_t virt)
+{
+	return physmem_unmap(virt);
+}
+
 /** Enable range of I/O space for task.
  *
@@ -217,6 +258,5 @@
  *
  */
-NO_TRACE static int ddi_iospace_enable(task_id_t id, uintptr_t ioaddr,
-    size_t size)
+NO_TRACE static int iospace_enable(task_id_t id, uintptr_t ioaddr, size_t size)
 {
 	/*
@@ -243,28 +283,8 @@
 	/* Lock the task and release the lock protecting tasks_btree. */
 	irq_spinlock_exchange(&tasks_lock, &task->lock);
-	
 	int rc = ddi_iospace_enable_arch(task, ioaddr, size);
-	
 	irq_spinlock_unlock(&task->lock, true);
 	
 	return rc;
-}
-
-/** Wrapper for SYS_PHYSMEM_MAP syscall.
- *
- * @param phys_base Physical base address to map
- * @param virt_base Destination virtual address
- * @param pages Number of pages
- * @param flags Flags of newly mapped pages
- *
- * @return 0 on success, otherwise it returns error code found in errno.h
- *
- */
-sysarg_t sys_physmem_map(sysarg_t phys_base, sysarg_t virt_base,
-    sysarg_t pages, sysarg_t flags)
-{
-	return (sysarg_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
-	    FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
-	    (size_t) pages, (int) flags);
 }
 
@@ -283,8 +303,122 @@
 		return (sysarg_t) rc;
 	
-	return (sysarg_t) ddi_iospace_enable((task_id_t) arg.task_id,
+	return (sysarg_t) iospace_enable((task_id_t) arg.task_id,
 	    (uintptr_t) arg.ioaddr, (size_t) arg.size);
 }
 
+sysarg_t sys_iospace_disable(ddi_ioarg_t *uspace_io_arg)
+{
+	// TODO: implement
+	return ENOTSUP;
+}
+
+NO_TRACE static int dmamem_map(uintptr_t virt, size_t size, unsigned int map_flags,
+    unsigned int flags, void **phys)
+{
+	ASSERT(TASK);
+	
+	// TODO: implement locking of non-anonymous mapping
+	return page_find_mapping(virt, phys);
+}
+
+NO_TRACE static int dmamem_map_anonymous(size_t size, unsigned int map_flags,
+    unsigned int flags, void **phys, uintptr_t *virt, uintptr_t bound)
+{
+	ASSERT(TASK);
+	
+	size_t pages = SIZE2FRAMES(size);
+	uint8_t order;
+	
+	/* We need the 2^order >= pages */
+	if (pages == 1)
+		order = 0;
+	else
+		order = fnzb(pages - 1) + 1;
+	
+	*phys = frame_alloc_noreserve(order, 0);
+	if (*phys == NULL)
+		return ENOMEM;
+	
+	mem_backend_data_t backend_data;
+	backend_data.base = (uintptr_t) *phys;
+	backend_data.frames = pages;
+	
+	if (!as_area_create(TASK->as, map_flags, size,
+	    AS_AREA_ATTR_NONE, &phys_backend, &backend_data, virt, bound)) {
+		frame_free_noreserve((uintptr_t) *phys);
+		return ENOMEM;
+	}
+	
+	return EOK;
+}
+
+NO_TRACE static int dmamem_unmap(uintptr_t virt, size_t size)
+{
+	// TODO: implement unlocking & unmap
+	return EOK;
+}
+
+NO_TRACE static int dmamem_unmap_anonymous(uintptr_t virt)
+{
+	// TODO: implement unlocking & unmap
+	return EOK;
+}
+
+sysarg_t sys_dmamem_map(size_t size, unsigned int map_flags, unsigned int flags,
+    void *phys_ptr, void *virt_ptr, uintptr_t bound)
+{
+	if ((flags & DMAMEM_FLAGS_ANONYMOUS) == 0) {
+		/*
+		 * Non-anonymous DMA mapping
+		 */
+		
+		void *phys;
+		int rc = dmamem_map((uintptr_t) virt_ptr, size, map_flags,
+		    flags, &phys);
+		
+		if (rc != EOK)
+			return rc;
+		
+		rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
+		if (rc != EOK) {
+			dmamem_unmap((uintptr_t) virt_ptr, size);
+			return rc;
+		}
+	} else {
+		/*
+		 * Anonymous DMA mapping
+		 */
+		
+		void *phys;
+		uintptr_t virt = (uintptr_t) -1;
+		int rc = dmamem_map_anonymous(size, map_flags, flags,
+		    &phys, &virt, bound);
+		if (rc != EOK)
+			return rc;
+		
+		rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
+		if (rc != EOK) {
+			dmamem_unmap_anonymous((uintptr_t) virt);
+			return rc;
+		}
+		
+		rc = copy_to_uspace(virt_ptr, &virt, sizeof(virt));
+		if (rc != EOK) {
+			dmamem_unmap_anonymous((uintptr_t) virt);
+			return rc;
+		}
+	}
+	
+	return EOK;
+}
+
+sysarg_t sys_dmamem_unmap(uintptr_t virt, size_t size, unsigned int flags)
+{
+	if ((flags & DMAMEM_FLAGS_ANONYMOUS) == 0)
+		return dmamem_unmap(virt, size);
+	else
+		return dmamem_unmap_anonymous(virt);
+}
+
 /** @}
  */
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/ipc/irq.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -42,6 +42,6 @@
  *
  * The structure of a notification message is as follows:
- * - IMETHOD: interface and method as registered by the SYS_REGISTER_IRQ
- *            syscall
+ * - IMETHOD: interface and method as registered by
+ *            the SYS_IRQ_REGISTER syscall
  * - ARG1: payload modified by a 'top-half' handler
  * - ARG2: payload modified by a 'top-half' handler
@@ -365,26 +365,15 @@
 		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++) {
+	if (current_as != irq->driver_as)
+		as_switch(AS, irq->driver_as);
+	
+	for (size_t i = 0; i < code->cmdcount; i++) {
 		uint32_t dstval;
+		void *va;
+		uint8_t val8;
+		uint16_t val16;
+		uint32_t val32;
+		
 		uintptr_t srcarg = code->cmds[i].srcarg;
 		uintptr_t dstarg = code->cmds[i].dstarg;
@@ -442,50 +431,56 @@
 			}
 			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_READ_8:
+			va = code->cmds[i].addr;
+			memcpy_from_uspace(&val8, va, sizeof(val8));
+			if (dstarg)
+				scratch[dstarg] = val8;
+			break;
+		case CMD_MEM_READ_16:
+			va = code->cmds[i].addr;
+			memcpy_from_uspace(&val16, va, sizeof(val16));
+			if (dstarg)
+				scratch[dstarg] = val16;
+			break;
+		case CMD_MEM_READ_32:
+			va = code->cmds[i].addr;
+			memcpy_from_uspace(&val32, va, sizeof(val32));
+			if (dstarg)
+				scratch[dstarg] = val32;
+			break;
+		case CMD_MEM_WRITE_8:
+			val8 = code->cmds[i].value;
+			va = code->cmds[i].addr;
+			memcpy_to_uspace(va, &val8, sizeof(val8));
+			break;
+		case CMD_MEM_WRITE_16:
+			val16 = code->cmds[i].value;
+			va = code->cmds[i].addr;
+			memcpy_to_uspace(va, &val16, sizeof(val16));
+			break;
+		case CMD_MEM_WRITE_32:
+			val32 = code->cmds[i].value;
+			va = code->cmds[i].addr;
+			memcpy_to_uspace(va, &val32, sizeof(val32));
+			break;
 		case CMD_MEM_WRITE_A_8:
 			if (srcarg) {
-				uint8_t val = scratch[srcarg];
-				CMD_MEM_WRITE(val);
+				val8 = scratch[srcarg];
+				va = code->cmds[i].addr;
+				memcpy_to_uspace(va, &val8, sizeof(val8));
 			}
 			break;
 		case CMD_MEM_WRITE_A_16:
 			if (srcarg) {
-				uint16_t val = scratch[srcarg];
-				CMD_MEM_WRITE(val);
+				val16 = scratch[srcarg];
+				va = code->cmds[i].addr;
+				memcpy_to_uspace(va, &val16, sizeof(val16));
 			}
 			break;
 		case CMD_MEM_WRITE_A_32:
 			if (srcarg) {
-				uint32_t val = scratch[srcarg];
-				CMD_MEM_WRITE(val);
+				val32 = scratch[srcarg];
+				va = code->cmds[i].addr;
+				memcpy_to_uspace(va, &val32, sizeof(val32));
 			}
 			break;
@@ -513,4 +508,5 @@
 		}
 	}
+	
 	if (AS != current_as)
 		as_switch(AS, current_as);
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/ipc/sysipc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -271,19 +271,27 @@
 			irq_spinlock_unlock(&answer->sender->lock, true);
 			
+			uintptr_t dst_base = (uintptr_t) -1;
 			int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
-			    IPC_GET_ARG2(*olddata), AS,
-			    IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
+			    IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
+			    &dst_base, IPC_GET_ARG1(answer->data));
+			
+			if (rc == EOK)
+				rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
+				    &dst_base, sizeof(dst_base));
+			
 			IPC_SET_RETVAL(answer->data, rc);
 			return rc;
 		}
 	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
-		if (!IPC_GET_RETVAL(answer->data)) { 
+		if (!IPC_GET_RETVAL(answer->data)) {
 			irq_spinlock_lock(&answer->sender->lock, true);
 			as_t *as = answer->sender->as;
 			irq_spinlock_unlock(&answer->sender->lock, true);
 			
+			uintptr_t dst_base = (uintptr_t) -1;
 			int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
-			    IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
-			    IPC_GET_ARG2(answer->data));
+			    IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
+			    &dst_base, IPC_GET_ARG3(answer->data));
+			IPC_SET_ARG4(answer->data, dst_base);
 			IPC_SET_RETVAL(answer->data, rc);
 		}
@@ -1185,5 +1193,5 @@
  *
  */
-sysarg_t sys_register_irq(inr_t inr, devno_t devno, sysarg_t imethod,
+sysarg_t sys_irq_register(inr_t inr, devno_t devno, sysarg_t imethod,
     irq_code_t *ucode)
 {
@@ -1202,5 +1210,5 @@
  *
  */
-sysarg_t sys_unregister_irq(inr_t inr, devno_t devno)
+sysarg_t sys_irq_unregister(inr_t inr, devno_t devno)
 {
 	if (!(cap_get(TASK) & CAP_IRQ_REG))
Index: kernel/generic/src/lib/elf.c
===================================================================
--- kernel/generic/src/lib/elf.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/lib/elf.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -226,6 +226,6 @@
 	size_t mem_sz = entry->p_memsz + (entry->p_vaddr - base);
 	
-	as_area_t *area = as_area_create(as, flags, mem_sz, base,
-	    AS_AREA_ATTR_NONE, &elf_backend, &backend_data);
+	as_area_t *area = as_area_create(as, flags, mem_sz,
+	    AS_AREA_ATTR_NONE, &elf_backend, &backend_data, &base, 0);
 	if (!area)
 		return EE_MEMORY;
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/mm/as.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -387,4 +387,71 @@
 }
 
+/** Return pointer to unmapped address space area
+ *
+ * The address space must be already locked when calling
+ * this function.
+ *
+ * @param as    Address space.
+ * @param bound Lowest address bound.
+ * @param size  Requested size of the allocation.
+ *
+ * @return Address of the beginning of unmapped address space area.
+ * @return -1 if no suitable address space area was found.
+ *
+ */
+NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound,
+    size_t size)
+{
+	ASSERT(mutex_locked(&as->lock));
+	
+	if (size == 0)
+		return (uintptr_t) -1;
+	
+	/*
+	 * Make sure we allocate from page-aligned
+	 * address. Check for possible overflow in
+	 * each step.
+	 */
+	
+	size_t pages = SIZE2FRAMES(size);
+	
+	/*
+	 * Find the lowest unmapped address aligned on the size
+	 * boundary, not smaller than bound and of the required size.
+	 */
+	
+	/* First check the bound address itself */
+	uintptr_t addr = ALIGN_UP(bound, PAGE_SIZE);
+	if ((addr >= bound) &&
+	    (check_area_conflicts(as, addr, pages, NULL)))
+		return addr;
+	
+	/* Eventually check the addresses behind each area */
+	list_foreach(as->as_area_btree.leaf_list, cur) {
+		btree_node_t *node =
+		    list_get_instance(cur, btree_node_t, leaf_link);
+		
+		for (btree_key_t i = 0; i < node->keys; i++) {
+			as_area_t *area = (as_area_t *) node->value[i];
+			
+			mutex_lock(&area->lock);
+			
+			addr =
+			    ALIGN_UP(area->base + P2SZ(area->pages), PAGE_SIZE);
+			bool avail =
+			    ((addr >= bound) && (addr >= area->base) &&
+			    (check_area_conflicts(as, addr, pages, area)));
+			
+			mutex_unlock(&area->lock);
+			
+			if (avail)
+				return addr;
+		}
+	}
+	
+	/* No suitable address space area found */
+	return (uintptr_t) -1;
+}
+
 /** Create address space area of common attributes.
  *
@@ -394,8 +461,11 @@
  * @param flags        Flags of the area memory.
  * @param size         Size of area.
- * @param base         Base address of area.
  * @param attrs        Attributes of the area.
  * @param backend      Address space area backend. NULL if no backend is used.
  * @param backend_data NULL or a pointer to an array holding two void *.
+ * @param base         Starting virtual address of the area.
+ *                     If set to -1, a suitable mappable area is found.
+ * @param bound        Lowest address bound if base is set to -1.
+ *                     Otherwise ignored.
  *
  * @return Address space area on success or NULL on failure.
@@ -403,8 +473,8 @@
  */
 as_area_t *as_area_create(as_t *as, unsigned int flags, size_t size,
-    uintptr_t base, unsigned int attrs, mem_backend_t *backend,
-    mem_backend_data_t *backend_data)
-{
-	if ((base % PAGE_SIZE) != 0)
+    unsigned int attrs, mem_backend_t *backend,
+    mem_backend_data_t *backend_data, uintptr_t *base, uintptr_t bound)
+{
+	if ((*base != (uintptr_t) -1) && ((*base % PAGE_SIZE) != 0))
 		return NULL;
 	
@@ -420,5 +490,13 @@
 	mutex_lock(&as->lock);
 	
-	if (!check_area_conflicts(as, base, pages, NULL)) {
+	if (*base == (uintptr_t) -1) {
+		*base = as_get_unmapped_area(as, bound, size);
+		if (*base == (uintptr_t) -1) {
+			mutex_unlock(&as->lock);
+			return NULL;
+		}
+	}
+	
+	if (!check_area_conflicts(as, *base, pages, NULL)) {
 		mutex_unlock(&as->lock);
 		return NULL;
@@ -434,5 +512,5 @@
 	area->pages = pages;
 	area->resident = 0;
-	area->base = base;
+	area->base = *base;
 	area->sh_info = NULL;
 	area->backend = backend;
@@ -452,5 +530,6 @@
 	
 	btree_create(&area->used_space);
-	btree_insert(&as->as_area_btree, base, (void *) area, NULL);
+	btree_insert(&as->as_area_btree, *base, (void *) area,
+	    NULL);
 	
 	mutex_unlock(&as->lock);
@@ -860,6 +939,9 @@
  * @param acc_size       Expected size of the source area.
  * @param dst_as         Pointer to destination address space.
- * @param dst_base       Target base address.
  * @param dst_flags_mask Destination address space area flags mask.
+ * @param dst_base       Target base address. If set to -1,
+ *                       a suitable mappable area is found.
+ * @param bound          Lowest address bound if dst_base is set to -1.
+ *                       Otherwise ignored.
  *
  * @return Zero on success.
@@ -873,5 +955,6 @@
  */
 int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
-    as_t *dst_as, uintptr_t dst_base, unsigned int dst_flags_mask)
+    as_t *dst_as, unsigned int dst_flags_mask, uintptr_t *dst_base,
+    uintptr_t bound)
 {
 	mutex_lock(&src_as->lock);
@@ -945,6 +1028,7 @@
 	 * to support sharing in less privileged mode.
 	 */
-	as_area_t *dst_area = as_area_create(dst_as, dst_flags_mask, src_size,
-	    dst_base, AS_AREA_ATTR_PARTIAL, src_backend, &src_backend_data);
+	as_area_t *dst_area = as_area_create(dst_as, dst_flags_mask,
+	    src_size, AS_AREA_ATTR_PARTIAL, src_backend,
+	    &src_backend_data, dst_base, bound);
 	if (!dst_area) {
 		/*
@@ -1955,15 +2039,16 @@
  */
 
-/** Wrapper for as_area_create(). */
-sysarg_t sys_as_area_create(uintptr_t address, size_t size, unsigned int flags)
-{
-	if (as_area_create(AS, flags | AS_AREA_CACHEABLE, size, address,
-	    AS_AREA_ATTR_NONE, &anon_backend, NULL))
-		return (sysarg_t) address;
-	else
+sysarg_t sys_as_area_create(uintptr_t base, size_t size, unsigned int flags,
+    uintptr_t bound)
+{
+	uintptr_t virt = base;
+	as_area_t *area = as_area_create(AS, flags | AS_AREA_CACHEABLE, size,
+	    AS_AREA_ATTR_NONE, &anon_backend, NULL, &virt, bound);
+	if (area == NULL)
 		return (sysarg_t) -1;
-}
-
-/** Wrapper for as_area_resize(). */
+	
+	return (sysarg_t) virt;
+}
+
 sysarg_t sys_as_area_resize(uintptr_t address, size_t size, unsigned int flags)
 {
@@ -1971,5 +2056,4 @@
 }
 
-/** Wrapper for as_area_change_flags(). */
 sysarg_t sys_as_area_change_flags(uintptr_t address, unsigned int flags)
 {
@@ -1977,75 +2061,7 @@
 }
 
-/** Wrapper for as_area_destroy(). */
 sysarg_t sys_as_area_destroy(uintptr_t address)
 {
 	return (sysarg_t) as_area_destroy(AS, address);
-}
-
-/** Return pointer to unmapped address space area
- *
- * @param base Lowest address bound.
- * @param size Requested size of the allocation.
- *
- * @return Pointer to the beginning of unmapped address space area.
- *
- */
-sysarg_t sys_as_get_unmapped_area(uintptr_t base, size_t size)
-{
-	if (size == 0)
-		return 0;
-	
-	/*
-	 * Make sure we allocate from page-aligned
-	 * address. Check for possible overflow in
-	 * each step.
-	 */
-	
-	size_t pages = SIZE2FRAMES(size);
-	uintptr_t ret = 0;
-	
-	/*
-	 * Find the lowest unmapped address aligned on the sz
-	 * boundary, not smaller than base and of the required size.
-	 */
-	
-	mutex_lock(&AS->lock);
-	
-	/* First check the base address itself */
-	uintptr_t addr = ALIGN_UP(base, PAGE_SIZE);
-	if ((addr >= base) &&
-	    (check_area_conflicts(AS, addr, pages, NULL)))
-		ret = addr;
-	
-	/* Eventually check the addresses behind each area */
-	list_foreach(AS->as_area_btree.leaf_list, cur) {
-		if (ret != 0)
-			break;
-
-		btree_node_t *node =
-		    list_get_instance(cur, btree_node_t, leaf_link);
-		
-		btree_key_t i;
-		for (i = 0; (ret == 0) && (i < node->keys); i++) {
-			uintptr_t addr;
-
-			as_area_t *area = (as_area_t *) node->value[i];
-			
-			mutex_lock(&area->lock);
-			
-			addr = ALIGN_UP(area->base + P2SZ(area->pages),
-			    PAGE_SIZE);
-			
-			if ((addr >= base) && (addr >= area->base) &&
-			    (check_area_conflicts(AS, addr, pages, area)))
-				ret = addr;
-			
-			mutex_unlock(&area->lock);
-		}
-	}
-	
-	mutex_unlock(&AS->lock);
-	
-	return (sysarg_t) ret;
 }
 
Index: kernel/generic/src/mm/page.c
===================================================================
--- kernel/generic/src/mm/page.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/mm/page.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -53,5 +53,5 @@
  * We assume that the other processors are either not using the mapping yet
  * (i.e. during the bootstrap) or are executing the TLB shootdown code.  While
- * we don't care much about the former case, the processors in the latter case 
+ * we don't care much about the former case, the processors in the latter case
  * will do an implicit serialization by virtue of running the TLB shootdown
  * interrupt handler.
@@ -74,4 +74,5 @@
 #include <syscall/copy.h>
 #include <errno.h>
+#include <align.h>
 
 /** Virtual operations for page subsystem. */
@@ -176,33 +177,37 @@
 }
 
+int page_find_mapping(uintptr_t virt, void **phys)
+{
+	mutex_lock(&AS->lock);
+	
+	pte_t *pte = page_mapping_find(AS, virt, false);
+	if ((!PTE_VALID(pte)) || (!PTE_PRESENT(pte))) {
+		mutex_unlock(&AS->lock);
+		return ENOENT;
+	}
+	
+	*phys = (void *) PTE_GET_FRAME(pte) +
+	    (virt - ALIGN_DOWN(virt, PAGE_SIZE));
+	
+	mutex_unlock(&AS->lock);
+	
+	return EOK;
+}
+
 /** 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;
+ *
+ * @return EOK on success.
+ * @return ENOENT if no virtual address mapping found.
+ *
+ */
+sysarg_t sys_page_find_mapping(uintptr_t virt, void *phys_ptr)
+{
+	void *phys;
+	int rc = page_find_mapping(virt, &phys);
+	if (rc != EOK)
+		return rc;
+	
+	rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
+	return (sysarg_t) rc;
 }
 
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/proc/program.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -87,8 +87,8 @@
 	 * Create the stack address space area.
 	 */
+	uintptr_t virt = USTACK_ADDRESS;
 	as_area_t *area = as_area_create(as,
 	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
-	    STACK_SIZE, USTACK_ADDRESS, AS_AREA_ATTR_NONE,
-	    &anon_backend, NULL);
+	    STACK_SIZE, AS_AREA_ATTR_NONE, &anon_backend, NULL, &virt, 0);
 	if (!area)
 		return ENOMEM;
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ kernel/generic/src/syscall/syscall.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -146,5 +146,4 @@
 	(syshandler_t) sys_as_area_change_flags,
 	(syshandler_t) sys_as_area_destroy,
-	(syshandler_t) sys_as_get_unmapped_area,
 	
 	/* Page mapping related syscalls. */
@@ -176,7 +175,11 @@
 	(syshandler_t) sys_device_assign_devno,
 	(syshandler_t) sys_physmem_map,
+	(syshandler_t) sys_physmem_unmap,
+	(syshandler_t) sys_dmamem_map,
+	(syshandler_t) sys_dmamem_unmap,
 	(syshandler_t) sys_iospace_enable,
-	(syshandler_t) sys_register_irq,
-	(syshandler_t) sys_unregister_irq,
+	(syshandler_t) sys_iospace_disable,
+	(syshandler_t) sys_irq_register,
+	(syshandler_t) sys_irq_unregister,
 	
 	/* Sysinfo syscalls. */
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -64,4 +64,5 @@
 	app/nettest1 \
 	app/nettest2 \
+	app/nettest3 \
 	app/ping \
 	app/websrv \
@@ -121,5 +122,6 @@
 	drv/bus/usb/vhc \
 	drv/nic/lo \
-	drv/nic/ne2k
+	drv/nic/ne2k \
+	drv/nic/e1k
 
 ifeq ($(CONFIG_PCC),y)
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/klog/klog.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -205,13 +205,6 @@
 	klog_length = size / sizeof(wchar_t);
 	
-	klog = (wchar_t *) as_get_mappable_page(size);
-	if (klog == NULL) {
-		fprintf(stderr, "%s: Unable to allocate virtual memory area\n",
-		    NAME);
-		return ENOMEM;
-	}
-	
-	rc = physmem_map((void *) faddr, (void *) klog, pages,
-	    AS_AREA_READ | AS_AREA_CACHEABLE);
+	rc = physmem_map((void *) faddr, pages,
+	    AS_AREA_READ | AS_AREA_CACHEABLE, (void *) &klog);
 	if (rc != EOK) {
 		fprintf(stderr, "%s: Unable to map klog\n", NAME);
Index: uspace/app/mkbd/main.c
===================================================================
--- uspace/app/mkbd/main.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/mkbd/main.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -48,4 +48,5 @@
 #include <usb/dev/pipes.h>
 #include <async.h>
+#include <usb/dev.h>
 #include <usb/hid/usages/core.h>
 #include <usb/hid/hidparser.h>
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/netecho/netecho.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -241,4 +241,6 @@
 		/* Accept a socket if a stream socket is used */
 		addrlen = sizeof(address_buf);
+		if (verbose)
+			printf("accept()\n");
             	socket_id = accept(listening_id, (void *) address_buf, &addrlen);
 		if (socket_id <= 0) {
@@ -258,4 +260,6 @@
 
 		/* Receive a message to echo */
+		if (verbose)
+			printf("recvfrom()\n");
 		rcv_size = recvfrom(socket_id, data, size, 0, address,
 		    &addrlen);
@@ -297,7 +301,17 @@
 
 			/* Answer the request either with the static reply or the original data */
-			rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen);
-			if (rc != EOK)
-				socket_print_error(stderr, rc, "Socket send: ", "\n");
+			if (type == SOCK_STREAM) {
+				if (verbose)
+					printf("send()\n");
+				rc = send(socket_id, reply ? reply : data, reply ? reply_length : length, 0);
+				if (rc != EOK)
+					socket_print_error(stderr, rc, "Socket send: ", "\n");
+			} else {
+				if (verbose)
+					printf("sendto()\n");
+				rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen);
+				if (rc != EOK)
+					socket_print_error(stderr, rc, "Socket send: ", "\n");
+			}
 		}
 
Index: uspace/app/nettest3/Makefile
===================================================================
--- uspace/app/nettest3/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/app/nettest3/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS =
+EXTRA_CFLAGS =
+BINARY = nettest3
+
+SOURCES = \
+	nettest3.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nettest3/nettest3.c
===================================================================
--- uspace/app/nettest3/nettest3.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/app/nettest3/nettest3.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2011 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 nettest
+ * @{
+ */
+
+/** @file
+ * Networking test 3.
+ */
+
+#include <async.h>
+#include <stdio.h>
+#include <str.h>
+
+#include <net/in.h>
+#include <net/in6.h>
+#include <net/inet.h>
+#include <net/socket.h>
+
+#define BUF_SIZE 32
+
+static char *data;
+static size_t size;
+
+static char buf[BUF_SIZE];
+
+static struct sockaddr_in addr;
+
+static uint16_t port;
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	int fd;
+	char *endptr;
+
+	port = 7;
+
+	data = (char *)"Hello World!";
+	size = str_size(data);
+
+	/* Connect to local IP address by default */
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = htonl(0x7f000001);
+
+	if (argc >= 2) {
+		printf("parsing address '%s'\n", argv[1]);
+		rc = inet_pton(AF_INET, argv[1], (uint8_t *)&addr.sin_addr.s_addr);
+		if (rc != EOK) {
+			fprintf(stderr, "Error parsing address\n");
+			return 1;
+		}
+		printf("result: rc=%d, family=%d, addr=%x\n", rc,
+		    addr.sin_family, addr.sin_addr.s_addr);
+	}
+
+	if (argc >= 3) {
+		printf("parsing port '%s'\n", argv[2]);
+		addr.sin_port = htons(strtoul(argv[2], &endptr, 10));
+		if (*endptr != '\0') {
+			fprintf(stderr, "Error parsing port\n");
+			return 1;
+		}
+	}
+
+	printf("socket()\n");
+	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	printf(" -> %d\n", fd);
+	if (fd < 0)
+		return 1;
+
+	printf("connect()\n");
+	rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+	printf(" -> %d\n", rc);
+	if (rc != 0)
+		return 1;
+
+	printf("send()\n");
+	rc = send(fd, data, size, 0);
+	printf(" -> %d\n", rc);
+	if (rc < 0)
+		return 1;
+
+	do {
+		printf("recv()\n");
+		rc = recv(fd, buf, BUF_SIZE, 0);
+		printf(" -> %d\n", rc);
+	} while (rc > 0);
+
+	async_usleep(1000*1000);
+
+	printf("closesocket()\n");
+	rc = closesocket(fd);
+	printf(" -> %d\n", rc);
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/tester/mm/common.c
===================================================================
--- uspace/app/tester/mm/common.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/tester/mm/common.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -342,16 +342,9 @@
 	link_initialize(&area->link);
 	
-	/* Map the memory area */
-	void *addr = as_get_mappable_page(size);
-	if (addr == NULL) {
+	area->addr = as_area_create((void *) -1, size,
+	    AS_AREA_WRITE | AS_AREA_READ);
+	if (area->addr == (void *) -1) {
 		free(area);
 		check_consistency("map_area (a)");
-		return NULL;
-	}
-	
-	area->addr = as_area_create(addr, size, AS_AREA_WRITE | AS_AREA_READ);
-	if (area->addr == (void *) -1) {
-		free(area);
-		check_consistency("map_area (b)");
 		return NULL;
 	}
Index: uspace/app/tester/mm/mapping1.c
===================================================================
--- uspace/app/tester/mm/mapping1.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/tester/mm/mapping1.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -35,15 +35,16 @@
 #include "../tester.h"
 
-#define BUFFER1_PAGES 4
-#define BUFFER2_PAGES 2
+#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) {
+	
+	void *result = as_area_create((void *) -1, size,
+	    AS_AREA_READ | AS_AREA_WRITE);
+	if (result == (void *) -1)
 		return NULL;
-	}
+	
 	return result;
 }
@@ -71,5 +72,5 @@
 	int i;
 	for (i = 0; i < page_count; i++) {
-		void *page_start = ((char *)area) + PAGE_SIZE * i;
+		void *page_start = ((char *) area) + PAGE_SIZE * i;
 		int rc = as_get_physical_mapping(page_start, NULL);
 		if (rc != expected_rc) {
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/trace/syscalls.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -72,6 +72,6 @@
     [SYS_PHYSMEM_MAP] = { "physmem_map",		4,	V_ERRNO },
     [SYS_IOSPACE_ENABLE] = { "iospace_enable",		1,	V_ERRNO },
-    [SYS_REGISTER_IRQ] = { "register_irq",	4,	V_ERRNO },
-    [SYS_UNREGISTER_IRQ] = { "unregister_irq",	2,	V_ERRNO },
+    [SYS_IRQ_REGISTER] = { "irq_register",	4,	V_ERRNO },
+    [SYS_IRQ_UNREGISTER] = { "irq_unregister",	2,	V_ERRNO },
 
     [SYS_SYSINFO_GET_VAL_TYPE] = { "sysinfo_get_val_type",		2,	V_INTEGER },
Index: uspace/app/usbinfo/dev.c
===================================================================
--- uspace/app/usbinfo/dev.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/usbinfo/dev.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,5 +34,6 @@
  * Representation of queried device.
  */
-#include <usb/dev/pipes.h>
+#include <usb/dev.h>
+#include <usb/hc.h>
 #include <errno.h>
 #include <str_error.h>
@@ -52,5 +53,8 @@
 	bool transfer_started = false;
 
-	rc = usb_device_connection_initialize(&dev->wire, hc_handle, dev_addr);
+	usb_hc_connection_initialize(&dev->hc_conn, hc_handle);
+
+	rc = usb_device_connection_initialize(
+	    &dev->wire, &dev->hc_conn, dev_addr);
 	if (rc != EOK) {
 		fprintf(stderr,
Index: uspace/app/usbinfo/info.c
===================================================================
--- uspace/app/usbinfo/info.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/usbinfo/info.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -287,4 +287,19 @@
 void dump_strings(usbinfo_device_t *dev)
 {
+	/* Find used indexes. Devices 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);
+
+	if (str_mask == 0) {
+		printf("Device does not support string descriptors.\n");
+		return;
+	}
+
 	/* Get supported languages. */
 	l18_win_locales_t *langs;
@@ -305,15 +320,4 @@
 	}
 	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. */
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/usbinfo/main.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -44,4 +44,5 @@
 #include <loc.h>
 #include <usb/hc.h>
+#include <usb/dev.h>
 #include <usb/dev/pipes.h>
 #include "usbinfo.h"
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/usbinfo/usbinfo.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -44,6 +44,7 @@
 
 typedef struct {
+	usb_hc_connection_t hc_conn;
+	usb_device_connection_t wire;
 	usb_pipe_t ctrl_pipe;
-	usb_device_connection_t wire;
 	usb_standard_device_descriptor_t device_descriptor;
 	uint8_t *full_configuration_descriptor;
Index: uspace/app/websrv/websrv.c
===================================================================
--- uspace/app/websrv/websrv.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/app/websrv/websrv.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,8 +31,14 @@
  */
 /**
- * @file (Less-than-skeleton) web server.
+ * @file Skeletal web server.
  */
 
+#include <bool.h>
+#include <errno.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
 
 #include <net/in.h>
@@ -44,13 +50,194 @@
 #define PORT_NUMBER 8080
 
+#define WEB_ROOT "/data/web"
+
 /** Buffer for receiving the request. */
 #define BUFFER_SIZE 1024
-static char buf[BUFFER_SIZE];
+static char rbuf[BUFFER_SIZE];
+static size_t rbuf_out, rbuf_in;
+
+static char lbuf[BUFFER_SIZE + 1];
+static size_t lbuf_used;
+
+static char fbuf[BUFFER_SIZE];
 
 /** Response to send to client. */
-static const char *response_msg =
+static const char *ok_msg =
     "HTTP/1.0 200 OK\r\n"
-    "\r\n"
-    "<h1>Hello from HelenOS!</h1>\r\n";
+    "\r\n";
+
+/** Receive one character (with buffering) */
+static int recv_char(int fd, char *c)
+{
+	ssize_t rc;
+
+	if (rbuf_out == rbuf_in) {
+		rbuf_out = 0;
+		rbuf_in = 0;
+
+		rc = recv(fd, rbuf, BUFFER_SIZE, 0);
+		if (rc <= 0) {
+			printf("recv() failed (%zd)\n", rc);
+			return rc;
+		}
+
+		rbuf_in = rc;
+	}
+
+	*c = rbuf[rbuf_out++];
+	return EOK;
+}
+
+/** Receive one line with length limit. */
+static int recv_line(int fd)
+{
+	char c, prev;
+	int rc;
+	char *bp;
+
+	bp = lbuf; c = '\0';
+	while (bp < lbuf + BUFFER_SIZE) {
+		prev = c;
+		rc = recv_char(fd, &c);
+		if (rc != EOK)
+			return rc;
+
+		*bp++ = c;
+		if (prev == '\r' && c == '\n')
+			break;
+	}
+
+	lbuf_used = bp - lbuf;
+	*bp = '\0';
+
+	if (bp == lbuf + BUFFER_SIZE)
+		return ELIMIT;
+
+	return EOK;
+}
+
+static bool uri_is_valid(char *uri)
+{
+	char *cp;
+	char c;
+
+	if (uri[0] != '/')
+		return false;
+	if (uri[1] == '.')
+		return false;
+
+	cp = uri + 1;
+	while (*cp != '\0') {
+		c = *cp++;
+		if (c == '/')
+			return false;
+	}
+
+	return true;
+}
+
+static int send_response(int conn_sd, const char *msg)
+{
+	size_t response_size;
+	ssize_t rc;
+
+	response_size = str_size(msg);
+
+	/* Send a canned response. */
+        printf("Send response...\n");
+	rc = send(conn_sd, (void *) msg, response_size, 0);
+	if (rc < 0) {
+		printf("send() failed.\n");
+		return rc;
+	}
+
+	return EOK;
+}
+
+static int uri_get(const char *uri, int conn_sd)
+{
+	int rc;
+	char *fname;
+	int fd;
+	ssize_t nr;
+
+	if (str_cmp(uri, "/") == 0)
+		uri = "/index.htm";
+
+	rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
+	if (rc < 0)
+		return ENOMEM;
+
+	fd = open(fname, O_RDONLY);
+	if (fd < 0) {
+		printf("File '%s' not found.\n", fname);
+		free(fname);
+		return ENOENT;
+	}
+
+	free(fname);
+
+	rc = send_response(conn_sd, ok_msg);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		nr = read(fd, fbuf, BUFFER_SIZE);
+		if (nr == 0)
+			break;
+
+		if (nr < 0) {
+			close(fd);
+			return EIO;
+		}
+
+		rc = send(conn_sd, fbuf, nr, 0);
+		if (rc < 0) {
+			printf("send() failed\n");
+			close(fd);
+			return rc;
+		}
+	}
+
+	close(fd);
+
+	return EOK;
+}
+
+static int req_process(int conn_sd)
+{
+	int rc;
+	char *uri, *end_uri;
+
+	rc = recv_line(conn_sd);
+	if (rc != EOK) {
+		printf("recv_line() failed\n");
+		return rc;
+	}
+
+	printf("%s", lbuf);
+
+	if (str_lcmp(lbuf, "GET ", 4) != 0) {
+		printf("Invalid HTTP method.\n");
+		return EINVAL;
+	}
+
+	uri = lbuf + 4;
+	end_uri = str_chr(uri, ' ');
+	if (end_uri == NULL) {
+		end_uri = lbuf + lbuf_used - 2;
+		assert(*end_uri == '\r');
+	}
+
+	*end_uri = '\0';
+	printf("Requested URI '%s'.\n", uri);
+
+	if (!uri_is_valid(uri)) {
+		printf("Invalid request URI.\n");
+		return EINVAL;
+	}
+
+	return uri_get(uri, conn_sd);
+}
 
 int main(int argc, char *argv[])
@@ -64,5 +251,4 @@
 	int rc;
 
-	size_t response_size;
 
 	addr.sin_family = AF_INET;
@@ -94,6 +280,4 @@
 		return 1;
 	}
-
-	response_size = str_size(response_msg);
 
 	printf("Listening for connections at port number %u.\n", PORT_NUMBER);
@@ -105,5 +289,5 @@
 		if (conn_sd < 0) {
 			printf("accept() failed.\n");
-			return 1;
+			continue;
 		}
 
@@ -111,23 +295,14 @@
 
 		printf("Wait for client request\n");
-
-		/* Really we should wait for a blank line. */
-		rc = recv(conn_sd, buf, BUFFER_SIZE, 0);
-		if (rc < 0) {
-			printf("recv() failed\n");
-			return 1;
-		}
-
-		/* Send a canned response. */
-                printf("Send response...\n");
-		rc = send(conn_sd, (void *) response_msg, response_size, 0);
-		if (rc < 0) {
-			printf("send() failed.\n");
-			return 1;
-		}
+		rbuf_out = rbuf_in = 0;
+
+		rc = req_process(conn_sd);
+		if (rc != EOK) 
+			printf("Error processing request.\n");
 
 		rc = closesocket(conn_sd);
 		if (rc != EOK) {
 			printf("Error closing connection socket: %d\n", rc);
+			closesocket(listen_sd);
 			return 1;
 		}
Index: uspace/dist/data/web/bar.htm
===================================================================
--- uspace/dist/data/web/bar.htm	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/dist/data/web/bar.htm	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,10 @@
+<html>
+    <head>
+	<title>Bar!</title>
+    </head>
+    <body>
+	<h1>Bar!</h1>
+
+	<a href="/">Back to top</a>
+    </body>
+</html>
Index: uspace/dist/data/web/foo.htm
===================================================================
--- uspace/dist/data/web/foo.htm	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/dist/data/web/foo.htm	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,10 @@
+<html>
+    <head>
+	<title>Foo!</title>
+    </head>
+    <body>
+	<h1>Foo!</h1>
+
+	<a href="/">Back to top</a>
+    </body>
+</html>
Index: uspace/dist/data/web/index.htm
===================================================================
--- uspace/dist/data/web/index.htm	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/dist/data/web/index.htm	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>
+    	    Hello from HelenOS!
+        </title>
+    </head>
+    <body>
+        <h1>Hello from HelenOS!</h1>
+        <p>
+            This web page is brought to you by courtesy of HelenOS web server
+    	    and TCP/IP stack.
+        </p>
+	<p>
+    	    Now <a href="foo.htm">go to page foo</a> or <a href="bar.htm">go
+    	    to bar</a>.
+        </p>
+    </body>
+</html>
Index: uspace/drv/bus/isa/Makefile
===================================================================
--- uspace/drv/bus/isa/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/isa/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2010 Lenka Trochtova
+# Copyright (c) 2011 Jan Vesely
 # All rights reserved.
 #
@@ -33,4 +34,5 @@
 
 SOURCES = \
+	i8237.c \
 	isa.c
 
Index: uspace/drv/bus/isa/i8237.c
===================================================================
--- uspace/drv/bus/isa/i8237.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/bus/isa/i8237.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,430 @@
+/*
+ * 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 isa
+ * @{
+ */
+
+/** @file
+ * @brief DMA controller management
+ */
+
+#include <assert.h>
+#include <bool.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <ddf/log.h>
+#include "i8237.h"
+
+/** DMA Slave controller I/O Address. */
+#define DMA_CONTROLLER_FIRST_BASE  ((void *) 0x00)
+
+/** DMA Master controller I/O Address. */
+#define DMA_CONTROLLER_SECOND_BASE  ((void *) 0xc0)
+
+/** Shared DMA page address register I/O address. */
+#define DMA_CONTROLLER_PAGE_BASE  ((void *) 0x81)
+
+#define DMA_STATUS_REQ(x)       (1 << (((x) % 4) + 4))
+#define DMA_STATUS_COMPLETE(x)  (1 << ((x) % 4))
+
+/** http://wiki.osdev.org/DMA: The only bit that works is COND (bit 2) */
+#define DMA_COMMAND_COND  (1 << 2)  /**< Disables DMA controller */
+
+#define DMA_SINGLE_MASK_CHAN_SEL_MASK   0x03
+#define DMA_SINGLE_MASK_CHAN_SEL_SHIFT  0
+
+#define DMA_SINGLE_MASK_CHAN_TO_REG(x) \
+	(((x) & DMA_SINGLE_MASK_CHAN_SEL_MASK) << DMA_SINGLE_MASK_CHAN_SEL_SHIFT)
+
+#define DMA_SINGLE_MASK_MASKED_FLAG  (1 << 2)
+
+#define DMA_MODE_CHAN_SELECT_MASK   0x03
+#define DMA_MODE_CHAN_SELECT_SHIFT  0
+
+#define DMA_MODE_CHAN_TO_REG(x) \
+	(((x) & DMA_MODE_CHAN_SELECT_MASK) << DMA_MODE_CHAN_SELECT_SHIFT)
+
+#define DMA_MODE_CHAN_TRA_MASK       0x03
+#define DMA_MODE_CHAN_TRA_SHIFT      2
+#define DMA_MODE_CHAN_TRA_SELF_TEST  0
+#define DMA_MODE_CHAN_TRA_WRITE      0x01
+#define DMA_MODE_CHAN_TRA_READ       0x02
+
+#define DMA_MODE_CHAN_AUTO_FLAG  (1 << 4)
+#define DMA_MODE_CHAN_DOWN_FLAG  (1 << 5)
+
+#define DMA_MODE_CHAN_MODE_MASK     0x03
+#define DMA_MODE_CHAN_MODE_SHIFT    6
+#define DMA_MODE_CHAN_MODE_DEMAND   0
+#define DMA_MODE_CHAN_MODE_SINGLE   1
+#define DMA_MODE_CHAN_MODE_BLOCK    2
+#define DMA_MODE_CHAN_MODE_CASCADE  3
+
+#define DMA_MULTI_MASK_CHAN(x)  (1 << ((x) % 4))
+
+typedef struct {
+	uint8_t channel_start0;
+	uint8_t channel_count0;
+	uint8_t channel_start1;
+	uint8_t channel_count1;
+	uint8_t channel_start2;
+	uint8_t channel_count2;
+	uint8_t channel_start3;
+	uint8_t channel_count3;
+	
+	uint8_t command_status;
+	
+	/** Memory to memory transfers, NOT implemented on PCs */
+	uint8_t request;
+	uint8_t single_mask;
+	uint8_t mode;
+	uint8_t flip_flop;
+	
+	/*
+	 * Master reset sets Flip-Flop low, clears status,
+	 * sets all mask bits on.
+	 *
+	 * Intermediate is not implemented on PCs.
+	 *
+	 */
+	uint8_t master_reset;
+	uint8_t mask_reset;
+	uint8_t multi_mask;
+} dma_controller_regs_first_t;
+
+typedef struct {
+	uint8_t channel_start4;
+	uint8_t reserved0;
+	uint8_t channel_count4;
+	uint8_t reserved1;
+	uint8_t channel_start5;
+	uint8_t reserved2;
+	uint8_t channel_count5;
+	uint8_t reserved3;
+	uint8_t channel_start6;
+	uint8_t reserved4;
+	uint8_t channel_count6;
+	uint8_t reserved5;
+	uint8_t channel_start7;
+	uint8_t reserved6;
+	uint8_t channel_count7;
+	
+	uint8_t command_status;
+	uint8_t reserved8;
+	uint8_t request;
+	uint8_t reserved9;
+	uint8_t single_mask;
+	uint8_t reserveda;
+	uint8_t mode;
+	uint8_t reservedb;
+	uint8_t flip_flop;
+	uint8_t reservedc;
+	uint8_t master_reset;
+	uint8_t reservedd;
+	uint8_t multi_mask;
+} dma_controller_regs_second_t;
+
+typedef struct {
+	uint8_t channel2;
+	uint8_t channel3;
+	uint8_t channel1;
+	uint8_t reserved0;
+	uint8_t reserved1;
+	uint8_t reserved2;
+	uint8_t channel0;
+	uint8_t reserved3;
+	uint8_t channel6;
+	uint8_t channel7;
+	uint8_t channel5;
+	uint8_t reserved4;
+	uint8_t reserved5;
+	uint8_t reserved6;
+	uint8_t channel4;
+} dma_page_regs_t;
+
+/** Addresses needed to setup a DMA channel. */
+typedef struct {
+	ioport8_t *offset_reg_address;
+	ioport8_t *size_reg_address;
+	ioport8_t *page_reg_address;
+	ioport8_t *single_mask_address;
+	ioport8_t *mode_address;
+	ioport8_t *flip_flop_address;
+} dma_channel_t;
+
+typedef struct {
+	dma_channel_t channels[8];
+	dma_page_regs_t *page_table;
+	dma_controller_regs_first_t *first;
+	dma_controller_regs_second_t *second;
+	bool initialized;
+} dma_controller_t;
+
+static fibril_mutex_t guard = FIBRIL_MUTEX_INITIALIZER(guard);
+
+/** Standard i8237 DMA controller.
+ *
+ * http://zet.aluzina.org/index.php/8237_DMA_controller#DMA_Channel_Registers
+ *
+ */
+static dma_controller_t controller_8237 = {
+	.channels = {
+		/* The first chip 8-bit */
+		{
+			(uint8_t *) 0x00,
+			(uint8_t *) 0x01,
+			(uint8_t *) 0x87,
+			(uint8_t *) 0x0a,
+			(uint8_t *) 0x0b,
+			(uint8_t *) 0x0c,
+		},
+		{
+			(uint8_t *) 0x02,
+			(uint8_t *) 0x03,
+			(uint8_t *) 0x83,
+			(uint8_t *) 0x0a,
+			(uint8_t *) 0x0b,
+			(uint8_t *) 0x0c,
+		},
+		{
+			(uint8_t *) 0x04,
+			(uint8_t *) 0x05,
+			(uint8_t *) 0x81,
+			(uint8_t *) 0x0a,
+			(uint8_t *) 0x0b,
+			(uint8_t *) 0x0c,
+		},
+		{
+			(uint8_t *) 0x06,
+			(uint8_t *) 0x07,
+			(uint8_t *) 0x82,
+			(uint8_t *) 0x0a,
+			(uint8_t *) 0x0b,
+			(uint8_t *) 0x0c,
+		},
+		
+		/* The second chip 16-bit */
+		{
+			(uint8_t *) 0xc0,
+			(uint8_t *) 0xc2,
+			(uint8_t *) 0x8f,
+			(uint8_t *) 0xd4,
+			(uint8_t *) 0xd6,
+			(uint8_t *) 0xd8,
+		},
+		{
+			(uint8_t *) 0xc4,
+			(uint8_t *) 0xc6,
+			(uint8_t *) 0x8b,
+			(uint8_t *) 0xd4,
+			(uint8_t *) 0xd6,
+			(uint8_t *) 0xd8,
+		},
+		{
+			(uint8_t *) 0xc8,
+			(uint8_t *) 0xca,
+			(uint8_t *) 0x89,
+			(uint8_t *) 0xd4,
+			(uint8_t *) 0xd6,
+			(uint8_t *) 0xd8,
+		},
+		{
+			(uint8_t *) 0xcc,
+			(uint8_t *) 0xce,
+			(uint8_t *) 0x8a,
+			(uint8_t *) 0xd4,
+			(uint8_t *) 0xd6,
+			(uint8_t *) 0xd8,
+		},
+	},
+	
+	.page_table = NULL,
+	.first = NULL,
+	.second = NULL,
+	.initialized = false,
+};
+
+/* Initialize I/O access to DMA controller I/O ports.
+ *
+ * @param controller DMA Controller structure to initialize.
+ *
+ * @return Error code.
+ *
+ */
+static inline int dma_controller_init(dma_controller_t *controller)
+{
+	assert(controller);
+	int ret = pio_enable(DMA_CONTROLLER_PAGE_BASE, sizeof(dma_page_regs_t),
+	    (void **) &controller->page_table);
+	if (ret != EOK)
+		return EIO;
+	
+	ret = pio_enable(DMA_CONTROLLER_FIRST_BASE,
+	    sizeof(dma_controller_regs_first_t), (void **) &controller->first);
+	if (ret != EOK)
+		return EIO;
+	
+	ret = pio_enable(DMA_CONTROLLER_SECOND_BASE,
+		sizeof(dma_controller_regs_second_t), (void **) &controller->second);
+	if (ret != EOK)
+		return EIO;
+	
+	controller->initialized = true;
+	
+	/* Reset the controller */
+	pio_write_8(&controller->second->master_reset, 0xff);
+	pio_write_8(&controller->first->master_reset, 0xff);
+	
+	return EOK;
+}
+
+/** Setup DMA channel to specified place and mode.
+ *
+ * @param channel DMA Channel 1, 2, 3 for 8 bit transfers,
+ *                    5, 6, 7 for 16 bit.
+ * @param pa      Physical address of the buffer. Must be < 16 MB
+ *                for 16 bit and < 1 MB for 8 bit transfers.
+ * @param size    DMA buffer size, limited to 64 KB.
+ * @param mode    Mode of the DMA channel:
+ *                - Read or Write
+ *                - Allow automatic reset
+ *                - Use address decrement instead of increment
+ *                - Use SINGLE/BLOCK/ON DEMAND transfer mode
+ *
+ * @return Error code.
+ *
+ */
+int dma_setup_channel(unsigned int channel, uint32_t pa, uint16_t size,
+    uint8_t mode)
+{
+	if ((channel == 0) || (channel == 4))
+		return ENOTSUP;
+	
+	if (channel > 7)
+		return ENOENT;
+	
+	/* DMA is limited to 24bit addresses. */
+	if (pa >= (1 << 24))
+		return EINVAL;
+	
+	/* 8 bit channels use only 4 bits from the page register. */
+	if ((channel > 0) && (channel < 4) && (pa >= (1 << 20)))
+		return EINVAL;
+	
+	fibril_mutex_lock(&guard);
+	
+	if (!controller_8237.initialized)
+		dma_controller_init(&controller_8237);
+	
+	if (!controller_8237.initialized) {
+		fibril_mutex_unlock(&guard);
+		return EIO;
+	}
+	
+	/* 16 bit transfers are a bit special */
+	ddf_msg(LVL_DEBUG, "Unspoiled address: %p and size: %zu.", pa, size);
+	if (channel > 4) {
+		/* Size must be aligned to 16 bits */
+		if ((size & 1) != 0) {
+			fibril_mutex_unlock(&guard);
+			return EINVAL;
+		}
+		
+		size >>= 1;
+		
+		/* Address is fun: lower 16 bits need to be shifted by 1 */
+		pa = ((pa & 0xffff) >> 1) | (pa & 0xff0000);
+	}
+	
+	const dma_channel_t dma_channel = controller_8237.channels[channel];
+	
+	ddf_msg(LVL_DEBUG, "Setting channel %u, to address %p(%zu), mode %hhx.",
+	    channel, pa, size, mode);
+	
+	/* Mask DMA request */
+	uint8_t value = DMA_SINGLE_MASK_CHAN_TO_REG(channel) |
+	    DMA_SINGLE_MASK_MASKED_FLAG;
+	pio_write_8(dma_channel.single_mask_address, value);
+	
+	/* Set mode */
+	value = DMA_MODE_CHAN_TO_REG(channel) | mode;
+	ddf_msg(LVL_DEBUG2, "Writing mode byte: %p:%hhx.",
+	    dma_channel.mode_address, value);
+	pio_write_8(dma_channel.mode_address, value);
+	
+	/* Set address - reset flip-flop */
+	pio_write_8(dma_channel.flip_flop_address, 0);
+	
+	/* Low byte */
+	value = pa & 0xff;
+	ddf_msg(LVL_DEBUG2, "Writing address low byte: %p:%hhx.",
+	    dma_channel.offset_reg_address, value);
+	pio_write_8(dma_channel.offset_reg_address, value);
+	
+	/* High byte */
+	value = (pa >> 8) & 0xff;
+	ddf_msg(LVL_DEBUG2, "Writing address high byte: %p:%hhx.",
+	    dma_channel.offset_reg_address, value);
+	pio_write_8(dma_channel.offset_reg_address, value);
+	
+	/* Page address - third byte */
+	value = (pa >> 16) & 0xff;
+	ddf_msg(LVL_DEBUG2, "Writing address page byte: %p:%hhx.",
+	    dma_channel.page_reg_address, value);
+	pio_write_8(dma_channel.page_reg_address, value);
+	
+	/* Set size - reset flip-flop */
+	pio_write_8(dma_channel.flip_flop_address, 0);
+	
+	/* Low byte */
+	value = (size - 1) & 0xff;
+	ddf_msg(LVL_DEBUG2, "Writing size low byte: %p:%hhx.",
+	    dma_channel.size_reg_address, value);
+	pio_write_8(dma_channel.size_reg_address, value);
+	
+	/* High byte */
+	value = ((size - 1) >> 8) & 0xff;
+	ddf_msg(LVL_DEBUG2, "Writing size high byte: %p:%hhx.",
+	    dma_channel.size_reg_address, value);
+	pio_write_8(dma_channel.size_reg_address, value);
+	
+	/* Unmask DMA request */
+	value = DMA_SINGLE_MASK_CHAN_TO_REG(channel);
+	pio_write_8(dma_channel.single_mask_address, value);
+	
+	fibril_mutex_unlock(&guard);
+	
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/isa/i8237.h
===================================================================
--- uspace/drv/bus/isa/i8237.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/bus/isa/i8237.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,46 @@
+/*
+ * 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 isa
+ * @{
+ */
+
+/** @file
+ * @brief DMA memory management
+ */
+
+#ifndef DRV_BUS_ISA_I8237_H
+#define DRV_BUS_ISA_I8237_H
+
+extern int dma_setup_channel(unsigned int, uint32_t, uint16_t, uint8_t);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/isa/isa.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -2,4 +2,5 @@
  * Copyright (c) 2010 Lenka Trochtova
  * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -56,4 +57,8 @@
 #include <ns.h>
 #include <sys/stat.h>
+#include <ipc/irc.h>
+#include <ipc/services.h>
+#include <sysinfo.h>
+#include <ns.h>
 
 #include <ddf/driver.h>
@@ -65,4 +70,6 @@
 #include <device/hw_res.h>
 
+#include "i8237.h"
+
 #define NAME "isa"
 #define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
@@ -74,5 +81,5 @@
 #define ISA_FUN(fun) ((isa_fun_t *) ((fun)->driver_data))
 
-#define ISA_MAX_HW_RES 4
+#define ISA_MAX_HW_RES 5
 
 typedef struct {
@@ -141,7 +148,29 @@
 }
 
+static int isa_dma_channel_fun_setup(ddf_fun_t *fnode,
+    unsigned int channel, uint32_t pa, uint16_t size, uint8_t mode)
+{
+	assert(fnode);
+	isa_fun_t *isa_fun = fnode->driver_data;
+	const hw_resource_list_t *res = &isa_fun->hw_resources;
+	assert(res);
+	
+	const unsigned int ch = channel;
+	for (size_t i = 0; i < res->count; ++i) {
+		if (((res->resources[i].type == DMA_CHANNEL_16) &&
+		    (res->resources[i].res.dma_channel.dma16 == ch)) ||
+		    ((res->resources[i].type == DMA_CHANNEL_8) &&
+		    (res->resources[i].res.dma_channel.dma8 == ch))) {
+			return dma_setup_channel(channel, pa, size, mode);
+		}
+	}
+	
+	return EINVAL;
+}
+
 static hw_res_ops_t isa_fun_hw_res_ops = {
-	&isa_get_fun_resources,
-	&isa_enable_fun_interrupt
+	.get_resource_list = isa_get_fun_resources,
+	.enable_interrupt = isa_enable_fun_interrupt,
+	.dma_channel_setup = isa_dma_channel_fun_setup,
 };
 
@@ -314,4 +343,37 @@
 }
 
+static void isa_fun_set_dma(isa_fun_t *fun, int dma)
+{
+	size_t count = fun->hw_resources.count;
+	hw_resource_t *resources = fun->hw_resources.resources;
+	
+	if (count < ISA_MAX_HW_RES) {
+		if ((dma > 0) && (dma < 4)) {
+			resources[count].type = DMA_CHANNEL_8;
+			resources[count].res.dma_channel.dma8 = dma;
+			
+			fun->hw_resources.count++;
+			ddf_msg(LVL_NOTE, "Added dma 0x%x to function %s", dma,
+			    fun->fnode->name);
+			
+			return;
+		}
+
+		if ((dma > 4) && (dma < 8)) {
+			resources[count].type = DMA_CHANNEL_16;
+			resources[count].res.dma_channel.dma16 = dma;
+			
+			fun->hw_resources.count++;
+			ddf_msg(LVL_NOTE, "Added dma 0x%x to function %s", dma,
+			    fun->fnode->name);
+			
+			return;
+		}
+		
+		ddf_msg(LVL_WARN, "Skipped dma 0x%x for function %s", dma,
+		    fun->fnode->name);
+	}
+}
+
 static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
 {
@@ -343,4 +405,16 @@
 	if (val != end)
 		isa_fun_set_irq(fun, irq);
+}
+
+static void fun_parse_dma(isa_fun_t *fun, char *val)
+{
+	unsigned int dma = 0;
+	char *end = NULL;
+	
+	val = skip_spaces(val);
+	dma = (unsigned int) strtol(val, &end, 10);
+	
+	if (val != end)
+		isa_fun_set_dma(fun, dma);
 }
 
@@ -436,4 +510,5 @@
 	if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
 	    !prop_parse(fun, line, "irq", &fun_parse_irq) &&
+	    !prop_parse(fun, line, "dma", &fun_parse_dma) &&
 	    !prop_parse(fun, line, "match", &fun_parse_match_id)) {
 
@@ -446,5 +521,5 @@
 {
 	fun->hw_resources.resources =
-	    (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
+	    (hw_resource_t *) malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
 }
 
@@ -630,5 +705,5 @@
 
 
-static void isa_init() 
+static void isa_init()
 {
 	ddf_log_init(NAME, LVL_ERROR);
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/isa/isa.dev	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -15,2 +15,15 @@
 	io_range 060 5
 	
+
+ne2k:
+	match 100 isa/ne2k
+	irq 5
+	io_range 300 20
+
+sb16:
+	match 100 isa/sb16
+	io_range 220 20
+	io_range 330 2
+	irq 5
+	dma 1
+	dma 5
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -187,6 +187,6 @@
 
 static hw_res_ops_t pciintel_hw_res_ops = {
-	&pciintel_get_resources,
-	&pciintel_enable_interrupt
+	.get_resource_list = &pciintel_get_resources,
+	.enable_interrupt = &pciintel_enable_interrupt,
 };
 
Index: uspace/drv/bus/pci/pciintel/pci.h
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/pci/pciintel/pci.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -137,6 +137,4 @@
 		return ret;
 	}
-	usb_device_manager_bind_address(&instance->generic.dev_manager,
-	    instance->rh.address, hub_fun->handle);
 
 #define CHECK_RET_UNREG_RETURN(ret, message...) \
@@ -150,4 +148,5 @@
 	return ret; \
 } else (void)0
+
 	ret = usb_endpoint_manager_add_ep(
 	    &instance->generic.ep_manager, instance->rh.address, 0,
@@ -165,4 +164,10 @@
 	CHECK_RET_UNREG_RETURN(ret,
 	    "Failed to bind root hub function: %s.\n", str_error(ret));
+
+	ret = usb_device_manager_bind_address(&instance->generic.dev_manager,
+	    instance->rh.address, hub_fun->handle);
+	if (ret != EOK)
+		usb_log_warning("Failed to bind root hub address: %s.\n",
+		    str_error(ret));
 
 	return EOK;
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -140,23 +140,23 @@
 int device_setup_ohci(ddf_dev_t *device)
 {
-	assert(device);
-
-	ohci_t *instance = malloc(sizeof(ohci_t));
+	if (device == NULL)
+		return EBADMEM;
+
+	ohci_t *instance = ddf_dev_data_alloc(device,sizeof(ohci_t));
 	if (instance == NULL) {
 		usb_log_error("Failed to allocate OHCI driver.\n");
 		return ENOMEM;
 	}
-	instance->rh_fun = NULL;
-	instance->hc_fun = NULL;
 
 #define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
 if (ret != EOK) { \
 	if (instance->hc_fun) { \
+		instance->hc_fun->driver_data = NULL; \
 		ddf_fun_destroy(instance->hc_fun); \
 	} \
 	if (instance->rh_fun) { \
+		instance->rh_fun->driver_data = NULL; \
 		ddf_fun_destroy(instance->rh_fun); \
 	} \
-	free(instance); \
 	usb_log_error(message); \
 	return ret; \
@@ -219,6 +219,4 @@
 	    "Failed to init ohci_hcd: %s.\n", str_error(ret));
 
-	device->driver_data = instance;
-
 #define CHECK_RET_FINI_RETURN(ret, message...) \
 if (ret != EOK) { \
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,4 +34,5 @@
 #include <errno.h>
 #include <str_error.h>
+#include <macros.h>
 
 #include <usb/usb.h>
@@ -53,6 +54,9 @@
 		return;
 	if (ohci_batch->tds) {
+		const ohci_endpoint_t *ohci_ep =
+		    ohci_endpoint_get(ohci_batch->usb_batch->ep);
+		assert(ohci_ep);
 		for (unsigned i = 0; i < ohci_batch->td_count; ++i) {
-			if (i != ohci_batch->leave_td)
+			if (ohci_batch->tds[i] != ohci_ep->td)
 				free32(ohci_batch->tds[i]);
 		}
@@ -64,4 +68,8 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Finishes usb_transfer_batch and destroys the structure.
+ *
+ * @param[in] uhci_batch Instance to finish and destroy.
+ */
 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)
 {
@@ -69,9 +77,18 @@
 	assert(ohci_batch->usb_batch);
 	usb_transfer_batch_finish(ohci_batch->usb_batch,
-	    ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size,
-	    ohci_batch->usb_batch->buffer_size);
+	    ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size);
 	ohci_transfer_batch_dispose(ohci_batch);
 }
 /*----------------------------------------------------------------------------*/
+/** Allocate memory and initialize internal data structure.
+ *
+ * @param[in] usb_batch Pointer to generic USB batch structure.
+ * @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.
+ */
 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
 {
@@ -105,5 +122,4 @@
 	ohci_batch->ed = ohci_endpoint_get(usb_batch->ep)->ed;
 	ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td;
-	ohci_batch->leave_td = 0;
 
 	for (unsigned i = 1; i <= ohci_batch->td_count; ++i) {
@@ -152,5 +168,5 @@
  * completes with the last TD.
  */
-bool ohci_transfer_batch_is_complete(ohci_transfer_batch_t *ohci_batch)
+bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *ohci_batch)
 {
 	assert(ohci_batch);
@@ -174,5 +190,5 @@
 
 	/* Assume we will leave the last(unused) TD behind */
-	ohci_batch->leave_td = ohci_batch->td_count;
+	unsigned leave_td = ohci_batch->td_count;
 
 	/* Check all TDs */
@@ -212,14 +228,14 @@
 			 * It will be the one TD we leave behind.
 			 */
-			ohci_batch->leave_td = i + 1;
+			leave_td = i + 1;
 
 			/* Check TD assumption */
-			const uint32_t pa = addr_to_phys(
-			    ohci_batch->tds[ohci_batch->leave_td]);
-			assert((ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK)
+			const uint32_t pa =
+			    addr_to_phys(ohci_batch->tds[leave_td]);
+			assert((ohci_batch->ed->td_head & ED_TDHEAD_PTR_MASK)
 			    == pa);
 
 			ed_set_tail_td(ohci_batch->ed,
-			    ohci_batch->tds[ohci_batch->leave_td]);
+			    ohci_batch->tds[leave_td]);
 
 			/* Clear possible ED HALT */
@@ -234,5 +250,5 @@
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
 	assert(ohci_ep);
-	ohci_ep->td = ohci_batch->tds[ohci_batch->leave_td];
+	ohci_ep->td = ohci_batch->tds[leave_td];
 
 	/* Make sure that we are leaving the right TD behind */
@@ -248,5 +264,5 @@
  * @param[in] ohci_batch Batch structure to use
  */
-void ohci_transfer_batch_commit(ohci_transfer_batch_t *ohci_batch)
+void ohci_transfer_batch_commit(const ohci_transfer_batch_t *ohci_batch)
 {
 	assert(ohci_batch);
@@ -295,6 +311,5 @@
 	while (remain_size > 0) {
 		const size_t transfer_size =
-		    remain_size > OHCI_TD_MAX_TRANSFER ?
-		    OHCI_TD_MAX_TRANSFER : remain_size;
+		    min(remain_size, OHCI_TD_MAX_TRANSFER);
 		toggle = 1 - toggle;
 
@@ -378,4 +393,5 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Transfer setup table. */
 static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t) =
 {
Index: uspace/drv/bus/usb/ohci/ohci_batch.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/ohci_batch.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -53,6 +53,4 @@
 	/** 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 by the OHCI hw. */
 	char *device_buffer;
@@ -62,6 +60,6 @@
 
 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *batch);
-bool ohci_transfer_batch_is_complete(ohci_transfer_batch_t *batch);
-void ohci_transfer_batch_commit(ohci_transfer_batch_t *batch);
+bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *batch);
+void ohci_transfer_batch_commit(const ohci_transfer_batch_t *batch);
 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch);
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/ohci/pci.c
===================================================================
--- uspace/drv/bus/usb/ohci/pci.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/pci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -42,5 +42,5 @@
 #include <ddi.h>
 #include <libarch/ddi.h>
-#include <device/hw_res.h>
+#include <device/hw_res_parsed.h>
 
 #include <usb/debug.h>
@@ -61,7 +61,4 @@
 {
 	assert(dev);
-	assert(mem_reg_address);
-	assert(mem_reg_size);
-	assert(irq_no);
 
 	async_sess_t *parent_sess =
@@ -71,48 +68,27 @@
 		return ENOMEM;
 
-	hw_resource_list_t hw_resources;
-	int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	hw_res_list_parsed_t hw_res;
+	hw_res_list_parsed_init(&hw_res);
+	const int ret =  hw_res_get_list_parsed(parent_sess, &hw_res, 0);
 	async_hangup(parent_sess);
-	if (rc != EOK) {
-		return rc;
+	if (ret != EOK) {
+		return ret;
 	}
 
-	uintptr_t mem_address = 0;
-	size_t mem_size = 0;
-	bool mem_found = false;
+	/* We want one irq and one mem range. */
+	if (hw_res.irqs.count != 1 || hw_res.mem_ranges.count != 1) {
+		hw_res_list_parsed_clean(&hw_res);
+		return EINVAL;
+	}
 
-	int irq = 0;
-	bool irq_found = false;
+	if (mem_reg_address)
+		*mem_reg_address = hw_res.mem_ranges.ranges[0].address;
+	if (mem_reg_size)
+		*mem_reg_size = hw_res.mem_ranges.ranges[0].size;
+	if (irq_no)
+		*irq_no = hw_res.irqs.irqs[0];
 
-	for (size_t 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;
-		}
-	}
-	free(hw_resources.resources);
-
-	if (mem_found && irq_found) {
-		*mem_reg_address = mem_address;
-		*mem_reg_size = mem_size;
-		*irq_no = irq;
-		return EOK;
-	}
-	return ENOENT;
+	hw_res_list_parsed_clean(&hw_res);
+	return EOK;
 }
 
Index: uspace/drv/bus/usb/ohci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/root_hub.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -100,5 +100,5 @@
 	.attributes = USB_TRANSFER_INTERRUPT,
 	.descriptor_type = USB_DESCTYPE_ENDPOINT,
-	.endpoint_address = 1 + (1 << 7),
+	.endpoint_address = 1 | (1 << 7),
 	.length = sizeof(usb_standard_endpoint_descriptor_t),
 	.max_packet_size = 2,
@@ -109,26 +109,33 @@
 static void rh_init_descriptors(rh_t *instance);
 static uint16_t create_interrupt_mask(const rh_t *instance);
-static int get_status(const rh_t *instance, usb_transfer_batch_t *request);
-static int get_descriptor(const rh_t *instance, usb_transfer_batch_t *request);
-static int set_feature(const rh_t *instance, usb_transfer_batch_t *request);
-static int clear_feature(const rh_t *instance, usb_transfer_batch_t *request);
+static void get_status(const rh_t *instance, usb_transfer_batch_t *request);
+static void get_descriptor(const rh_t *instance, usb_transfer_batch_t *request);
+static void set_feature(const rh_t *instance, usb_transfer_batch_t *request);
+static void clear_feature(const rh_t *instance, usb_transfer_batch_t *request);
 static int set_feature_port(
     const rh_t *instance, uint16_t feature, uint16_t port);
 static int clear_feature_port(
     const rh_t *instance, uint16_t feature, uint16_t port);
-static int control_request(rh_t *instance, usb_transfer_batch_t *request);
+static void control_request(rh_t *instance, usb_transfer_batch_t *request);
 static inline void interrupt_request(
     usb_transfer_batch_t *request, uint16_t mask, size_t size)
 {
 	assert(request);
-
-	request->transfered_size = size;
 	usb_transfer_batch_finish_error(request, &mask, size, EOK);
-}
-
-#define TRANSFER_OK(bytes) \
+	usb_transfer_batch_destroy(request);
+}
+
+#define TRANSFER_END_DATA(request, data, bytes) \
 do { \
-	request->transfered_size = bytes; \
-	return EOK; \
+	usb_transfer_batch_finish_error(request, data, bytes, EOK); \
+	usb_transfer_batch_destroy(request); \
+	return; \
+} while (0)
+
+#define TRANSFER_END(request, error) \
+do { \
+	usb_transfer_batch_finish_error(request, NULL, 0, error); \
+	usb_transfer_batch_destroy(request); \
+	return; \
 } while (0)
 
@@ -212,7 +219,7 @@
 	case USB_TRANSFER_CONTROL:
 		usb_log_debug("Root hub got CONTROL packet\n");
-		const int ret = control_request(instance, request);
-		usb_transfer_batch_finish_error(request, NULL, 0, ret);
+		control_request(instance, request);
 		break;
+
 	case USB_TRANSFER_INTERRUPT:
 		usb_log_debug("Root hub got INTERRUPT packet\n");
@@ -221,11 +228,11 @@
 		const uint16_t mask = create_interrupt_mask(instance);
 		if (mask == 0) {
-			usb_log_debug("No changes..\n");
+			usb_log_debug("No changes...\n");
 			instance->unfinished_interrupt_transfer = request;
-			fibril_mutex_unlock(&instance->guard);
-			return;
+		} else {
+			usb_log_debug("Processing changes...\n");
+			interrupt_request(
+			    request, mask, instance->interrupt_mask_size);
 		}
-		usb_log_debug("Processing changes...\n");
-		interrupt_request(request, mask, instance->interrupt_mask_size);
 		fibril_mutex_unlock(&instance->guard);
 		break;
@@ -233,7 +240,6 @@
 	default:
 		usb_log_error("Root hub got unsupported request.\n");
-		usb_transfer_batch_finish_error(request, NULL, 0, EINVAL);
-	}
-	usb_transfer_batch_destroy(request);
+		TRANSFER_END(request, ENOTSUP);
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -254,6 +260,4 @@
 		interrupt_request(instance->unfinished_interrupt_transfer,
 		    mask, instance->interrupt_mask_size);
-		usb_transfer_batch_destroy(
-		    instance->unfinished_interrupt_transfer);
 		instance->unfinished_interrupt_transfer = NULL;
 	}
@@ -384,39 +388,80 @@
  * @return error code
  */
-int get_status(const rh_t *instance, usb_transfer_batch_t *request)
+void get_status(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
 	assert(request);
+
 
 	const usb_device_request_setup_packet_t *request_packet =
 	    (usb_device_request_setup_packet_t*)request->setup_buffer;
 
-	if (request->buffer_size < 4) {
-		usb_log_error("Buffer too small for get status request.\n");
-		return EOVERFLOW;
-	}
-
+	switch (request_packet->request_type)
+	{
+	case USB_HUB_REQ_TYPE_GET_HUB_STATUS:
 	/* Hub status: just filter relevant info from rh_status reg */
-	if (request_packet->request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS) {
-		const uint32_t data = instance->registers->rh_status &
-		    (RHS_LPS_FLAG | RHS_LPSC_FLAG | RHS_OCI_FLAG | RHS_OCIC_FLAG);
-		memcpy(request->buffer, &data, sizeof(data));
-		TRANSFER_OK(sizeof(data));
-	}
+		if (request->buffer_size < 4) {
+			usb_log_error("Buffer(%zu) too small for hub get "
+			    "status request.\n", request->buffer_size);
+			TRANSFER_END(request, EOVERFLOW);
+		} else {
+			const uint32_t data = instance->registers->rh_status &
+			    (RHS_LPS_FLAG | RHS_LPSC_FLAG
+			        | RHS_OCI_FLAG | RHS_OCIC_FLAG);
+			TRANSFER_END_DATA(request, &data, sizeof(data));
+		}
 
 	/* Copy appropriate rh_port_status register, OHCI designers were
 	 * kind enough to make those bit values match USB specification */
-	if (request_packet->request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS) {
-		const unsigned port = request_packet->index;
-		if (port < 1 || port > instance->port_count)
-			return EINVAL;
-
-		const uint32_t data =
-		    instance->registers->rh_port_status[port - 1];
-		memcpy(request->buffer, &data, sizeof(data));
-		TRANSFER_OK(sizeof(data));
-	}
-
-	return ENOTSUP;
+	case USB_HUB_REQ_TYPE_GET_PORT_STATUS:
+		if (request->buffer_size < 4) {
+			usb_log_error("Buffer(%zu) too small for hub get "
+			    "status request.\n", request->buffer_size);
+			TRANSFER_END(request, EOVERFLOW);
+		} else {
+			const unsigned port = request_packet->index;
+			if (port < 1 || port > instance->port_count)
+				TRANSFER_END(request, EINVAL);
+
+			const uint32_t data =
+			    instance->registers->rh_port_status[port - 1];
+			TRANSFER_END_DATA(request, &data, sizeof(data));
+		}
+	case SETUP_REQUEST_TO_HOST(USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE):
+		if (request->buffer_size < 2) {
+			usb_log_error("Buffer(%zu) too small for hub generic "
+			    "get status request.\n", request->buffer_size);
+			TRANSFER_END(request, EOVERFLOW);
+		} else {
+			static const uint16_t data =
+			    uint16_host2usb(USB_DEVICE_STATUS_SELF_POWERED);
+			TRANSFER_END_DATA(request, &data, sizeof(data));
+		}
+
+	case SETUP_REQUEST_TO_HOST(USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE):
+		/* Hubs are allowed to have only one interface */
+		if (request_packet->index != 0)
+			TRANSFER_END(request, EINVAL);
+		/* Fall through, as the answer will be the same: 0x0000 */
+	case SETUP_REQUEST_TO_HOST(USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_ENDPOINT):
+		/* Endpoint 0 (default control) and 1 (interrupt) */
+		if (request_packet->index >= 2)
+			TRANSFER_END(request, EINVAL);
+
+		if (request->buffer_size < 2) {
+			usb_log_error("Buffer(%zu) too small for hub generic "
+			    "get status request.\n", request->buffer_size);
+			TRANSFER_END(request, EOVERFLOW);
+		} else {
+			/* Endpoints are OK. (We don't halt) */
+			static const uint16_t data = 0;
+			TRANSFER_END_DATA(request, &data, sizeof(data));
+		}
+
+	default:
+		usb_log_error("Unsupported GET_STATUS request.\n");
+		TRANSFER_END(request, ENOTSUP);
+	}
+
 }
 /*----------------------------------------------------------------------------*/
@@ -430,5 +475,5 @@
  * @return Error code
  */
-int get_descriptor(const rh_t *instance, usb_transfer_batch_t *request)
+void get_descriptor(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -437,47 +482,45 @@
 	const usb_device_request_setup_packet_t *setup_request =
 	    (usb_device_request_setup_packet_t *) request->setup_buffer;
-	size_t size;
-	const void *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_debug2("USB_DESCTYPE_HUB\n");
-		/* Hub descriptor was generated locally */
-		descriptor = instance->descriptors.hub;
-		size = instance->hub_descriptor_size;
-		break;
+		/* Hub descriptor was generated locally.
+		 * Class specific request. */
+		TRANSFER_END_DATA(request, instance->descriptors.hub,
+		    instance->hub_descriptor_size);
 
 	case USB_DESCTYPE_DEVICE:
 		usb_log_debug2("USB_DESCTYPE_DEVICE\n");
-		/* Device descriptor is shared (No one should ask for it)*/
-		descriptor = &ohci_rh_device_descriptor;
-		size = sizeof(ohci_rh_device_descriptor);
-		break;
+		/* Device descriptor is shared
+		 * (No one should ask for it, as the device is already setup)
+		 * Standard USB device request. */
+		TRANSFER_END_DATA(request, &ohci_rh_device_descriptor,
+		    sizeof(ohci_rh_device_descriptor));
 
 	case USB_DESCTYPE_CONFIGURATION:
 		usb_log_debug2("USB_DESCTYPE_CONFIGURATION\n");
 		/* Start with configuration and add others depending on
-		 * request size */
-		descriptor = &instance->descriptors;
-		size = instance->descriptors.configuration.total_length;
-		break;
+		 * request size. Standard USB request. */
+		TRANSFER_END_DATA(request, &instance->descriptors,
+		    instance->descriptors.configuration.total_length);
 
 	case USB_DESCTYPE_INTERFACE:
 		usb_log_debug2("USB_DESCTYPE_INTERFACE\n");
 		/* Use local interface descriptor. There is one and it
-		 * might be modified */
-		descriptor = &instance->descriptors.interface;
-		size = sizeof(instance->descriptors.interface);
-		break;
+		 * might be modified. Hub driver should not ask or this
+		 * descriptor as it is not part of standard requests set. */
+		TRANSFER_END_DATA(request, &instance->descriptors.interface,
+		    sizeof(instance->descriptors.interface));
 
 	case USB_DESCTYPE_ENDPOINT:
 		/* Use local endpoint descriptor. There is one
-		 * it might have max_packet_size field modified*/
+		 * it might have max_packet_size field modified. Hub driver
+		 * should not ask for this descriptor as it is not part
+		 * of standard requests set. */
 		usb_log_debug2("USB_DESCTYPE_ENDPOINT\n");
-		descriptor = &instance->descriptors.endpoint;
-		size = sizeof(instance->descriptors.endpoint);
-		break;
+		TRANSFER_END_DATA(request, &instance->descriptors.endpoint,
+		    sizeof(instance->descriptors.endpoint));
 
 	default:
@@ -489,12 +532,8 @@
 		    setup_request_value, setup_request->index,
 		    setup_request->length);
-		return EINVAL;
-	}
-	if (request->buffer_size < size) {
-		size = request->buffer_size;
-	}
-
-	memcpy(request->buffer, descriptor, size);
-	TRANSFER_OK(size);
+		TRANSFER_END(request, EINVAL);
+	}
+
+	TRANSFER_END(request, ENOTSUP);
 }
 /*----------------------------------------------------------------------------*/
@@ -604,5 +643,5 @@
  * @return error code
  */
-int set_feature(const rh_t *instance, usb_transfer_batch_t *request)
+void set_feature(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -615,6 +654,7 @@
 	case USB_HUB_REQ_TYPE_SET_PORT_FEATURE:
 		usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
-		return set_feature_port(instance,
+		const int ret = set_feature_port(instance,
 		    setup_request->value, setup_request->index);
+		TRANSFER_END(request, ret);
 
 	case USB_HUB_REQ_TYPE_SET_HUB_FEATURE:
@@ -623,9 +663,10 @@
 		 * features. It makes no sense to SET either. */
 		usb_log_error("Invalid HUB set feature request.\n");
-		return ENOTSUP;
+		TRANSFER_END(request, ENOTSUP);
+	//TODO: Consider standard USB requests: REMOTE WAKEUP, ENDPOINT STALL
 	default:
 		usb_log_error("Invalid set feature request type: %d\n",
 		    setup_request->request_type);
-		return EINVAL;
+		TRANSFER_END(request, ENOTSUP);
 	}
 }
@@ -640,5 +681,5 @@
  * @return error code
  */
-int clear_feature(const rh_t *instance, usb_transfer_batch_t *request)
+void clear_feature(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -647,6 +688,4 @@
 	const usb_device_request_setup_packet_t *setup_request =
 	    (usb_device_request_setup_packet_t *) request->setup_buffer;
-
-	request->transfered_size = 0;
 
 	switch (setup_request->request_type)
@@ -654,6 +693,7 @@
 	case USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE:
 		usb_log_debug("USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE\n");
-		return clear_feature_port(instance,
+		const int ret = clear_feature_port(instance,
 		    setup_request->value, setup_request->index);
+		TRANSFER_END(request, ret);
 
 	case USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE:
@@ -668,10 +708,11 @@
 		if (setup_request->value == USB_HUB_FEATURE_C_HUB_OVER_CURRENT) {
 			instance->registers->rh_status = RHS_OCIC_FLAG;
-			TRANSFER_OK(0);
+			TRANSFER_END(request, EOK);
 		}
+	//TODO: Consider standard USB requests: REMOTE WAKEUP, ENDPOINT STALL
 	default:
 		usb_log_error("Invalid clear feature request type: %d\n",
 		    setup_request->request_type);
-		return EINVAL;
+		TRANSFER_END(request, ENOTSUP);
 	}
 }
@@ -695,5 +736,5 @@
  * @return error code
  */
-int control_request(rh_t *instance, usb_transfer_batch_t *request)
+void control_request(rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -702,10 +743,10 @@
 	if (!request->setup_buffer) {
 		usb_log_error("Root hub received empty transaction!");
-		return EINVAL;
+		TRANSFER_END(request, EBADMEM);
 	}
 
 	if (sizeof(usb_device_request_setup_packet_t) > request->setup_size) {
 		usb_log_error("Setup packet too small\n");
-		return EOVERFLOW;
+		TRANSFER_END(request, EOVERFLOW);
 	}
 
@@ -718,45 +759,58 @@
 	case USB_DEVREQ_GET_STATUS:
 		usb_log_debug("USB_DEVREQ_GET_STATUS\n");
-		return get_status(instance, request);
+		get_status(instance, request);
+		break;
 
 	case USB_DEVREQ_GET_DESCRIPTOR:
 		usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
-		return get_descriptor(instance, request);
+		get_descriptor(instance, request);
+		break;
 
 	case USB_DEVREQ_GET_CONFIGURATION:
 		usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
-		if (request->buffer_size != 1)
-			return EINVAL;
-		request->buffer[0] = 1;
-		TRANSFER_OK(1);
+		if (request->buffer_size == 0)
+			TRANSFER_END(request, EOVERFLOW);
+		static const uint8_t config = 1;
+		TRANSFER_END_DATA(request, &config, sizeof(config));
 
 	case USB_DEVREQ_CLEAR_FEATURE:
-		usb_log_debug2("Processing request without "
-		    "additional data\n");
-		return clear_feature(instance, request);
+		usb_log_debug2("USB_DEVREQ_CLEAR_FEATURE\n");
+		clear_feature(instance, request);
+		break;
 
 	case USB_DEVREQ_SET_FEATURE:
-		usb_log_debug2("Processing request without "
-		    "additional data\n");
-		return set_feature(instance, request);
+		usb_log_debug2("USB_DEVREQ_SET_FEATURE\n");
+		set_feature(instance, request);
+		break;
 
 	case USB_DEVREQ_SET_ADDRESS:
-		usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
+		usb_log_debug("USB_DEVREQ_SET_ADDRESS: %u\n",
+		    setup_request->value);
+		if (uint16_usb2host(setup_request->value) > 127)
+			TRANSFER_END(request, EINVAL);
+
 		instance->address = setup_request->value;
-		TRANSFER_OK(0);
+		TRANSFER_END(request, EOK);
 
 	case USB_DEVREQ_SET_CONFIGURATION:
-		usb_log_debug("USB_DEVREQ_SET_CONFIGURATION\n");
-		/* We don't need to do anything */
-		TRANSFER_OK(0);
-
-	case USB_DEVREQ_SET_DESCRIPTOR: /* Not supported by OHCI RH */
+		usb_log_debug("USB_DEVREQ_SET_CONFIGURATION: %u\n",
+		    setup_request->value);
+		/* We have only one configuration, it's number is 1 */
+		if (uint16_usb2host(setup_request->value) != 1)
+			TRANSFER_END(request, EINVAL);
+		TRANSFER_END(request, EOK);
+
+	/* Both class specific and std is optional for hubs */
+	case USB_DEVREQ_SET_DESCRIPTOR:
+	/* Hubs have only one interface GET/SET is not supported */
+	case USB_DEVREQ_GET_INTERFACE:
+	case USB_DEVREQ_SET_INTERFACE:
 	default:
+		/* Hub class GET_STATE(2) falls in here too. */
 		usb_log_error("Received unsupported request: %d.\n",
 		    setup_request->request);
-		return ENOTSUP;
-	}
-}
-
+		TRANSFER_END(request, ENOTSUP);
+	}
+}
 /**
  * @}
Index: uspace/drv/bus/usb/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -56,8 +56,9 @@
 	uintptr_t result;
 	int ret = as_get_physical_mapping(addr, &result);
-
+	
 	if (ret != EOK)
 		return 0;
-	return (result | ((uintptr_t)addr & 0xfff));
+	
+	return result;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -130,5 +130,5 @@
 			uhci_transfer_batch_t *batch =
 			    uhci_transfer_batch_from_link(item);
-			uhci_transfer_batch_call_dispose(batch);
+			uhci_transfer_batch_finish_dispose(batch);
 		}
 	}
Index: uspace/drv/bus/usb/uhci/pci.c
===================================================================
--- uspace/drv/bus/usb/uhci/pci.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/pci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -26,5 +26,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /**
  * @addtogroup drvusbuhcihc
@@ -39,5 +38,5 @@
 #include <assert.h>
 #include <devman.h>
-#include <device/hw_res.h>
+#include <device/hw_res_parsed.h>
 
 #include <usb/debug.h>
@@ -68,46 +67,26 @@
 		return ENOMEM;
 
-	hw_resource_list_t hw_resources;
-	const int rc = hw_res_get_resource_list(parent_sess, &hw_resources);
+	hw_res_list_parsed_t hw_res;
+	hw_res_list_parsed_init(&hw_res);
+	const int ret =  hw_res_get_list_parsed(parent_sess, &hw_res, 0);
 	async_hangup(parent_sess);
-	if (rc != EOK) {
-		return rc;
+	if (ret != EOK) {
+		return ret;
 	}
 
-	uintptr_t io_address = 0;
-	size_t io_size = 0;
-	bool io_found = false;
+	/* We want one irq and one io range. */
+	if (hw_res.irqs.count != 1 || hw_res.io_ranges.count != 1) {
+		hw_res_list_parsed_clean(&hw_res);
+		return EINVAL;
+	}
 
-	int irq = 0;
-	bool irq_found = false;
+	if (io_reg_address)
+		*io_reg_address = hw_res.io_ranges.ranges[0].address;
+	if (io_reg_size)
+		*io_reg_size = hw_res.io_ranges.ranges[0].size;
+	if (irq_no)
+		*irq_no = hw_res.irqs.irqs[0];
 
-	for (size_t 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;
-		}
-	}
-	free(hw_resources.resources);
-
-	if (!io_found || !irq_found)
-		return ENOENT;
-
-	*io_reg_address = io_address;
-	*io_reg_size = io_size;
-	*irq_no = irq;
-
+	hw_res_list_parsed_clean(&hw_res);
 	return EOK;
 }
Index: uspace/drv/bus/usb/uhci/transfer_list.c
===================================================================
--- uspace/drv/bus/usb/uhci/transfer_list.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/transfer_list.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -184,6 +184,5 @@
 		    uhci_transfer_batch_from_link(current);
 		transfer_list_remove_batch(instance, batch);
-		batch->usb_batch->error = EINTR;
-		uhci_transfer_batch_call_dispose(batch);
+		uhci_transfer_batch_abort(batch);
 	}
 	fibril_mutex_unlock(&instance->guard);
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -148,6 +148,8 @@
 int device_setup_uhci(ddf_dev_t *device)
 {
-	assert(device);
-	uhci_t *instance = malloc(sizeof(uhci_t));
+	if (!device)
+		return EBADMEM;
+
+	uhci_t *instance = ddf_dev_data_alloc(device, sizeof(uhci_t));
 	if (instance == NULL) {
 		usb_log_error("Failed to allocate OHCI driver.\n");
@@ -158,13 +160,10 @@
 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); \
 	} \
-	device->driver_data = NULL; \
 	usb_log_error(message); \
 	return ret; \
@@ -227,6 +226,4 @@
 	    "Failed to init uhci_hcd: %s.\n", str_error(ret));
 
-	device->driver_data = instance;
-
 #define CHECK_RET_FINI_RETURN(ret, message...) \
 if (ret != EOK) { \
Index: uspace/drv/bus/usb/uhci/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -34,4 +34,5 @@
 #include <errno.h>
 #include <str_error.h>
+#include <macros.h>
 
 #include <usb/usb.h>
@@ -45,4 +46,8 @@
 #define DEFAULT_ERROR_COUNT 3
 
+/** Safely destructs uhci_transfer_batch_t structure.
+ *
+ * @param[in] uhci_batch Instance to destroy.
+ */
 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch)
 {
@@ -54,31 +59,23 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Safely destructs uhci_transfer_batch_t structure
- *
- * @param[in] uhci_batch Instance to destroy.
- */
-void uhci_transfer_batch_call_dispose(uhci_transfer_batch_t *uhci_batch)
+/** Finishes usb_transfer_batch and destroys the structure.
+ *
+ * @param[in] uhci_batch Instance to finish and destroy.
+ */
+void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch)
 {
 	assert(uhci_batch);
 	assert(uhci_batch->usb_batch);
 	usb_transfer_batch_finish(uhci_batch->usb_batch,
-	    uhci_transfer_batch_data_buffer(uhci_batch),
-	    uhci_batch->usb_batch->buffer_size);
+	    uhci_transfer_batch_data_buffer(uhci_batch));
 	uhci_transfer_batch_dispose(uhci_batch);
 }
 /*----------------------------------------------------------------------------*/
+/** Transfer batch setup table. */
 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t);
 /*----------------------------------------------------------------------------*/
 /** 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
+ * @param[in] usb_batch Pointer to generic USB batch structure.
  * @return Valid pointer if all structures were successfully created,
  * NULL otherwise.
@@ -156,5 +153,5 @@
  * is reached.
  */
-bool uhci_transfer_batch_is_complete(uhci_transfer_batch_t *uhci_batch)
+bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch)
 {
 	assert(uhci_batch);
@@ -200,4 +197,5 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Direction to pid conversion table */
 static const usb_packet_id direction_pids[] = {
 	[USB_DIRECTION_IN] = USB_PID_IN,
@@ -237,6 +235,5 @@
 
 	while (remain_size > 0) {
-		const size_t packet_size =
-		    (remain_size < mps) ? remain_size : mps;
+		const size_t packet_size = min(remain_size, mps);
 
 		const td_t *next_td = (td + 1 < uhci_batch->td_count)
@@ -309,6 +306,5 @@
 
 	while (remain_size > 0) {
-		const size_t packet_size =
-		    (remain_size < mps) ? remain_size : mps;
+		const size_t packet_size = min(remain_size, mps);
 
 		td_init(
Index: uspace/drv/bus/usb/uhci/uhci_batch.h
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/uhci_batch.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -61,7 +61,11 @@
 
 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch);
-void uhci_transfer_batch_call_dispose(uhci_transfer_batch_t *uhci_batch);
-bool uhci_transfer_batch_is_complete(uhci_transfer_batch_t *uhci_batch);
+void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch);
+bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch);
 
+/** Get offset to setup buffer accessible to the HC hw.
+ * @param uhci_batch UHCI batch structure.
+ * @return Pointer to the setup buffer.
+ */
 static inline void * uhci_transfer_batch_setup_buffer(
     const uhci_transfer_batch_t *uhci_batch)
@@ -73,4 +77,8 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Get offset to data buffer accessible to the HC hw.
+ * @param uhci_batch UHCI batch structure.
+ * @return Pointer to the data buffer.
+ */
 static inline void * uhci_transfer_batch_data_buffer(
     const uhci_transfer_batch_t *uhci_batch)
@@ -82,4 +90,22 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Aborts the batch.
+ * Sets error to EINTR and size off transferd data to 0, before finishing the
+ * batch.
+ * @param uhci_batch Batch to abort.
+ */
+static inline void uhci_transfer_batch_abort(uhci_transfer_batch_t *uhci_batch)
+{
+	assert(uhci_batch);
+	assert(uhci_batch->usb_batch);
+	uhci_batch->usb_batch->error = EINTR;
+	uhci_batch->usb_batch->transfered_size = 0;
+	uhci_transfer_batch_finish_dispose(uhci_batch);
+}
+/*----------------------------------------------------------------------------*/
+/** Linked list conversion wrapper.
+ * @param l Linked list link.
+ * @return Pointer to the uhci batch structure.
+ */
 static inline uhci_transfer_batch_t *uhci_transfer_batch_from_link(link_t *l)
 {
Index: uspace/drv/bus/usb/uhci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -54,10 +54,11 @@
 	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));
+	
+	return result;
 }
 /*----------------------------------------------------------------------------*/
@@ -97,11 +98,9 @@
 static inline void * get_page(void)
 {
-	void *free_address = as_get_mappable_page(UHCI_REQUIRED_PAGE_SIZE);
-	if (free_address == 0)
+	void *address = as_area_create((void *) -1, UHCI_REQUIRED_PAGE_SIZE,
+	    AS_AREA_READ | AS_AREA_WRITE);
+	if (address == (void *) -1)
 		return NULL;
-	void *address = as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE,
-		  AS_AREA_READ | AS_AREA_WRITE);
-	if (address != free_address)
-		return NULL;
+	
 	return address;
 }
Index: uspace/drv/bus/usb/uhcirh/main.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/main.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -36,5 +36,5 @@
 #include <ddf/driver.h>
 #include <devman.h>
-#include <device/hw_res.h>
+#include <device/hw_res_parsed.h>
 #include <errno.h>
 #include <str_error.h>
@@ -136,5 +136,5 @@
 {
 	assert(dev);
-	
+
 	async_sess_t *parent_sess =
 	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
@@ -142,37 +142,25 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
-	hw_resource_list_t hw_resources;
-	const int ret = hw_res_get_resource_list(parent_sess, &hw_resources);
+
+	hw_res_list_parsed_t hw_res;
+	hw_res_list_parsed_init(&hw_res);
+	const int ret =  hw_res_get_list_parsed(parent_sess, &hw_res, 0);
+	async_hangup(parent_sess);
 	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;
-		}
-	
+
+	if (hw_res.io_ranges.count != 1) {
+		hw_res_list_parsed_clean(&hw_res);
+		return EINVAL;
 	}
-	async_hangup(parent_sess);
-	
-	if (!io_found)
-		return ENOENT;
-	
+
 	if (io_reg_address != NULL)
-		*io_reg_address = io_address;
-	
+		*io_reg_address = hw_res.io_ranges.ranges[0].address;
+
 	if (io_reg_size != NULL)
-		*io_reg_size = io_size;
-	
+		*io_reg_size = hw_res.io_ranges.ranges[0].size;
+
+	hw_res_list_parsed_clean(&hw_res);
 	return EOK;
 }
Index: uspace/drv/bus/usb/uhcirh/port.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/port.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/uhcirh/port.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -260,5 +260,4 @@
 {
 	assert(port);
-	assert(usb_hc_connection_is_opened(&port->hc_connection));
 
 	usb_log_debug("%s: Detected new device.\n", port->id_string);
@@ -314,6 +313,6 @@
 
 	/* Driver stopped, free used address */
-	ret = usb_hc_unregister_device(&port->hc_connection,
-	    port->attached_device.address);
+	ret = usb_hub_unregister_device(&port->hc_connection,
+	    &port->attached_device);
 	if (ret != EOK) {
 		usb_log_error("%s: Failed to unregister address of removed "
Index: uspace/drv/bus/usb/usbhub/port.c
===================================================================
--- uspace/drv/bus/usb/usbhub/port.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/usbhub/port.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -288,21 +288,9 @@
 	port->attached_device.fun = NULL;
 
-	ret = usb_hc_connection_open(&hub->connection);
-	if (ret == EOK) {
-		ret = usb_hc_unregister_device(&hub->connection,
-		    port->attached_device.address);
-		if (ret != EOK) {
-			usb_log_warning("Failed to unregister address of the "
-			    "removed device: %s.\n", str_error(ret));
-		}
-		ret = usb_hc_connection_close(&hub->connection);
-		if (ret != EOK) {
-			usb_log_warning("Failed to close hc connection %s.\n",
-			    str_error(ret));
-		}
-
-	} else {
-		usb_log_warning("Failed to open hc connection %s.\n",
-		    str_error(ret));
+	ret = usb_hub_unregister_device(&hub->usb_device->hc_conn,
+	    &port->attached_device);
+	if (ret != EOK) {
+		usb_log_warning("Failed to unregister address of the "
+		    "removed device: %s.\n", str_error(ret));
 	}
 
@@ -438,5 +426,5 @@
 
 	const int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
-	    &data->hub->connection, data->speed, enable_port_callback,
+	    &data->hub->usb_device->hc_conn, data->speed, enable_port_callback,
 	    data->port, &new_address, NULL, NULL, &child_fun);
 
Index: uspace/drv/bus/usb/usbhub/usbhub.c
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -99,10 +99,8 @@
 	fibril_condvar_initialize(&hub_dev->pending_ops_cv);
 
-	/* Create hc connection */
-	usb_log_debug("Initializing USB wire abstraction.\n");
-	int opResult = usb_hc_connection_initialize_from_device(
-	    &hub_dev->connection, hub_dev->usb_device->ddf_dev);
-	if (opResult != EOK) {
-		usb_log_error("Could not initialize connection to device: %s\n",
+
+	int opResult = usb_pipe_start_long_transfer(&usb_dev->ctrl_pipe);
+	if (opResult != EOK) {
+		usb_log_error("Failed to start long ctrl pipe transfer: %s\n",
 		    str_error(opResult));
 		return opResult;
@@ -112,4 +110,5 @@
 	opResult = usb_set_first_configuration(usb_dev);
 	if (opResult != EOK) {
+		usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe);
 		usb_log_error("Could not set hub configuration: %s\n",
 		    str_error(opResult));
@@ -120,4 +119,5 @@
 	opResult = usb_hub_process_hub_specific_info(hub_dev);
 	if (opResult != EOK) {
+		usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe);
 		usb_log_error("Could process hub specific info, %s\n",
 		    str_error(opResult));
@@ -130,4 +130,5 @@
 	    fun_exposed, HUB_FNC_NAME);
 	if (hub_dev->hub_fun == NULL) {
+		usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe);
 		usb_log_error("Failed to create hub function.\n");
 		return ENOMEM;
@@ -137,4 +138,5 @@
 	opResult = ddf_fun_bind(hub_dev->hub_fun);
 	if (opResult != EOK) {
+		usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe);
 		usb_log_error("Failed to bind hub function: %s.\n",
 		   str_error(opResult));
@@ -148,4 +150,5 @@
 	    usb_hub_polling_terminated_callback, hub_dev);
 	if (opResult != EOK) {
+		usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe);
 		/* Function is already bound */
 		ddf_fun_unbind(hub_dev->hub_fun);
@@ -159,4 +162,5 @@
 	    hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
 
+	usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe);
 	return EOK;
 }
Index: uspace/drv/bus/usb/usbhub/usbhub.h
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/usbhub/usbhub.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -57,6 +57,4 @@
 	/** Port structures, one for each port */
 	usb_hub_port_t *ports;
-	/** Connection to hcd */
-	usb_hc_connection_t connection;
 	/** Generic usb device data*/
 	usb_device_t *usb_device;
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -300,13 +300,11 @@
 		return;
 	}
-
-	comm_buf = as_get_mappable_page(comm_size);
-	if (comm_buf == NULL) {
+	
+	(void) async_share_out_finalize(callid, &comm_buf);
+	if (comm_buf == (void *) -1) {
 		async_answer_0(callid, EHANGUP);
 		return;
 	}
-
-	(void) async_share_out_finalize(callid, comm_buf);
-
+	
 	mfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
 
Index: uspace/drv/bus/usb/usbmid/main.c
===================================================================
--- uspace/drv/bus/usb/usbmid/main.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/usbmid/main.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -53,9 +53,5 @@
 	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);
+	const bool accept = usbmid_explore_device(dev);
 
 	if (!accept) {
Index: uspace/drv/bus/usb/vhc/hub.c
===================================================================
--- uspace/drv/bus/usb/vhc/hub.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/bus/usb/vhc/hub.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -107,6 +107,5 @@
 
 	usb_hc_connection_t hc_conn;
-	rc = usb_hc_connection_initialize(&hc_conn, hc_dev->handle);
-	assert(rc == EOK);
+	usb_hc_connection_initialize(&hc_conn, hc_dev->handle);
 
 	rc = usb_hc_connection_open(&hc_conn);
Index: uspace/drv/infrastructure/rootpc/rootpc.c
===================================================================
--- uspace/drv/infrastructure/rootpc/rootpc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -109,6 +109,6 @@
 
 static hw_res_ops_t fun_hw_res_ops = {
-	&rootpc_get_resources,
-	&rootpc_enable_interrupt
+	.get_resource_list = &rootpc_get_resources,
+	.enable_interrupt = &rootpc_enable_interrupt,
 };
 
Index: uspace/drv/nic/e1k/Makefile
===================================================================
--- uspace/drv/nic/e1k/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/e1k/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 Radim Vansa
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 $(LIBNET_PREFIX)/libnet.a $(LIBNIC_PREFIX)/libnic.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include -I$(LIBNIC_PREFIX)/include
+BINARY = e1k
+
+SOURCES = \
+	e1k.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/e1k/e1k.c
===================================================================
--- uspace/drv/nic/e1k/e1k.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/e1k/e1k.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,2231 @@
+/*
+ * Copyright (c) 2011 Zdenek Bouska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 e1k.c
+ *
+ * Driver for Intel Pro/1000 8254x Family of Gigabit Ethernet Controllers
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <adt/list.h>
+#include <align.h>
+#include <byteorder.h>
+#include <sysinfo.h>
+#include <ipc/irc.h>
+#include <ipc/ns.h>
+#include <libarch/ddi.h>
+#include <as.h>
+#include <ddf/interrupt.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <device/pci.h>
+#include <nic.h>
+#include <nil_remote.h>
+#include <ops/nic.h>
+#include <packet_client.h>
+#include <packet_remote.h>
+#include <net/packet_header.h>
+#include "e1k.h"
+
+#define NAME  "e1k"
+
+#define E1000_DEFAULT_INTERRUPT_INTERVAL_USEC  250
+
+/* Must be power of 8 */
+#define E1000_RX_PACKETS_COUNT  128
+#define E1000_TX_PACKETS_COUNT  128
+
+#define E1000_RECEIVE_ADDRESS  16
+
+/** Maximum receiving packet size */
+#define E1000_MAX_RECEIVE_PACKET_SIZE  2048
+
+/** nic_driver_data_t* -> e1000_t* cast */
+#define DRIVER_DATA_NIC(nic) \
+	((e1000_t *) nic_get_specific(nic))
+
+/** device_t* -> nic_driver_data_t* cast */
+#define NIC_DATA_DEV(dev) \
+	((nic_t *) ((dev)->driver_data))
+
+/** device_t* -> e1000_t* cast */
+#define DRIVER_DATA_DEV(dev) \
+	(DRIVER_DATA_NIC(NIC_DATA_DEV(dev)))
+
+/** Cast pointer to uint64_t
+ *
+ * @param ptr Pointer to cast
+ *
+ * @return The uint64_t pointer representation.
+ *
+ */
+#define PTR_TO_U64(ptr)  ((uint64_t) ((uintptr_t) (ptr)))
+
+/** Cast the memaddr part to the void*
+ *
+ * @param memaddr The memaddr value
+ *
+ */
+#define MEMADDR_TO_PTR(memaddr)  ((void *) ((size_t) (memaddr)))
+
+#define E1000_REG_BASE(e1000) \
+	((e1000)->reg_base_virt)
+
+#define E1000_REG_ADDR(e1000, reg) \
+	((uint32_t *) (E1000_REG_BASE(e1000) + reg))
+
+#define E1000_REG_READ(e1000, reg) \
+	(pio_read_32(E1000_REG_ADDR(e1000, reg)))
+
+#define E1000_REG_WRITE(e1000, reg, value) \
+	(pio_write_32(E1000_REG_ADDR(e1000, reg), value))
+
+/** E1000 device data */
+typedef struct {
+	/** Physical registers base address */
+	void *reg_base_phys;
+	/** Virtual registers base address */
+	void *reg_base_virt;
+	
+	/** Physical tx ring address */
+	void *tx_ring_phys;
+	/** Virtual tx ring address */
+	void *tx_ring_virt;
+	
+	/** Packets in tx ring  */
+	packet_t **tx_ring_packets;
+	
+	/** Physical rx ring address */
+	void *rx_ring_phys;
+	/** Virtual rx ring address */
+	void *rx_ring_virt;
+	
+	/** Packets in rx ring  */
+	packet_t **rx_ring_packets;
+	
+	/** VLAN tag */
+	uint16_t vlan_tag;
+	
+	/** Add VLAN tag to packet */
+	bool vlan_tag_add;
+	
+	/** Used unicast Receive Address count */
+	unsigned int unicast_ra_count;
+	
+	/** Used milticast Receive addrress count */
+	unsigned int multicast_ra_count;
+	
+	/** PCI device ID */
+	uint16_t device_id;
+	
+	/** The irq assigned */
+	int irq;
+	
+	/** Lock for CTRL register */
+	fibril_mutex_t ctrl_lock;
+	
+	/** Lock for receiver */
+	fibril_mutex_t rx_lock;
+	
+	/** Lock for transmitter */
+	fibril_mutex_t tx_lock;
+	
+	/** Lock for EEPROM access */
+	fibril_mutex_t eeprom_lock;
+} e1000_t;
+
+/** Global mutex for work with shared irq structure */
+FIBRIL_MUTEX_INITIALIZE(irq_reg_mutex);
+
+static int e1000_get_address(e1000_t *, nic_address_t *);
+static void e1000_eeprom_get_address(e1000_t *, nic_address_t *);
+static int e1000_set_addr(ddf_fun_t *, const nic_address_t *);
+
+static int e1000_defective_get_mode(ddf_fun_t *, uint32_t *);
+static int e1000_defective_set_mode(ddf_fun_t *, uint32_t);
+
+static int e1000_get_cable_state(ddf_fun_t *, nic_cable_state_t *);
+static int e1000_get_device_info(ddf_fun_t *, nic_device_info_t *);
+static int e1000_get_operation_mode(ddf_fun_t *, int *,
+    nic_channel_mode_t *, nic_role_t *);
+static int e1000_set_operation_mode(ddf_fun_t *, int,
+    nic_channel_mode_t, nic_role_t);
+static int e1000_autoneg_enable(ddf_fun_t *, uint32_t);
+static int e1000_autoneg_disable(ddf_fun_t *);
+static int e1000_autoneg_restart(ddf_fun_t *);
+
+static int e1000_vlan_set_tag(ddf_fun_t *, uint16_t, bool, bool);
+
+/** Network interface options for E1000 card driver */
+static nic_iface_t e1000_nic_iface;
+
+/** Network interface options for E1000 card driver */
+static nic_iface_t e1000_nic_iface = {
+	.set_address = &e1000_set_addr,
+	.get_device_info = &e1000_get_device_info,
+	.get_cable_state = &e1000_get_cable_state,
+	.get_operation_mode = &e1000_get_operation_mode,
+	.set_operation_mode = &e1000_set_operation_mode,
+	.autoneg_enable = &e1000_autoneg_enable,
+	.autoneg_disable = &e1000_autoneg_disable,
+	.autoneg_restart = &e1000_autoneg_restart,
+	.vlan_set_tag = &e1000_vlan_set_tag,
+	.defective_get_mode = &e1000_defective_get_mode,
+	.defective_set_mode = &e1000_defective_set_mode,
+};
+
+/** Basic device operations for E1000 driver */
+static ddf_dev_ops_t e1000_dev_ops;
+
+static int e1000_dev_add(ddf_dev_t *);
+
+/** Basic driver operations for E1000 driver */
+static driver_ops_t e1000_driver_ops = {
+	.dev_add = e1000_dev_add
+};
+
+/** Driver structure for E1000 driver */
+static driver_t e1000_driver = {
+	.name = NAME,
+	.driver_ops = &e1000_driver_ops
+};
+
+/* The default implementation callbacks */
+static int e1000_on_activating(nic_t *);
+static int e1000_on_stopping(nic_t *);
+static void e1000_write_packet(nic_t *, packet_t *);
+
+/** Commands to deal with interrupt
+ *
+ */
+irq_cmd_t e1000_irq_commands[] = {
+	{
+		/* Get the interrupt status */
+		.cmd = CMD_PIO_READ_32,
+		.addr = NULL,
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 2
+	},
+	{
+		/* Disable interrupts until interrupt routine is finished */
+		.cmd = CMD_PIO_WRITE_32,
+		.addr = NULL,
+		.value = 0xffffffff
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+/** Interrupt code definition */
+irq_code_t e1000_irq_code = {
+	.cmdcount = sizeof(e1000_irq_commands) / sizeof(irq_cmd_t),
+	.cmds = e1000_irq_commands
+};
+
+/** Get the device information
+ *
+ * @param dev  NIC device
+ * @param info Information to fill
+ *
+ * @return EOK
+ *
+ */
+static int e1000_get_device_info(ddf_fun_t *dev, nic_device_info_t *info)
+{
+	assert(dev);
+	assert(info);
+	
+	bzero(info, sizeof(nic_device_info_t));
+	
+	info->vendor_id = 0x8086;
+	str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH,
+	    "Intel Corporation");
+	str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH,
+	    "Intel Pro");
+	
+	info->ethernet_support[ETH_10M] = ETH_10BASE_T;
+	info->ethernet_support[ETH_100M] = ETH_100BASE_TX;
+	info->ethernet_support[ETH_1000M] = ETH_1000BASE_T;
+	
+	return EOK;
+}
+
+/** Check the cable state
+ *
+ * @param[in]  dev   device
+ * @param[out] state state to fill
+ *
+ * @return EOK
+ *
+ */
+static int e1000_get_cable_state(ddf_fun_t *dev, nic_cable_state_t *state)
+{
+	assert(dev);
+	assert(DRIVER_DATA_DEV(dev));
+	assert(state);
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	if (E1000_REG_READ(e1000, E1000_STATUS) & (STATUS_LU))
+		*state = NIC_CS_PLUGGED;
+	else
+		*state = NIC_CS_UNPLUGGED;
+	
+	return EOK;
+}
+
+static uint16_t e1000_calculate_itr_interval_from_usecs(suseconds_t useconds)
+{
+	return useconds * 4;
+}
+
+/** Get operation mode of the device
+ *
+ */
+static int e1000_get_operation_mode(ddf_fun_t *dev, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	uint32_t status = E1000_REG_READ(e1000, E1000_STATUS);
+	
+	if (status & STATUS_FD)
+		*duplex = NIC_CM_FULL_DUPLEX;
+	else
+		*duplex = NIC_CM_HALF_DUPLEX;
+	
+	uint32_t speed_bits =
+	    (status >> STATUS_SPEED_SHIFT) & STATUS_SPEED_ALL;
+	
+	if (speed_bits == STATUS_SPEED_10)
+		*speed = 10;
+	else if (speed_bits == STATUS_SPEED_100)
+		*speed = 100;
+	else if ((speed_bits == STATUS_SPEED_1000A) ||
+	    (speed_bits == STATUS_SPEED_1000B))
+		*speed = 1000;
+	
+	*role = NIC_ROLE_UNKNOWN;
+	return EOK;
+}
+
+static void e1000_link_restart(e1000_t *e1000)
+{
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	if (ctrl & CTRL_SLU) {
+		ctrl &= ~(CTRL_SLU);
+		fibril_mutex_unlock(&e1000->ctrl_lock);
+		usleep(10);
+		fibril_mutex_lock(&e1000->ctrl_lock);
+		ctrl |= CTRL_SLU;
+	}
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+}
+
+/** Set operation mode of the device
+ *
+ */
+static int e1000_set_operation_mode(ddf_fun_t *dev, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	if ((speed != 10) && (speed != 100) && (speed != 1000))
+		return EINVAL;
+	
+	if ((duplex != NIC_CM_HALF_DUPLEX) && (duplex != NIC_CM_FULL_DUPLEX))
+		return EINVAL;
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	ctrl |= CTRL_FRCSPD;
+	ctrl |= CTRL_FRCDPLX;
+	ctrl &= ~(CTRL_ASDE);
+	
+	if (duplex == NIC_CM_FULL_DUPLEX)
+		ctrl |= CTRL_FD;
+	else
+		ctrl &= ~(CTRL_FD);
+	
+	ctrl &= ~(CTRL_SPEED_MASK);
+	if (speed == 1000)
+		ctrl |= CTRL_SPEED_1000 << CTRL_SPEED_SHIFT;
+	else if (speed == 100)
+		ctrl |= CTRL_SPEED_100 << CTRL_SPEED_SHIFT;
+	else
+		ctrl |= CTRL_SPEED_10 << CTRL_SPEED_SHIFT;
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+	
+	return EOK;
+}
+
+/** Enable auto-negotiation
+ *
+ * @param dev           Device to update
+ * @param advertisement Ignored on E1000
+ *
+ * @return EOK if advertisement mode set successfully
+ *
+ */
+static int e1000_autoneg_enable(ddf_fun_t *dev, uint32_t advertisement)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	ctrl &= ~(CTRL_FRCSPD);
+	ctrl &= ~(CTRL_FRCDPLX);
+	ctrl |= CTRL_ASDE;
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+	
+	return EOK;
+}
+
+/** Disable auto-negotiation
+ *
+ * @param dev Device to update
+ *
+ * @return EOK
+ *
+ */
+static int e1000_autoneg_disable(ddf_fun_t *dev)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	ctrl |= CTRL_FRCSPD;
+	ctrl |= CTRL_FRCDPLX;
+	ctrl &= ~(CTRL_ASDE);
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+	
+	return EOK;
+}
+
+/** Restart auto-negotiation
+ *
+ * @param dev Device to update
+ *
+ * @return EOK if advertisement mode set successfully
+ *
+ */
+static int e1000_autoneg_restart(ddf_fun_t *dev)
+{
+	return e1000_autoneg_enable(dev, 0);
+}
+
+/** Get state of acceptance of weird packets
+ *
+ * @param      device Device to check
+ * @param[out] mode   Current mode
+ *
+ */
+static int e1000_defective_get_mode(ddf_fun_t *device, uint32_t *mode)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(device);
+	
+	*mode = 0;
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	if (rctl & RCTL_SBP)
+		*mode = NIC_DEFECTIVE_BAD_CRC | NIC_DEFECTIVE_SHORT;
+	
+	return EOK;
+};
+
+/** Set acceptance of weird packets
+ *
+ * @param device Device to update
+ * @param mode   Mode to set
+ *
+ * @return ENOTSUP if the mode is not supported
+ * @return EOK of mode was set
+ *
+ */
+static int e1000_defective_set_mode(ddf_fun_t *device, uint32_t mode)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(device);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	bool short_mode = (mode & NIC_DEFECTIVE_SHORT ? true : false);
+	bool bad_mode = (mode & NIC_DEFECTIVE_BAD_CRC ? true : false);
+	
+	if (short_mode && bad_mode)
+		rctl |= RCTL_SBP;
+	else if ((!short_mode) && (!bad_mode))
+		rctl &= ~RCTL_SBP;
+	else
+		rc = ENOTSUP;
+	
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+};
+
+/** Write receive address to RA registr
+ *
+ * @param e1000      E1000 data structure
+ * @param position   RA register position
+ * @param address    Ethernet address
+ * @param set_av_bit Set the Addtess Valid bit
+ *
+ */
+static void e1000_write_receive_address(e1000_t *e1000, unsigned int position,
+    const nic_address_t * address, bool set_av_bit)
+{
+	uint8_t *mac0 = (uint8_t *) address->address;
+	uint8_t *mac1 = (uint8_t *) address->address + 1;
+	uint8_t *mac2 = (uint8_t *) address->address + 2;
+	uint8_t *mac3 = (uint8_t *) address->address + 3;
+	uint8_t *mac4 = (uint8_t *) address->address + 4;
+	uint8_t *mac5 = (uint8_t *) address->address + 5;
+	
+	uint32_t rah;
+	uint32_t ral;
+	
+	ral = ((*mac3) << 24) | ((*mac2) << 16) | ((*mac1) << 8) | (*mac0);
+	rah = ((*mac5) << 8) | ((*mac4));
+	
+	if (set_av_bit)
+		rah |= RAH_AV;
+	else
+		rah |= E1000_REG_READ(e1000, E1000_RAH_ARRAY(position)) & RAH_AV;
+	
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(position), rah);
+	E1000_REG_WRITE(e1000, E1000_RAL_ARRAY(position), ral);
+}
+
+/** Disable receive address in RA registr
+ *
+ *  Clear Address Valid bit
+ *
+ * @param e1000    E1000 data structure
+ * @param position RA register position
+ *
+ */
+static void e1000_disable_receive_address(e1000_t *e1000, unsigned int position)
+{
+	uint32_t rah = E1000_REG_READ(e1000, E1000_RAH_ARRAY(position));
+	rah = rah & ~RAH_AV;
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(position), rah);
+}
+
+/** Clear all unicast addresses from RA registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_clear_unicast_receive_addresses(e1000_t *e1000)
+{
+	for (unsigned int ra_num = 1;
+	    ra_num <= e1000->unicast_ra_count;
+	    ra_num++)
+		e1000_disable_receive_address(e1000, ra_num);
+	
+	e1000->unicast_ra_count = 0;
+}
+
+/** Clear all multicast addresses from RA registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_clear_multicast_receive_addresses(e1000_t *e1000)
+{
+	unsigned int first_multicast_ra_num =
+	    E1000_RECEIVE_ADDRESS - e1000->multicast_ra_count;
+	
+	for (unsigned int ra_num = E1000_RECEIVE_ADDRESS - 1;
+	    ra_num >= first_multicast_ra_num;
+	    ra_num--)
+		e1000_disable_receive_address(e1000, ra_num);
+	
+	e1000->multicast_ra_count = 0;
+}
+
+/** Return receive address filter positions count usable for unicast
+ *
+ * @param e1000 E1000 data structure
+ *
+ * @return receive address filter positions count usable for unicast
+ *
+ */
+static unsigned int get_free_unicast_address_count(e1000_t *e1000)
+{
+	return E1000_RECEIVE_ADDRESS - 1 - e1000->multicast_ra_count;
+}
+
+/** Return receive address filter positions count usable for multicast
+ *
+ * @param e1000 E1000 data structure
+ *
+ * @return receive address filter positions count usable for multicast
+ *
+ */
+static unsigned int get_free_multicast_address_count(e1000_t *e1000)
+{
+	return E1000_RECEIVE_ADDRESS - 1 - e1000->unicast_ra_count;
+}
+
+/** Write unicast receive addresses to receive address filter registers
+ *
+ * @param e1000    E1000 data structure
+ * @param addr     Pointer to address array
+ * @param addr_cnt Address array count
+ *
+ */
+static void e1000_add_unicast_receive_addresses(e1000_t *e1000,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	assert(addr_cnt <= get_free_unicast_address_count(e1000));
+	
+	nic_address_t *addr_iterator = (nic_address_t *) addr;
+	
+	/* ra_num = 0 is primary address */
+	for (unsigned int ra_num = 1;
+	    ra_num <= addr_cnt;
+	    ra_num++) {
+		e1000_write_receive_address(e1000, ra_num, addr_iterator, true);
+		addr_iterator++;
+	}
+}
+
+/** Write multicast receive addresses to receive address filter registers
+ *
+ * @param e1000    E1000 data structure
+ * @param addr     Pointer to address array
+ * @param addr_cnt Address array count
+ *
+ */
+static void e1000_add_multicast_receive_addresses(e1000_t *e1000,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	assert(addr_cnt <= get_free_multicast_address_count(e1000));
+	
+	nic_address_t *addr_iterator = (nic_address_t *) addr;
+	
+	unsigned int first_multicast_ra_num = E1000_RECEIVE_ADDRESS - addr_cnt;
+	for (unsigned int ra_num = E1000_RECEIVE_ADDRESS - 1;
+	    ra_num >= first_multicast_ra_num;
+	    ra_num--) {
+		e1000_write_receive_address(e1000, ra_num, addr_iterator, true);
+		addr_iterator++;
+	}
+}
+
+/** Disable receiving packets for default address
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void disable_ra0_address_filter(e1000_t *e1000)
+{
+	uint32_t rah0 = E1000_REG_READ(e1000, E1000_RAH_ARRAY(0));
+	rah0 = rah0 & ~RAH_AV;
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(0), rah0);
+}
+
+/** Enable receiving packets for default address
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void enable_ra0_address_filter(e1000_t *e1000)
+{
+	uint32_t rah0 = E1000_REG_READ(e1000, E1000_RAH_ARRAY(0));
+	rah0 = rah0 | RAH_AV;
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(0), rah0);
+}
+
+/** Disable unicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_unicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_UPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable unicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_unicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_UPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Disable multicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_multicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_MPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable multicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_multicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_MPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable accepting of broadcast packets
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_broadcast_accept(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_BAM;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Disable accepting of broadcast packets
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_broadcast_accept(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_BAM;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable VLAN filtering according to VFTA registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_vlan_filter(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_VFE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Disable VLAN filtering
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_vlan_filter(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_VFE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Set multicast packets acceptance mode
+ *
+ * @param nic      NIC device to update
+ * @param mode     Mode to set
+ * @param addr     Address list (used in mode = NIC_MULTICAST_LIST)
+ * @param addr_cnt Length of address list (used in mode = NIC_MULTICAST_LIST)
+ *
+ * @return EOK
+ *
+ */
+static int e1000_on_multicast_mode_change(nic_t *nic, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	switch (mode) {
+	case NIC_MULTICAST_BLOCKED:
+		e1000_clear_multicast_receive_addresses(e1000);
+		e1000_disable_multicast_promisc(e1000);
+		nic_report_hw_filtering(nic, -1, 1, -1);
+		break;
+	case NIC_MULTICAST_LIST:
+		e1000_clear_multicast_receive_addresses(e1000);
+		if (addr_cnt > get_free_multicast_address_count(e1000)) {
+			/*
+			 * Future work: fill MTA table
+			 * Not strictly neccessary, it only saves some compares
+			 * in the NIC library.
+			 */
+			e1000_enable_multicast_promisc(e1000);
+			nic_report_hw_filtering(nic, -1, 0, -1);
+		} else {
+			e1000_disable_multicast_promisc(e1000);
+			e1000_add_multicast_receive_addresses(e1000, addr, addr_cnt);
+			nic_report_hw_filtering(nic, -1, 1, -1);
+		}
+		break;
+	case NIC_MULTICAST_PROMISC:
+		e1000_enable_multicast_promisc(e1000);
+		e1000_clear_multicast_receive_addresses(e1000);
+		nic_report_hw_filtering(nic, -1, 1, -1);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+}
+
+/** Set unicast packets acceptance mode
+ *
+ * @param nic      NIC device to update
+ * @param mode     Mode to set
+ * @param addr     Address list (used in mode = NIC_MULTICAST_LIST)
+ * @param addr_cnt Length of address list (used in mode = NIC_MULTICAST_LIST)
+ *
+ * @return EOK
+ *
+ */
+static int e1000_on_unicast_mode_change(nic_t *nic, nic_unicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	switch (mode) {
+	case NIC_UNICAST_BLOCKED:
+		disable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		e1000_disable_unicast_promisc(e1000);
+		nic_report_hw_filtering(nic, 1, -1, -1);
+		break;
+	case NIC_UNICAST_DEFAULT:
+		enable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		e1000_disable_unicast_promisc(e1000);
+		nic_report_hw_filtering(nic, 1, -1, -1);
+		break;
+	case NIC_UNICAST_LIST:
+		enable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		if (addr_cnt > get_free_unicast_address_count(e1000)) {
+			e1000_enable_unicast_promisc(e1000);
+			nic_report_hw_filtering(nic, 0, -1, -1);
+		} else {
+			e1000_disable_unicast_promisc(e1000);
+			e1000_add_unicast_receive_addresses(e1000, addr, addr_cnt);
+			nic_report_hw_filtering(nic, 1, -1, -1);
+		}
+		break;
+	case NIC_UNICAST_PROMISC:
+		e1000_enable_unicast_promisc(e1000);
+		enable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		nic_report_hw_filtering(nic, 1, -1, -1);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+}
+
+/** Set broadcast packets acceptance mode
+ *
+ * @param nic  NIC device to update
+ * @param mode Mode to set
+ *
+ * @return EOK
+ *
+ */
+static int e1000_on_broadcast_mode_change(nic_t *nic, nic_broadcast_mode_t mode)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	switch (mode) {
+	case NIC_BROADCAST_BLOCKED:
+		e1000_disable_broadcast_accept(e1000);
+		break;
+	case NIC_BROADCAST_ACCEPTED:
+		e1000_enable_broadcast_accept(e1000);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+}
+
+/** Check if receiving is enabled
+ *
+ * @param e1000 E1000 data structure
+ *
+ * @return true if receiving is enabled
+ *
+ */
+static bool e1000_is_rx_enabled(e1000_t *e1000)
+{
+	if (E1000_REG_READ(e1000, E1000_RCTL) & (RCTL_EN))
+		return true;
+	
+	return false;
+}
+
+/** Enable receiving
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_rx(e1000_t *e1000)
+{
+	/* Set Receive Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_RCTL,
+	    E1000_REG_READ(e1000, E1000_RCTL) | (RCTL_EN));
+}
+
+/** Disable receiving
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_rx(e1000_t *e1000)
+{
+	/* Clear Receive Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_RCTL,
+	    E1000_REG_READ(e1000, E1000_RCTL) & ~(RCTL_EN));
+}
+
+/** Set VLAN mask
+ *
+ * @param nic       NIC device to update
+ * @param vlan_mask VLAN mask
+ *
+ */
+static void e1000_on_vlan_mask_change(nic_t *nic,
+    const nic_vlan_mask_t *vlan_mask)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	if (vlan_mask) {
+		/*
+		 * Disable receiving, so that packet matching
+		 * partially written VLAN is not received.
+		 */
+		bool rx_enabled = e1000_is_rx_enabled(e1000);
+		if (rx_enabled)
+			e1000_disable_rx(e1000);
+		
+		for (unsigned int i = 0; i < NIC_VLAN_BITMAP_SIZE; i += 4) {
+			uint32_t bitmap_part =
+			    ((uint32_t) vlan_mask->bitmap[i]) |
+			    (((uint32_t) vlan_mask->bitmap[i + 1]) << 8) |
+			    (((uint32_t) vlan_mask->bitmap[i + 2]) << 16) |
+			    (((uint32_t) vlan_mask->bitmap[i + 3]) << 24);
+			E1000_REG_WRITE(e1000, E1000_VFTA_ARRAY(i / 4), bitmap_part);
+		}
+		
+		e1000_enable_vlan_filter(e1000);
+		if (rx_enabled)
+			e1000_enable_rx(e1000);
+	} else
+		e1000_disable_vlan_filter(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+}
+
+/** Set VLAN mask
+ *
+ * @param device E1000 device
+ * @param tag    VLAN tag
+ *
+ * @return EOK
+ * @return ENOTSUP
+ *
+ */
+static int e1000_vlan_set_tag(ddf_fun_t *device, uint16_t tag, bool add,
+    bool strip)
+{
+	/* VLAN CFI bit cannot be set */
+	if (tag & VLANTAG_CFI)
+		return ENOTSUP;
+	
+	/*
+	 * CTRL.VME is neccessary for both strip and add
+	 * but CTRL.VME means stripping tags on receive.
+	 */
+	if (!strip && add)
+		return ENOTSUP;
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(device);
+	
+	e1000->vlan_tag = tag;
+	e1000->vlan_tag_add = add;
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	if (strip)
+		ctrl |= CTRL_VME;
+	else
+		ctrl &= ~CTRL_VME;
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	return EOK;
+}
+
+/** Fill receive descriptor with new empty packet
+ *
+ * Store packet in e1000->rx_ring_packets
+ *
+ * @param nic    NIC data stricture
+ * @param offset Receive descriptor offset
+ *
+ */
+static void e1000_fill_new_rx_descriptor(nic_t *nic, size_t offset)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	packet_t *packet =
+	    nic_alloc_packet(nic, E1000_MAX_RECEIVE_PACKET_SIZE);
+	
+	assert(packet);
+	
+	*(e1000->rx_ring_packets + offset) = packet;
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + offset * sizeof(e1000_rx_descriptor_t));
+	
+	void *phys;
+	int rc =
+	    nic_dma_lock_packet(packet, E1000_MAX_RECEIVE_PACKET_SIZE, &phys);
+	
+	if (rc == EOK)
+		rx_descriptor->phys_addr = PTR_TO_U64(phys + packet->data_start);
+	else
+		rx_descriptor->phys_addr = 0;
+	
+	rx_descriptor->length = 0;
+	rx_descriptor->checksum = 0;
+	rx_descriptor->status = 0;
+	rx_descriptor->errors = 0;
+	rx_descriptor->special = 0;
+}
+
+/** Clear receive descriptor
+ *
+ * @param e1000  E1000 data
+ * @param offset Receive descriptor offset
+ *
+ */
+static void e1000_clear_rx_descriptor(e1000_t *e1000, unsigned int offset)
+{
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + offset * sizeof(e1000_rx_descriptor_t));
+	
+	rx_descriptor->length = 0;
+	rx_descriptor->checksum = 0;
+	rx_descriptor->status = 0;
+	rx_descriptor->errors = 0;
+	rx_descriptor->special = 0;
+}
+
+/** Clear receive descriptor
+ *
+ * @param nic    NIC data
+ * @param offset Receive descriptor offset
+ *
+ */
+static void e1000_clear_tx_descriptor(nic_t *nic, unsigned int offset)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	e1000_tx_descriptor_t *tx_descriptor = (e1000_tx_descriptor_t *)
+	    (e1000->tx_ring_virt + offset * sizeof(e1000_tx_descriptor_t));
+	
+	if (tx_descriptor->length) {
+		packet_t *old_packet = *(e1000->tx_ring_packets + offset);
+		if (old_packet)
+			nic_release_packet(nic, old_packet);
+	}
+	
+	tx_descriptor->phys_addr = 0;
+	tx_descriptor->length = 0;
+	tx_descriptor->checksum_offset = 0;
+	tx_descriptor->command = 0;
+	tx_descriptor->status = 0;
+	tx_descriptor->checksum_start_field = 0;
+	tx_descriptor->special = 0;
+}
+
+/** Increment tail pointer for receive or transmit ring
+ *
+ * @param tail              Old Tail
+ * @param descriptors_count Ring length
+ *
+ * @return New tail
+ *
+ */
+static uint32_t e1000_inc_tail(uint32_t tail, uint32_t descriptors_count)
+{
+	if (tail + 1 == descriptors_count)
+		return 0;
+	else
+		return tail + 1;
+}
+
+/** Receive packets
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_receive_packets(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	uint32_t *tail_addr = E1000_REG_ADDR(e1000, E1000_RDT);
+	uint32_t next_tail = e1000_inc_tail(*tail_addr, E1000_RX_PACKETS_COUNT);
+	
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + next_tail * sizeof(e1000_rx_descriptor_t));
+	
+	while (rx_descriptor->status & 0x01) {
+		uint32_t packet_size = rx_descriptor->length - E1000_CRC_SIZE;
+		
+		packet_t *packet = *(e1000->rx_ring_packets + next_tail);
+		packet_suffix(packet, packet_size);
+		
+		nic_dma_unlock_packet(packet, E1000_MAX_RECEIVE_PACKET_SIZE);
+		nic_received_packet(nic, packet);
+		
+		e1000_fill_new_rx_descriptor(nic, next_tail);
+		
+		*tail_addr = e1000_inc_tail(*tail_addr, E1000_RX_PACKETS_COUNT);
+		next_tail = e1000_inc_tail(*tail_addr, E1000_RX_PACKETS_COUNT);
+		
+		rx_descriptor = (e1000_rx_descriptor_t *)
+		    (e1000->rx_ring_virt + next_tail * sizeof(e1000_rx_descriptor_t));
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+}
+
+/** Enable E1000 interupts
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_interrupts(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_IMS, ICR_RXT0);
+}
+
+/** Disable E1000 interupts
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_interrupts(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_IMS, 0);
+}
+
+/** Interrupt handler implementation
+ *
+ * This function is called from e1000_interrupt_handler()
+ * and e1000_poll()
+ *
+ * @param nic NIC data
+ * @param icr ICR register value
+ *
+ */
+static void e1000_interrupt_handler_impl(nic_t *nic, uint32_t icr)
+{
+	if (icr & ICR_RXT0)
+		e1000_receive_packets(nic);
+}
+
+/** Handle device interrupt
+ *
+ * @param dev   E1000 device
+ * @param iid   IPC call id
+ * @param icall IPC call structure
+ *
+ */
+static void e1000_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	uint32_t icr = (uint32_t) IPC_GET_ARG2(*icall);
+	nic_t *nic = NIC_DATA_DEV(dev);
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	e1000_interrupt_handler_impl(nic, icr);
+	e1000_enable_interrupts(e1000);
+}
+
+/** Register interrupt handler for the card in the system
+ *
+ * Note: The global irq_reg_mutex is locked because of work with global
+ * structure.
+ *
+ * @param nic Driver data
+ *
+ * @return EOK if the handler was registered
+ * @return Negative error code otherwise
+ *
+ */
+inline static int e1000_register_int_handler(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	/* Lock the mutex in whole driver while working with global structure */
+	fibril_mutex_lock(&irq_reg_mutex);
+	
+	e1000_irq_code.cmds[0].addr = e1000->reg_base_virt + E1000_ICR;
+	e1000_irq_code.cmds[2].addr = e1000->reg_base_virt + E1000_IMC;
+	
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic),
+	    e1000->irq, e1000_interrupt_handler, &e1000_irq_code);
+	
+	fibril_mutex_unlock(&irq_reg_mutex);
+	return rc;
+}
+
+/** Force receiving all packets in the receive buffer
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_poll(nic_t *nic)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = nic_get_specific(nic);
+	assert(e1000);
+	
+	uint32_t icr = E1000_REG_READ(e1000, E1000_ICR);
+	e1000_interrupt_handler_impl(nic, icr);
+}
+
+/** Calculates ITR register interrupt from timeval structure
+ *
+ * @param period Period
+ *
+ */
+static uint16_t e1000_calculate_itr_interval(const struct timeval *period)
+{
+	// TODO: use also tv_sec
+	return e1000_calculate_itr_interval_from_usecs(period->tv_usec);
+}
+
+/** Set polling mode
+ *
+ * @param device  Device to set
+ * @param mode    Mode to set
+ * @param period  Period for NIC_POLL_PERIODIC
+ *
+ * @return EOK if succeed
+ * @return ENOTSUP if the mode is not supported
+ *
+ */
+static int e1000_poll_mode_change(nic_t *nic, nic_poll_mode_t mode,
+    const struct timeval *period)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = nic_get_specific(nic);
+	assert(e1000);
+	
+	switch (mode) {
+	case NIC_POLL_IMMEDIATE:
+		E1000_REG_WRITE(e1000, E1000_ITR, 0);
+		e1000_enable_interrupts(e1000);
+		break;
+	case NIC_POLL_ON_DEMAND:
+		e1000_disable_interrupts(e1000);
+		break;
+	case NIC_POLL_PERIODIC:
+		assert(period);
+		uint16_t itr_interval = e1000_calculate_itr_interval(period);
+		E1000_REG_WRITE(e1000, E1000_ITR, (uint32_t) itr_interval);
+		e1000_enable_interrupts(e1000);
+		break;
+	default:
+		return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+/** Initialize receive registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_initialize_rx_registers(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_RDLEN, E1000_RX_PACKETS_COUNT * 16);
+	E1000_REG_WRITE(e1000, E1000_RDH, 0);
+	
+	/* It is not posible to let HW use all descriptors */
+	E1000_REG_WRITE(e1000, E1000_RDT, E1000_RX_PACKETS_COUNT - 1);
+	
+	/* Set Broadcast Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_RCTL, RCTL_BAM);
+}
+
+/** Initialize receive structure
+ *
+ * @param nic NIC data
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_initialize_rx_structure(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	int rc = dmamem_map_anonymous(
+	    E1000_RX_PACKETS_COUNT * sizeof(e1000_rx_descriptor_t),
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &e1000->rx_ring_phys,
+	    &e1000->rx_ring_virt);
+	if (rc != EOK)
+		return rc;
+	
+	E1000_REG_WRITE(e1000, E1000_RDBAH,
+	    (uint32_t) (PTR_TO_U64(e1000->rx_ring_phys) >> 32));
+	E1000_REG_WRITE(e1000, E1000_RDBAL,
+	    (uint32_t) PTR_TO_U64(e1000->rx_ring_phys));
+	
+	e1000->rx_ring_packets =
+	    malloc(E1000_RX_PACKETS_COUNT * sizeof(packet_t *));
+	// FIXME: Check return value
+	
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_RX_PACKETS_COUNT;
+	    offset++)
+		e1000_fill_new_rx_descriptor(nic, offset);
+	
+	e1000_initialize_rx_registers(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return EOK;
+}
+
+/** Uninitialize receive structure
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_uninitialize_rx_structure(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_RX_PACKETS_COUNT;
+	    offset++) {
+		packet_t *packet = *(e1000->rx_ring_packets + offset);
+		nic_dma_unlock_packet(packet, E1000_MAX_RECEIVE_PACKET_SIZE);
+		nic_release_packet(nic, packet);
+	}
+	
+	free(e1000->rx_ring_packets);
+	dmamem_unmap_anonymous(e1000->rx_ring_virt);
+}
+
+/** Clear receive descriptor ring
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_clear_rx_ring(e1000_t *e1000)
+{
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_RX_PACKETS_COUNT;
+	    offset++)
+		e1000_clear_rx_descriptor(e1000, offset);
+}
+
+/** Initialize filters
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_initialize_filters(e1000_t *e1000)
+{
+	/* Initialize address filter */
+	e1000->unicast_ra_count = 0;
+	e1000->multicast_ra_count = 0;
+	e1000_clear_unicast_receive_addresses(e1000);
+}
+
+/** Initialize VLAN
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_initialize_vlan(e1000_t *e1000)
+{
+	e1000->vlan_tag_add = false;
+}
+
+/** Fill MAC address from EEPROM to RA[0] register
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_fill_mac_from_eeprom(e1000_t *e1000)
+{
+	/* MAC address from eeprom to RA[0] */
+	nic_address_t address;
+	e1000_eeprom_get_address(e1000, &address);
+	e1000_write_receive_address(e1000, 0, &address, true);
+}
+
+/** Initialize other registers
+ *
+ * @param dev E1000 data.
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static void e1000_initialize_registers(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_ITR,
+	    e1000_calculate_itr_interval_from_usecs(
+	    E1000_DEFAULT_INTERRUPT_INTERVAL_USEC));
+	E1000_REG_WRITE(e1000, E1000_FCAH, 0);
+	E1000_REG_WRITE(e1000, E1000_FCAL, 0);
+	E1000_REG_WRITE(e1000, E1000_FCT, 0);
+	E1000_REG_WRITE(e1000, E1000_FCTTV, 0);
+	E1000_REG_WRITE(e1000, E1000_VET, VET_VALUE);
+	E1000_REG_WRITE(e1000, E1000_CTRL, CTRL_ASDE);
+}
+
+/** Initialize transmit registers
+ *
+ * @param e1000 E1000 data.
+ *
+ */
+static void e1000_initialize_tx_registers(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_TDLEN, E1000_TX_PACKETS_COUNT * 16);
+	E1000_REG_WRITE(e1000, E1000_TDH, 0);
+	E1000_REG_WRITE(e1000, E1000_TDT, 0);
+	
+	E1000_REG_WRITE(e1000, E1000_TIPG,
+	    10 << TIPG_IPGT_SHIFT |
+	    8 << TIPG_IPGR1_SHIFT |
+	    6 << TIPG_IPGR2_SHIFT);
+	
+	E1000_REG_WRITE(e1000, E1000_TCTL,
+	    0x0F << TCTL_CT_SHIFT /* Collision Threshold */ |
+	    0x40 << TCTL_COLD_SHIFT /* Collision Distance */ |
+	    TCTL_PSP /* Pad Short Packets */);
+}
+
+/** Initialize transmit structure
+ *
+ * @param e1000 E1000 data.
+ *
+ */
+static int e1000_initialize_tx_structure(e1000_t *e1000)
+{
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	int rc = dmamem_map_anonymous(
+	    E1000_TX_PACKETS_COUNT * sizeof(e1000_tx_descriptor_t),
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &e1000->tx_ring_phys,
+	    &e1000->tx_ring_virt);
+	if (rc != EOK)
+		return rc;
+	
+	bzero(e1000->tx_ring_virt,
+	    E1000_TX_PACKETS_COUNT * sizeof(e1000_tx_descriptor_t));
+	
+	E1000_REG_WRITE(e1000, E1000_TDBAH,
+	    (uint32_t) (PTR_TO_U64(e1000->tx_ring_phys) >> 32));
+	E1000_REG_WRITE(e1000, E1000_TDBAL,
+	    (uint32_t) PTR_TO_U64(e1000->tx_ring_phys));
+	
+	e1000->tx_ring_packets =
+	    malloc(E1000_TX_PACKETS_COUNT * sizeof(packet_t *));
+	// FIXME: Check return value
+	
+	e1000_initialize_tx_registers(e1000);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+	return EOK;
+}
+
+/** Uninitialize transmit structure
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_uninitialize_tx_structure(e1000_t *e1000)
+{
+	free(e1000->tx_ring_packets);
+	dmamem_unmap_anonymous(e1000->tx_ring_virt);
+}
+
+/** Clear transmit descriptor ring
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_clear_tx_ring(nic_t *nic)
+{
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_TX_PACKETS_COUNT;
+	    offset++)
+		e1000_clear_tx_descriptor(nic, offset);
+}
+
+/** Enable transmit
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_enable_tx(e1000_t *e1000)
+{
+	/* Set Transmit Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_TCTL,
+	    E1000_REG_READ(e1000, E1000_TCTL) | (TCTL_EN));
+}
+
+/** Disable transmit
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_disable_tx(e1000_t *e1000)
+{
+	/* Clear Transmit Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_TCTL,
+	    E1000_REG_READ(e1000, E1000_TCTL) & ~(TCTL_EN));
+}
+
+/** Reset E1000 device
+ *
+ * @param e1000 The E1000 data
+ *
+ */
+static int e1000_reset(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, CTRL_RST);
+	
+	/* Wait for the reset */
+	usleep(20);
+	
+	/* check if RST_BIT cleared */
+	if (E1000_REG_READ(e1000, E1000_CTRL) & (CTRL_RST))
+		return EINVAL;
+	
+	e1000_initialize_registers(e1000);
+	e1000_initialize_rx_registers(e1000);
+	e1000_initialize_tx_registers(e1000);
+	e1000_fill_mac_from_eeprom(e1000);
+	e1000_initialize_filters(e1000);
+	e1000_initialize_vlan(e1000);
+	
+	return EOK;
+}
+
+/** Activate the device to receive and transmit packets
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if activated successfully
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_activating(nic_t *nic)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	e1000_enable_interrupts(e1000);
+	
+	nic_enable_interrupt(nic, e1000->irq);
+	
+	e1000_clear_rx_ring(e1000);
+	e1000_enable_rx(e1000);
+	
+	e1000_clear_tx_ring(nic);
+	e1000_enable_tx(e1000);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	ctrl |= CTRL_SLU;
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return EOK;
+}
+
+/** Callback for NIC_STATE_DOWN change
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if succeed
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_down_unlocked(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	ctrl &= ~CTRL_SLU;
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	e1000_disable_tx(e1000);
+	e1000_disable_rx(e1000);
+	
+	nic_disable_interrupt(nic, e1000->irq);
+	e1000_disable_interrupts(e1000);
+	
+	/*
+	 * Wait for the for the end of all data
+	 * transfers to descriptors.
+	 */
+	usleep(100);
+	
+	return EOK;
+}
+
+/** Callback for NIC_STATE_DOWN change
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if succeed
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_down(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	int rc = e1000_on_down_unlocked(nic);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return rc;
+}
+
+/** Callback for NIC_STATE_STOPPED change
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if succeed
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_stopping(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	int rc = e1000_on_down_unlocked(nic);
+	if (rc == EOK)
+		rc = e1000_reset(nic);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return rc;
+}
+
+/** Create driver data structure
+ *
+ * @return Intialized device data structure or NULL
+ *
+ */
+static e1000_t *e1000_create_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(!dev->driver_data);
+	
+	nic_t *nic = nic_create_and_bind(dev);
+	if (!nic)
+		return NULL;
+	
+	e1000_t *e1000 = malloc(sizeof(e1000_t));
+	if (!e1000) {
+		nic_unbind_and_destroy(dev);
+		return NULL;
+	}
+	
+	bzero(e1000, sizeof(e1000_t));
+	
+	nic_set_specific(nic, e1000);
+	nic_set_write_packet_handler(nic, e1000_write_packet);
+	nic_set_state_change_handlers(nic, e1000_on_activating,
+	    e1000_on_down, e1000_on_stopping);
+	nic_set_filtering_change_handlers(nic,
+	    e1000_on_unicast_mode_change, e1000_on_multicast_mode_change,
+	    e1000_on_broadcast_mode_change, NULL, e1000_on_vlan_mask_change);
+	nic_set_poll_handlers(nic, e1000_poll_mode_change, e1000_poll);
+	
+	fibril_mutex_initialize(&e1000->ctrl_lock);
+	fibril_mutex_initialize(&e1000->rx_lock);
+	fibril_mutex_initialize(&e1000->tx_lock);
+	fibril_mutex_initialize(&e1000->eeprom_lock);
+	
+	return e1000;
+}
+
+/** Delete driver data structure
+ *
+ * @param data E1000 device data structure
+ *
+ */
+inline static void e1000_delete_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	if (dev->driver_data != NULL)
+		nic_unbind_and_destroy(dev);
+}
+
+/** Clean up the E1000 device structure.
+ *
+ * @param dev Device structure.
+ *
+ */
+static void e1000_dev_cleanup(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	e1000_delete_dev_data(dev);
+	
+	if (dev->parent_sess != NULL) {
+		async_hangup(dev->parent_sess);
+		dev->parent_sess = NULL;
+	}
+}
+
+/** Fill the irq and io_addr part of device data structure
+ *
+ * The hw_resources must be obtained before calling this function
+ *
+ * @param dev          Device structure
+ * @param hw_resources Hardware resources obtained from the parent device
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_fill_resource_info(ddf_dev_t *dev,
+    const hw_res_list_parsed_t *hw_resources)
+{
+	assert(dev != NULL);
+	assert(hw_resources != NULL);
+	assert(dev->driver_data != NULL);
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	if (hw_resources->irqs.count != 1)
+		return EINVAL;
+	
+	e1000->irq = hw_resources->irqs.irqs[0];
+	e1000->reg_base_phys =
+	    MEMADDR_TO_PTR(hw_resources->mem_ranges.ranges[0].address);
+	
+	return EOK;
+}
+
+/** Obtain information about hardware resources of the device
+ *
+ * The device must be connected to the parent
+ *
+ * @param dev Device structure
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_get_resource_info(ddf_dev_t *dev)
+{
+	assert(dev != NULL);
+	assert(NIC_DATA_DEV(dev) != NULL);
+	
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+	
+	/* Get hw resources form parent driver */
+	int rc = nic_get_resources(NIC_DATA_DEV(dev), &hw_res_parsed);
+	if (rc != EOK)
+		return rc;
+	
+	/* Fill resources information to the device */
+	rc = e1000_fill_resource_info(dev, &hw_res_parsed);
+	hw_res_list_parsed_clean(&hw_res_parsed);
+	
+	return rc;
+}
+
+/** Initialize the E1000 device structure
+ *
+ * @param dev Device information
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_device_initialize(ddf_dev_t *dev)
+{
+	/* Allocate driver data for the device. */
+	e1000_t *e1000 = e1000_create_dev_data(dev);
+	if (e1000 == NULL)
+		return ENOMEM;
+	
+	/* Obtain and fill hardware resources info */
+	int rc = e1000_get_resource_info(dev);
+	if (rc != EOK) {
+		e1000_dev_cleanup(dev);
+		return rc;
+	}
+	
+	rc = pci_config_space_read_16(dev->parent_sess, PCI_DEVICE_ID,
+	    &e1000->device_id);
+	if (rc != EOK) {
+		e1000_dev_cleanup(dev);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/** Enable the I/O ports of the device.
+ *
+ * @param dev E1000 device.
+ *
+ * @return EOK if successed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_pio_enable(ddf_dev_t *dev)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	int rc = pio_enable(e1000->reg_base_phys, 8 * PAGE_SIZE,
+	    &e1000->reg_base_virt);
+	if (rc != EOK)
+		return EADDRNOTAVAIL;
+	
+	return EOK;
+}
+
+/** Probe and initialize the newly added device.
+ *
+ * @param dev E1000 device.
+ *
+ */
+int e1000_dev_add(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	/* Initialize device structure for E1000 */
+	int rc = e1000_device_initialize(dev);
+	if (rc != EOK)
+		return rc;
+	
+	/* Device initialization */
+	nic_t *nic = dev->driver_data;
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	/* Map registers */
+	rc = e1000_pio_enable(dev);
+	if (rc != EOK)
+		goto err_destroy;
+	
+	e1000_initialize_registers(e1000);
+	rc = e1000_initialize_tx_structure(e1000);
+	if (rc != EOK)
+		goto err_pio;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	e1000_fill_mac_from_eeprom(e1000);
+	e1000_initialize_filters(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	e1000_initialize_vlan(e1000);
+	
+	rc = nic_register_as_ddf_fun(nic, &e1000_dev_ops);
+	if (rc != EOK)
+		goto err_tx_structure;
+	
+	rc = e1000_register_int_handler(nic);
+	if (rc != EOK)
+		goto err_tx_structure;
+	
+	rc = nic_connect_to_services(nic);
+	if (rc != EOK)
+		goto err_irq;
+	
+	rc = e1000_initialize_rx_structure(nic);
+	if (rc != EOK)
+		goto err_irq;
+	
+	nic_address_t e1000_address;
+	e1000_get_address(e1000, &e1000_address);
+	rc = nic_report_address(nic, &e1000_address);
+	if (rc != EOK)
+		goto err_rx_structure;
+	
+	struct timeval period;
+	period.tv_sec = 0;
+	period.tv_usec = E1000_DEFAULT_INTERRUPT_INTERVAL_USEC;
+	rc = nic_report_poll_mode(nic, NIC_POLL_PERIODIC, &period);
+	if (rc != EOK)
+		goto err_rx_structure;
+	
+	return EOK;
+	
+err_rx_structure:
+	e1000_uninitialize_rx_structure(nic);
+err_irq:
+	unregister_interrupt_handler(dev, DRIVER_DATA_DEV(dev)->irq);
+err_tx_structure:
+	e1000_uninitialize_tx_structure(e1000);
+err_pio:
+	// TODO: e1000_pio_disable(dev);
+err_destroy:
+	e1000_dev_cleanup(dev);
+	return rc;
+}
+
+/** Read 16-bit value from EEPROM of E1000 adapter
+ *
+ * Read using the EERD register.
+ *
+ * @param device         E1000 device
+ * @param eeprom_address 8-bit EEPROM address
+ *
+ * @return 16-bit value from EEPROM
+ *
+ */
+static uint16_t e1000_eeprom_read(e1000_t *e1000, uint8_t eeprom_address)
+{
+	fibril_mutex_lock(&e1000->eeprom_lock);
+	
+	uint32_t eerd_done;
+	uint32_t eerd_address_offset;
+	
+	switch (e1000->device_id) {
+	case 0x107c:
+	case 0x1013:
+	case 0x1018:
+	case 0x1019:
+	case 0x101A:
+	case 0x1076:
+	case 0x1077:
+	case 0x1078:
+	case 0x10b9:
+		/* 82541xx and 82547GI/EI */
+		eerd_done = EERD_DONE_82541XX_82547GI_EI;
+		eerd_address_offset = EERD_ADDRESS_OFFSET_82541XX_82547GI_EI;
+		break;
+	default:
+		eerd_done = EERD_DONE;
+		eerd_address_offset = EERD_ADDRESS_OFFSET;
+		break;
+	}
+	
+	/* Write address and START bit to EERD register */
+	uint32_t write_data = EERD_START |
+	    (((uint32_t) eeprom_address) << eerd_address_offset);
+	E1000_REG_WRITE(e1000, E1000_EERD, write_data);
+	
+	uint32_t eerd = E1000_REG_READ(e1000, E1000_EERD);
+	while ((eerd & eerd_done) == 0) {
+		usleep(1);
+		eerd = E1000_REG_READ(e1000, E1000_EERD);
+	}
+	
+	fibril_mutex_unlock(&e1000->eeprom_lock);
+	
+	return (uint16_t) (eerd >> EERD_DATA_OFFSET);
+}
+
+/** Get MAC address of the E1000 adapter
+ *
+ * @param device  E1000 device
+ * @param address Place to store the address
+ * @param max_len Maximal addresss length to store
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_get_address(e1000_t *e1000, nic_address_t *address)
+{
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	uint8_t *mac0_dest = (uint8_t *) address->address;
+	uint8_t *mac1_dest = (uint8_t *) address->address + 1;
+	uint8_t *mac2_dest = (uint8_t *) address->address + 2;
+	uint8_t *mac3_dest = (uint8_t *) address->address + 3;
+	uint8_t *mac4_dest = (uint8_t *) address->address + 4;
+	uint8_t *mac5_dest = (uint8_t *) address->address + 5;
+	
+	uint32_t rah = E1000_REG_READ(e1000, E1000_RAH_ARRAY(0));
+	uint32_t ral = E1000_REG_READ(e1000, E1000_RAL_ARRAY(0));
+	
+	*mac0_dest = (uint8_t) ral;
+	*mac1_dest = (uint8_t) (ral >> 8);
+	*mac2_dest = (uint8_t) (ral >> 16);
+	*mac3_dest = (uint8_t) (ral >> 24);
+	*mac4_dest = (uint8_t) rah;
+	*mac5_dest = (uint8_t) (rah >> 8);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return EOK;
+};
+
+/** Set card MAC address
+ *
+ * @param device  E1000 device
+ * @param address Address
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ */
+static int e1000_set_addr(ddf_fun_t *dev, const nic_address_t *addr)
+{
+	nic_t *nic = NIC_DATA_DEV(dev);
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	int rc = nic_report_address(nic, addr);
+	if (rc == EOK)
+		e1000_write_receive_address(e1000, 0, addr, false);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return rc;
+}
+
+static void e1000_eeprom_get_address(e1000_t *e1000,
+    nic_address_t *address)
+{
+	uint16_t *mac0_dest = (uint16_t *) address->address;
+	uint16_t *mac2_dest = (uint16_t *) (address->address + 2);
+	uint16_t *mac4_dest = (uint16_t *) (address->address + 4);
+	
+	*mac0_dest = e1000_eeprom_read(e1000, 0);
+	*mac2_dest = e1000_eeprom_read(e1000, 1);
+	*mac4_dest = e1000_eeprom_read(e1000, 2);
+}
+
+/** Send packet
+ *
+ * @param nic    NIC driver data structure
+ * @param packet Packet to send
+ *
+ * @return EOK if succeed
+ * @return Error code in the case of error
+ *
+ */
+static void e1000_write_packet(nic_t *nic, packet_t *packet)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	uint32_t tdt = E1000_REG_READ(e1000, E1000_TDT);
+	e1000_tx_descriptor_t *tx_descriptor_addr = (e1000_tx_descriptor_t *)
+	    (e1000->tx_ring_virt + tdt * sizeof(e1000_tx_descriptor_t));
+	
+	bool descriptor_available = false;
+	
+	/* Descriptor never used */
+	if (tx_descriptor_addr->length == 0)
+		descriptor_available = true;
+	
+	/* Descriptor done */
+	if (tx_descriptor_addr->status & TXDESCRIPTOR_STATUS_DD) {
+		descriptor_available = true;
+		packet_t *old_packet = *(e1000->tx_ring_packets + tdt);
+		if (old_packet) {
+			size_t old_packet_size = packet_get_data_length(old_packet);
+			nic_dma_unlock_packet(old_packet, old_packet_size);
+			nic_release_packet(nic, old_packet);
+		}
+	}
+	
+	if (!descriptor_available) {
+		/* Packet lost */
+		fibril_mutex_unlock(&e1000->tx_lock);
+		return;
+	}
+	
+	size_t packet_size = packet_get_data_length(packet);
+	
+	void *phys;
+	int rc = nic_dma_lock_packet(packet, packet_size, &phys);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&e1000->tx_lock);
+		return;
+	}
+	
+	*(e1000->tx_ring_packets + tdt) = packet;
+	
+	tx_descriptor_addr->phys_addr =
+	    PTR_TO_U64(phys + packet->data_start);
+	tx_descriptor_addr->length = packet_size;
+	
+	/*
+	 * Report status to STATUS.DD (descriptor done),
+	 * add ethernet CRC, end of packet.
+	 */
+	tx_descriptor_addr->command = TXDESCRIPTOR_COMMAND_RS |
+	    TXDESCRIPTOR_COMMAND_IFCS |
+	    TXDESCRIPTOR_COMMAND_EOP;
+	
+	tx_descriptor_addr->checksum_offset = 0;
+	tx_descriptor_addr->status = 0;
+	if (e1000->vlan_tag_add) {
+		tx_descriptor_addr->special = e1000->vlan_tag;
+		tx_descriptor_addr->command |= TXDESCRIPTOR_COMMAND_VLE;
+	} else
+		tx_descriptor_addr->special = 0;
+	
+	tx_descriptor_addr->checksum_start_field = 0;
+	
+	tdt++;
+	if (tdt == E1000_TX_PACKETS_COUNT)
+		tdt = 0;
+	
+	E1000_REG_WRITE(e1000, E1000_TDT, tdt);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+}
+
+int main(void)
+{
+	int rc = nic_driver_init(NAME);
+	if (rc != EOK)
+		return rc;
+	
+	nic_driver_implement(&e1000_driver_ops, &e1000_dev_ops,
+	    &e1000_nic_iface);
+	return ddf_driver_main(&e1000_driver);
+}
Index: uspace/drv/nic/e1k/e1k.h
===================================================================
--- uspace/drv/nic/e1k/e1k.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/e1k/e1k.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2011 Zdenek Bouska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 e1k.h
+ *
+ * Registers, bit positions and masks definition of the E1000 network family
+ * cards
+ *
+ */
+
+#ifndef E1K_H_
+#define E1K_H_
+
+#include <stdint.h>
+
+/** Ethernet CRC size after packet received in rx_descriptor */
+#define E1000_CRC_SIZE  4
+
+#define VET_VALUE  0x8100
+
+#define E1000_RAL_ARRAY(n)   (E1000_RAL + ((n) * 8))
+#define E1000_RAH_ARRAY(n)   (E1000_RAH + ((n) * 8))
+#define E1000_VFTA_ARRAY(n)  (E1000_VFTA + (0x04 * (n)))
+
+/** Receive descriptior */
+typedef struct {
+	/** Buffer Address - physical */
+	uint64_t phys_addr;
+	/** Length is per segment */
+	uint16_t length;
+	/** Checksum - not all types, on some reseved  */
+	uint16_t checksum;
+	/** Status field */
+	uint8_t status;
+	/** Errors field */
+	uint8_t errors;
+	/** Special Field - not all types, on some reseved  */
+	uint16_t special;
+} e1000_rx_descriptor_t;
+
+/** Legacy transmit descriptior */
+typedef struct {
+	/** Buffer Address - physical */
+	uint64_t phys_addr;
+	/** Length is per segment */
+	uint16_t length;
+	/** Checksum Offset */
+	uint8_t checksum_offset;
+	/** Command field */
+	uint8_t command;
+	/** Status field, upper bits are reserved */
+	uint8_t status;
+	/** Checksum Start Field */
+	uint8_t checksum_start_field;
+	/** Special Field */
+	uint16_t special;
+} e1000_tx_descriptor_t;
+
+/** VLAN tag bits */
+enum e1000_vlantag {
+	VLANTAG_CFI = (1 << 12),  /**< Canonical Form Indicator */
+};
+
+/** Transmit descriptor COMMAND field bits */
+enum e1000_txdescriptor_command {
+	TXDESCRIPTOR_COMMAND_VLE = (1 << 6),   /**< VLAN Packet Enable */
+	TXDESCRIPTOR_COMMAND_RS = (1 << 3),    /**< Report Status */
+	TXDESCRIPTOR_COMMAND_IFCS = (1 << 1),  /**< Insert FCS */
+	TXDESCRIPTOR_COMMAND_EOP = (1 << 0)    /**< End Of Packet */
+};
+
+/** Transmit descriptor STATUS field bits */
+enum e1000_txdescriptor_status {
+	TXDESCRIPTOR_STATUS_DD = (1 << 0)  /**< Descriptor Done */
+};
+
+/** E1000 Registers */
+enum e1000_registers {
+	E1000_CTRL = 0x0,      /**< Device Control Register */
+	E1000_STATUS = 0x8,    /**< Device Status Register */
+	E1000_EERD = 0x14,     /**< EEPROM Read Register */
+	E1000_TCTL = 0x400,    /**< Transmit Control Register */
+	E1000_TIPG = 0x410,    /**< Transmit IPG Register */
+	E1000_TDBAL = 0x3800,  /**< Transmit Descriptor Base Address Low */
+	E1000_TDBAH = 0x3804,  /**< Transmit Descriptor Base Address High */
+	E1000_TDLEN = 0x3808,  /**< Transmit Descriptor Length */
+	E1000_TDH = 0x3810,    /**< Transmit Descriptor Head */
+	E1000_TDT = 0x3818,    /**< Transmit Descriptor Tail */
+	E1000_RCTL = 0x100,    /**< Receive Control Register */
+	E1000_RDBAL = 0x2800,  /**< Receive Descriptor Base Address Low */
+	E1000_RDBAH = 0x2804,  /**< Receive Descriptor Base Address High */
+	E1000_RDLEN = 0x2808,  /**< Receive Descriptor Length */
+	E1000_RDH = 0x2810,    /**< Receive Descriptor Head */
+	E1000_RDT = 0x2818,    /**< Receive Descriptor Tail */
+	E1000_RAL = 0x5400,    /**< Receive Address Low */
+	E1000_RAH = 0x5404,    /**< Receive Address High */
+	E1000_VFTA = 0x5600,   /**< VLAN Filter Table Array */
+	E1000_VET = 0x38,      /**< VLAN Ether Type */
+	E1000_FCAL = 0x28,     /**< Flow Control Address Low */
+	E1000_FCAH = 0x2C,     /**< Flow Control Address High */
+	E1000_FCTTV = 0x170,   /**< Flow Control Transmit Timer Value */
+	E1000_FCT = 0x30,      /**< Flow Control Type */
+	E1000_ICR = 0xC0,      /**< Interrupt Cause Read Register */
+	E1000_ITR = 0xC4,      /**< Interrupt Throttling Register */
+	E1000_IMS = 0xD0,      /**< Interrupt Mask Set/Read Register */
+	E1000_IMC = 0xD8       /**< Interrupt Mask Clear Register */
+};
+
+/** EEPROM Read Register fields */
+enum e1000_eerd {
+	/** Start Read */
+	EERD_START = (1 << 0),
+	/** Read Done */
+	EERD_DONE = (1 << 4),
+	/** Read Done for 82541xx and 82547GI/EI */
+	EERD_DONE_82541XX_82547GI_EI = (1 << 1),
+	/** Read Address offset */
+	EERD_ADDRESS_OFFSET = 8,
+	/** Read Address offset for 82541xx and 82547GI/EI */
+	EERD_ADDRESS_OFFSET_82541XX_82547GI_EI = 2,
+	/** Read Data */
+	EERD_DATA_OFFSET = 16
+};
+
+/** Device Control Register fields */
+enum e1000_ctrl {
+	CTRL_FD = (1 << 0),    /**< Full-Duplex */
+	CTRL_LRST = (1 << 3),  /**< Link Reset */
+	CTRL_ASDE = (1 << 5),  /**< Auto-Speed Detection Enable */
+	CTRL_SLU = (1 << 6),   /**< Set Link Up */
+	CTRL_ILOS = (1 << 7),  /**< Invert Loss-of-Signal */
+	
+	/** Speed selection shift */
+	CTRL_SPEED_SHIFT = 8,
+	/** Speed selection size */
+	CTRL_SPEED_SIZE = 2,
+	/** Speed selection all bit set value */
+	CTRL_SPEED_ALL = ((1 << CTRL_SPEED_SIZE) - 1),
+	/** Speed selection shift */
+	CTRL_SPEED_MASK = CTRL_SPEED_ALL << CTRL_SPEED_SHIFT,
+	/** Speed selection 10 Mb/s value */
+	CTRL_SPEED_10 = 0,
+	/** Speed selection 10 Mb/s value */
+	CTRL_SPEED_100 = 1,
+	/** Speed selection 10 Mb/s value */
+	CTRL_SPEED_1000 = 2,
+	
+	CTRL_FRCSPD = (1 << 11),   /**< Force Speed */
+	CTRL_FRCDPLX = (1 << 12),  /**< Force Duplex */
+	CTRL_RST = (1 << 26),      /**< Device Reset */
+	CTRL_VME = (1 << 30),      /**< VLAN Mode Enable */
+	CTRL_PHY_RST = (1 << 31)   /**< PHY Reset */
+};
+
+/** Device Status Register fields */
+enum e1000_status {
+	STATUS_FD = (1 << 0),  /**< Link Full Duplex configuration Indication */
+	STATUS_LU = (1 << 1),  /**< Link Up Indication */
+	
+	/** Link speed setting shift */
+	STATUS_SPEED_SHIFT = 6,
+	/** Link speed setting size */
+	STATUS_SPEED_SIZE = 2,
+	/** Link speed setting all bits set */
+	STATUS_SPEED_ALL = ((1 << STATUS_SPEED_SIZE) - 1),
+	/** Link speed setting 10 Mb/s value */
+	STATUS_SPEED_10 = 0,
+	/** Link speed setting 100 Mb/s value */
+	STATUS_SPEED_100 = 1,
+	/** Link speed setting 1000 Mb/s value variant A */
+	STATUS_SPEED_1000A = 2,
+	/** Link speed setting 1000 Mb/s value variant B */
+	STATUS_SPEED_1000B = 3,
+};
+
+/** Transmit IPG Register fields
+ *
+ * IPG = Inter Packet Gap
+ *
+ */
+enum e1000_tipg {
+	TIPG_IPGT_SHIFT = 0,    /**< IPG Transmit Time shift */
+	TIPG_IPGR1_SHIFT = 10,  /**< IPG Receive Time 1 */
+	TIPG_IPGR2_SHIFT = 20   /**< IPG Receive Time 2 */
+};
+
+/** Transmit Control Register fields */
+enum e1000_tctl {
+	TCTL_EN = (1 << 1),    /**< Transmit Enable */
+	TCTL_PSP =  (1 << 3),  /**< Pad Short Packets */
+	TCTL_CT_SHIFT = 4,     /**< Collision Threshold shift */
+	TCTL_COLD_SHIFT = 12   /**< Collision Distance shift */
+};
+
+/** ICR register fields */
+enum e1000_icr {
+	ICR_TXDW = (1 << 0),  /**< Transmit Descriptor Written Back */
+	ICR_RXT0 = (1 << 7)   /**< Receiver Timer Interrupt */
+};
+
+/** RAH register fields */
+enum e1000_rah {
+	RAH_AV = (1 << 31)   /**< Address Valid */
+};
+
+/** RCTL register fields */
+enum e1000_rctl {
+	RCTL_EN = (1 << 1),    /**< Receiver Enable */
+	RCTL_SBP = (1 << 2),   /**< Store Bad Packets */
+	RCTL_UPE = (1 << 3),   /**< Unicast Promiscuous Enabled */
+	RCTL_MPE = (1 << 4),   /**< Multicast Promiscuous Enabled */
+	RCTL_BAM = (1 << 15),  /**< Broadcast Accept Mode */
+	RCTL_VFE = (1 << 18)   /**< VLAN Filter Enable */
+};
+
+#endif
Index: uspace/drv/nic/e1k/e1k.ma
===================================================================
--- uspace/drv/nic/e1k/e1k.ma	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/e1k/e1k.ma	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,26 @@
+10 pci/ven=8086&dev=100e
+10 pci/ven=8086&dev=100f
+10 pci/ven=8086&dev=1010
+10 pci/ven=8086&dev=1011
+10 pci/ven=8086&dev=1012
+10 pci/ven=8086&dev=1013
+10 pci/ven=8086&dev=1015
+10 pci/ven=8086&dev=1016
+10 pci/ven=8086&dev=1017
+10 pci/ven=8086&dev=1018
+10 pci/ven=8086&dev=1019
+10 pci/ven=8086&dev=101a
+10 pci/ven=8086&dev=101d
+10 pci/ven=8086&dev=1026
+10 pci/ven=8086&dev=1027
+10 pci/ven=8086&dev=1028
+10 pci/ven=8086&dev=1076
+10 pci/ven=8086&dev=1077
+10 pci/ven=8086&dev=1078
+10 pci/ven=8086&dev=1079
+10 pci/ven=8086&dev=107a
+10 pci/ven=8086&dev=107b
+10 pci/ven=8086&dev=107c
+10 pci/ven=8086&dev=1107
+10 pci/ven=8086&dev=1112
+10 pci/ven=8086&dev=10b9
Index: uspace/drv/nic/ne2k/dp8390.c
===================================================================
--- uspace/drv/nic/ne2k/dp8390.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/drv/nic/ne2k/dp8390.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -142,8 +142,9 @@
 static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
 {
+	size_t esize_ru = (size + 1) & ~1;
 	size_t esize = size & ~1;
 	
-	pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
-	pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
+	pio_write_8(ne2k->port + DP_RBCR0, esize_ru & 0xff);
+	pio_write_8(ne2k->port + DP_RBCR1, (esize_ru >> 8) & 0xff);
 	pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
 	pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
Index: uspace/drv/nic/rtl8139/Makefile
===================================================================
--- uspace/drv/nic/rtl8139/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011 Radim Vansa
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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 $(LIBNET_PREFIX)/libnet.a $(LIBNIC_PREFIX)/libnic.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include -I$(LIBNIC_PREFIX)/include
+BINARY = rtl8139
+
+SOURCES = \
+	driver.c \
+	general.c \
+	defs.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/rtl8139/defs.c
===================================================================
--- uspace/drv/nic/rtl8139/defs.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/defs.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "rtl8139_defs.h"
+
+const char* model_names[RTL8139_VER_COUNT] = {
+	"RTL8139",
+	"RTL8139A",
+	"RTL8139A_G",
+	"RTL8139B",
+	"RTL8130",
+	"RTL8139C",
+	"RTL8100",
+	"RTL8139C+",
+	"RTL8139D",
+	"RTL8101"
+};
+
+#define HWVER(b1, b2, b3, b4, b5, b6, b7) ((b1 << 6) | (b2 << 5) | (b3 << 4) \
+    | (b4 << 3) | (b5 << 2) | (b6 << 1) | (b7))
+
+const struct rtl8139_hwver_map rtl8139_versions[RTL8139_VER_COUNT + 1] = {
+	{ HWVER(1,1,0,0,0,0,0), RTL8139 },
+	{ HWVER(1,1,1,0,0,0,0), RTL8139A },
+	{ HWVER(1,1,1,0,0,1,0), RTL8139A_G },
+	{ HWVER(1,1,1,1,0,0,0), RTL8139B },
+	{ HWVER(1,1,1,1,1,0,0), RTL8130 },
+	{ HWVER(1,1,1,0,1,0,0), RTL8139C },
+	{ HWVER(1,1,1,1,0,1,0), RTL8100 },
+	{ HWVER(1,1,1,0,1,0,1), RTL8139D },
+	{ HWVER(1,1,1,0,1,1,0), RTL8139Cp },
+	{ HWVER(1,1,1,0,1,1,1), RTL8101 },
+	/* End value */
+	{ 0, RTL8139_VER_COUNT}
+};
+
Index: uspace/drv/nic/rtl8139/defs.h
===================================================================
--- uspace/drv/nic/rtl8139/defs.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/defs.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 rtl8139_defs.h
+ *
+ *  Registers, bit positions and masks definition of the RTL8139 network family 
+ *  cards
+ */
+
+#ifndef RTL8139_DEFS_H_INCLUDED_
+#define RTL8139_DEFS_H_INCLUDED_
+#include <sys/types.h>
+#include <libarch/ddi.h>
+
+
+/** The size of RTL8139 registers address space */
+#define RTL8139_IO_SIZE 256
+
+/** The maximal transmitted packet length in bytes allowed according to RTL8139
+ *  documentation (see SIZE part of TSD documentation)
+ */
+#define RTL8139_PACKET_MAX_LENGTH 1792
+
+
+/** HW version
+ *
+ *  as can be detected from HWVERID part of TCR
+ *  (Transmit Configuration Register)
+ */
+enum rtl8139_version_id {
+	RTL8139 = 0,          /**< RTL8139 */
+	RTL8139A,             /**< RTL8139A */
+	RTL8139A_G,           /**< RTL8139A-G */
+	RTL8139B,             /**< RTL8139B */
+	RTL8130,              /**< RTL8130 */
+	RTL8139C,             /**< RTL8139C */
+	RTL8100,              /**< RTL8100 */
+	RTL8139Cp,            /**< RTL8139C+ */
+	RTL8139D,             /**< RTL8139D */
+	RTL8100B = RTL8139D,  /**< RTL8100B and RTL8139D, the same HWVERID in TCR */
+	RTL8101,              /**< RTL8101 */
+	RTL8139_VER_COUNT     /**< Count of known RTL versions, the last value */
+};
+
+extern const char* model_names[RTL8139_VER_COUNT];
+
+/** Registers of RTL8139 family card offsets from the memory address base */
+enum rtl8139_registers {
+	IDR0  = 0x00,    /**< First MAC address bit, 6 1b registres sequence */
+	MAC0  = IDR0,    /**< Alias for IDR0 */
+
+	// 0x6 - 0x7 reserved
+
+	MAR0    = 0x08,  /**< Multicast mask registers 8 1b registers sequence */
+
+	TSD0    = 0x10,  /**< Transmit status of descriptor 0 */
+	TSD1    = 0x14,  /**< Transmit status of descriptor 1 */
+	TSD2    = 0x18,  /**< Transmit status of descriptor 2 */
+	TSD3    = 0x1C,  /**< Transmit status of descriptor 3 */
+
+	TSAD0   = 0x20,  /**< Physical address of the 1st transmitter buffer, 4b */
+	TSAD1   = 0x24,  /**< Physical address of the 2nd transmitter buffer, 4b */
+	TSAD2   = 0x28,  /**< Physical address of the 3rd transmitter buffer, 4b */
+	TSAD3   = 0x3C,  /**< Physical address of the 4th transmitter buffer, 4b */
+
+	RBSTART = 0x30,  /**< Receive (Rx) buffer start address, 4b */
+	ERBCR   = 0x34,  /**< Early receive (Rx) byte count register, 2b */
+	ERSR    = 0x36,  /**< Early receive (Rx) status register, 1b */
+
+	CR      = 0x37,  /**< Command register, 1b */
+	CAPR    = 0x38,  /**< Current address of packet read, 2b */
+	CBA     = 0x3a,  /**< Current buffer address, 2b */
+
+	IMR     = 0x3c,  /**< Interrupt mask register, 2b */
+	ISR     = 0x3e,  /**< Interrupt status register, 2b */
+
+	TCR     = 0x40,  /**< Transmit (Tx) configuration register, 4b */
+	RCR     = 0x44,  /**< Receive (Rx) configuration register, 4b */
+
+	TCTR    = 0x48,  /**< Timer count register */
+	MPC     = 0x4c,  /**< Missed packet count */
+
+	CR9346  = 0x50,  /**< 93C46 command register (locking of registers) */
+
+	CONFIG0 = 0x51,  /**< Configuration register 0, 1b */
+	CONFIG1 = 0x52,  /**< Configuration register 1, 1b */
+
+	// 0x53 reserved
+
+	TIMERINT = 0x54,  /**< Timer interrupt register, 4b */
+	MSR      = 0x58,  /**< Media status register, 1b */
+
+	CONFIG3  = 0x59,  /**< Configuration register 3, 1b */
+	CONFIG4  = 0x5a,  /**< Configuration register 4, 1b */
+
+	// 0x5b reserved
+
+	MULINT   = 0x5c,  /**< Multiple interrupt select, 2b */
+	RERID    = 0x5e,  /**< PCI revision ID = 0x10, 1b */
+
+	// 0x5f reserved
+
+	TSALLD  = 0x60,   /**< Transmit status of all descriptors, 2b */
+
+	BMCR    = 0x62,   /**< Basic mode control register */
+	BMSR    = 0x64,   /**< Basic mode status register */
+
+	ANAR    = 0x66,   /**< Auto-negotiation advertisement register */
+	ANLPAR  = 0x68,   /**< Auto-negotiation link partner register */
+	ANER    = 0x6a,   /**< Auto-negotiation expansion register */
+	DIS     = 0x6c,   /**< Disconnect counter */
+	FCSC    = 0x6e,   /**< False carrier sense counter */
+	NWAYTR  = 0x70,   /**< n-way test register */
+	REC     = 0x72,   /**< RX_ER counter */
+	CSCR    = 0x74,   /**< CS configuration register */
+
+	// 0x76 - 0x77 reserved
+
+	PHY1_PARM = 0x78, /**< PHY parameter 1 */
+	TW_PARM   = 0x7c, /**< Twister parameter */
+	PHY2_PARM = 0x80, /**< PHY parameter 2 */
+
+	// 0x81 reserved
+
+	TDOKLA  = 0x82,   /**< Low Address of a Tx Descriptor with Tx DMA Ok */
+	CRC0    = 0x84,   /**< Power Management CRC register0 for wakeup frame 0 */
+	WAKEUP0 = 0x8c,   /**< Power Management wakeup frame 0 */
+	LSBCRC0 = 0xcc,   /**< Least significant masked byte of WF0 */
+	FLASH   = 0xd4,   /**< Flash memory read/write register */
+
+	CONFIG5 = 0xd8,   /**< Configuration register 5 */
+
+	TPPOL   = 0xd9,   /**< Transmit priority polling register */
+
+	// 0xda - 0xdf reserved
+
+	CPCR    = 0xe0,   /**< C+ mode command register */
+
+	// 0xe2 - 0xe3 reserved
+
+	RDSAR   = 0xe4,   /**< Receive Descriptor Start Address Register */
+	ETTHR   = 0xec,   /**< Early transmit threshold register */
+
+	// 0xed - 0xef reserved
+
+	FER   = 0xf0,    /**< Function event register */
+	FEMR  = 0xf4,    /**< Function event mask register */
+	FPSR  = 0xf8,    /**< Function present state register */
+	FFER  = 0xfc,    /**< Function force event register */
+	MIIR  = 0xfc     /**< MII register */
+};
+
+/** Mask of valid bits in MPC value */
+#define MPC_VMASK UINT32_C(0xFFFFFF);
+
+/** Command register bits */
+enum rtl8139_cr {
+	CR_BUFE = (1 << 0),  /**< Buffer empty bit - read only */
+	CR_TE   = (1 << 2),  /**< Transmitter enable bit */
+	CR_RE   = (1 << 3),  /**< Receiver enable bit */
+	CR_RST  = (1 << 4)   /**< Reset -  set to 1 to force software reset */
+};
+
+/** Config1 register bits */
+enum rtl8139_config1 {
+	CONFIG1_LEDS_SHIFT = 6,       /**< Shift of CONFIG1_LEDS bits */
+	CONFIG1_LEDS_SIZE  = 2,       /**< Size of CONFIG1_LEDS bits */
+
+	CONFIG1_DVRLOAD  = (1 << 5),  /**< Driver load */
+	CONFIG1_LWACT    = (1 << 4),  /**< LWAKE active mode */
+	CONFIG1_MEMMAP   = (1 << 3),  /**< Memory mapping  */
+	CONFIG1_IOMAP    = (1 << 2),  /**< I/O space mapping */
+	CONFIG1_VPD      = (1 << 1),  /**< Set to enable Vital Product Data */
+	CONFIG1_PMEn     = (1 << 0)   /**< Power management enabled */
+};
+
+/** Mask of 9346CR register for lock configuration registers */
+#define RTL8139_REGS_LOCKED 0
+/** Mask of 9346CR register for unlock configuration registers */
+#define RTL8139_REGS_UNLOCKED 0xC0
+
+/** Put rtl8139 to normal mode.
+ *
+ * Writing to Config0-4 and part of BMCR registers is not allowed
+ */
+static inline void rtl8139_regs_lock(void *io_base)
+{
+	pio_write_8(io_base + CR9346, RTL8139_REGS_LOCKED);
+}
+/** Allow to change Config0-4 and BMCR register  */
+static inline void rtl8139_regs_unlock(void *io_base)
+{
+	pio_write_8((io_base) + CR9346, RTL8139_REGS_UNLOCKED);
+}
+
+/** Force soft reset of the chip. After it:
+ *	receiver and transmitter are disabled
+ *	transmitter FIFO is cleared
+ *	transmitter buffer is set to TSDA0
+ *	receiver buffer is empty
+ *
+ *	The reset bit in command register must be set to 1, the value of the
+ *	the register is 1 during reset operation
+ *
+ *	@param base_port The base address of the port mappings
+ */
+#define rtl8139_hw_reset(base_port)\
+	{\
+		pio_write_8(base_port + CR, CR_RST);\
+		while((pio_read_8(base_port + CR) & CR_RST) != 0);\
+	}
+
+/** Interrupt_masks
+ *
+ *  The masks are the same for both IMR and ISR
+ */
+enum rtl8139_interrupts {
+	INT_SERR          = (1 << 15),  /**< System error interrupt */
+	INT_TIME_OUT      = (1 << 14),  /**< Time out interrupt */
+	INT_LENGTH_CHANGE = (1 << 13),  /**< Cable length change interrupt  */
+
+	/* bits 7 - 12 reserved */
+
+	INT_FIFOOVW = (1 << 6),   /**< Receiver FIFO overflow interrupt */
+	INT_PUN     = (1 << 5),   /**< Packet Underrun/Link Change Interrupt  */
+	INT_RXOVW   = (1 << 4),   /**< Receiver buffer overflow */
+	INT_TER     = (1 << 3),   /**< Transmit error interrupt */
+	INT_TOK     = (1 << 2),   /**< Transmit OK interrupt */
+	INT_RER     = (1 << 1),   /**< Receive error interrupt */
+	INT_ROK     = (1 << 0)    /**< Receive OK interrupt */
+};
+
+/** Transmit status descriptor registers bits */
+enum rtl8139_tsd {
+	TSD_CRS          = (1 << 31),   /**< Carrier Sense Lost */
+	TSD_TABT         = (1 << 30),   /**<  Transmit Abort */
+	TSD_OWC          = (1 << 29),   /**< Out of Window Collision */
+	TSD_CDH          = (1 << 28),   /**< CD Heart Beat */
+	TSD_NCC_SHIFT    = 24,          /**< Collision Count - bit shift */
+	TSD_NCC_SIZE     = 4,           /**< Collision Count - bit size */
+	TSD_NCC_MASK     = (1 << 4)-1,  /**< Collision Count - bit size */
+	TSD_ERTXTH_SHIFT = 16,          /**< Early Tx Threshold - bit shift */
+	TSD_ERTXTH_SIZE  = 6,           /**< Early Tx  Treshold - bit size */
+	TSD_TOK          = (1 << 15),   /**< Transmit OK */
+	TSD_TUN          = (1 << 14),   /**< Transmit FIFO Underrun */
+	TSD_OWN          = (1 << 13),   /**< OWN */
+	TSD_SIZE_SHIFT   = 0,           /**< Size - bit shift */
+	TSD_SIZE_SIZE    = 13,          /**< Size - bit size */
+	TSD_SIZE_MASK    = 0x1fff       /**< Size - bit mask */
+};
+
+/** Receiver control register values */
+enum rtl8139_rcr {
+	RCR_ERTH_SHIFT = 24,       /**< Early Rx treshold part shift */
+	RCR_ERTH_SIZE = 4,         /**< Early Rx treshold part size */
+
+	RCR_MulERINT = 1 << 17,    /**< Multiple early interrupt select */
+
+	/** Minimal error packet length (1 = 8B, 0 = 64B). If AER/AR is set, RER8
+	 * is "Don't care"
+	 */
+	RCR_RER8 = 1 << 16,
+
+	RCR_RXFTH_SHIFT = 13,    /**< Rx FIFO treshold part shitf */
+	RCR_RXFTH_SIZE  = 3,     /**< Rx FIFO treshold part size */
+
+	RCR_RBLEN_SHIFT = 11,    /**< Rx buffer length part shift */
+	RCR_RBLEN_SIZE  = 2,     /**< Rx buffer length part size */
+
+	RCR_RBLEN_8k  = 0x00 << RCR_RBLEN_SHIFT,  /**< 8K + 16 byte rx buffer */
+	RCR_RBLEN_16k = 0x01 << RCR_RBLEN_SHIFT,  /**< 16K + 16 byte rx buffer */
+	RCR_RBLEN_32k = 0x02 << RCR_RBLEN_SHIFT,  /**< 32K + 16 byte rx buffer */
+	RCR_RBLEN_64k = 0x03 << RCR_RBLEN_SHIFT,  /**< 64K + 16 byte rx buffer */
+
+	RCR_MXDMA_SHIFT = 8,             /**< Max DMA Burst Size part shift */
+	RCR_MXDMA_SIZE  = 3,             /**< Max DMA Burst Size part size */
+
+	RCR_WRAP              = 1 << 7,  /**< Rx buffer wrapped */
+	RCR_ACCEPT_ERROR      = 1 << 5,  /**< Accept error packet */
+	RCR_ACCEPT_RUNT       = 1 << 4,  /**< Accept Runt (8-64 bytes) packets */
+	RCR_ACCEPT_BROADCAST  = 1 << 3,  /**< Accept broadcast */
+	RCR_ACCEPT_MULTICAST  = 1 << 2,  /**< Accept multicast */
+	RCR_ACCEPT_PHYS_MATCH = 1 << 1,  /**< Accept device MAC address match */
+	RCR_ACCEPT_ALL_PHYS   = 1 << 0,  /**< Accept all packets with 
+	                                  * phys. desticnation 
+									  */
+	RCR_ACCEPT_MASK = (1 << 6) - 1   /**< Mask of accept part */
+};
+
+
+/** CSCR register bits */
+enum rtl8139_cscr {
+	CS_Testfun       = (1 << 15),
+	CS_LD            = (1 << 9),  /**< Low TPI link disable signal */
+	CS_HEART_BEAT    = (1 << 8),  /**< Heart beat enable; 10Mbit mode only */
+	CS_JABBER_ENABLE = (1 << 7),  /**< Enable jabber function */
+	CS_F_LINK100     = (1 << 6),
+	CS_F_CONNECT     = (1 << 5),
+	CS_CON_STATUS    = (1 << 3),  /**< connection status: 
+	                               *   1 = valid, 0 = disconnected 
+								   */
+	CS_CON_STATUS_EN = (1 << 2),  /**< LED1 pin connection status indication */
+	CS_PASS_SCR      = (1 << 0)   /**< Bypass Scramble  */
+};
+
+/** MSR register bits */
+enum rtl8139_msr {
+	MSR_TXFCE       = (1 << 7),  /**< Transmitter flow control enable */
+	MSR_RXFCE       = (1 << 6),  /**< Receiver flow control enable */
+
+	MSR_AUX_PRESENT = (1 << 4),  /**< Aux. Power present Status */
+	MSR_SPEED10     = (1 << 3),  /**< 10MBit mode sign (1 = 10Mb, 0 = 100Mb) */
+	MSR_LINKB       = (1 << 2),  /**< Link Bad (fail) */
+	MSR_TXPF        = (1 << 1),  /**< Transmitter pause flag */
+	MSR_RXPF        = (1 << 0)   /**< Receiver pause flag */
+};
+
+/** BMCR register bits (basic mode control register) */
+enum rtl8139_bmcr {
+	BMCR_Reset     = (1 << 15),  /**< Software reset */
+	BMCR_Spd_100   = (1 << 13),  /**< 100 MBit mode set, 10 MBit otherwise */
+	BMCR_AN_ENABLE = (1 << 12),  /**< Autonegotion enable */
+
+	/* 10,11 reserved*/
+
+	BMCR_AN_RESTART = (1 << 9),  /**< Restart autonegotion */
+	BMCR_DUPLEX     = (1 << 8)   /**< Duplex mode: 1=full duplex */
+
+	/* 0-7 reserved */
+};
+
+/** Auto-negotiation advertisement register */
+enum rtl8139_anar {
+	ANAR_NEXT_PAGE    = (1 << 15),  /**< Next page bit, 0 - primary capability
+	                                 *  1 - protocol specific 
+									 */
+	ANAR_ACK          = (1 << 14),  /**< Capability reception acknowledge */
+	ANAR_REMOTE_FAULT = (1 << 13),  /**< Remote fault detection capability */
+	ANAR_PAUSE        = (1 << 10),  /**< Symetric pause packet capability */
+	ANAR_100T4        = (1 << 9),   /**< T4, not supported by the device */
+	ANAR_100TX_FD     = (1 << 8),   /**< 100BASE_TX full duplex */
+	ANAR_100TX_HD     = (1 << 7),   /**< 100BASE_TX half duplex */
+	ANAR_10_FD        = (1 << 6),   /**< 10BASE_T full duplex */
+	ANAR_10_HD        = (1 << 5),   /**< 10BASE_T half duplex */
+	ANAR_SELECTOR     = 0x1         /**< Selector, 
+	                                 *   CSMA/CD (0x1) supported only
+									 */
+};
+
+/**  Autonegotiation expansion register bits */
+enum rtl8139_aner {
+	ANER_MFL        = (1 << 4),  /**< Multiple link fault occured */
+	ANER_LP_NP_ABLE = (1 << 3),  /**< Link parent supports next page */
+	ANER_NP_ABLE    = (1 << 2),  /**< Local node is able to send next pages */
+	ANER_PAGE_RX    = (1 << 1),  /** New page received, cleared on LPAR read */
+	ANER_LP_NW_ABLE = (1 << 0)   /**< Link partner autonegotiation support */
+};
+
+enum rtl8139_config5 {
+	CONFIG5_BROADCAST_WAKEUP = (1 << 6),  /**< Broadcast wakeup frame enable */
+	CONFIG5_MULTICAST_WAKEUP = (1 << 5),  /**< Multicast wakeup frame enable */
+	CONFIG5_UNICAST_WAKEUP   = (1 << 4),  /**< Unicast wakeup frame enable */
+
+	/** Descending/ascending grow of Rx/Tx FIFO (to test FIFO SRAM only) */
+	CONFIG5_FIFO_ADDR_PTR = (1 << 3),    
+	/** Powersave if cable is disconnected */
+	CONFIG5_LINK_DOWN_POWERSAVE = (1 << 2), 
+
+	CONFIG5_LAN_WAKE     = (1 << 1),   /**< LANWake signal enabled */
+	CONFIG5_PME_STATUS   = (1 << 0)    /**< PMEn change: 0 = SW, 1 = SW+PCI */
+};
+
+enum rtl8139_config3 {
+	CONFIG3_GNT_SELECT = (1 << 7),  /**< Gnt select */
+	CONFIG3_PARM_EN    = (1 << 6),  /**< Parameter enabled (100MBit mode) */
+	CONFIG3_MAGIC      = (1 << 5),  /**< WoL Magic packet enable */
+	CONFIG3_LINK_UP    = (1 << 4),  /**< Wakeup if link is reestablished */
+	CONFIG3_CLKRUN_EN  = (1 << 2),  /**< CLKRUN enabled */ /* TODO: check what does it mean */
+	CONFIG3_FBTBEN     = (1 << 0)   /**< Fast back to back enabled */
+};
+
+enum rtl8139_config4 {
+	CONFIG4_RxFIFOAutoClr = (1 << 7),  /**< Automatic RxFIFO owerflow clear */
+	CONFIG4_AnaOff        = (1 << 6),  /**< Analog poweroff */
+	CONFIG4_LongWF        = (1 << 5),  /**< Long wakeup frame 
+	                                    *   (2xCRC8 + 3xCRC16) 
+										*/
+	CONFIG4_LWPME         = (1 << 4),  /**< LWAKE and PMEB assertion  */
+	CONFIG4_LWPTN         = (1 << 2),  /**< LWake pattern */
+	CONFIG4_PBWakeup      = (1 << 0)   /**< Preboot wakeup */
+};
+
+/** Maximal runt packet size + 1 */
+#define RTL8139_RUNT_MAX_SIZE 64
+
+/** Bits in packet header */
+enum rtl8139_packet_header {
+	RSR_MAR  = (1 << 15),  /**< Multicast received */
+	RSR_PAM  = (1 << 14),  /**< Physical address match */
+	RSR_BAR  = (1 << 13),  /**< Broadcast match */
+
+	RSR_ISE  = (1 << 5),   /**< Invalid symbol error, 100BASE-TX only */
+	RSR_RUNT = (1 << 4),   /**< Runt packet (< RTL8139_RUNT_MAX_SIZE bytes) */
+
+	RSR_LONG = (1 << 3),   /**< Long packet (size > 4k bytes) */
+	RSR_CRC  = (1 << 2),   /**< CRC error */
+	RSR_FAE  = (1 << 1),   /**< Frame alignment error */
+	RSR_ROK  = (1 << 0)    /**< Good packet received */
+};
+
+enum rtl8139_tcr_bits {
+	HWVERID_A_SHIFT = 26,           /**< HW version id, part A shift */
+	HWVERID_A_SIZE  = 5,            /**< HW version id, part A bit size */
+	HWVERID_A_MASK  = (1 << 5) - 1, /**< HW version id, part A mask */
+
+	IFG_SHIFT = 24,           /**< The interframe gap time setting shift */
+	IFG_SIZE  = 2,            /**< The interframe gap time setting bit size */
+
+	HWVERID_B_SHIFT = 22,           /**< HW version id, part B shift */
+	HWVERID_B_SIZE  = 2,            /**< HW version id, part B bit size */
+	HWVERID_B_MASK  = (1 << 2) - 1, /**< HW version id, part B mask */
+
+	LOOPBACK_SHIFT  = 17,           /**< Loopback mode shift */
+	LOOPBACK_SIZE   = 2,            /**< Loopback mode size 
+	                                  *  00 = normal, 11 = loopback 
+									  */
+
+	APPEND_CRC = 1 << 16,        /**< Append CRC at the end of a packet */
+
+	MXTxDMA_SHIFT = 8,  /**< Max. DMA Burst per TxDMA shift, burst = 16^value */
+	MXTxDMA_SIZE  = 3,  /**< Max. DMA Burst per TxDMA bit size */
+
+	TX_RETRY_COUNT_SHIFT = 4,            /**< Retries before aborting shift */
+	TX_RETRY_COUNT_SIZE  = 4,            /**< Retries before aborting size */
+
+	CLEAR_ABORT = 1 << 0    /**< Retransmit aborted packet at the last 
+	                          *  transmitted descriptor 
+							  */
+};
+
+#define RTL8139_HWVERID_A(tcr) (((tcr) >> HWVERID_A_SHIFT) & HWVERID_A_MASK)
+#define RTL8139_HWVERID_B(tcr) (((tcr) >> HWVERID_B_SHIFT) & HWVERID_B_MASK)
+#define RTL8139_HWVERID(tcr) ((RTL8139_HWVERID_A(tcr) << HWVERID_B_SIZE) | \
+    RTL8139_HWVERID_B(tcr))
+
+/** Mapping of HW version -> version ID */
+struct rtl8139_hwver_map { 
+	uint32_t hwverid;                /**< HW version value in the register */
+	enum rtl8139_version_id ver_id;  /**< appropriate version id */
+};
+
+/** Mapping of HW version -> version ID */
+extern const struct rtl8139_hwver_map rtl8139_versions[RTL8139_VER_COUNT + 1];
+
+/** Size in the packet header while copying from RxFIFO to Rx buffer */
+#define RTL8139_EARLY_SIZE UINT16_C(0xfff0)
+/** The only supported pause packet time value */
+#define RTL8139_PAUSE_VAL UINT16_C(0xFFFF)
+
+/** Size of the packet header in front of the received frame */
+#define RTL_PACKET_HEADER_SIZE 4
+
+/** 8k buffer */
+#define RTL8139_RXFLAGS_SIZE_8  0
+/** 16k buffer */
+#define RTL8139_RXFLAGS_SIZE_16 1
+/** 32k buffer */
+#define RTL8139_RXFLAGS_SIZE_32 2
+/** 64k buffer */
+#define RTL8139_RXFLAGS_SIZE_64 3
+
+/** Get the buffer initial size without 16B padding 
+ *  Size is (8 + 2^flags) kB (^ in mean power)
+ *
+ *  @param flags The flags for Rx buffer size, 0-3
+ */
+#define RTL8139_RXSIZE(flags) (1 << (13 + (flags)))
+
+/** Padding of the receiver buffer */
+#define RTL8139_RXBUF_PAD 16
+/** Size needed for buffer allocation */
+#define RTL8139_RXBUF_LENGTH(flags) (RTL8139_RXSIZE(flags) + RTL8139_RXBUF_PAD)
+
+#endif
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/driver.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,2173 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <assert.h>
+#include <errno.h>
+#include <align.h>
+#include <byteorder.h>
+#include <libarch/ddi.h>
+#include <libarch/barrier.h>
+#include <nlog.h>
+
+#include <dma.h>
+#include <ddf/interrupt.h>
+#include <devman.h>
+#include <nic.h>
+#include <packet_client.h>
+#include <device/pci.h>
+
+#include <ipc/irc.h>
+#include <sysinfo.h>
+#include <ipc/ns.h>
+
+#include <net_checksum.h>
+
+#include <str.h>
+
+#include "rtl8139_defs.h"
+#include "rtl8139_driver.h"
+#include "rtl8139_general.h"
+
+/** Global mutex for work with shared irq structure */
+FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
+/** Lock interrupt structure mutex */
+#define RTL8139_IRQ_STRUCT_LOCK() fibril_mutex_lock(&irq_reg_lock)
+/** Unlock interrupt structure mutex */
+#define RTL8139_IRQ_STRUCT_UNLOCK() fibril_mutex_unlock(&irq_reg_lock)
+
+/** PCI clock frequency in kHz */
+#define RTL8139_PCI_FREQ_KHZ 33000
+
+#define RTL8139_AUTONEG_CAPS (ETH_AUTONEG_10BASE_T_HALF \
+    | ETH_AUTONEG_10BASE_T_FULL | ETH_AUTONEG_100BASE_TX_HALF \
+    | ETH_AUTONEG_100BASE_TX_FULL | ETH_AUTONEG_PAUSE_SYMETRIC)
+
+/** Lock transmitter and receiver data
+ *  This function shall be called whenever both transmitter and receiver locking
+ *  to force safe lock ordering (deadlock prevention)
+ *
+ *  @param rtl8139  RTL8139 private data
+ */
+inline static void rtl8139_lock_all(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+	fibril_mutex_lock(&rtl8139->tx_lock);
+	fibril_mutex_lock(&rtl8139->rx_lock);
+}
+
+/** Unlock transmitter and receiver data
+ *
+ *  @param rtl8139  RTL8139 private data
+ */
+inline static void rtl8139_unlock_all(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	fibril_mutex_unlock(&rtl8139->tx_lock);
+}
+
+#ifndef RXBUF_SIZE_FLAGS
+	/** Flags for receiver buffer - 16kB default */
+	#define RXBUF_SIZE_FLAGS RTL8139_RXFLAGS_SIZE_16
+#endif
+
+#if (RXBUF_SIZE_FLAGS > RTL8139_RXFLAGS_SIZE_64) || (RXBUF_SIZE_FLAGS < 0)
+	#error Bad receiver buffer flags size flags
+#endif
+
+/** Size of the receiver buffer
+ *
+ *  Incrementing flags by one twices the buffer size
+ *  the lowest size is 8*1024 (flags = 0)
+ */
+#define RxBUF_SIZE RTL8139_RXSIZE(RXBUF_SIZE_FLAGS)
+
+/** Total size of the receiver buffer to allocate */
+#define RxBUF_TOT_LENGTH RTL8139_RXBUF_LENGTH(RXBUF_SIZE_FLAGS)
+
+
+/** Default interrupt mask */
+#define RTL_DEFAULT_INTERRUPTS UINT16_C(0xFFFF)
+
+/** Obtain the value of the register part
+ *  The bit operations will be done
+ *  The _SHIFT and _MASK for the register part must exists as macros
+ *  or variables
+ */
+#define REG_GET_VAL(value, reg_part)\
+		(((value) >> reg_part##_SHIFT) & reg_part##_MASK)
+
+
+/** Disable interrupts on controller
+ *
+ *  @param rtl8139  The card private structure
+ */
+inline static void rtl8139_hw_int_disable(rtl8139_t *rtl8139)
+{
+	pio_write_16(rtl8139->io_port + IMR, 0x0);
+}
+/** Enable interrupts on controller
+ *
+ *  @param rtl8139  The card private structure
+ */
+inline static void rtl8139_hw_int_enable(rtl8139_t *rtl8139)
+{
+	pio_write_16(rtl8139->io_port + IMR, rtl8139->int_mask);
+}
+
+/** Check on the controller if the receiving buffer is empty
+ *
+ *  @param rtl8139  The controller data
+ *
+ *  @return Nonzero if empty, zero otherwise
+ */
+inline static int rtl8139_hw_buffer_empty(rtl8139_t *rtl8139)
+{
+	return pio_read_16(rtl8139->io_port + CR) & CR_BUFE;
+}
+
+/** Update the mask of accepted packets in the RCR register according to
+ * rcr_accept_mode value in rtl8139_t
+ *
+ * @param rtl8139  The rtl8139 private data
+ */
+static void rtl8139_hw_update_rcr(rtl8139_t *rtl8139)
+{
+	uint32_t rcr = rtl8139->rcr_data.rcr_base | rtl8139->rcr_data.ucast_mask
+	    | rtl8139->rcr_data.mcast_mask | rtl8139->rcr_data.bcast_mask
+	    | rtl8139->rcr_data.defect_mask | 
+	    (RXBUF_SIZE_FLAGS << RCR_RBLEN_SHIFT);
+	
+	nlog_debug("Rewriting rcr: %x -> %x", pio_read_32(rtl8139->io_port + RCR),
+	    rcr);
+
+	pio_write_32(rtl8139->io_port + RCR, rcr);
+}
+
+/** Fill the mask of accepted multicast packets in the card registers
+ *
+ *  @param rtl8139  The rtl8139 private data
+ *  @param mask     The mask to set
+ */
+inline static void rtl8139_hw_set_mcast_mask(rtl8139_t *rtl8139,
+    uint64_t mask)
+{
+	pio_write_32(rtl8139->io_port + MAR0, (uint32_t) mask);
+	pio_write_32(rtl8139->io_port + MAR0 + sizeof(uint32_t),
+	    (uint32_t)(mask >> 32));
+	return;
+}
+
+#include <device/pci.h>
+
+/** Set PmEn (Power management enable) bit value
+ *
+ *  @param rtl8139  rtl8139 card data
+ *  @param bit_val  If bit_val is zero pmen is set to 0, otherwise pmen is set to 1
+ */
+inline static void rtl8139_hw_pmen_set(rtl8139_t *rtl8139, uint8_t bit_val)
+{
+	uint8_t config1 = pio_read_8(rtl8139->io_port + CONFIG1);
+	uint8_t config1_new;
+	if (bit_val)
+		config1_new = config1 | CONFIG1_PMEn;
+	else
+		config1_new = config1 & ~(uint8_t)(CONFIG1_PMEn);
+
+	if (config1_new == config1)
+		return;
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_8(rtl8139->io_port + CONFIG1, config1_new);
+	rtl8139_regs_lock(rtl8139->io_port);
+
+	if (bit_val) {
+		async_sess_t *pci_sess =
+			nic_get_ddf_dev(rtl8139->nic_data)->parent_sess;
+		uint8_t pmen;
+		pci_config_space_read_8(pci_sess, 0x55, &pmen);
+		pci_config_space_write_8(pci_sess, 0x55, pmen | 1 | (1 << 7));
+	} else {
+		async_sess_t *pci_sess =
+			nic_get_ddf_dev(rtl8139->nic_data)->parent_sess;
+		uint8_t pmen;
+		pci_config_space_read_8(pci_sess, 0x55, &pmen);
+		pci_config_space_write_8(pci_sess, 0x55, pmen & ~(1 | (1 << 7)));
+	}
+}
+
+/** Get MAC address of the RTL8139 adapter
+ *
+ *  @param rtl8139  The RTL8139 device
+ *  @param address  The place to store the address
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+inline static void rtl8139_hw_get_addr(rtl8139_t *rtl8139,
+    nic_address_t *addr)
+{
+	assert(rtl8139);
+	assert(addr);
+
+	uint32_t *mac0_dest = (uint32_t *)addr->address;
+	uint16_t *mac4_dest = (uint16_t *)(addr->address + 4);
+
+	/* Read MAC address from the i/o (4byte + 2byte reads) */
+	*mac0_dest = pio_read_32(rtl8139->io_port + MAC0);
+	*mac4_dest = pio_read_16(rtl8139->io_port + MAC0 + 4);
+};
+
+/** Set MAC address to the device
+ *
+ *  @param rtl8139  Controller private structure
+ *  @param addr     The address to set
+ */
+static void rtl8139_hw_set_addr(rtl8139_t *rtl8139, const nic_address_t *addr)
+{
+	assert(rtl8139);
+	assert(addr);
+
+	const uint32_t *val1 = (const uint32_t*)addr->address;
+	const uint16_t *val2 = (const uint16_t*)(addr->address + sizeof(uint32_t));
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_32(rtl8139->io_port + MAC0, *val1);
+	pio_write_32(rtl8139->io_port + MAC0 + 4, *val2);
+	rtl8139_regs_lock(rtl8139->io_port);
+}
+
+/**  Provide OR in the 8bit register (set selected bits to 1)
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The value to or
+ */
+inline static void rtl8139_hw_reg_add_8(rtl8139_t * rtl8139, size_t reg_offset,
+    uint8_t bits_add)
+{
+	uint8_t value = pio_read_8(rtl8139->io_port + reg_offset);
+	value |= bits_add;
+	pio_write_8(rtl8139->io_port + reg_offset, value);
+}
+
+/**  Provide OR in the 32bit register (set selected bits to 1)
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The value to or
+ */
+inline static void rtl8139_hw_reg_add_32(rtl8139_t * rtl8139, size_t reg_offset,
+    uint32_t bits_add)
+{
+	uint32_t value = pio_read_32(rtl8139->io_port + reg_offset);
+	value |= bits_add;
+	pio_write_32(rtl8139->io_port + reg_offset, value);
+}
+
+/**  Unset selected bits in 8bit register
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The mask of bits to remove
+ */
+inline static void rtl8139_hw_reg_rem_8(rtl8139_t * rtl8139, size_t reg_offset,
+    uint8_t bits_add)
+{
+	uint8_t value = pio_read_8(rtl8139->io_port + reg_offset);
+	value &= ~bits_add;
+	pio_write_8(rtl8139->io_port + reg_offset, value);
+}
+
+/**  Unset selected bits in 32bit register
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The mask of bits to remove
+ */
+inline static void rtl8139_hw_reg_rem_32(rtl8139_t * rtl8139, size_t reg_offset,
+    uint32_t bits_add)
+{
+	uint32_t value = pio_read_32(rtl8139->io_port + reg_offset);
+	value &= ~bits_add;
+	pio_write_32(rtl8139->io_port + reg_offset, value);
+}
+
+
+static int rtl8139_set_addr(ddf_fun_t *fun, const nic_address_t *);
+static int rtl8139_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
+static int rtl8139_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
+static int rtl8139_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role);
+static int rtl8139_set_operation_mode(ddf_fun_t *fun, int speed,
+    nic_channel_mode_t duplex, nic_role_t);
+
+static int rtl8139_pause_get(ddf_fun_t*, nic_result_t*, nic_result_t*, 
+    uint16_t *);
+static int rtl8139_pause_set(ddf_fun_t*, int, int, uint16_t);
+
+static int rtl8139_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
+static int rtl8139_autoneg_disable(ddf_fun_t *fun);
+static int rtl8139_autoneg_probe(ddf_fun_t *fun, uint32_t *our_advertisement,
+    uint32_t *their_advertisement, nic_result_t *result, 
+    nic_result_t *their_result);
+static int rtl8139_autoneg_restart(ddf_fun_t *fun);
+
+static int rtl8139_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
+static int rtl8139_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
+
+static int rtl8139_wol_virtue_add(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue);
+static void rtl8139_wol_virtue_rem(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue);
+
+static int rtl8139_poll_mode_change(nic_t *nic_data, nic_poll_mode_t mode,
+    const struct timeval *period);
+static void rtl8139_poll(nic_t *nic_data);
+
+/** Network interface options for RTL8139 card driver */
+static nic_iface_t rtl8139_nic_iface = {
+	.set_address = &rtl8139_set_addr,
+	.get_device_info = &rtl8139_get_device_info,
+	.get_cable_state = &rtl8139_get_cable_state,
+	.get_operation_mode = &rtl8139_get_operation_mode,
+	.set_operation_mode = &rtl8139_set_operation_mode,
+
+	.get_pause = &rtl8139_pause_get,
+	.set_pause = &rtl8139_pause_set,
+
+	.autoneg_enable = &rtl8139_autoneg_enable,
+	.autoneg_disable = &rtl8139_autoneg_disable,
+	.autoneg_probe = &rtl8139_autoneg_probe,
+	.autoneg_restart = &rtl8139_autoneg_restart,
+
+	.defective_get_mode = &rtl8139_defective_get_mode,
+	.defective_set_mode = &rtl8139_defective_set_mode,
+};
+
+/** Basic device operations for RTL8139 driver */
+static ddf_dev_ops_t rtl8139_dev_ops;
+
+static int rtl8139_add_device(ddf_dev_t *dev);
+
+/** Basic driver operations for RTL8139 driver */
+static driver_ops_t rtl8139_driver_ops = {
+	.add_device = &rtl8139_add_device,
+};
+
+/** Driver structure for RTL8139 driver */
+static driver_t rtl8139_driver = {
+	.name = NAME,
+	.driver_ops = &rtl8139_driver_ops
+};
+
+/* The default implementation callbacks */
+static int rtl8139_on_activated(nic_t *nic_data);
+static int rtl8139_on_stopped(nic_t *nic_data);
+static void rtl8139_write_packet(nic_t *nic_data, packet_t *packet);
+
+/** Check if the transmit buffer is busy */
+#define rtl8139_tbuf_busy(tsd) ((pio_read_32(tsd) & TSD_OWN) == 0)
+
+/** Send packet with the hardware
+ *
+ * note: the main_lock is locked when framework calls this function
+ *
+ * @param nic_data  The nic driver data structure
+ * @param packet    The packet to send
+ *
+ * @return EOK if succeed, error code in the case of error
+ */
+static void rtl8139_write_packet(nic_t *nic_data, packet_t *packet)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+	nlog_debug("Sending packet");
+
+	/* Get the packet data and check if it can be send */
+	size_t packet_length = packet_get_data_length(packet);
+	void *packet_data = packet_get_data(packet);
+
+	assert(packet_data);
+
+	if ((packet_length > RTL8139_PACKET_MAX_LENGTH) || !packet_data) {
+		nlog_error("Write packet length error: data %p, length %z", 
+		    packet_data, packet_length);
+		nic_report_send_error(rtl8139->nic_data, NIC_SEC_OTHER, 1);
+		goto err_size;
+	}
+
+	assert((packet_length & TSD_SIZE_MASK) == packet_length);
+
+	/* Lock transmitter structure for obtaining next buffer */
+	fibril_mutex_lock(&rtl8139->tx_lock);
+
+	/* Check if there is free buffer */
+	if (rtl8139->tx_next - TX_BUFF_COUNT == rtl8139->tx_used) {
+		nic_set_tx_busy(nic_data, 1);
+		fibril_mutex_unlock(&rtl8139->tx_lock);
+		nic_report_send_error(nic_data, NIC_SEC_BUFFER_FULL, 1);
+		goto err_busy_no_inc;
+	}
+
+	/* Get buffer id to use and set next buffer to use */
+	size_t tx_curr = rtl8139->tx_next++ % TX_BUFF_COUNT;
+
+	fibril_mutex_unlock(&rtl8139->tx_lock);
+
+	/* Get address of the buffer descriptor and packet data */
+	void *tsd = rtl8139->io_port + TSD0 + tx_curr * 4;
+	void *buf_addr = rtl8139->tx_buff[tx_curr];
+
+	/* Wait until the buffer is free */
+	assert(!rtl8139_tbuf_busy(tsd));
+
+	/* Write packet data to the buffer, set the size to TSD and clear OWN bit */
+	memcpy(buf_addr, packet_data, packet_length);
+
+	/* Set size of the data to send */
+	uint32_t tsd_value = pio_read_32(tsd);
+	tsd_value = rtl8139_tsd_set_size(tsd_value, packet_length);
+	pio_write_32(tsd, tsd_value);
+
+	/* barrier for HW to really see the current buffer data */
+	write_barrier();
+
+	tsd_value &= ~(uint32_t)TSD_OWN;
+	pio_write_32(tsd, tsd_value);
+	nic_release_packet(nic_data, packet);
+	return;
+
+err_busy_no_inc:
+err_size:
+	nic_release_packet(nic_data, packet);
+	return;
+};
+
+
+/** Reset the controller
+ *
+ *  @param io_base  The address of the i/o port mapping start
+ */
+inline static void rtl8139_hw_soft_reset(void *io_base)
+{
+	pio_write_8(io_base + CR, CR_RST);
+	memory_barrier();
+	while(pio_read_8(io_base + CR) & CR_RST) {
+		usleep(1);
+		read_barrier();
+	}
+}
+
+/** Provide soft reset of the controller
+ *
+ * The caller must lock tx_lock and rx_lock before calling this function
+ *
+ */
+static void rtl8139_soft_reset(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+
+	rtl8139_hw_soft_reset(rtl8139->io_port);
+	nic_t *nic_data = rtl8139->nic_data;
+
+	/* Write MAC address to the card */
+	nic_address_t addr;
+	nic_query_address(nic_data, &addr);
+	rtl8139_hw_set_addr(rtl8139, &addr);
+
+	/* Recover accept modes back */
+	rtl8139_hw_set_mcast_mask(rtl8139, nic_query_mcast_hash(nic_data));
+	rtl8139_hw_update_rcr(rtl8139);
+
+	rtl8139->tx_used = 0;
+	rtl8139->tx_next = 0;
+	nic_set_tx_busy(rtl8139->nic_data, 0);
+}
+
+/** Create packet structure from the buffer data
+ *
+ * @param nic_data      NIC driver data
+ * @param rx_buffer     The receiver buffer
+ * @param rx_size       The buffer size
+ * @param packet_start  The offset where packet data start
+ * @param packet_size   The size of the packet data
+ *
+ * @return The packet   list node (not connected)
+ */
+static nic_frame_t *rtl8139_read_packet(nic_t *nic_data,
+    void *rx_buffer, size_t rx_size, size_t packet_start, size_t packet_size)
+{
+	nic_frame_t *frame = nic_alloc_frame(nic_data, packet_size);
+	if (! frame) {
+		nlog_error("Can not allocate frame for received packet.");
+		return NULL;
+	}
+
+	void *packet_data = packet_suffix(frame->packet, packet_size);
+	if (!packet_data) {
+		nlog_error("Can not get the packet suffix.");
+		nic_release_frame(nic_data, frame);
+		return NULL;
+	}
+
+	void *ret = rtl8139_memcpy_wrapped(packet_data, rx_buffer, packet_start,
+	    RxBUF_SIZE, packet_size);
+	if (ret == NULL) {
+		nic_release_frame(nic_data, frame);
+		return NULL;
+	}
+	return frame;
+}
+
+/* Reset receiver
+ *
+ * Use in the case of receiver error (lost in the rx_buff)
+ *
+ * @param rtl8139  controller private data
+ */
+static void rtl8139_rx_reset(rtl8139_t *rtl8139) 
+{
+	/* Disable receiver, update offset and enable receiver again */
+	uint8_t cr = pio_read_8(rtl8139->io_port + CR);
+	rtl8139_regs_unlock(rtl8139);
+
+	pio_write_8(rtl8139->io_port + CR, cr & ~(uint8_t)CR_RE);
+
+	write_barrier();
+	pio_write_32(rtl8139->io_port + CAPR, 0);
+	pio_write_32(rtl8139->io_port + RBSTART, 
+	    PTR2U32(rtl8139->rx_buff.physical));
+
+	write_barrier();
+
+	rtl8139_hw_update_rcr(rtl8139);
+	pio_write_8(rtl8139->io_port + CR, cr);
+	rtl8139_regs_lock(rtl8139);
+
+	nic_report_receive_error(rtl8139->nic_data, NIC_REC_OTHER, 1);
+}
+
+/** Receive all packets in queue
+ *
+ *  @param nic_data  The controller data
+ *  @return The linked list of packet_list_t nodes, each containing one packet
+ */
+static nic_frame_list_t *rtl8139_packet_receive(nic_t *nic_data)
+{
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	if (rtl8139_hw_buffer_empty(rtl8139))
+		return NULL;
+
+	nic_frame_list_t *frames = nic_alloc_frame_list();
+	if (!frames)
+		nlog_error("Can not allocate frame list for received packets.");
+
+	void *rx_buffer = rtl8139->rx_buff.virtual;
+
+	/* where to start reading */
+	uint16_t rx_offset = pio_read_16(rtl8139->io_port + CAPR) + 16;
+	/* unread bytes count */
+	uint16_t bytes_received = pio_read_16(rtl8139->io_port + CBA);
+	uint16_t max_read;
+	uint16_t cur_read = 0;
+
+	/* get values to the <0, buffer size) */
+	bytes_received %= RxBUF_SIZE;
+	rx_offset %= RxBUF_SIZE;
+	
+	/* count how many bytes to read maximaly */
+	if (bytes_received < rx_offset)
+		max_read = bytes_received + (RxBUF_SIZE - rx_offset);
+	else
+		max_read = bytes_received - rx_offset;
+
+	memory_barrier();
+	while (!rtl8139_hw_buffer_empty(rtl8139)) {
+		void *rx_ptr = rx_buffer + rx_offset % RxBUF_SIZE;
+		uint32_t packet_header = uint32_t_le2host( *((uint32_t*)rx_ptr) );
+		uint16_t size = packet_header >> 16;
+		uint16_t packet_size = size - RTL8139_CRC_SIZE;
+		/* received packet flags in packet header */
+		uint16_t rcs = (uint16_t) packet_header;
+
+		if (size == RTL8139_EARLY_SIZE) {
+			/* The packet copying is still in progress, break receiving */
+			nlog_debug("Early threshold reached, not completely coppied");
+			break;
+		}
+
+		/* Check if the header is valid, otherwise we are lost in the buffer */
+		if (size == 0 || size > RTL8139_PACKET_MAX_LENGTH) {
+			nlog_error("Receiver error -> receiver reset (size: %4"PRIu16", "
+			    "header 0x%4"PRIx16". Offset: %zu)", size, packet_header, 
+			    rx_offset);
+			goto rx_err;
+		}
+		if (size < RTL8139_RUNT_MAX_SIZE && !(rcs & RSR_RUNT)) {
+			nlog_error("Receiver error -> receiver reset (%"PRIx16")", size);
+			goto rx_err;
+		}
+
+		cur_read += size + RTL_PACKET_HEADER_SIZE;
+		if (cur_read > max_read)
+			break;
+
+		if (frames) {
+			nic_frame_t *frame = rtl8139_read_packet(nic_data, rx_buffer,
+			    RxBUF_SIZE, rx_offset + RTL_PACKET_HEADER_SIZE, packet_size);
+
+			if (frame)
+				nic_frame_list_append(frames, frame);
+		}
+
+		/* Update offset */
+		rx_offset = ALIGN_UP(rx_offset + size + RTL_PACKET_HEADER_SIZE, 4);
+
+		/* Write lesser value to prevent overflow into unread packet
+		 * (the recomendation from the RealTech rtl8139 programming guide)
+		 */
+		uint16_t capr_val = rx_offset - 16;
+		pio_write_16(rtl8139->io_port + CAPR, capr_val);
+
+		/* Ensure no CR read optimalization during next empty buffer test */
+		memory_barrier();
+	}
+	return frames;
+rx_err:
+	rtl8139_rx_reset(rtl8139);
+	return frames;
+};
+
+
+
+/** Commands to deal with interrupt
+ *
+ *  Read ISR, check if tere is any interrupt pending.
+ *  If so, reset it and accept the interrupt.
+ *  The .addr of the first and third command must
+ *  be filled to the ISR port address
+ */
+irq_cmd_t rtl8139_irq_commands[] = {
+		{
+				/* Get the interrupt status */
+				.cmd = CMD_PIO_READ_16,
+				.addr = NULL,
+				.dstarg = 2
+		},
+		{
+				.cmd = CMD_PREDICATE,
+				.value = 3,
+				.srcarg = 2
+		},
+		{
+				/* Mark interrupts as solved */
+				.cmd = CMD_PIO_WRITE_16,
+				.addr = NULL,
+				.value = 0xFFFF
+		},
+		{
+				/* Disable interrupts until interrupt routine is finished */
+				.cmd = CMD_PIO_WRITE_16,
+				.addr = NULL,
+				.value = 0x0000
+		},
+		{
+				.cmd = CMD_ACCEPT
+		}
+};
+
+/** Interrupt code definition */
+irq_code_t rtl8139_irq_code = {
+	.cmdcount = sizeof(rtl8139_irq_commands)/sizeof(irq_cmd_t),
+	.cmds = rtl8139_irq_commands
+};
+
+/** Deal with transmitter interrupt
+ *
+ *  @param nic_data  Nic driver data
+ */
+static void rtl8139_tx_interrupt(nic_t *nic_data)
+{
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	fibril_mutex_lock(&rtl8139->tx_lock);
+
+	size_t tx_next = rtl8139->tx_next;
+	size_t tx_used = rtl8139->tx_used;
+	while (tx_used != tx_next) {
+		size_t desc_to_check = tx_used % TX_BUFF_COUNT;
+		void * tsd_to_check = rtl8139->io_port + TSD0 
+		    + desc_to_check * sizeof(uint32_t);
+		uint32_t tsd_value = pio_read_32(tsd_to_check);
+
+		/* If sending is still in the progress */
+		if ((tsd_value & TSD_OWN) == 0)
+			break;
+
+		tx_used++;
+
+		/* If the packet was sent */
+		if (tsd_value & TSD_TOK) {
+			size_t size = REG_GET_VAL(tsd_value, TSD_SIZE);
+			nic_report_send_ok(nic_data, 1, size);
+		} else if (tsd_value & TSD_CRS) {
+			nic_report_send_error(nic_data, NIC_SEC_CARRIER_LOST, 1);
+		} else if (tsd_value & TSD_OWC) {
+			nic_report_send_error(nic_data, NIC_SEC_WINDOW_ERROR, 1);
+		} else if (tsd_value & TSD_TABT) {
+			nic_report_send_error(nic_data, NIC_SEC_ABORTED, 1);
+		} else if (tsd_value & TSD_CDH) {
+			nic_report_send_error(nic_data, NIC_SEC_HEARTBEAT, 1);
+		}
+
+		unsigned collisions = REG_GET_VAL(tsd_value, TSD_NCC);
+		if (collisions > 0) {
+			nic_report_collisions(nic_data, collisions);
+		}
+
+		if (tsd_value & TSD_TUN) {
+			nic_report_send_error(nic_data, NIC_SEC_FIFO_OVERRUN, 1);
+		}
+	}
+	if (rtl8139->tx_used != tx_used) {
+		rtl8139->tx_used = tx_used;
+		nic_set_tx_busy(nic_data, 0);
+	}
+	fibril_mutex_unlock(&rtl8139->tx_lock);
+}
+
+/** Receive all packets from the buffer
+ *
+ *  @param rtl8139  driver private data
+ */
+static void rtl8139_receive_packets(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	nic_frame_list_t *frames = rtl8139_packet_receive(nic_data);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+
+	if (frames)
+		nic_received_frame_list(nic_data, frames);
+}
+
+
+/** Deal with poll interrupt
+ *
+ *  @param nic_data  Nic driver data
+ */
+static int rtl8139_poll_interrupt(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	uint32_t timer_val;
+	int receive = rtl8139_timer_act_step(&rtl8139->poll_timer, &timer_val);
+
+	assert(timer_val);
+	pio_write_32(rtl8139->io_port + TIMERINT, timer_val);
+	pio_write_32(rtl8139->io_port + TCTR, 0x0);
+	nlog_debug("rtl8139 timer: %"PRIu32"\treceive: %d", timer_val, receive);
+	return receive;
+}
+
+
+/** Poll device according to isr status
+ *
+ *  The isr value must be obtained and cleared by the caller. The reason
+ *  of this function separate is to allow polling from both interrupt
+ *  (which clears controller ISR before the handler runs) and the polling
+ *  callbacks.
+ *
+ *  @param nic_data  Driver data
+ *  @param isr       Interrupt status register value
+ */
+static void rtl8139_interrupt_impl(nic_t *nic_data, uint16_t isr)
+{
+	assert(nic_data);
+	
+	nic_poll_mode_t poll_mode = nic_query_poll_mode(nic_data, 0);
+
+	/* Process only when should in the polling mode */
+	if (poll_mode == NIC_POLL_PERIODIC) {
+		int receive = 0;
+		if (isr & INT_TIME_OUT) {
+			receive = rtl8139_poll_interrupt(nic_data);
+		}
+		if (! receive)
+			return;
+	}
+
+	/* Check transmittion interrupts first to allow transmit next packets
+	 * sooner
+	 */
+	if (isr & (INT_TOK | INT_TER)) {
+		rtl8139_tx_interrupt(nic_data);
+	}
+	if (isr & INT_ROK) {
+		rtl8139_receive_packets(nic_data);
+	}
+	if (isr & (INT_RER | INT_RXOVW | INT_FIFOOVW)) {
+		if (isr & INT_RER) {
+			//TODO: is this only the general error, or any particular?
+		}
+		if (isr & (INT_FIFOOVW)) {
+			nic_report_receive_error(nic_data, NIC_REC_FIFO_OVERRUN, 1);
+		} else if (isr & (INT_RXOVW)) {
+			rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+			assert(rtl8139);
+
+			uint32_t miss = pio_read_32(rtl8139->io_port + MPC) & MPC_VMASK;
+			pio_write_32(rtl8139->io_port + MPC, 0);
+			nic_report_receive_error(nic_data, NIC_REC_BUFFER_OVERFLOW, miss);
+		}
+	}
+}
+
+/** Handle device interrupt
+ *
+ *  @param dev    The rtl8139 device
+ *  @param iid    The IPC call id
+ *  @param icall  The IPC call structure
+ */
+static void rtl8139_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	assert(dev);
+	assert(icall);
+
+	uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall);
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	rtl8139_interrupt_impl(nic_data, isr);
+
+	/* Turn the interrupts on again */
+	rtl8139_hw_int_enable(rtl8139);
+};
+
+/** Register interrupt handler for the card in the system
+ *
+ *  Note: the global irq_reg_mutex is locked because of work with global
+ *  structure.
+ *
+ *  @param nic_data  The driver data
+ *
+ *  @return EOK if the handler was registered, negative error code otherwise
+ */
+inline static int rtl8139_register_int_handler(nic_t *nic_data)
+{
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	/* Lock the mutex in whole driver while working with global structure */
+	RTL8139_IRQ_STRUCT_LOCK();
+
+	rtl8139_irq_code.cmds[0].addr = rtl8139->io_port + ISR;
+	rtl8139_irq_code.cmds[2].addr = rtl8139->io_port + ISR;
+	rtl8139_irq_code.cmds[3].addr = rtl8139->io_port + IMR;
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
+		rtl8139->irq, rtl8139_interrupt_handler, &rtl8139_irq_code);
+
+	RTL8139_IRQ_STRUCT_UNLOCK();
+
+	return rc;
+}
+
+/** Start the controller
+ *
+ * The caller must lock tx_lock and rx_lock before calling this function
+ *
+ * @param rtl8139  The card private data
+ */
+inline static void rtl8139_card_up(rtl8139_t *rtl8139)
+{
+	void *io_base = rtl8139->io_port;
+	size_t i;
+
+	/* Wake up the device */
+	pio_write_8(io_base + CONFIG1, 0x00);
+	/* Reset the device */
+	rtl8139_soft_reset(rtl8139);
+
+	/* Write transmittion buffer addresses */
+	for(i = 0; i < TX_BUFF_COUNT; ++i) {
+		uint32_t addr = PTR2U32(rtl8139->tx_buff_mem.physical + i*TX_BUFF_SIZE);
+		pio_write_32(io_base + TSAD0 + 4*i, addr);
+	}
+	rtl8139->tx_next = 0;
+	rtl8139->tx_used = 0;
+	nic_set_tx_busy(rtl8139->nic_data, 0);
+
+	pio_write_32(io_base + RBSTART, PTR2U32(rtl8139->rx_buff.physical));
+
+	/* Enable transmitter and receiver */
+	uint8_t cr_value = pio_read_8(io_base + CR);
+	pio_write_8(io_base + CR, cr_value | CR_TE | CR_RE);
+	rtl8139_hw_update_rcr(rtl8139);
+}
+
+/** Activate the device to receive and transmit packets
+ *
+ *  @param nic_data  The nic driver data
+ *
+ *  @return EOK if activated successfully, error code otherwise
+ */
+static int rtl8139_on_activated(nic_t *nic_data)
+{
+	assert(nic_data);
+	nlog_info("Activating device");
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	rtl8139_lock_all(rtl8139);
+	rtl8139_card_up(rtl8139);
+	rtl8139_unlock_all(rtl8139);
+
+	rtl8139->int_mask = RTL_DEFAULT_INTERRUPTS;
+	rtl8139_hw_int_enable(rtl8139);
+	nic_enable_interrupt(nic_data, rtl8139->irq);
+
+	nlog_debug("Device activated, interrupt %d registered", rtl8139->irq);
+	return EOK;
+}
+
+/** Callback for NIC_STATE_STOPPED change
+ *
+ *  @param nic_data  The nic driver data
+ *
+ *  @return EOK if succeed, error code otherwise
+ */
+static int rtl8139_on_stopped(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	rtl8139->rcr_data.ucast_mask = RTL8139_RCR_UCAST_DEFAULT;
+	rtl8139->rcr_data.mcast_mask = RTL8139_RCR_MCAST_DEFAULT;
+	rtl8139->rcr_data.bcast_mask = RTL8139_RCR_BCAST_DEFAULT;
+	rtl8139->rcr_data.defect_mask = RTL8139_RCR_DEFECT_DEFAULT;
+
+	/* Reset the card to the initial state (interrupts, Tx and Rx disabled) */
+	rtl8139_lock_all(rtl8139);
+	rtl8139_soft_reset(rtl8139);
+	rtl8139_unlock_all(rtl8139);
+	return EOK;
+}
+
+
+static int rtl8139_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
+    const nic_address_t *, size_t);
+static int rtl8139_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count);
+static int rtl8139_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
+
+
+/** Create driver data structure
+ *
+ *  @return Intialized device data structure or NULL
+ */
+static rtl8139_t *rtl8139_create_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(!nic_get_from_ddf_dev(dev));
+
+	nic_t *nic_data = nic_create_and_bind(dev);
+	if (!nic_data)
+		return NULL;
+
+	rtl8139_t *rtl8139 = malloc(sizeof(rtl8139_t));
+	if (!rtl8139) {
+		nic_unbind_and_destroy(dev);
+		return NULL;
+	}
+
+	bzero(rtl8139, sizeof(rtl8139_t));
+
+	rtl8139->nic_data = nic_data;
+	nic_set_specific(nic_data, rtl8139);
+	nic_set_write_packet_handler(nic_data, rtl8139_write_packet);
+	nic_set_state_change_handlers(nic_data,
+		rtl8139_on_activated, NULL, rtl8139_on_stopped);
+	nic_set_filtering_change_handlers(nic_data,
+		rtl8139_unicast_set, rtl8139_multicast_set, rtl8139_broadcast_set,
+		NULL, NULL);
+	nic_set_wol_virtue_change_handlers(nic_data,
+		rtl8139_wol_virtue_add, rtl8139_wol_virtue_rem);
+	nic_set_poll_handlers(nic_data, rtl8139_poll_mode_change, rtl8139_poll);
+
+
+	fibril_mutex_initialize(&rtl8139->rx_lock);
+	fibril_mutex_initialize(&rtl8139->tx_lock);
+
+	nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
+	nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
+	nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
+
+	return rtl8139;
+}
+
+/** Clean up the rtl8139 device structure.
+ *
+ * @param dev  The device structure.
+ */
+static void rtl8139_dev_cleanup(ddf_dev_t *dev)
+{
+	assert(dev);
+
+	if (dev->driver_data)
+		nic_unbind_and_destroy(dev);
+
+	if (dev->parent_sess != NULL) {
+		async_hangup(dev->parent_sess);
+		dev->parent_sess = NULL;
+	}
+}
+
+/** Fill the irq and io_addr part of device data structure
+ *
+ *  The hw_resources must be obtained before calling this function
+ *
+ *  @param dev           The device structure
+ *  @param hw_resources  Devices hardware resources
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
+    *hw_resources)
+{
+	assert(dev);
+	assert(hw_resources);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_dev(dev));
+	assert(rtl8139);
+
+	if (hw_resources->irqs.count != 1) {
+		nlog_error("%s device: unexpected irq count", dev->name);
+		return EINVAL;
+	};
+	if (hw_resources->io_ranges.count != 1) {
+		nlog_error("%s device: unexpected io ranges count", dev->name);
+		return EINVAL;
+	}
+
+	rtl8139->irq = hw_resources->irqs.irqs[0];
+	nlog_debug("%s device: irq 0x%x assigned", dev->name, rtl8139->irq);
+
+	rtl8139->io_addr = IOADDR_TO_PTR(hw_resources->io_ranges.ranges[0].address);
+	if (hw_resources->io_ranges.ranges[0].size < RTL8139_IO_SIZE) {
+		nlog_error("i/o range assigned to the device "
+		    "%s is too small.", dev->name);
+		return EINVAL;
+	}
+	nlog_debug("%s device: i/o addr %p assigned.", dev->name, rtl8139->io_addr);
+
+	return EOK;
+}
+
+/** Obtain information about hardware resources of the device
+ *
+ *  The device must be connected to the parent
+ *
+ *  @param dev  The device structure
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_get_resource_info(ddf_dev_t *dev)
+{
+	assert(dev);
+
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	assert(nic_data);
+
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+
+	/* Get hw resources form parent driver */
+	int rc = nic_get_resources(nic_data, &hw_res_parsed);
+	if (rc != EOK)
+		return rc;
+
+	/* Fill resources information to the device */
+	int ret = rtl8139_fill_resource_info(dev, &hw_res_parsed);
+	hw_res_list_parsed_clean(&hw_res_parsed);
+
+	return ret;
+}
+
+
+/** Allocate buffers using DMA framework
+ *
+ * The buffers structures in the device specific data is filled
+ *
+ * @param data  The device specific structure to fill
+ *
+ * @return EOK in the case of success, error code otherwise
+ */
+static int rtl8139_buffers_create(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+	size_t i = 0;
+	int rc;
+
+	nlog_debug("Creating buffers");
+
+	rtl8139->tx_buff_mem.size = TX_PAGES;
+	rtl8139->tx_buff_mem.mapping_flags = AS_AREA_WRITE;
+	rc = dma_allocate_anonymous(&rtl8139->tx_buff_mem, DMA_32_BITS);
+	if (rc != EOK) {
+		nlog_error("Can not allocate transmitter buffers.");
+		goto err_tx_alloc;
+	}
+
+	for(i = 0; i < TX_BUFF_COUNT; ++i)
+		rtl8139->tx_buff[i] = rtl8139->tx_buff_mem.virtual + i * TX_BUFF_SIZE;
+
+	nlog_debug("The transmittion buffers allocated");
+
+	/* Use the first buffer for next transmittion */
+	rtl8139->tx_next = 0;
+	rtl8139->tx_used = 0;
+
+	/* Allocate buffer for receiver */
+	size_t rx_pages = ALIGN_UP(RxBUF_TOT_LENGTH, PAGE_SIZE) / PAGE_SIZE;
+	nlog_debug("Allocating receiver buffer of the size %zd pages", rx_pages);
+
+	rtl8139->rx_buff.size = rx_pages;
+	rtl8139->rx_buff.mapping_flags = AS_AREA_READ;
+	rc = dma_allocate_anonymous(&rtl8139->rx_buff, DMA_32_BITS);
+	if( rc != EOK ) {
+		nlog_error("Can not allocate receiver buffer.");
+		goto err_rx_alloc;
+	}
+	nlog_debug("The buffers created");
+
+	return EOK;
+
+err_rx_alloc:
+	dma_free(&rtl8139->tx_buff_mem);
+err_tx_alloc:
+	return rc;
+}
+
+/** Initialize the rtl8139 device structure
+ *
+ *  @param dev  The device information
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_device_initialize(ddf_dev_t *dev)
+{
+	nlog_debug("rtl8139_dev_initialize %s", dev->name);
+
+	int ret = EOK;
+
+	nlog_debug("rtl8139: creating device data");
+
+	/* Allocate driver data for the device. */
+	rtl8139_t *rtl8139 = rtl8139_create_dev_data(dev);
+	if (rtl8139 == NULL) {
+		nlog_error("Not enough memory for initializing %s.", dev->name);
+		return ENOMEM;
+	}
+
+	nlog_debug("rtl8139: dev_data created");
+
+	/* Obtain and fill hardware resources info and connect to parent */
+	ret = rtl8139_get_resource_info(dev);
+	if (ret != EOK) {
+		nlog_error("Can not obatin hw resources information");
+		goto failed;
+	}
+
+	nlog_debug("rtl8139: resource_info obtained");
+
+	/* Allocate DMA buffers */
+	ret = rtl8139_buffers_create(rtl8139);
+	if (ret != EOK)
+		goto failed;
+
+	/* Set default packet acceptance */
+	rtl8139->rcr_data.ucast_mask = RTL8139_RCR_UCAST_DEFAULT;
+	rtl8139->rcr_data.mcast_mask = RTL8139_RCR_MCAST_DEFAULT;
+	rtl8139->rcr_data.bcast_mask = RTL8139_RCR_BCAST_DEFAULT;
+	rtl8139->rcr_data.defect_mask = RTL8139_RCR_DEFECT_DEFAULT;
+	/* Set receiver early treshold to 8/16 of packet length */
+	rtl8139->rcr_data.rcr_base = (0x8 << RCR_ERTH_SHIFT);
+
+	nlog_debug("The device is initialized");
+	return ret;
+
+failed:
+	nlog_error("The device initialization failed");
+	rtl8139_dev_cleanup(dev);
+	return ret;
+}
+
+/** Enable the i/o ports of the device.
+ *
+ * @param dev  The RTL8139 device.
+ *
+ * @return EOK if successed, negative error code otherwise
+ */
+static int rtl8139_pio_enable(ddf_dev_t *dev)
+{
+	nlog_debug(NAME ": rtl8139_pio_enable %s", dev->name);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_dev(dev));
+
+	/* Gain control over port's registers. */
+	if (pio_enable(rtl8139->io_addr, RTL8139_IO_SIZE, &rtl8139->io_port)) {
+		nlog_error("Cannot gain the port %lx for device %s.", rtl8139->io_addr,
+		    dev->name);
+		return EADDRNOTAVAIL;
+	}
+
+	return EOK;
+}
+
+/** Initialize the driver private data according to the
+ *  device registers
+ *
+ *  @param rtl8139 rtl8139 private data
+ */
+static void rtl8139_data_init(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+
+	/* Check the version id */
+	uint32_t tcr = pio_read_32(rtl8139->io_port + TCR);
+	uint32_t hwverid = RTL8139_HWVERID(tcr);
+	size_t i = 0;
+	rtl8139->hw_version = RTL8139_VER_COUNT;
+	for (i = 0; i < RTL8139_VER_COUNT; ++i) {
+		if (rtl8139_versions[i].hwverid == 0)
+			break;
+
+		if (rtl8139_versions[i].hwverid == hwverid) {
+			rtl8139->hw_version = rtl8139_versions[i].ver_id;
+			nlog_info("HW version found: index %zu, ver_id %d (%s)", i,
+			    rtl8139_versions[i].ver_id, model_names[rtl8139->hw_version]);
+		}
+	}
+}
+
+/** The add_device callback of RTL8139 callback
+ *
+ * Probe and initialize the newly added device.
+ *
+ * @param dev  The RTL8139 device.
+ *
+ * @return EOK if added successfully, negative error code otherwise
+ */
+int rtl8139_add_device(ddf_dev_t *dev)
+{
+	assert(dev);
+	nlog_info("RTL8139_add_device %s (handle = %d)", dev->name, dev->handle);
+
+	/* Init device structure for rtl8139 */
+	int rc = rtl8139_device_initialize(dev);
+	if (rc != EOK)
+		return rc;
+
+	/* Map I/O ports */
+	rc = rtl8139_pio_enable(dev);
+	if (rc != EOK)
+		goto err_destroy;
+
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	nic_address_t addr;
+	rtl8139_hw_get_addr(rtl8139, &addr);
+	rc = nic_report_address(nic_data, &addr);
+	if (rc != EOK)
+		goto err_pio;
+
+	/* Initialize the driver private structure */
+	rtl8139_data_init(rtl8139);
+
+	/* Register interrupt handler */
+	rc = rtl8139_register_int_handler(nic_data);
+	if (rc != EOK)
+		goto err_pio;
+
+	rc = nic_connect_to_services(nic_data);
+	if (rc != EOK) {
+		nlog_error("Failed to connect to services", rc);
+		goto err_irq;
+	}
+
+	rc = nic_register_as_ddf_fun(nic_data, &rtl8139_dev_ops);
+	if (rc != EOK) {
+		nlog_error("Failed to register as DDF function - error %d", rc);
+		goto err_irq;
+	}
+
+	nlog_info("The %s device has been successfully initialized.",
+	    dev->name);
+
+	return EOK;
+
+err_irq:
+	unregister_interrupt_handler(dev, rtl8139->irq);
+err_pio:
+	// rtl8139_pio_disable(dev);
+	/* TODO: find out if the pio_disable is needed */
+err_destroy:
+	rtl8139_dev_cleanup(dev);
+	return rc;
+};
+
+/** Set card MAC address
+ *
+ *  @param device   The RTL8139 device
+ *  @param address  The place to store the address
+ *  @param max_len  Maximal addresss length to store
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
+{
+	assert(fun);
+	assert(addr);
+
+	nic_t *nic_data =nic_get_from_ddf_fun((fun));
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	rtl8139_lock_all(rtl8139);
+
+	int rc = nic_report_address(nic_data, addr);
+	if ( rc != EOK) {
+		rtl8139_unlock_all(rtl8139);
+		return rc;
+	}
+
+	rtl8139_hw_set_addr(rtl8139, addr);
+
+	rtl8139_unlock_all(rtl8139);
+	return EOK;
+}
+
+/** Get the device information
+ *
+ *  @param dev   The NIC device
+ *  @param info  The information to fill
+ *
+ *  @return EOK
+ */
+static int rtl8139_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
+{
+	assert(fun);
+	assert(info);
+
+	nic_t *nic_data = nic_get_from_ddf_fun(fun);
+	assert(nic_data);
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	/* TODO: fill the information more completely */
+	info->vendor_id = 0x10ec;
+	str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Realtek");
+
+	if (rtl8139->hw_version < RTL8139_VER_COUNT) {
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, 
+		    model_names[rtl8139->hw_version]);
+	} else {
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8139");
+	}
+
+	info->ethernet_support[ETH_10M] = ETH_10BASE_T;
+	info->ethernet_support[ETH_100M] = ETH_100BASE_TX;
+
+	info->autoneg_support = RTL8139_AUTONEG_CAPS;
+	return EOK;
+}
+
+/** Check the cable state
+ *
+ *  @param[in]  dev    The device
+ *  @param[out] state  The state to fill
+ *
+ *  @return EOK
+ */
+static int rtl8139_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
+{
+	assert(fun);
+	assert(state);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (pio_read_16(rtl8139->io_port + CSCR) & CS_CON_STATUS) {
+		*state = NIC_CS_PLUGGED;
+	} else {
+		*state = NIC_CS_UNPLUGGED;
+	}
+
+	return EOK;
+}
+
+/** Get operation mode of the device
+ */
+static int rtl8139_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	assert(fun);
+	assert(speed);
+	assert(duplex);
+	assert(role);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+	uint8_t msr_val = pio_read_8(rtl8139->io_port + MSR);
+
+	if (bmcr_val & BMCR_DUPLEX) {
+		*duplex = NIC_CM_FULL_DUPLEX;
+	} else {
+		*duplex = NIC_CM_HALF_DUPLEX;
+	}
+
+	if (msr_val & MSR_SPEED10) {
+		*speed = 10;
+	} else {
+		*speed = 100;
+	}
+
+	*role = NIC_ROLE_UNKNOWN;
+	return EOK;
+}
+
+/** Value validity */
+enum access_mode {
+	/** Value is invalid now */
+	VALUE_INVALID = 0,
+	/** Read-only */
+	VALUE_RO,
+	/** Read-write */
+	VALUE_RW
+};
+
+/** Check if pause packet operations are valid in current situation 
+ *
+ *  @param rtl8139  RTL8139 private structure
+ *
+ *  @return VALUE_INVALID if the value has no sense in current moment
+ *  @return VALUE_RO if the state is read-only in current moment
+ *  @return VALUE_RW if the state can be modified
+ */
+static int rtl8139_pause_is_valid(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+
+	uint16_t bmcr = pio_read_16(rtl8139->io_port + BMCR);
+	if ((bmcr & (BMCR_AN_ENABLE | BMCR_DUPLEX)) == 0)
+		return VALUE_INVALID;
+
+	if (bmcr & BMCR_AN_ENABLE) {
+		uint16_t anar_lp = pio_read_16(rtl8139->io_port + ANLPAR);
+		if (anar_lp & ANAR_PAUSE)
+			return VALUE_RO;
+	}
+
+	return VALUE_RW;
+}
+
+/** Get current pause packet configuration
+ *
+ *  Values are filled with NIC_RESULT_NOT_AVAILABLE if the value has no sense in
+ *  the moment (half-duplex).
+ *
+ *  @param[in]  fun         The DDF structure of the RTL8139
+ *  @param[out] we_send     Sign if local constroller sends pause packets
+ *  @param[out] we_receive  Sign if local constroller receives pause packets
+ *  @param[out] time        Time filled in pause packets. 0xFFFF in rtl8139
+ *
+ *  @return EOK if succeed
+ */
+static int rtl8139_pause_get(ddf_fun_t *fun, nic_result_t *we_send, 
+    nic_result_t *we_receive, uint16_t *time)
+{
+	assert(fun);
+	assert(we_send);
+	assert(we_receive);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (rtl8139_pause_is_valid(rtl8139) == VALUE_INVALID) {
+		*we_send = NIC_RESULT_NOT_AVAILABLE;
+		*we_receive = NIC_RESULT_NOT_AVAILABLE;
+		*time = 0;
+		return EOK;
+	}
+
+	uint8_t msr = pio_read_8(rtl8139->io_port + MSR);
+
+	*we_send = (msr & MSR_TXFCE) ? NIC_RESULT_ENABLED : NIC_RESULT_DISABLED;
+	*we_receive = (msr & MSR_RXFCE) ? NIC_RESULT_ENABLED : NIC_RESULT_DISABLED;
+	*time = RTL8139_PAUSE_VAL;
+
+	return EOK;
+};
+
+/** Set current pause packet configuration
+ *
+ *  @param fun            The DDF structure of the RTL8139
+ *  @param allow_send     Sign if local constroller sends pause packets
+ *  @param allow_receive  Sign if local constroller receives pause packets
+ *  @param time           Time to use, ignored (not supported by device)
+ *
+ *  @return EOK if succeed, INVAL if the pause packet has no sence
+ */
+static int rtl8139_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive, 
+    uint16_t time)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (rtl8139_pause_is_valid(rtl8139) != VALUE_RW)
+		return EINVAL;
+	
+	uint8_t msr = pio_read_8(rtl8139->io_port + MSR);
+	msr &= ~(uint8_t)(MSR_TXFCE | MSR_RXFCE);
+
+	if (allow_receive)
+		msr |= MSR_RXFCE;
+	if (allow_send)
+		msr |= MSR_TXFCE;
+	
+	pio_write_8(rtl8139->io_port + MSR, msr);
+
+	if (allow_send && time > 0) {
+		nlog_warning("Time setting is not supported in set_pause method.");
+	}
+	return EOK;
+};
+
+/** Set operation mode of the device
+ *
+ */
+static int rtl8139_set_operation_mode(ddf_fun_t *fun, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (speed != 10 && speed != 100)
+		return EINVAL;
+	if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
+		return EINVAL;
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+
+	/* Set autonegotion disabled */
+	bmcr_val &= ~(uint16_t)BMCR_AN_ENABLE;
+
+	if (duplex == NIC_CM_FULL_DUPLEX) {
+		bmcr_val |= BMCR_DUPLEX;
+	} else {
+		bmcr_val &= ~((uint16_t)BMCR_DUPLEX);
+	}
+
+	if (speed == 100) {
+		bmcr_val |= BMCR_Spd_100;
+	} else {
+		bmcr_val &= ~((uint16_t)BMCR_Spd_100);
+	}
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr_val);
+	rtl8139_regs_lock(rtl8139->io_port);
+	return EOK;
+}
+
+/** Enable autonegoation with specific advertisement
+ *
+ *  @param dev            The device to update
+ *  @param advertisement  The advertisement to set
+ *
+ *  @returns EINVAL if the advertisement mode is not supproted
+ *  @returns EOK if advertisement mode set successfully
+ */
+static int rtl8139_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (advertisement == 0) {
+		advertisement = RTL8139_AUTONEG_CAPS;
+	}
+
+	if ((advertisement | RTL8139_AUTONEG_CAPS) != RTL8139_AUTONEG_CAPS)
+		return EINVAL; /* some unsuported mode is requested */
+	
+	assert(advertisement != 0);
+
+	/* Set the autonegotiation advertisement */
+	uint16_t anar = ANAR_SELECTOR; /* default selector */
+	if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
+		anar |= ANAR_10_FD;
+	if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
+		anar |= ANAR_10_HD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
+		anar |= ANAR_100TX_FD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
+		anar |= ANAR_100TX_HD;
+	if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
+		anar |= ANAR_PAUSE;
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+	bmcr_val |= BMCR_AN_ENABLE;
+
+	pio_write_16(rtl8139->io_port + ANAR, anar);
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr_val);
+	rtl8139_regs_lock(rtl8139->io_port);
+	return EOK;
+}
+
+/** Disable advertisement functionality
+ *
+ *  @param dev  The device to update
+ *
+ *  @returns EOK
+ */
+static int rtl8139_autoneg_disable(ddf_fun_t *fun)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+
+	bmcr_val &= ~((uint16_t)BMCR_AN_ENABLE);
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr_val);
+	rtl8139_regs_lock(rtl8139->io_port);
+
+	return EOK;
+}
+
+/** Obtain the advertisement NIC framework value from the ANAR/ANLPAR register
+ * value
+ *
+ *  @param[in]  anar           The ANAR register value
+ *  @param[out] advertisement  The advertisement result
+ */
+static void rtl8139_get_anar_state(uint16_t anar, uint32_t *advertisement)
+{
+	*advertisement = 0;
+	if (anar & ANAR_10_HD)
+		*advertisement |= ETH_AUTONEG_10BASE_T_HALF;
+	if (anar & ANAR_10_FD)
+		*advertisement |= ETH_AUTONEG_10BASE_T_FULL;
+	if (anar & ANAR_100TX_HD)
+		*advertisement |= ETH_AUTONEG_100BASE_TX_HALF;
+	if (anar & ANAR_100TX_FD)
+		*advertisement |= ETH_AUTONEG_100BASE_TX_FULL;
+	if (anar & ANAR_100T4)
+		*advertisement |= ETH_AUTONEG_100BASE_T4_HALF;
+	if (anar & ANAR_PAUSE)
+		*advertisement |= ETH_AUTONEG_PAUSE_SYMETRIC;
+}
+
+/** Check the autonegotion state
+ *
+ *  @param[in]  dev            The device to check
+ *  @param[out] advertisement  The device advertisement
+ *  @param[out] their_adv      The partners advertisement
+ *  @param[out] result         The autonegotion state
+ *  @param[out] their_result   The link partner autonegotion status
+ *
+ *  @returns EOK
+ */
+static int rtl8139_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
+    uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr = pio_read_16(rtl8139->io_port + BMCR);
+	uint16_t anar = pio_read_16(rtl8139->io_port + ANAR);
+	uint16_t anar_lp = pio_read_16(rtl8139->io_port + ANLPAR);
+	uint16_t aner = pio_read_16(rtl8139->io_port + ANER);
+
+	if (bmcr & BMCR_AN_ENABLE) {
+		*result = NIC_RESULT_ENABLED;
+	} else {
+		*result = NIC_RESULT_DISABLED;
+	}
+
+	if (aner & ANER_LP_NW_ABLE) {
+		*their_result = NIC_RESULT_ENABLED;
+	} else {
+		*their_result = NIC_RESULT_DISABLED;
+	}
+
+	rtl8139_get_anar_state(anar, advertisement);
+	rtl8139_get_anar_state(anar_lp, their_adv);
+
+	return EOK;
+}
+
+/** Restart autonegotiation process
+ *
+ *  @param dev  The device to update
+ *
+ *  @returns EOK
+ */
+static int rtl8139_autoneg_restart(ddf_fun_t *fun)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr = pio_read_16(rtl8139->io_port + BMCR);
+	bmcr |= BMCR_AN_RESTART;
+	bmcr |= BMCR_AN_ENABLE;
+
+	rtl8139_regs_unlock(rtl8139);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr);
+	rtl8139_regs_lock(rtl8139);
+
+	return EOK;
+}
+
+/** Notify NIC framework about HW filtering state when promisc mode was disabled
+ *
+ *  @param nic_data     The NIC data
+ *  @param mcast_mode   Current multicast mode
+ *  @param was_promisc  Sign if the promiscuous mode was active before disabling
+ */
+inline static void rtl8139_rcx_promics_rem(nic_t *nic_data,
+    nic_multicast_mode_t mcast_mode, uint8_t was_promisc)
+{
+	assert(nic_data);
+
+	if (was_promisc != 0) {
+		if (mcast_mode == NIC_MULTICAST_LIST)
+			nic_report_hw_filtering(nic_data, 1, 0, -1);
+		else
+			nic_report_hw_filtering(nic_data, 1, 1, -1);
+	} else {
+		nic_report_hw_filtering(nic_data, 1, -1, -1);
+	}
+}
+
+/** Set unicast packets acceptance mode
+ *
+ *  @param nic_data  The nic device to update
+ *  @param mode      The mode to set
+ *  @param addr      Ignored, no HW support, just use unicast promisc
+ *  @param addr_cnt  Ignored, no HW support
+ *
+ *  @returns EOK
+ */
+static int rtl8139_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	uint8_t was_promisc = rtl8139->rcr_data.ucast_mask & RCR_ACCEPT_ALL_PHYS;
+
+	nic_multicast_mode_t mcast_mode;
+	nic_query_multicast(nic_data, &mcast_mode, 0, NULL, NULL);
+
+	switch (mode) {
+	case NIC_UNICAST_BLOCKED:
+		rtl8139->rcr_data.ucast_mask = 0;
+		rtl8139_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
+		break;
+	case NIC_UNICAST_DEFAULT:
+		rtl8139->rcr_data.ucast_mask = RCR_ACCEPT_PHYS_MATCH;
+		rtl8139_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
+		break;
+	case NIC_UNICAST_LIST:
+		rtl8139->rcr_data.ucast_mask = RCR_ACCEPT_PHYS_MATCH
+		    | RCR_ACCEPT_ALL_PHYS;
+
+		if (mcast_mode == NIC_MULTICAST_PROMISC)
+			nic_report_hw_filtering(nic_data, 0, 1, -1);
+		else
+			nic_report_hw_filtering(nic_data, 0, 0, -1);
+		break;
+	case NIC_UNICAST_PROMISC:
+		rtl8139->rcr_data.ucast_mask = RCR_ACCEPT_PHYS_MATCH
+		    | RCR_ACCEPT_ALL_PHYS;
+
+		if (mcast_mode == NIC_MULTICAST_PROMISC)
+			nic_report_hw_filtering(nic_data, 1, 1, -1);
+		else
+			nic_report_hw_filtering(nic_data, 1, 0, -1);
+		break;
+	default:
+		return ENOTSUP;
+	}
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+}
+
+/** Set multicast packets acceptance mode
+ *
+ *  @param nic_data  The nic device to update
+ *  @param mode      The mode to set
+ *  @param addr      Addresses to accept
+ *  @param addr_cnt  Addresses count
+ *
+ *  @returns EOK
+ */
+static int rtl8139_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count)
+{
+	assert(nic_data);
+	assert(addr_count == 0 || addr);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch (mode) {
+	case NIC_MULTICAST_BLOCKED:
+		rtl8139->rcr_data.mcast_mask = 0;
+		if ((rtl8139->rcr_data.ucast_mask & RCR_ACCEPT_ALL_PHYS) != 0)
+			nic_report_hw_filtering(nic_data, -1, 0, -1);
+		else
+			nic_report_hw_filtering(nic_data, -1, 1, -1);
+		break;
+	case NIC_MULTICAST_LIST:
+		rtl8139_hw_set_mcast_mask(rtl8139, nic_mcast_hash(addr, addr_count));
+		rtl8139->rcr_data.mcast_mask = RCR_ACCEPT_MULTICAST;
+		nic_report_hw_filtering(nic_data, -1, 0, -1);
+		break;
+	case NIC_MULTICAST_PROMISC:
+		rtl8139_hw_set_mcast_mask(rtl8139, RTL8139_MCAST_MASK_PROMISC);
+		rtl8139->rcr_data.mcast_mask = RCR_ACCEPT_MULTICAST;
+		nic_report_hw_filtering(nic_data, -1, 1, -1);
+		break;
+	default:
+		return ENOTSUP;
+	}
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+}
+
+/** Set broadcast packets acceptance mode
+ *
+ *  @param nic_data  The nic device to update
+ *  @param mode      The mode to set
+ *
+ *  @returns EOK
+ */
+static int rtl8139_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch (mode) {
+	case NIC_BROADCAST_BLOCKED:
+		rtl8139->rcr_data.bcast_mask = 0;
+		break;
+	case NIC_BROADCAST_ACCEPTED:
+		rtl8139->rcr_data.bcast_mask = RCR_ACCEPT_BROADCAST;
+		break;
+	default:
+		return ENOTSUP;
+	}
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+}
+
+/** Get state of acceptance of weird packets
+ *
+ *  @param[in]  device  The device to check
+ *  @param[out] mode    The current mode
+ */
+static int rtl8139_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
+{
+	assert(fun);
+	assert(mode);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	*mode = 0;
+	if (rtl8139->rcr_data.defect_mask & RCR_ACCEPT_ERROR)
+		*mode |= NIC_DEFECTIVE_BAD_CRC;
+	if (rtl8139->rcr_data.defect_mask & RCR_ACCEPT_RUNT)
+		*mode |= NIC_DEFECTIVE_SHORT;
+
+	return EOK;
+};
+
+/** Set acceptance of weird packets
+ *
+ *  @param device  The device to update
+ *  @param mode    The mode to set
+ *
+ *  @returns ENOTSUP if the mode is not supported
+ *  @returns EOK of mode was set
+ */
+static int rtl8139_defective_set_mode(ddf_fun_t *fun, uint32_t mode)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if ((mode & (NIC_DEFECTIVE_SHORT | NIC_DEFECTIVE_BAD_CRC)) != mode)
+		return ENOTSUP;
+
+	rtl8139->rcr_data.defect_mask = 0;
+	if (mode & NIC_DEFECTIVE_SHORT)
+		rtl8139->rcr_data.defect_mask |= RCR_ACCEPT_RUNT;
+	if (mode & NIC_DEFECTIVE_BAD_CRC)
+		rtl8139->rcr_data.defect_mask |= RCR_ACCEPT_ERROR;
+
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+};
+
+
+/** Turn Wakeup On Lan method on
+ *
+ *  @param nic_data  The NIC to update
+ *  @param virtue    The method to turn on
+ *
+ *  @returns EINVAL if the method is not supported
+ *  @returns EOK if succeed
+ *  @returns ELIMIT if no more methods of this kind can be enabled
+ */
+static int rtl8139_wol_virtue_add(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue)
+{
+	assert(nic_data);
+	assert(virtue);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch(virtue->type) {
+	case NIC_WV_BROADCAST:
+		rtl8139_hw_reg_add_8(rtl8139, CONFIG5, CONFIG5_BROADCAST_WAKEUP);
+		break;
+	case NIC_WV_LINK_CHANGE:
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_add_8(rtl8139, CONFIG3, CONFIG3_LINK_UP);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	case NIC_WV_MAGIC_PACKET:
+		if (virtue->data)
+			return EINVAL;
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_add_8(rtl8139, CONFIG3, CONFIG3_MAGIC);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	default:
+		return EINVAL;
+	};
+	if(rtl8139->pm.active++ == 0)
+		rtl8139_hw_pmen_set(rtl8139, 1);
+	return EOK;
+}
+
+/** Turn Wakeup On Lan method off
+ *
+ *  @param nic_data  The NIC to update
+ *  @param virtue    The method to turn off
+ */
+static void rtl8139_wol_virtue_rem(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue)
+{
+	assert(nic_data);
+	assert(virtue);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch(virtue->type) {
+	case NIC_WV_BROADCAST:
+		rtl8139_hw_reg_rem_8(rtl8139, CONFIG5, CONFIG5_BROADCAST_WAKEUP);
+		break;
+	case NIC_WV_LINK_CHANGE:
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_rem_8(rtl8139, CONFIG3, CONFIG3_LINK_UP);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	case NIC_WV_MAGIC_PACKET:
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_rem_8(rtl8139, CONFIG3, CONFIG3_MAGIC);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	default:
+		return;
+	};
+	rtl8139->pm.active--;
+	if (rtl8139->pm.active == 0)
+		rtl8139_hw_pmen_set(rtl8139, 0);
+}
+
+
+/** Set polling mode
+ *
+ *  @param device  The device to set
+ *  @param mode    The mode to set
+ *  @param period  The period for NIC_POLL_PERIODIC
+ *
+ *  @returns EOK if succeed
+ *  @returns ENOTSUP if the mode is not supported
+ */
+static int rtl8139_poll_mode_change(nic_t *nic_data, nic_poll_mode_t mode,
+    const struct timeval *period)
+{
+	assert(nic_data);
+	int rc = EOK;
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	fibril_mutex_lock(&rtl8139->rx_lock);
+
+	switch(mode) {
+	case NIC_POLL_IMMEDIATE:
+		rtl8139->int_mask = RTL_DEFAULT_INTERRUPTS;
+		break;
+	case NIC_POLL_ON_DEMAND:
+		rtl8139->int_mask = 0;
+		break;
+	case NIC_POLL_PERIODIC:
+		assert(period);
+
+		rtl8139_timer_act_t new_timer;
+		rc = rtl8139_timer_act_init(&new_timer, RTL8139_PCI_FREQ_KHZ, period);
+		if (rc != EOK)
+			break;
+
+		/* Disable timer interrupts while working with timer-related data */
+		rtl8139->int_mask = 0;
+		rtl8139_hw_int_enable(rtl8139);
+
+		rtl8139->poll_timer = new_timer;
+		rtl8139->int_mask = INT_TIME_OUT;
+
+		/* Force timer interrupt start be writing nonzero value to timer 
+		 * interrutp register (should be small to prevent big delay)
+		 * Read TCTR to reset timer counter
+		 * Change values to simulate the last interrupt from the period.
+		 */
+		pio_write_32(rtl8139->io_port + TIMERINT, 10);
+		pio_write_32(rtl8139->io_port + TCTR, 0);
+
+		nlog_debug("Periodic mode. Interrupt mask %"PRIx16", poll.full_skips %"
+		    PRIu32", last timer %"PRIu32".", rtl8139->int_mask, 
+		    rtl8139->poll_timer.full_skips, rtl8139->poll_timer.last_val);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+
+	rtl8139_hw_int_enable(rtl8139);
+
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+
+	return rc;
+}
+
+/** Force receiving all packets in the receive buffer
+ *
+ *  @param device  The device to receive
+ */
+static void rtl8139_poll(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	uint16_t isr = pio_read_16(rtl8139->io_port + ISR);
+	pio_write_16(rtl8139->io_port + ISR, 0);
+
+	rtl8139_interrupt_impl(nic_data, isr);
+}
+
+
+/** Main function of RTL8139 driver
+ *
+ *  Just initialize the driver structures and
+ *  put it into the device drivers interface
+ */
+int main(void)
+{
+	int rc = nic_driver_init(NAME);
+	if (rc != EOK)
+		return rc;
+	nic_driver_implement(
+		&rtl8139_driver_ops, &rtl8139_dev_ops, &rtl8139_nic_iface);
+
+	nlog_set_min_severity(DEBUG);
+	nlog_info("HelenOS RTL8139 driver started");
+	return ddf_driver_main(&rtl8139_driver);
+}
Index: uspace/drv/nic/rtl8139/driver.h
===================================================================
--- uspace/drv/nic/rtl8139/driver.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/driver.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTL8139_DRIVER_H_
+#define RTL8139_DRIVER_H_
+
+#include "rtl8139_defs.h"
+#include "rtl8139_general.h"
+#include <sys/types.h>
+#include <stdint.h>
+#include <dma.h>
+
+/** The driver name */
+#define NAME "rtl8139"
+/** Transmittion buffers count */
+#define TX_BUFF_COUNT 4
+/** Size of buffer for one packet
+ *  - 2kB
+ */
+#define TX_BUFF_SIZE (2 * 1024)
+/** Count of pages to allocate for TxBuffers */
+#define TX_PAGES 2
+
+/** Size of the CRC after the received frame in the receiver buffer */
+#define RTL8139_CRC_SIZE 4
+
+/** The default mode of accepting unicast packets */
+#define RTL8139_RCR_UCAST_DEFAULT RCR_ACCEPT_PHYS_MATCH
+/** The default mode of accepting multicast packets */
+#define RTL8139_RCR_MCAST_DEFAULT 0
+/** The default mode of accepting broadcast packets */
+#define RTL8139_RCR_BCAST_DEFAULT RCR_ACCEPT_BROADCAST
+/** The default mode of accepting defect packets */
+#define RTL8139_RCR_DEFECT_DEFAULT 0
+
+/** Mask for accepting all multicast */
+#define RTL8139_MCAST_MASK_PROMISC UINT64_MAX
+
+/** Data  */
+struct rtl8139_rcr_data {
+	/** Configuration part of RCR */
+	uint32_t rcr_base;
+	/** Mask of unicast  */
+	uint8_t ucast_mask;
+	/** Mask of multicast */
+	uint8_t mcast_mask;
+	/** Mask of broadcast */
+	uint8_t bcast_mask;
+	/** Mask of defective */
+	uint8_t defect_mask;
+};
+
+/** Power management related data */
+typedef struct rtl8139_pm {
+	/** Count of used activities which needs PMEn bit set */
+	int active;
+} rtl8139_pm_t;
+
+/** RTL8139 device data */
+typedef struct rtl8139_data {
+	/** I/O address of the device */
+	void *io_addr;
+	/** Mapped I/O port */
+	void *io_port;
+	/** The irq assigned */
+	int irq;
+
+	/** Mask of the turned interupts (IMR value) */
+	uint16_t int_mask;
+
+	/** The memory allocated for the transmittion buffers
+	 *  Each buffer takes 2kB
+	 */
+	dma_mem_t tx_buff_mem;
+	/** Virtual adresses of the Tx buffers */
+	void *tx_buff[TX_BUFF_COUNT];
+
+	/** The nubmer of the next buffer to use, index = tx_next % TX_BUFF_COUNT */
+	size_t tx_next;
+	/** The number of the first used buffer in the row
+	 *
+	 *  tx_used is in the interval tx_next - TX_BUFF_COUNT and tx_next:
+	 *  	tx_next - TX_BUFF_COUNT: there is no useable Tx descriptor
+	 *  	tx_next: all Tx descriptors are can be used
+	 */
+	size_t tx_used;
+
+	/** Buffer for receiving packets */
+	dma_mem_t rx_buff;
+
+	/** Receiver control register data */
+	struct rtl8139_rcr_data rcr_data;
+
+	/** Power management information */
+	rtl8139_pm_t pm;
+
+	/** Lock for receiver */
+	fibril_mutex_t rx_lock;
+	/** Lock for transmitter */
+	fibril_mutex_t tx_lock;
+
+	/** Polling mode information */
+	rtl8139_timer_act_t poll_timer;
+
+	/** Backward pointer to nic_data */
+	nic_t *nic_data;
+
+	/** Version of RT8139 controller */
+	enum rtl8139_version_id hw_version;
+} rtl8139_t;
+
+
+/* ***** Pointers casting - for both amd64 and ia32 ***** */
+
+/** Cast pointer to uint32_t
+ *
+ *  @param ptr The pointer to cast
+ *  @return The uint32_t pointer representation. The low 32 bit is taken
+ *  in the case of the 64 bit pointers
+ */
+#define PTR2U32(ptr) ((uint32_t)((size_t)(ptr)))
+
+/** Check if the pointer can be cast to uint32_t without the data lost
+ *
+ *  @param ptr The pointer to check
+ *  @return The true value if the pointer can be cast, false if not
+ */
+#define PTR_IS_32(ptr) ((size_t)PTR2U32(ptr) == (size_t)(ptr))
+
+/** Cast the ioaddr part to the void*
+ *
+ *  @param ioaddr The ioaddr value
+ */
+#define IOADDR_TO_PTR(ioaddr) ((void*)((size_t)(ioaddr)))
+
+
+
+/* ***** Bit operation macros ***** */
+
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The bit from the src is used if the corresponding bit in the mask is 0,
+ * the bit from the value is used if the corresponding bit in the mask is 1
+ *
+ * @param src The original value
+ * @param value The new bit value
+ * @param mask The mask to specify modified bits
+ * @param type The values type
+ *
+ * @return New value
+ */
+#define bit_set_part_g( src, value, mask, type ) \
+	((type)(((src) & ~((type)(mask))) | ((value) & (type)(mask))))
+
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The version of the uint32_t
+ *
+ * @see bit_set_part_g
+ */
+
+#define bit_set_part_32(src, value, mask) bit_set_part_g(src, value, mask, uint32_t)
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The version of the uint16_t
+ *
+ * @see bit_set_part_g
+ */
+
+#define bit_set_part_16(src, value, mask) bit_set_part_g(src, value, mask, uint16_t)
+
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The version of the uint8_t
+ *
+ * @see bit_set_part_g
+ */
+#define bit_set_part_8(src, value, mask) bit_set_part_g(src, value, mask, uint8_t)
+
+/** Clear specified bits in the value
+ *
+ * @param src Original value
+ * @param clear_mask Bits to clear mask
+ * @param type The values type
+ */
+#define bit_clear_g(src, clear_mask, type) ((type)((src) & ~((type)(clear_mask))))
+
+/** Clear specified bits in the value, 32bit version
+ *
+ *  @see bit_clear_g
+ */
+#define bit_clear_32(src, clear_mask) bit_clear_g(src, clear_mask, uint32_t)
+/** Clear specified bits in the value, 16bit version
+ *
+ *  @see bit_clear_g
+ */
+#define bit_clear_16(src, clear_mask) bit_clear_g(src, clear_mask, uint16_t)
+/** Clear specified bits in the value, 8bit version
+ *
+ *  @see bit_clear_g
+ */
+#define bit_clear_8(src, clear_mask) bit_clear_g(src, clear_mask, uint8_t)
+
+/** Obtain value of the TSD register with size part modified
+ *
+ *  @param tsd_value Old value of the TSD
+ *  @param size The size to set
+ */
+#define rtl8139_tsd_set_size(tsd_value, size) \
+	bit_set_part_32(tsd_value, (size) << TSD_SIZE_SHIFT, TSD_SIZE_MASK << TSD_SIZE_SHIFT)
+
+
+#endif
Index: uspace/drv/nic/rtl8139/general.c
===================================================================
--- uspace/drv/nic/rtl8139/general.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/general.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ *
+ *  General functions and structures used in rtl8139 driver
+ */
+
+#include "rtl8139_general.h"
+
+#include <mem.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+/** Copy block of the memory from wrapped source buffer.
+ *
+ * Start on the specific offset in the source buffer and * copy data_size bytes
+ * - continue from the buffer start after getting the end
+ *
+ * @param dest        The destination memory
+ * @param src_begin   The begin of the source buffer
+ * @param src_offset  The offset in the source buffer to start copy
+ * @param src_size    The source buffer size
+ * @param data_size   The amount of data to copy
+ *
+ * @return NULL if the error occures, dest if succeed
+ */
+void* rtl8139_memcpy_wrapped(void *dest, const void *src, size_t src_offset,
+    size_t src_size, size_t data_size)
+{
+	src_offset %= src_size;
+	if (data_size > src_size)
+		return NULL;
+
+	size_t to_src_end = src_size - src_offset;
+	if (data_size <= to_src_end) {
+		return memcpy(dest, src + src_offset, data_size);
+	}
+
+	size_t rem_size = data_size - to_src_end;
+
+	/* First copy the end part of the data (from the source begining),
+	 * then copy the begining
+	 */
+	memcpy(dest + to_src_end, src, rem_size);
+	return memcpy(dest, src + src_offset, to_src_end);
+}
+
+/** Initialize the timer register structures 
+ *
+ *  The structure will be initialized to the state that the first call of 
+ *  rtl8139_timer_act_step function will be the period expiration
+ *
+ *  @param ta          The timer structure
+ *  @param timer_freq  The timer frequency in kHz
+ *  @param time        The requested time
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+int rtl8139_timer_act_init(rtl8139_timer_act_t * ta, uint32_t timer_freq,
+    const struct timeval *time) 
+{
+	if (!ta || timer_freq == 0 || !time)
+		return EINVAL;
+	memset(ta, 0, sizeof(rtl8139_timer_act_t));
+
+	uint32_t tics_per_ms = timer_freq;
+	uint32_t seconds_in_reg = UINT32_MAX / (tics_per_ms * 1000);
+	ta->full_val = seconds_in_reg * tics_per_ms * 1000;
+
+	struct timeval remains = *time;
+	ta->full_skips = remains.tv_sec / seconds_in_reg;
+	remains.tv_sec = remains.tv_sec % seconds_in_reg;
+
+	if (remains.tv_usec > RTL8139_USEC_IN_SEC) {
+		remains.tv_sec += remains.tv_usec / RTL8139_USEC_IN_SEC;
+		remains.tv_usec = remains.tv_usec % RTL8139_USEC_IN_SEC;
+
+		/* it can be increased above seconds_in_reg again */
+		ta->full_skips += remains.tv_sec / seconds_in_reg;
+		remains.tv_sec = remains.tv_sec % seconds_in_reg;
+	}
+
+	ta->last_val = remains.tv_sec * 1000 + remains.tv_usec / 1000;
+	ta->last_val *= tics_per_ms;
+
+	/* Force inital setting in the next step */
+	ta->full_skips_remains = 0;
+	ta->last_run = 1;
+	return EOK;
+};
+
+
+/** Make one step timer step
+ *
+ *  @param ta            Timer structure
+ *  @param new_reg[out]  Register value to set
+ *
+ *  @return Nonzero if whole period expired, zero if part of period expired
+ */
+int rtl8139_timer_act_step(rtl8139_timer_act_t * ta, uint32_t *new_reg)
+{
+	uint32_t next_val = 0;
+	int expired = 0;
+
+	if (ta->last_run || (ta->last_val == 0 && ta->full_skips_remains == 0)) {
+		ta->full_skips_remains = ta->full_skips;
+		ta->last_run = 0;
+		expired = 1;
+	}
+
+	if (ta->full_skips_remains > 0) {
+		next_val = ta->full_val;
+		ta->full_skips_remains--;
+	} else {
+		next_val = ta->last_val;
+		ta->last_run = 1;
+	}
+
+	if (new_reg)
+		*new_reg = next_val;
+
+	return expired;
+};
+
Index: uspace/drv/nic/rtl8139/general.h
===================================================================
--- uspace/drv/nic/rtl8139/general.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/general.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ *
+ *  General functions and structures used in rtl8139 driver
+ */
+
+#ifndef RTL8139_GENERAL_H_
+#define RTL8139_GENERAL_H_
+
+#include <unistd.h>
+
+extern void* rtl8139_memcpy_wrapped(void *dest, const void *src_buf,
+    size_t src_offset, size_t src_size, size_t data_size);
+
+
+/** Structure for HW timer control */
+typedef struct rtl8139_timer_act {
+	/** Register value set in the last timer period */
+	uint32_t last_val;
+	/** Register value set in the common timer period */
+	uint32_t full_val;
+
+	/** Amount of full register periods in timer period */
+	size_t full_skips;
+	/** Remaining full register periods to the next period end */
+	size_t full_skips_remains;
+	/** Mark if there is a last run */
+	int last_run;
+} rtl8139_timer_act_t;
+
+/** Count of microseconds in second */
+#define RTL8139_USEC_IN_SEC 1000000
+
+extern int rtl8139_timer_act_init(rtl8139_timer_act_t *ta, uint32_t timer_freq,
+    const struct timeval *time);
+extern int rtl8139_timer_act_step(rtl8139_timer_act_t *ta, uint32_t *new_reg);
+
+
+#endif
Index: uspace/drv/nic/rtl8139/rtl8139.ma
===================================================================
--- uspace/drv/nic/rtl8139/rtl8139.ma	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/drv/nic/rtl8139/rtl8139.ma	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,1 @@
+10 pci/ven=10ec&dev=8139
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -70,4 +70,5 @@
 	generic/device/char_dev.c \
 	generic/device/nic.c \
+	generic/device/pci.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/as.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -45,15 +45,18 @@
 /** Create address space area.
  *
- * @param address Virtual address where to place new address space area.
- * @param size    Size of the area.
- * @param flags   Flags describing type of the area.
+ * @param base  Starting virtual address of the area.
+ *              If set to (void *) -1, the kernel finds
+ *              a mappable area.
+ * @param size  Size of the area.
+ * @param flags Flags describing type of the area.
  *
- * @return address on success, (void *) -1 otherwise.
+ * @return Starting virtual address of the created area on success.
+ * @return (void *) -1 otherwise.
  *
  */
-void *as_area_create(void *address, size_t size, unsigned int flags)
+void *as_area_create(void *base, size_t size, unsigned int flags)
 {
-	return (void *) __SYSCALL3(SYS_AS_AREA_CREATE, (sysarg_t) address,
-	    (sysarg_t) size, (sysarg_t) flags);
+	return (void *) __SYSCALL4(SYS_AS_AREA_CREATE, (sysarg_t) base,
+	    (sysarg_t) size, (sysarg_t) flags, (sysarg_t) __entry);
 }
 
@@ -102,41 +105,17 @@
 }
 
-/** Return pointer to unmapped address space area
+/** Find mapping to physical address.
  *
- * @param size Requested size of the allocation.
+ * @param      virt Virtual address to find mapping for.
+ * @param[out] phys Physical adress.
  *
- * @return Pointer to the beginning of unmapped address space area.
+ * @return EOK on no error.
+ * @retval ENOENT if no mapping was found.
  *
  */
-void *as_get_mappable_page(size_t size)
+int as_get_physical_mapping(const void *virt, uintptr_t *phys)
 {
-	return (void *) __SYSCALL2(SYS_AS_GET_UNMAPPED_AREA,
-	    (sysarg_t) __entry, (sysarg_t) size);
-}
-
-/** 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(const 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;
+	return (int) __SYSCALL2(SYS_PAGE_FIND_MAPPING, (sysarg_t) virt,
+	    (sysarg_t) phys);
 }
 
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/async.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1846,5 +1846,5 @@
 	
 	fibril_mutex_lock(&async_sess_mutex);
-
+	
 	int rc = async_hangup_internal(sess->phone);
 	
@@ -1998,25 +1998,27 @@
  *
  * @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.
+ * @param dst   Destination address space area base. Cannot be NULL.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int async_share_in_start(async_exch_t *exch, void *dst, size_t size,
-    sysarg_t arg, unsigned int *flags)
+int async_share_in_start(async_exch_t *exch, size_t size, sysarg_t arg,
+    unsigned int *flags, void **dst)
 {
 	if (exch == NULL)
 		return ENOENT;
 	
-	sysarg_t tmp_flags;
-	int res = async_req_3_2(exch, IPC_M_SHARE_IN, (sysarg_t) dst,
-	    (sysarg_t) size, arg, NULL, &tmp_flags);
+	sysarg_t _flags = 0;
+	sysarg_t _dst = (sysarg_t) -1;
+	int res = async_req_2_4(exch, IPC_M_SHARE_IN, (sysarg_t) size,
+	    arg, NULL, &_flags, NULL, &_dst);
 	
 	if (flags)
-		*flags = (unsigned int) tmp_flags;
-	
+		*flags = (unsigned int) _flags;
+	
+	*dst = (void *) _dst;
 	return res;
 }
@@ -2047,5 +2049,5 @@
 		return false;
 	
-	*size = (size_t) IPC_GET_ARG2(data);
+	*size = (size_t) IPC_GET_ARG1(data);
 	return true;
 }
@@ -2053,5 +2055,5 @@
 /** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework.
  *
- * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
+ * This wrapper only makes it more comfortable to answer IPC_M_SHARE_IN
  * calls so that the user doesn't have to remember the meaning of each IPC
  * argument.
@@ -2131,5 +2133,5 @@
  *
  */
-int async_share_out_finalize(ipc_callid_t callid, void *dst)
+int async_share_out_finalize(ipc_callid_t callid, void **dst)
 {
 	return ipc_share_out_finalize(callid, dst);
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/ddi.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -33,4 +33,7 @@
  */
 
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <abi/ddi/arg.h>
@@ -42,4 +45,5 @@
 #include <align.h>
 #include <libarch/config.h>
+#include "private/libc.h"
 
 /** Return unique device number.
@@ -57,8 +61,8 @@
  * Caller of this function must have the CAP_MEM_MANAGER capability.
  *
- * @param pf    Physical address of the starting frame.
- * @param vp    Virtual address of the starting page.
+ * @param phys  Physical address of the starting frame.
  * @param pages Number of pages to map.
  * @param flags Flags for the new address space area.
+ * @param virt  Virtual address of the starting page.
  *
  * @return EOK on success
@@ -69,8 +73,35 @@
  *
  */
-int physmem_map(void *pf, void *vp, size_t pages, unsigned int flags)
+int physmem_map(void *phys, size_t pages, unsigned int flags, void **virt)
 {
-	return __SYSCALL4(SYS_PHYSMEM_MAP, (sysarg_t) pf, (sysarg_t) vp,
-	    pages, flags);
+	return __SYSCALL5(SYS_PHYSMEM_MAP, (sysarg_t) phys,
+	    pages, flags, (sysarg_t) virt, (sysarg_t) __entry);
+}
+
+int dmamem_map(void *virt, size_t size, unsigned int map_flags,
+    unsigned int flags, void **phys)
+{
+	return (int) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
+	    (sysarg_t) map_flags, (sysarg_t) flags & ~DMAMEM_FLAGS_ANONYMOUS,
+	    (sysarg_t) phys, (sysarg_t) virt, 0);
+}
+
+int dmamem_map_anonymous(size_t size, unsigned int map_flags,
+    unsigned int flags, void **phys, void **virt)
+{
+	return (int) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
+	    (sysarg_t) map_flags, (sysarg_t) flags | DMAMEM_FLAGS_ANONYMOUS,
+	    (sysarg_t) phys, (sysarg_t) virt, (sysarg_t) __entry);
+}
+
+int dmamem_unmap(void *virt, size_t size)
+{
+	return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, (sysarg_t) size, 0);
+}
+
+int dmamem_unmap_anonymous(void *virt)
+{
+	return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, 0,
+	    DMAMEM_FLAGS_ANONYMOUS);
 }
 
@@ -79,21 +110,22 @@
  * Caller of this function must have the IO_MEM_MANAGER capability.
  *
- * @param id		Task ID.
- * @param ioaddr	Starting address of the I/O range.
- * @param size		Size of the range.
+ * @param id     Task ID.
+ * @param ioaddr Starting address of the I/O range.
+ * @param size   Size of the range.
  *
- * @return		0 on success, EPERM if the caller lacks the
- *			CAP_IO_MANAGER capability, ENOENT if there is no task
- *			with specified ID and ENOMEM if there was some problem
- *			in allocating memory.
+ * @return EOK on success
+ * @return EPERM if the caller lacks the CAP_IO_MANAGER capability
+ * @return ENOENT if there is no task with specified ID
+ * @return ENOMEM if there was some problem in allocating memory.
+ *
  */
 int iospace_enable(task_id_t id, void *ioaddr, unsigned long size)
 {
 	ddi_ioarg_t arg;
-
+	
 	arg.task_id = id;
 	arg.ioaddr = ioaddr;
 	arg.size = size;
-
+	
 	return __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg);
 }
@@ -101,31 +133,35 @@
 /** Enable PIO for specified I/O range.
  *
- * @param pio_addr	I/O start address.
- * @param size		Size of the I/O region.
- * @param use_addr	Address where the final address for application's PIO
- * 			will be stored.
+ * @param pio_addr I/O start address.
+ * @param size     Size of the I/O region.
+ * @param virt     Virtual address for application's
+ *                 PIO operations.
  *
- * @return		Zero on success or negative error code.
+ * @return EOK on success.
+ * @return Negative error code on failure.
+ *
  */
-int pio_enable(void *pio_addr, size_t size, void **use_addr)
+int pio_enable(void *pio_addr, size_t size, void **virt)
 {
-	void *phys;
-	void *virt;
-	size_t offset;
-	unsigned int pages;
-
 #ifdef IO_SPACE_BOUNDARY
 	if (pio_addr < IO_SPACE_BOUNDARY) {
-		*use_addr = pio_addr;
+		*virt = pio_addr;
 		return iospace_enable(task_get_id(), pio_addr, size);
 	}
 #endif
-
-	phys = (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
-	offset = pio_addr - phys;
-	pages = ALIGN_UP(offset + size, PAGE_SIZE) >> PAGE_WIDTH;
-	virt = as_get_mappable_page(pages << PAGE_WIDTH);
-	*use_addr = virt + offset;
-	return physmem_map(phys, virt, pages, AS_AREA_READ | AS_AREA_WRITE);
+	
+	void *phys_frame =
+	    (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
+	size_t offset = pio_addr - phys_frame;
+	size_t pages = SIZE2PAGES(offset + size);
+	
+	void *virt_page;
+	int rc = physmem_map(phys_frame, pages,
+	    AS_AREA_READ | AS_AREA_WRITE, &virt_page);
+	if (rc != EOK)
+		return rc;
+	
+	*virt = virt_page + offset;
+	return EOK;
 }
 
@@ -140,7 +176,7 @@
  *
  */
-int register_irq(int inr, int devno, int method, irq_code_t *ucode)
+int irq_register(int inr, int devno, int method, irq_code_t *ucode)
 {
-	return __SYSCALL4(SYS_REGISTER_IRQ, inr, devno, method,
+	return __SYSCALL4(SYS_IRQ_REGISTER, inr, devno, method,
 	    (sysarg_t) ucode);
 }
@@ -154,7 +190,7 @@
  *
  */
-int unregister_irq(int inr, int devno)
+int irq_unregister(int inr, int devno)
 {
-	return __SYSCALL2(SYS_UNREGISTER_IRQ, inr, devno);
+	return __SYSCALL2(SYS_IRQ_UNREGISTER, inr, devno);
 }
 
Index: uspace/lib/c/generic/device/nic.c
===================================================================
--- uspace/lib/c/generic/device/nic.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/device/nic.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -895,5 +895,5 @@
  *
  */
-int nic_vlan_set_tag(async_sess_t *dev_sess, uint16_t tag, int add, int strip)
+int nic_vlan_set_tag(async_sess_t *dev_sess, uint16_t tag, bool add, bool strip)
 {
 	async_exch_t *exch = async_exchange_begin(dev_sess);
Index: uspace/lib/c/generic/device/pci.c
===================================================================
--- uspace/lib/c/generic/device/pci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/lib/c/generic/device/pci.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING 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 <ipc/dev_iface.h>
+#include <assert.h>
+#include <device/pci.h>
+#include <errno.h>
+#include <async.h>
+#include <ipc/services.h>
+
+int pci_config_space_read_8(async_sess_t *sess, uint32_t address, uint8_t *val)
+{
+	sysarg_t res = 0;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_8, address, &res);
+	async_exchange_end(exch);
+	
+	*val = (uint8_t) res;
+	return rc;
+}
+
+int pci_config_space_read_16(async_sess_t *sess, uint32_t address,
+    uint16_t *val)
+{
+	sysarg_t res = 0;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_16, address, &res);
+	async_exchange_end(exch);
+	
+	*val = (uint16_t) res;
+	return rc;
+}
+
+int pci_config_space_read_32(async_sess_t *sess, uint32_t address,
+    uint32_t *val)
+{
+	sysarg_t res = 0;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, address, &res);
+	async_exchange_end(exch);
+	
+	*val = (uint32_t) res;
+	return rc;
+}
+
+int pci_config_space_write_8(async_sess_t *sess, uint32_t address, uint8_t val)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_8, address, val);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+int pci_config_space_write_16(async_sess_t *sess, uint32_t address,
+    uint16_t val)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_16, address, val);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+int pci_config_space_write_32(async_sess_t *sess, uint32_t address,
+    uint32_t val)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_32, address, val);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/elf/elf_load.c
===================================================================
--- uspace/lib/c/generic/elf/elf_load.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/elf/elf_load.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -364,9 +364,9 @@
 	 * and writeable.
 	 */
-	a = as_area_create((uint8_t *)base + bias, mem_sz,
+	a = as_area_create((uint8_t *) base + bias, mem_sz,
 	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
-	if (a == (void *)(-1)) {
+	if (a == (void *) -1) {
 		DPRINTF("memory mapping failed (0x%x, %d)\n",
-			base+bias, mem_sz);
+		    base + bias, mem_sz);
 		return EE_MEMORY;
 	}
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/fibril_synch.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -447,4 +447,135 @@
 }
 
+/** Timer fibril.
+ *
+ * @param arg	Timer
+ */
+static int fibril_timer_func(void *arg)
+{
+	fibril_timer_t *timer = (fibril_timer_t *) arg;
+	int rc;
+
+	fibril_mutex_lock(&timer->lock);
+
+	while (true) {
+		while (timer->state != fts_active &&
+		    timer->state != fts_cleanup) {
+
+			if (timer->state == fts_cleanup)
+				break;
+
+			fibril_condvar_wait(&timer->cv, &timer->lock);
+		}
+
+		if (timer->state == fts_cleanup)
+			break;
+
+		rc = fibril_condvar_wait_timeout(&timer->cv, &timer->lock,
+		    timer->delay);
+		if (rc == ETIMEOUT) {
+			timer->state = fts_fired;
+			fibril_mutex_unlock(&timer->lock);
+			timer->fun(timer->arg);
+			fibril_mutex_lock(&timer->lock);
+		}
+	}
+
+	fibril_mutex_unlock(&timer->lock);
+	return 0;
+}
+
+/** Create new timer.
+ *
+ * @return		New timer on success, @c NULL if out of memory.
+ */
+fibril_timer_t *fibril_timer_create(void)
+{
+	fid_t fid;
+	fibril_timer_t *timer;
+
+	timer = calloc(1, sizeof(fibril_timer_t));
+	if (timer == NULL)
+		return NULL;
+
+	fid = fibril_create(fibril_timer_func, (void *) timer);
+	if (fid == 0) {
+		free(timer);
+		return NULL;
+	}
+
+	fibril_mutex_initialize(&timer->lock);
+	fibril_condvar_initialize(&timer->cv);
+
+	timer->fibril = fid;
+	timer->state = fts_not_set;
+
+	fibril_add_ready(fid);
+
+	return timer;
+}
+
+/** Destroy timer.
+ *
+ * @param timer		Timer, must not be active or accessed by other threads.
+ */
+void fibril_timer_destroy(fibril_timer_t *timer)
+{
+	fibril_mutex_lock(&timer->lock);
+	assert(timer->state != fts_active);
+	timer->state = fts_cleanup;
+	fibril_condvar_broadcast(&timer->cv);
+	fibril_mutex_unlock(&timer->lock);
+}
+
+/** Set timer.
+ *
+ * Set timer to execute a callback function after the specified
+ * interval.
+ *
+ * @param timer		Timer
+ * @param delay		Delay in microseconds
+ * @param fun		Callback function
+ * @param arg		Argument for @a fun
+ */
+void fibril_timer_set(fibril_timer_t *timer, suseconds_t delay,
+    fibril_timer_fun_t fun, void *arg)
+{
+	fibril_mutex_lock(&timer->lock);
+	timer->state = fts_active;
+	timer->delay = delay;
+	timer->fun = fun;
+	timer->arg = arg;
+	fibril_condvar_broadcast(&timer->cv);
+	fibril_mutex_unlock(&timer->lock);
+}
+
+/** Clear timer.
+ *
+ * Clears (cancels) timer and returns last state of the timer.
+ * This can be one of:
+ *    - fts_not_set	If the timer has not been set or has been cleared
+ *    - fts_active	Timer was set but did not fire
+ *    - fts_fired	Timer fired
+ *
+ * @param timer		Timer
+ * @return		Last timer state
+ */
+fibril_timer_state_t fibril_timer_clear(fibril_timer_t *timer)
+{
+	fibril_timer_state_t old_state;
+
+	fibril_mutex_lock(&timer->lock);
+	old_state = timer->state;
+	timer->state = fts_not_set;
+
+	timer->delay = 0;
+	timer->fun = NULL;
+	timer->arg = NULL;
+	fibril_condvar_broadcast(&timer->cv);
+	fibril_mutex_unlock(&timer->lock);
+
+	return old_state;
+}
+
 /** @}
  */
Index: uspace/lib/c/generic/ipc.c
===================================================================
--- uspace/lib/c/generic/ipc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/ipc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -48,4 +48,5 @@
 #include <fibril.h>
 #include <macros.h>
+#include "private/libc.h"
 
 /**
@@ -760,22 +761,24 @@
  *
  * @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 received flags. Can be NULL.
+ * @param dst     Destination address space area base. Cannot be NULL.
  *
  * @return Zero on success or a negative error code from errno.h.
  *
  */
-int ipc_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
-    unsigned int *flags)
-{
-	sysarg_t tmp_flags = 0;
-	int res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
-	    (sysarg_t) size, arg, NULL, &tmp_flags);
+int ipc_share_in_start(int phoneid, size_t size, sysarg_t arg,
+    unsigned int *flags, void **dst)
+{
+	sysarg_t _flags = 0;
+	sysarg_t _dst = (sysarg_t) -1;
+	int res = ipc_call_sync_2_4(phoneid, IPC_M_SHARE_IN, (sysarg_t) size,
+	    arg, NULL, &_flags, NULL, &_dst);
 	
 	if (flags)
-		*flags = (unsigned int) tmp_flags;
-	
+		*flags = (unsigned int) _flags;
+	
+	*dst = (void *) _dst;
 	return res;
 }
@@ -783,5 +786,5 @@
 /** Wrapper for answering the IPC_M_SHARE_IN calls.
  *
- * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
+ * This wrapper only makes it more comfortable to answer IPC_M_SHARE_IN
  * calls so that the user doesn't have to remember the meaning of each
  * IPC argument.
@@ -796,5 +799,6 @@
 int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
 {
-	return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) flags);
+	return ipc_answer_3(callid, EOK, (sysarg_t) src, (sysarg_t) flags,
+	    (sysarg_t) __entry);
 }
 
@@ -826,7 +830,7 @@
  *
  */
-int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
-{
-	return ipc_answer_1(callid, EOK, (sysarg_t) dst);
+int ipc_share_out_finalize(ipc_callid_t callid, void **dst)
+{
+	return ipc_answer_2(callid, EOK, (sysarg_t) __entry, (sysarg_t) dst);
 }
 
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/malloc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -283,13 +283,8 @@
 static bool area_create(size_t size)
 {
-	void *start = as_get_mappable_page(size);
-	if (start == NULL)
-		return false;
-	
-	/* Align the heap area on page boundary */
-	void *astart = (void *) ALIGN_UP((uintptr_t) start, PAGE_SIZE);
+	/* Align the heap area size on page boundary */
 	size_t asize = ALIGN_UP(size, PAGE_SIZE);
-	
-	astart = as_area_create(astart, asize, AS_AREA_WRITE | AS_AREA_READ);
+	void *astart = as_area_create((void *) -1, asize,
+	    AS_AREA_WRITE | AS_AREA_READ);
 	if (astart == (void *) -1)
 		return false;
Index: uspace/lib/c/generic/mman.c
===================================================================
--- uspace/lib/c/generic/mman.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/mman.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -42,5 +42,5 @@
 {
 	if (!start)
-		start = as_get_mappable_page(length);
+		start = (void *) -1;
 	
 //	if (!((flags & MAP_SHARED) ^ (flags & MAP_PRIVATE)))
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/generic/time.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -147,12 +147,7 @@
 		}
 		
-		void *addr = as_get_mappable_page(PAGE_SIZE);
-		if (addr == NULL) {
-			errno = ENOMEM;
-			return -1;
-		}
-		
-		rc = physmem_map((void *) faddr, addr, 1,
-		    AS_AREA_READ | AS_AREA_CACHEABLE);
+		void *addr;
+		rc = physmem_map((void *) faddr, 1,
+		    AS_AREA_READ | AS_AREA_CACHEABLE, &addr);
 		if (rc != EOK) {
 			as_area_destroy(addr);
Index: uspace/lib/c/include/as.h
===================================================================
--- uspace/lib/c/include/as.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/as.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -59,5 +59,4 @@
 extern int as_area_destroy(void *);
 extern void *set_maxheapsize(size_t);
-extern void *as_get_mappable_page(size_t);
 extern int as_get_physical_mapping(const void *, uintptr_t *);
 
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/async.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -346,15 +346,15 @@
  */
 
-#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 *);
+#define async_share_in_start_0_0(exch, size, dst) \
+	async_share_in_start(exch, size, 0, NULL, dst)
+#define async_share_in_start_0_1(exch, size, flags, dst) \
+	async_share_in_start(exch, size, 0, flags, dst)
+#define async_share_in_start_1_0(exch, size, arg, dst) \
+	async_share_in_start(exch, size, arg, NULL, dst)
+#define async_share_in_start_1_1(exch, size, arg, flags, dst) \
+	async_share_in_start(exch, size, arg, flags, dst)
+
+extern int async_share_in_start(async_exch_t *, size_t, sysarg_t,
+    unsigned int *, void **);
 extern bool async_share_in_receive(ipc_callid_t *, size_t *);
 extern int async_share_in_finalize(ipc_callid_t, void *, unsigned int);
@@ -362,5 +362,5 @@
 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 *);
+extern int async_share_out_finalize(ipc_callid_t, void **);
 
 /*
Index: uspace/lib/c/include/bitops.h
===================================================================
--- uspace/lib/c/include/bitops.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/bitops.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -40,9 +40,9 @@
 /** Mask with bit @a n set. */
 #define BIT_V(type, n) \
-    ((type)1 << ((n) - 1))
+    ((type) 1 << (n))
 
 /** Mask with rightmost @a n bits set. */
 #define BIT_RRANGE(type, n) \
-    (BIT_V(type, (n) + 1) - 1)
+    (BIT_V(type, (n)) - 1)
 
 /** Mask with bits @a hi .. @a lo set. @a hi >= @a lo. */
Index: uspace/lib/c/include/ddi.h
===================================================================
--- uspace/lib/c/include/ddi.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/ddi.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -41,9 +41,18 @@
 
 extern int device_assign_devno(void);
-extern int physmem_map(void *, void *, size_t, unsigned int);
+
+extern int physmem_map(void *, size_t, unsigned int, void **);
+
+extern int dmamem_map(void *, size_t, unsigned int, unsigned int, void **);
+extern int dmamem_map_anonymous(size_t, unsigned int, unsigned int, void **,
+    void **);
+extern int dmamem_unmap(void *, size_t);
+extern int dmamem_unmap_anonymous(void *);
+
 extern int iospace_enable(task_id_t, void *, unsigned long);
 extern int pio_enable(void *, size_t, void **);
-extern int register_irq(int, int, int, irq_code_t *);
-extern int unregister_irq(int, int);
+
+extern int irq_register(int, int, int, irq_code_t *);
+extern int irq_unregister(int, int);
 
 #endif
Index: uspace/lib/c/include/device/hw_res.h
===================================================================
--- uspace/lib/c/include/device/hw_res.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/device/hw_res.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -40,8 +40,17 @@
 #include <bool.h>
 
+#define DMA_MODE_ON_DEMAND  0
+#define DMA_MODE_WRITE      (1 << 2)
+#define DMA_MODE_READ       (1 << 3)
+#define DMA_MODE_AUTO       (1 << 4)
+#define DMA_MODE_DOWN       (1 << 5)
+#define DMA_MODE_SINGLE     (1 << 6)
+#define DMA_MODE_BLOCK      (1 << 7)
+
 /** HW resource provider interface */
 typedef enum {
 	HW_RES_GET_RESOURCE_LIST = 0,
-	HW_RES_ENABLE_INTERRUPT
+	HW_RES_ENABLE_INTERRUPT,
+	HW_RES_DMA_CHANNEL_SETUP,
 } hw_res_method_t;
 
@@ -50,5 +59,7 @@
 	INTERRUPT,
 	IO_RANGE,
-	MEM_RANGE
+	MEM_RANGE,
+	DMA_CHANNEL_8,
+	DMA_CHANNEL_16,
 } hw_res_type_t;
 
@@ -77,4 +88,9 @@
 			int irq;
 		} interrupt;
+		
+		union {
+			unsigned int dma8;
+			unsigned int dma16;
+		} dma_channel;
 	} res;
 } hw_resource_t;
@@ -98,4 +114,7 @@
 extern bool hw_res_enable_interrupt(async_sess_t *);
 
+extern int hw_res_dma_channel_setup(async_sess_t *, unsigned int, uint32_t,
+    uint16_t, uint8_t);
+
 #endif
 
Index: uspace/lib/c/include/device/hw_res_parsed.h
===================================================================
--- uspace/lib/c/include/device/hw_res_parsed.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/device/hw_res_parsed.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -72,4 +72,13 @@
 } irq_list_t;
 
+/** List of ISA DMA channels */
+typedef struct dma_list {
+	/** Channel count */
+	size_t count;
+
+	/** Array of channels */
+	unsigned int *channels;
+} dma_list_t;
+
 /** List of memory areas */
 typedef struct addr_range_list {
@@ -91,4 +100,7 @@
 	/** List of IRQs */
 	irq_list_t irqs;
+	
+	/** List of DMA channels */
+	dma_list_t dma_channels;
 	
 	/** List of memory areas */
@@ -113,4 +125,5 @@
 	free(list->io_ranges.ranges);
 	free(list->mem_ranges.ranges);
+	free(list->dma_channels.channels);
 	
 	bzero(list, sizeof(hw_res_list_parsed_t));
Index: uspace/lib/c/include/device/nic.h
===================================================================
--- uspace/lib/c/include/device/nic.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/device/nic.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -127,5 +127,5 @@
 extern int nic_vlan_get_mask(async_sess_t *, nic_vlan_mask_t *);
 extern int nic_vlan_set_mask(async_sess_t *, const nic_vlan_mask_t *);
-extern int nic_vlan_set_tag(async_sess_t *, uint16_t, int, int);
+extern int nic_vlan_set_tag(async_sess_t *, uint16_t, bool, bool);
 
 extern int nic_wol_virtue_add(async_sess_t *, nic_wv_type_t, const void *,
Index: uspace/lib/c/include/device/pci.h
===================================================================
--- uspace/lib/c/include/device/pci.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/lib/c/include/device/pci.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING 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_DEVICE_PCI_H_
+#define LIBC_DEVICE_PCI_H_
+
+#include <async.h>
+
+#define PCI_DEVICE_ID  0x02
+
+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;
+
+extern int pci_config_space_read_8(async_sess_t *, uint32_t, uint8_t *);
+extern int pci_config_space_read_16(async_sess_t *, uint32_t, uint16_t *);
+extern int pci_config_space_read_32(async_sess_t *, uint32_t, uint32_t *);
+
+extern int pci_config_space_write_8(async_sess_t *, uint32_t, uint8_t);
+extern int pci_config_space_write_16(async_sess_t *, uint32_t, uint16_t);
+extern int pci_config_space_write_32(async_sess_t *, uint32_t, uint32_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/errno.h
===================================================================
--- uspace/lib/c/include/errno.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/errno.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -96,4 +96,8 @@
 #define ENOTCONN  (-10057)
 
+#define ECONNREFUSED  (-10058)
+
+#define ECONNABORTED  (-10059)
+
 /** The requested operation was not performed. Try again later. */
 #define EAGAIN  (-11002)
Index: uspace/lib/c/include/fibril_synch.h
===================================================================
--- uspace/lib/c/include/fibril_synch.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/fibril_synch.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -107,4 +107,35 @@
 	fibril_condvar_t name = FIBRIL_CONDVAR_INITIALIZER(name)
 
+typedef void (*fibril_timer_fun_t)(void *);
+
+typedef enum {
+	/** Timer has not been set or has been cleared */
+	fts_not_set,
+	/** Timer was set but did not fire yet */
+	fts_active,
+	/** Timer has fired and has not been cleared since */
+	fts_fired,
+	/** Timer is being destroyed */
+	fts_cleanup
+} fibril_timer_state_t;
+
+/** Fibril timer.
+ *
+ * When a timer is set it executes a callback function (in a separate
+ * fibril) after a specified time interval. The timer can be cleared
+ * (canceled) before that. From the return value of fibril_timer_clear()
+ * one can tell whether the timer fired or not.
+ */
+typedef struct {
+	fibril_mutex_t lock;
+	fibril_condvar_t cv;
+	fid_t fibril;
+	fibril_timer_state_t state;
+
+	suseconds_t delay;
+	fibril_timer_fun_t fun;
+	void *arg;
+} fibril_timer_t;
+
 extern void fibril_mutex_initialize(fibril_mutex_t *);
 extern void fibril_mutex_lock(fibril_mutex_t *);
@@ -129,4 +160,10 @@
 extern void fibril_condvar_broadcast(fibril_condvar_t *);
 
+extern fibril_timer_t *fibril_timer_create(void);
+extern void fibril_timer_destroy(fibril_timer_t *);
+extern void fibril_timer_set(fibril_timer_t *, suseconds_t, fibril_timer_fun_t,
+    void *);
+extern fibril_timer_state_t fibril_timer_clear(fibril_timer_t *);
+
 #endif
 
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/ipc/ipc.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -271,17 +271,17 @@
  */
 
-#define ipc_share_in_start_0_0(phoneid, dst, size) \
-	ipc_share_in_start((phoneid), (dst), (size), 0, NULL)
-#define ipc_share_in_start_0_1(phoneid, dst, size, flags) \
-	ipc_share_in_start((phoneid), (dst), (size), 0, (flags))
-#define ipc_share_in_start_1_0(phoneid, dst, size, arg) \
-	ipc_share_in_start((phoneid), (dst), (size), (arg), NULL)
-#define ipc_share_in_start_1_1(phoneid, dst, size, arg, flags) \
-	ipc_share_in_start((phoneid), (dst), (size), (arg), (flags))
-
-extern int ipc_share_in_start(int, void *, size_t, sysarg_t, unsigned int *);
+#define ipc_share_in_start_0_0(phoneid, size, dst) \
+	ipc_share_in_start((phoneid), (size), 0, NULL, (dst))
+#define ipc_share_in_start_0_1(phoneid, size, flags, dst) \
+	ipc_share_in_start((phoneid), (size), 0, (flags), (dst))
+#define ipc_share_in_start_1_0(phoneid, size, arg, dst) \
+	ipc_share_in_start((phoneid), (size), (arg), NULL, (dst))
+#define ipc_share_in_start_1_1(phoneid, size, arg, flags, dst) \
+	ipc_share_in_start((phoneid), (size), (arg), (flags), (dst))
+
+extern int ipc_share_in_start(int, size_t, sysarg_t, unsigned int *, void **);
 extern int ipc_share_in_finalize(ipc_callid_t, void *, unsigned int);
 extern int ipc_share_out_start(int, void *, unsigned int);
-extern int ipc_share_out_finalize(ipc_callid_t, void *);
+extern int ipc_share_out_finalize(ipc_callid_t, void **);
 extern int ipc_data_read_start(int, void *, size_t);
 extern int ipc_data_read_finalize(ipc_callid_t, const void *, size_t);
Index: uspace/lib/c/include/ipc/net.h
===================================================================
--- uspace/lib/c/include/ipc/net.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/ipc/net.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -305,5 +305,5 @@
  *
  */
-#define IPC_GET_DEVICE_HANDLE(call) ((devman_handle_t) IPC_GET_ARG2(call))
+#define IPC_GET_DEVICE_HANDLE(call)  ((devman_handle_t) IPC_GET_ARG2(call))
 
 /** Return the device driver service message argument.
Index: uspace/lib/c/include/net/device.h
===================================================================
--- uspace/lib/c/include/net/device.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/c/include/net/device.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -77,4 +77,12 @@
 #define NIC_PART_NUMBER_MAX_LENGTH    64
 #define NIC_SERIAL_NUMBER_MAX_LENGTH  64
+
+#define NIC_DEFECTIVE_LONG               0x0001
+#define NIC_DEFECTIVE_SHORT              0x0002
+#define NIC_DEFECTIVE_BAD_CRC            0x0010
+#define NIC_DEFECTIVE_BAD_IPV4_CHECKSUM  0x0020
+#define NIC_DEFECTIVE_BAD_IPV6_CHECKSUM  0x0040
+#define NIC_DEFECTIVE_BAD_TCP_CHECKSUM   0x0080
+#define NIC_DEFECTIVE_BAD_UDP_CHECKSUM   0x0100
 
 /**
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/drv/generic/driver.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -198,5 +198,5 @@
 		pseudocode = &default_pseudocode;
 	
-	int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
+	int res = irq_register(irq, dev->handle, ctx->id, pseudocode);
 	if (res != EOK) {
 		remove_interrupt_context(&interrupt_contexts, ctx);
@@ -211,5 +211,5 @@
 	interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
 	    dev, irq);
-	int res = unregister_irq(irq, dev->handle);
+	int res = irq_unregister(irq, dev->handle);
 	
 	if (ctx != NULL) {
Index: uspace/lib/drv/generic/remote_nic.c
===================================================================
--- uspace/lib/drv/generic/remote_nic.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/drv/generic/remote_nic.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -829,6 +829,6 @@
 	
 	uint16_t tag = (uint16_t) IPC_GET_ARG2(*call);
-	int add = (int) IPC_GET_ARG3(*call);
-	int strip = (int) IPC_GET_ARG4(*call);
+	bool add = (int) IPC_GET_ARG3(*call);
+	bool strip = (int) IPC_GET_ARG4(*call);
 	
 	int rc = nic_iface->vlan_set_tag(dev, tag, add, strip);
Index: uspace/lib/drv/include/ops/hw_res.h
===================================================================
--- uspace/lib/drv/include/ops/hw_res.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/drv/include/ops/hw_res.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 /*
- * Copyright (c) 2010 Lenka Trochtova 
+ * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -42,6 +43,7 @@
 
 typedef struct {
-	 hw_resource_list_t *(*get_resource_list)(ddf_fun_t *);
-	 bool (*enable_interrupt)(ddf_fun_t *);
+	hw_resource_list_t *(*get_resource_list)(ddf_fun_t *);
+	bool (*enable_interrupt)(ddf_fun_t *);
+	int (*dma_channel_setup)(ddf_fun_t *, unsigned, uint32_t, uint16_t, uint8_t);
 } hw_res_ops_t;
 
Index: uspace/lib/drv/include/ops/nic.h
===================================================================
--- uspace/lib/drv/include/ops/nic.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/drv/include/ops/nic.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -89,5 +89,5 @@
 	int (*vlan_get_mask)(ddf_fun_t *, nic_vlan_mask_t *);
 	int (*vlan_set_mask)(ddf_fun_t *, const nic_vlan_mask_t *);
-	int (*vlan_set_tag)(ddf_fun_t *, uint16_t, int, int);
+	int (*vlan_set_tag)(ddf_fun_t *, uint16_t, bool, bool);
 	
 	int (*wol_virtue_add)(ddf_fun_t *, nic_wv_type_t, const void *,
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,5 +27,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libdrv
  * @addtogroup usb
@@ -46,5 +46,5 @@
 int usbhc_get_handle(async_exch_t *, usb_address_t, devman_handle_t *);
 int usbhc_release_address(async_exch_t *, usb_address_t);
-int usbhc_register_endpoint(async_exch_t *, usb_address_t,  usb_endpoint_t,
+int usbhc_register_endpoint(async_exch_t *, usb_address_t, usb_endpoint_t,
     usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
 int usbhc_unregister_endpoint(async_exch_t *, usb_address_t, usb_endpoint_t,
Index: uspace/lib/fb/imgmap.c
===================================================================
--- uspace/lib/fb/imgmap.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/fb/imgmap.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -420,8 +420,7 @@
 	
 	if ((flags & IMGMAP_FLAG_SHARED) == IMGMAP_FLAG_SHARED) {
-		imgmap = (imgmap_t *) as_get_mappable_page(size);
-		
-		if (as_area_create((void *) imgmap, size, AS_AREA_READ |
-		    AS_AREA_WRITE | AS_AREA_CACHEABLE) != (void *) imgmap)
+		imgmap = (imgmap_t *) as_area_create((void *) -1, size,
+		    AS_AREA_READ | AS_AREA_WRITE);
+		if (imgmap == (void *) -1)
 			return NULL;
 	} else {
Index: uspace/lib/fb/screenbuffer.c
===================================================================
--- uspace/lib/fb/screenbuffer.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/fb/screenbuffer.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -79,8 +79,7 @@
 	
 	if ((flags & SCREENBUFFER_FLAG_SHARED) == SCREENBUFFER_FLAG_SHARED) {
-		scrbuf = (screenbuffer_t *) as_get_mappable_page(size);
-		
-		if (as_area_create((void *) scrbuf, size, AS_AREA_READ |
-		    AS_AREA_WRITE | AS_AREA_CACHEABLE) != (void *) scrbuf)
+		scrbuf = (screenbuffer_t *) as_area_create((void *) -1, size,
+		    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
+		if (scrbuf == (void *) -1)
 			return NULL;
 	} else {
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/fs/libfs.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -336,17 +336,12 @@
 	
 	/*
-	 * Allocate piece of address space for PLB.
-	 */
-	reg.plb_ro = as_get_mappable_page(PLB_SIZE);
-	if (!reg.plb_ro) {
+	 * Request sharing the Path Lookup Buffer with VFS.
+	 */
+	rc = async_share_in_start_0_0(exch, PLB_SIZE, (void *) &reg.plb_ro);
+	if (reg.plb_ro == (void *) -1) {
 		async_exchange_end(exch);
 		async_wait_for(req, NULL);
 		return ENOMEM;
 	}
-	
-	/*
-	 * Request sharing the Path Lookup Buffer with VFS.
-	 */
-	rc = async_share_in_start_0_0(exch, reg.plb_ro, PLB_SIZE);
 	
 	async_exchange_end(exch);
Index: uspace/lib/net/generic/packet_client.c
===================================================================
--- uspace/lib/net/generic/packet_client.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/net/generic/packet_client.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -39,5 +39,4 @@
 #include <unistd.h>
 #include <sys/mman.h>
-
 #include <packet_client.h>
 #include <packet_remote.h>
Index: uspace/lib/net/generic/packet_remote.c
===================================================================
--- uspace/lib/net/generic/packet_remote.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/net/generic/packet_remote.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -66,10 +66,8 @@
     packet_id_t packet_id, size_t size)
 {
-	*packet = (packet_t *) as_get_mappable_page(size);
-	
 	async_exch_t *exch = async_exchange_begin(sess);
 	ipc_call_t answer;
 	aid_t message = async_send_1(exch, NET_PACKET_GET, packet_id, &answer);
-	int rc = async_share_in_start_0_0(exch, *packet, size);
+	int rc = async_share_in_start_0_0(exch, size, (void *) packet);
 	async_exchange_end(exch);
 	
@@ -77,8 +75,9 @@
 	async_wait_for(message, &result);
 	
-	if (rc != EOK) {
-		munmap(*packet, size);
+	if (rc != EOK)
 		return rc;
-	}
+	
+	if (packet == (void *) -1)
+		return ENOMEM;
 	
 	rc = pm_add(*packet);
Index: uspace/lib/nic/include/nic.h
===================================================================
--- uspace/lib/nic/include/nic.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/nic/include/nic.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -275,6 +275,6 @@
 
 /* Packet DMA lock */
-extern void * nic_dma_lock_packet(packet_t * packet);
-extern void nic_dma_unlock_packet(packet_t * packet);
+extern int nic_dma_lock_packet(packet_t *, size_t, void **);
+extern int nic_dma_unlock_packet(packet_t *, size_t);
 
 #endif // __NIC_H__
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/nic/src/nic_driver.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -46,5 +46,5 @@
 #include <ipc/irc.h>
 #include <sysinfo.h>
-
+#include <as.h>
 #include <devman.h>
 #include <ddf/interrupt.h>
@@ -1329,7 +1329,4 @@
 }
 
-// FIXME: Later
-#if 0
-
 /** Lock packet for DMA usage
  *
@@ -1337,14 +1334,7 @@
  * @return physical address of packet
  */
-void *nic_dma_lock_packet(packet_t *packet)
-{
-	void *phys_addr;
-	size_t locked;
-	int rc = dma_lock(packet, &phys_addr, 1, &locked);
-	if (rc != EOK)
-		return NULL;
-	
-	assert(locked == 1);
-	return phys_addr;
+int nic_dma_lock_packet(packet_t *packet, size_t size, void **phys)
+{
+	return dmamem_map(packet, SIZE2PAGES(size), 0, 0, phys);
 }
 
@@ -1353,15 +1343,8 @@
  * @param packet
  */
-void nic_dma_unlock_packet(packet_t *packet)
-{
-	size_t unlocked;
-	int rc = dma_unlock(packet, 1, &unlocked);
-	if (rc != EOK)
-		return;
-	
-	assert(unlocked == 1);
-}
-
-#endif
+int nic_dma_unlock_packet(packet_t *packet, size_t size)
+{
+	return dmamem_unmap(packet, size);
+}
 
 /** @}
Index: uspace/lib/nic/src/nic_rx_control.c
===================================================================
--- uspace/lib/nic/src/nic_rx_control.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/nic/src/nic_rx_control.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -438,4 +438,5 @@
 		}
 	}
+	
 	/* Blocked source addresses */
 	if (rxc->block_sources) {
@@ -443,4 +444,5 @@
 			return false;
 	}
+	
 	/* VLAN filtering */
 	if (!rxc->vlan_exact && rxc->vlan_mask != NULL) {
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -37,8 +37,8 @@
 	src/class.c \
 	src/ddfiface.c \
+	src/dev.c \
 	src/debug.c \
 	src/dump.c \
 	src/hc.c \
-	src/resolve.c \
 	src/usb.c
 
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -84,7 +84,8 @@
 
 /**
- *	@brief usb hub descriptor
- *
- *	For more information see Universal Serial Bus Specification Revision 1.1 chapter 11.16.2
+ * @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 {
Index: uspace/lib/usb/include/usb/dev.h
===================================================================
--- uspace/lib/usb/include/usb/dev.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/lib/usb/include/usb/dev.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -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 libusb
+ * @{
+ */
+/** @file
+ * Common USB types and functions.
+ */
+#ifndef LIBUSB_DEV_H_
+#define LIBUSB_DEV_H_
+
+#include <devman.h>
+#include <usb/usb.h>
+
+int usb_get_info_by_handle(devman_handle_t,
+    devman_handle_t *, usb_address_t *, int *);
+
+static inline int usb_get_hc_by_handle(devman_handle_t dev, devman_handle_t *hc)
+{
+	return usb_get_info_by_handle(dev, hc, NULL, NULL);
+}
+
+static inline int usb_get_address_by_handle(
+    devman_handle_t dev, usb_address_t *address)
+{
+	return usb_get_info_by_handle(dev, NULL, address, NULL);
+}
+
+static inline int usb_get_iface_by_handle(devman_handle_t dev, int *iface)
+{
+	return usb_get_info_by_handle(dev, NULL, NULL, iface);
+}
+
+int usb_resolve_device_handle(const char *, devman_handle_t *, usb_address_t *,
+    devman_handle_t *);
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/hc.h
===================================================================
--- uspace/lib/usb/include/usb/hc.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/include/usb/hc.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,23 +27,27 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusb
  * @{
  */
 /** @file
- * General communication with host controller driver.
+ * General communication with host controller.
  */
 #ifndef LIBUSB_HC_H_
 #define LIBUSB_HC_H_
 
-#include <sys/types.h>
-#include <ipc/devman.h>
-#include <ipc/loc.h>
+#include <async.h>
+#include <devman.h>
 #include <ddf/driver.h>
 #include <bool.h>
-#include <async.h>
+#include <fibril_synch.h>
 #include <usb/usb.h>
 
-/** Connection to the host controller driver. */
+/** Connection to the host controller driver.
+ *
+ * This is a high level IPC communication wrapper. After the structure has been
+ * initialized using devman handle of an USB host controller, it
+ * will manage all communication to that host controller, including session
+ * creation/destruction and proper IPC protocol.
+ */
 typedef struct {
 	/** Devman handle of the host controller. */
@@ -50,25 +55,64 @@
 	/** Session to the host controller. */
 	async_sess_t *hc_sess;
+	/** Session guard. */
+	fibril_mutex_t guard;
+	/** Use counter. */
+	unsigned ref_count;
 } usb_hc_connection_t;
+
+/** Initialize connection to USB host controller.
+ *
+ * @param connection Connection to be initialized.
+ * @param hc_handle Devman handle of the host controller.
+ * @return Error code.
+ */
+static inline void 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;
+	connection->ref_count = 0;
+	fibril_mutex_initialize(&connection->guard);
+}
 
 int usb_hc_connection_initialize_from_device(usb_hc_connection_t *,
     const ddf_dev_t *);
-int usb_hc_connection_initialize(usb_hc_connection_t *, devman_handle_t);
+
+void usb_hc_connection_deinitialize(usb_hc_connection_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 *);
+
+usb_address_t usb_hc_request_address(usb_hc_connection_t *, usb_address_t, bool,
+    usb_speed_t);
+int usb_hc_bind_address(usb_hc_connection_t *, usb_address_t, devman_handle_t);
 int usb_hc_get_handle_by_address(usb_hc_connection_t *, usb_address_t,
     devman_handle_t *);
+int usb_hc_release_address(usb_hc_connection_t *, usb_address_t);
 
-usb_address_t usb_get_address_by_handle(devman_handle_t);
+int usb_hc_register_endpoint(usb_hc_connection_t *, usb_address_t,
+    usb_endpoint_t, usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
+int usb_hc_unregister_endpoint(usb_hc_connection_t *, usb_address_t,
+    usb_endpoint_t, usb_direction_t);
 
-int usb_hc_find(devman_handle_t, devman_handle_t *);
+int usb_hc_read(usb_hc_connection_t *, usb_address_t, usb_endpoint_t,
+    uint64_t, void *, size_t, size_t *);
+int usb_hc_write(usb_hc_connection_t *, usb_address_t, usb_endpoint_t,
+    uint64_t, const void *, size_t);
 
-int usb_resolve_device_handle(const char *, devman_handle_t *, usb_address_t *,
-    devman_handle_t *);
-
-int usb_ddf_get_hc_handle_by_sid(service_id_t, devman_handle_t *);
-
+/** Get host controller handle by its class index.
+ *
+ * @param sid Service ID of the HC function.
+ * @param hc_handle Where to store the HC handle
+ *	(can be NULL for existence test only).
+ * @return Error code.
+ */
+static inline int usb_ddf_get_hc_handle_by_sid(
+    service_id_t sid, devman_handle_t *handle)
+{
+	devman_handle_t h;
+	return devman_fun_sid_to_handle(sid, handle ? handle : &h);
+}
 
 #endif
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/include/usb/usb.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -26,5 +26,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusb
  * @{
Index: uspace/lib/usb/src/ddfiface.c
===================================================================
--- uspace/lib/usb/src/ddfiface.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/src/ddfiface.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -44,4 +44,6 @@
 #include <assert.h>
 
+#include <usb/dev.h>
+
 /** DDF interface for USB device, implementation for typical hub. */
 usb_iface_t usb_iface_hub_impl = {
@@ -66,5 +68,5 @@
 {
 	assert(fun);
-	return usb_hc_find(fun->handle, handle);
+	return usb_get_hc_by_handle(fun->handle, handle);
 }
 
@@ -97,23 +99,5 @@
 {
 	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);
-	if (!exch) {
-		async_hangup(parent_sess);
-		return ENOMEM;
-	}
-
-	const int ret = usb_get_my_address(exch, address);
-
-	async_exchange_end(exch);
-	async_hangup(parent_sess);
-
-	return ret;
+	return usb_get_address_by_handle(fun->handle, address);
 }
 
@@ -134,5 +118,5 @@
 	assert(fun);
 	assert(fun->driver_data);
-	usb_hub_attached_device_t *device = fun->driver_data;
+	const usb_hub_attached_device_t *device = fun->driver_data;
 	assert(device->fun == fun);
 	if (address)
Index: uspace/lib/usb/src/dev.c
===================================================================
--- uspace/lib/usb/src/dev.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/lib/usb/src/dev.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+
+#include <usb/dev.h>
+#include <usb/hc.h>
+#include <errno.h>
+#include <usb_iface.h>
+#include <str.h>
+#include <stdio.h>
+
+#define MAX_DEVICE_PATH 1024
+
+/** Find host controller handle, address and iface number for the 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.
+ * @param[out] address Place to store the device's address
+ * @param[out] iface Place to stoer the assigned USB interface number.
+ * @return Error code.
+ */
+int usb_get_info_by_handle(devman_handle_t device_handle,
+    devman_handle_t *hc_handle, usb_address_t *address, int *iface)
+{
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_ATOMIC, device_handle,
+	        IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+
+	async_exch_t *exch = async_exchange_begin(parent_sess);
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+
+	usb_address_t tmp_address;
+	devman_handle_t tmp_handle;
+	int tmp_iface;
+
+	if (address) {
+		const int ret = usb_get_my_address(exch, &tmp_address);
+		if (ret != EOK) {
+			async_exchange_end(exch);
+			async_hangup(parent_sess);
+			return ret;
+		}
+	}
+
+	if (hc_handle) {
+		const int ret = usb_get_hc_handle(exch, &tmp_handle);
+		if (ret != EOK) {
+			async_exchange_end(exch);
+			async_hangup(parent_sess);
+			return ret;
+		}
+	}
+
+	if (iface) {
+		const int ret = usb_get_my_interface(exch, &tmp_iface);
+		switch (ret) {
+		case ENOTSUP:
+			/* Implementing GET_MY_INTERFACE is voluntary. */
+			tmp_iface = -1;
+		case EOK:
+			break;
+		default:
+			async_exchange_end(exch);
+			async_hangup(parent_sess);
+			return ret;
+		}
+	}
+
+	if (hc_handle)
+		*hc_handle = tmp_handle;
+
+	if (address)
+		*address = tmp_address;
+
+	if (iface)
+		*iface = tmp_iface;
+
+	async_exchange_end(exch);
+	async_hangup(parent_sess);
+
+	return EOK;
+}
+
+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)
+{
+	uint64_t sid;
+	size_t address;
+	int rc;
+	char *ptr;
+
+	rc = str_uint64(path, &ptr, 10, false, &sid);
+	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_sid(sid, 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)
+{
+	usb_hc_connection_t conn;
+	usb_hc_connection_initialize(&conn, hc_handle);
+
+	const int rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
+
+	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_fun_get_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_fun_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_fun_get_handle(path, &tmp_handle, 0);
+		if (rc != EOK) {
+			free(path);
+			return rc;
+		}
+
+		/* Try to find its host controller. */
+		if (!found_hc) {
+			rc = usb_get_hc_by_handle(tmp_handle, &hc_handle);
+			if (rc == EOK) {
+				found_hc = true;
+			}
+		}
+
+		/* Try to get its address. */
+		if (!found_addr) {
+			rc = usb_get_address_by_handle(tmp_handle, &dev_addr);
+			if (rc == 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/hc.c
===================================================================
--- uspace/lib/usb/src/hc.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/src/hc.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,5 +27,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusb
  * @{
@@ -33,13 +33,72 @@
  * General communication with host controller driver (implementation).
  */
-#include <devman.h>
-#include <async.h>
-#include <dev_iface.h>
-#include <usb_iface.h>
+#include <usb/debug.h>
+
+#include <assert.h>
+#include <errno.h>
 #include <usbhc_iface.h>
+#include <usb/dev.h>
 #include <usb/hc.h>
-#include <usb/debug.h>
-#include <errno.h>
-#include <assert.h>
+
+static int usb_hc_connection_add_ref(usb_hc_connection_t *connection)
+{
+	assert(connection);
+	fibril_mutex_lock(&connection->guard);
+	if (connection->ref_count == 0) {
+		assert(connection->hc_sess == NULL);
+		/* Parallel exchange for us */
+		connection->hc_sess = devman_device_connect(EXCHANGE_PARALLEL,
+		        connection->hc_handle, 0);
+		if (!connection->hc_sess) {
+			fibril_mutex_unlock(&connection->guard);
+			return ENOMEM;
+		}
+	}
+	++connection->ref_count;
+	fibril_mutex_unlock(&connection->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static int usb_hc_connection_del_ref(usb_hc_connection_t *connection)
+{
+	assert(connection);
+	fibril_mutex_lock(&connection->guard);
+	if (connection->ref_count == 0) {
+		/* Closing already closed connection... */
+		assert(connection->hc_sess = NULL);
+		fibril_mutex_unlock(&connection->guard);
+		return EOK;
+	}
+	--connection->ref_count;
+	int ret = EOK;
+	if (connection->ref_count == 0) {
+		assert(connection->hc_sess);
+		ret = async_hangup(connection->hc_sess);
+		connection->hc_sess = NULL;
+	}
+	fibril_mutex_unlock(&connection->guard);
+	return ret;
+}
+
+#define EXCH_INIT(connection, exch) \
+do { \
+	exch = NULL; \
+	if (!connection) \
+		return EBADMEM; \
+	const int ret = usb_hc_connection_add_ref(connection); \
+	if (ret != EOK) \
+		return ret; \
+	exch = async_exchange_begin(connection->hc_sess); \
+	if (exch == NULL) { \
+		usb_hc_connection_del_ref(connection); \
+		return ENOMEM; \
+	} \
+} while (0)
+
+#define EXCH_FINI(connection, exch) \
+if (exch) { \
+	async_exchange_end(exch); \
+	usb_hc_connection_del_ref(connection); \
+} else (void)0
 
 /** Initialize connection to USB host controller.
@@ -59,31 +118,27 @@
 
 	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);
+	const int rc = usb_get_hc_by_handle(device->handle, &hc_handle);
+	if (rc == EOK) {
+		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;
-}
-
+/*----------------------------------------------------------------------------*/
+void usb_hc_connection_deinitialize(usb_hc_connection_t *connection)
+{
+	assert(connection);
+	fibril_mutex_lock(&connection->guard);
+	if (connection->ref_count != 0) {
+		usb_log_warning("%u stale reference(s) to HC connection.\n",
+		    connection->ref_count);
+		assert(connection->hc_sess);
+		async_hangup(connection->hc_sess);
+		connection->hc_sess = NULL;
+		connection->ref_count = 0;
+	}
+	fibril_mutex_unlock(&connection->guard);
+}
+/*----------------------------------------------------------------------------*/
 /** Open connection to host controller.
  *
@@ -93,52 +148,51 @@
 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_ATOMIC,
-	    connection->hc_handle, 0);
-	if (!sess)
-		return ENOMEM;
-	
-	connection->hc_sess = sess;
-	return EOK;
-}
-
-/** Tells whether connection to host controller is opened.
+	return usb_hc_connection_add_ref(connection);
+}
+/*----------------------------------------------------------------------------*/
+/** Close connection to the host controller.
  *
  * @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;
-}
-
+	return usb_hc_connection_del_ref(connection);
+}
+/*----------------------------------------------------------------------------*/
+/** Ask host controller for free address assignment.
+ *
+ * @param connection Opened connection to host controller.
+ * @param preferred Preferred SUB address.
+ * @param strict Fail if the preferred address is not avialable.
+ * @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_address_t preferred, bool strict, usb_speed_t speed)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	usb_address_t address = preferred;
+	const int ret = usbhc_request_address(exch, &address, strict, speed);
+
+	EXCH_FINI(connection, exch);
+	return ret == EOK ? address : ret;
+}
+/*----------------------------------------------------------------------------*/
+int usb_hc_bind_address(usb_hc_connection_t * connection,
+    usb_address_t address, devman_handle_t handle)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	const int ret = usbhc_bind_address(exch, address, handle);
+
+	EXCH_FINI(connection, exch);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
 /** Get handle of USB device with given address.
  *
@@ -151,90 +205,75 @@
     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);
-	if (!exch)
-		return ENOMEM;
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
 	const int ret = usbhc_get_handle(exch, address, handle);
-	async_exchange_end(exch);
-	return ret;
-}
-
-/** 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_get_address_by_handle(devman_handle_t dev_handle)
-{
-	async_sess_t *parent_sess =
-	    devman_parent_device_connect(EXCHANGE_ATOMIC, dev_handle,
-	    IPC_FLAG_BLOCKING);
-	if (!parent_sess)
-		return ENOMEM;
-
-	async_exch_t *exch = async_exchange_begin(parent_sess);
-	if (!exch) {
-		async_hangup(parent_sess);
-		return ENOMEM;
-	}
-	usb_address_t address;
-	const int ret = usb_get_my_address(exch, &address);
-
-	async_exchange_end(exch);
-	async_hangup(parent_sess);
-
-	if (ret != EOK)
-		return ret;
-
-	return address;
-}
-
-
-/** Get host controller handle by its class index.
- *
- * @param sid Service ID of the HC function.
- * @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_sid(service_id_t sid, devman_handle_t *hc_handle)
-{
-	devman_handle_t handle;
-	int rc;
-	
-	rc = devman_fun_sid_to_handle(sid, &handle);
-	if (hc_handle != NULL)
-		*hc_handle = handle;
-	
-	return rc;
-}
-
-/** 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_ATOMIC, device_handle,
-	    IPC_FLAG_BLOCKING);
-	if (!parent_sess)
-		return ENOMEM;
-
-	async_exch_t *exch = async_exchange_begin(parent_sess);
-	if (!exch) {
-		async_hangup(parent_sess);
-		return ENOMEM;
-	}
-	const int ret = usb_get_hc_handle(exch, hc_handle);
-
-	async_exchange_end(exch);
-	async_hangup(parent_sess);
-
+
+	EXCH_FINI(connection, exch);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usb_hc_release_address(usb_hc_connection_t *connection,
+    usb_address_t address)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	const int ret = usbhc_release_address(exch, address);
+
+	EXCH_FINI(connection, exch);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usb_hc_register_endpoint(usb_hc_connection_t *connection,
+    usb_address_t address, usb_endpoint_t endpoint, usb_transfer_type_t type,
+    usb_direction_t direction, size_t packet_size, unsigned interval)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	const int ret = usbhc_register_endpoint(exch, address, endpoint,
+	    type, direction, packet_size, interval);
+
+	EXCH_FINI(connection, exch);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usb_hc_unregister_endpoint(usb_hc_connection_t *connection,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	const int ret =
+	    usbhc_unregister_endpoint(exch, address, endpoint, direction);
+
+	EXCH_FINI(connection, exch);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usb_hc_read(usb_hc_connection_t *connection, usb_address_t address,
+    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
+    size_t *real_size)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	const int ret =
+	    usbhc_read(exch, address, endpoint, setup, data, size, real_size);
+
+	EXCH_FINI(connection, exch);
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usb_hc_write(usb_hc_connection_t *connection, usb_address_t address,
+    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
+{
+	async_exch_t *exch;
+	EXCH_INIT(connection, exch);
+
+	const int ret = usbhc_write(exch, address, endpoint, setup, data, size);
+
+	EXCH_FINI(connection, exch);
 	return ret;
 }
Index: pace/lib/usb/src/resolve.c
===================================================================
--- uspace/lib/usb/src/resolve.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ 	(revision )
@@ -1,244 +1,0 @@
-/*
- * 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)
-{
-	uint64_t sid;
-	size_t address;
-	int rc;
-	char *ptr;
-
-	rc = str_uint64(path, &ptr, 10, false, &sid);
-	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_sid(sid, 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_fun_get_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_fun_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_fun_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_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 cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usb/src/usb.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -39,27 +39,27 @@
 
 static const char *str_speed[] = {
-	"low",
-	"full",
-	"high"
+	[USB_SPEED_LOW] = "low",
+	[USB_SPEED_FULL] = "full",
+	[USB_SPEED_HIGH] = "high",
 };
 
 static const char *str_transfer_type[] = {
-	"control",
-	"isochronous",
-	"bulk",
-	"interrupt"
+	[USB_TRANSFER_CONTROL] = "control",
+	[USB_TRANSFER_ISOCHRONOUS] = "isochronous",
+	[USB_TRANSFER_BULK] = "bulk",
+	[USB_TRANSFER_INTERRUPT] = "interrupt",
 };
 
 static const char *str_transfer_type_short[] = {
-	"ctrl",
-	"iso",
-	"bulk",
-	"intr"
+	[USB_TRANSFER_CONTROL] = "ctrl",
+	[USB_TRANSFER_ISOCHRONOUS] = "iso",
+	[USB_TRANSFER_BULK] = "bulk",
+	[USB_TRANSFER_INTERRUPT] = "intr",
 };
 
 static const char *str_direction[] = {
-	"in",
-	"out",
-	"both"
+	[USB_DIRECTION_IN] = "in",
+	[USB_DIRECTION_OUT] = "out",
+	[USB_DIRECTION_BOTH] = "both",
 };
 
Index: uspace/lib/usbdev/Makefile
===================================================================
--- uspace/lib/usbdev/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -40,9 +40,6 @@
 	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
Index: uspace/lib/usbdev/include/usb/dev/driver.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/driver.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/include/usb/dev/driver.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -36,4 +36,6 @@
 #define LIBUSBDEV_DRIVER_H_
 
+#include <usb/hc.h>
+#include <usb/dev/usb_device_connection.h>
 #include <usb/dev/pipes.h>
 
@@ -72,4 +74,6 @@
 /** USB device structure. */
 typedef struct {
+	/** Connection to USB hc, used by wire and arbitrary requests. */
+	usb_hc_connection_t hc_conn;
 	/** Connection backing the pipes.
 	 * Typically, you will not need to use this attribute at all.
@@ -169,8 +173,8 @@
 void usb_device_release_descriptors(usb_device_descriptors_t *);
 
-int usb_device_create_pipes(const ddf_dev_t *, usb_device_connection_t *,
+int usb_device_create_pipes(usb_device_connection_t *,
     const usb_endpoint_description_t **, const uint8_t *, size_t, int, int,
     usb_endpoint_mapping_t **, size_t *);
-int usb_device_destroy_pipes(const ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
+void usb_device_destroy_pipes(usb_endpoint_mapping_t *, size_t);
 
 void * usb_device_data_alloc(usb_device_t *, size_t);
Index: uspace/lib/usbdev/include/usb/dev/hub.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/hub.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/include/usb/dev/hub.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -40,4 +40,5 @@
 #include <ddf/driver.h>
 #include <sys/types.h>
+#include <errno.h>
 #include <usb/hc.h>
 
@@ -59,9 +60,15 @@
 } usb_hub_attached_device_t;
 
-usb_address_t usb_hc_request_address(usb_hc_connection_t *, usb_address_t,
-    bool, usb_speed_t);
-int usb_hc_register_device(usb_hc_connection_t *,
+int usb_hub_register_device(usb_hc_connection_t *,
     const usb_hub_attached_device_t *);
-int usb_hc_unregister_device(usb_hc_connection_t *, usb_address_t);
+
+static inline int usb_hub_unregister_device(usb_hc_connection_t *conn,
+    const usb_hub_attached_device_t *attached_device)
+{
+	assert(conn);
+	if (attached_device == NULL)
+		return EBADMEM;
+	return usb_hc_release_address(conn, attached_device->address);
+}
 
 #endif
Index: uspace/lib/usbdev/include/usb/dev/pipes.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/pipes.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -26,5 +26,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusbdev
  * @{
@@ -37,38 +36,18 @@
 
 #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>
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/dev/usb_device_connection.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).
+#define CTRL_PIPE_MIN_PACKET_SIZE 8
+/** Abstraction of a logical connection to USB device endpoint.
+ * It encapsulates endpoint attributes (transfer type etc.).
+ * This endpoint must be bound with existing usb_device_connection_t
+ * (i.e. the wire to send data over).
  */
 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;
@@ -86,33 +65,4 @@
 	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.
@@ -120,5 +70,4 @@
 	bool auto_reset_halt;
 } usb_pipe_t;
-
 
 /** Description of endpoint characteristics. */
@@ -156,25 +105,18 @@
 } 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 *,
-    const ddf_dev_t *);
-int usb_device_connection_initialize(usb_device_connection_t *,
-    devman_handle_t, usb_address_t);
-
-int usb_device_get_assigned_interface(const 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, const uint8_t *, size_t, usb_device_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_register(usb_pipe_t *, unsigned);
+int usb_pipe_unregister(usb_pipe_t *);
+
+int usb_pipe_start_long_transfer(usb_pipe_t *);
+int usb_pipe_end_long_transfer(usb_pipe_t *);
 
 int usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *);
Index: uspace/lib/usbdev/include/usb/dev/poll.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/poll.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/include/usb/dev/poll.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -39,4 +39,5 @@
 #include <time.h>
 
+/** Parameters and callbacks for automated polling. */
 typedef struct {
 	/** Level of debugging messages from auto polling.
@@ -82,8 +83,10 @@
 	 */
 	bool (*on_error)(usb_device_t *dev, int err_code, void *arg);
+	/** Argument to pass to callbacks. */
+	void *arg;
 } usb_device_auto_polling_t;
 
 int usb_device_auto_polling(usb_device_t *, size_t,
-    const usb_device_auto_polling_t *, size_t, void *);
+    const usb_device_auto_polling_t *, size_t);
 
 typedef bool (*usb_polling_callback_t)(usb_device_t *,
Index: uspace/lib/usbdev/include/usb/dev/request.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/request.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/include/usb/dev/request.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -83,4 +83,10 @@
 	uint8_t request_type;
 #define SETUP_REQUEST_TYPE_DEVICE_TO_HOST (1 << 7)
+#define SETUP_REQUEST_TYPE_GET_TYPE(rt) ((rt >> 5) & 0x3)
+#define SETUP_REQUEST_TYPE_GET_RECIPIENT(rec) (rec & 0x1f)
+#define SETUP_REQUEST_TO_HOST(type, recipient) \
+    (uint8_t)((1 << 7) | ((type & 0x3) << 5) | (recipient & 0x1f))
+#define SETUP_REQUEST_TO_DEVICE(type, recipient) \
+    (uint8_t)(((type & 0x3) << 5) | (recipient & 0x1f))
 
 	/** Request identification. */
Index: uspace/lib/usbdev/include/usb/dev/usb_device_connection.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/usb_device_connection.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/lib/usbdev/include/usb/dev/usb_device_connection.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,172 @@
+/*
+ * 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 libusbdev
+ * @{
+ */
+/** @file
+ * Common USB types and functions.
+ */
+#ifndef LIBUSBDEV_DEVICE_CONNECTION_H_
+#define LIBUSBDEV_DEVICE_CONNECTION_H_
+
+#include <errno.h>
+#include <devman.h>
+#include <usb/usb.h>
+#include <usb/hc.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 {
+	/** Connection to the host controller device is connected to. */
+	usb_hc_connection_t *hc_connection;
+	/** Address of the device. */
+	usb_address_t address;
+} usb_device_connection_t;
+
+/** Initialize device connection. Set address and hc connection.
+ * @param instance Structure to initialize.
+ * @param hc_connection. Host controller connection to use.
+ * @param address USB address.
+ * @return Error code.
+ */
+static inline int usb_device_connection_initialize(
+    usb_device_connection_t *instance, usb_hc_connection_t *hc_connection,
+    usb_address_t address)
+{
+	assert(instance);
+	if (hc_connection == NULL)
+		return EBADMEM;
+	if ((address < 0) || (address >= USB11_ADDRESS_MAX))
+		return EINVAL;
+
+	instance->hc_connection = hc_connection;
+	instance->address = address;
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Register endpoint on the device.
+ * @param instance device connection structure to use.
+ * @param ep USB endpoint number.
+ * @param type Communication type of the endpoint.
+ * @param direction Communication direction.
+ * @param packet_size Maximum packet size for the endpoint.
+ * @param interval Preferrred interval between communication.
+ * @return Error code.
+ */
+static inline int usb_device_register_endpoint(
+    usb_device_connection_t *instance, usb_endpoint_t ep,
+    usb_transfer_type_t type, usb_direction_t direction,
+    size_t packet_size, unsigned interval)
+{
+	assert(instance);
+	return usb_hc_register_endpoint(instance->hc_connection,
+	    instance->address, ep, type, direction, packet_size, interval);
+}
+/*----------------------------------------------------------------------------*/
+/** Unregister endpoint on the device.
+ * @param instance device connection structure
+ * @param ep Endpoint number.
+ * @param dir Communication direction.
+ * @return Error code.
+ */
+static inline int usb_device_unregister_endpoint(
+    usb_device_connection_t *instance, usb_endpoint_t ep, usb_direction_t dir)
+{
+	assert(instance);
+	return usb_hc_unregister_endpoint(instance->hc_connection,
+	    instance->address, ep, dir);
+}
+/*----------------------------------------------------------------------------*/
+/** Get data from the device.
+ * @param[in] instance device connection structure to use.
+ * @param[in] ep target endpoint's number.
+ * @param[in] setup Setup stage data (control transfers).
+ * @param[in] data data buffer.
+ * @param[in] size size of the data buffer.
+ * @param[out] rsize bytes actually copied to the buffer.
+ * @return Error code.
+ */
+static inline int usb_device_control_read(usb_device_connection_t *instance,
+    usb_endpoint_t ep, uint64_t setup, void *data, size_t size, size_t *rsize)
+{
+	assert(instance);
+	return usb_hc_read(instance->hc_connection,
+	    instance->address, ep, setup, data, size, rsize);
+}
+/*----------------------------------------------------------------------------*/
+/** Send data to the device.
+ * @param instance device connection structure to use.
+ * @param ep target endpoint's number.
+ * @param setup Setup stage data (control transfers).
+ * @param data data buffer.
+ * @param size size of the data buffer.
+ * @return Error code.
+ */
+static inline int usb_device_control_write(usb_device_connection_t *instance,
+    usb_endpoint_t ep, uint64_t setup, const void *data, size_t size)
+{
+	assert(instance);
+	return usb_hc_write(instance->hc_connection,
+	    instance->address, ep, setup, data, size);
+}
+/*----------------------------------------------------------------------------*/
+/** Wrapper for read calls with no setup stage.
+ * @param[in] instance device connection structure.
+ * @param[in] address USB device address.
+ * @param[in] endpoint USB device endpoint.
+ * @param[in] data Data buffer.
+ * @param[in] size Size of the buffer.
+ * @param[out] real_size Size of the transferred data.
+ * @return Error code.
+ */
+static inline int usb_device_read(usb_device_connection_t *instance,
+    usb_endpoint_t ep, void *data, size_t size, size_t *real_size)
+{
+	return usb_device_control_read(instance, ep, 0, data, size, real_size);
+}
+/*----------------------------------------------------------------------------*/
+/** Wrapper for write calls with no setup stage.
+ * @param instance device connection structure.
+ * @param address USB device address.
+ * @param endpoint USB device endpoint.
+ * @param data Data buffer.
+ * @param size Size of the buffer.
+ * @return Error code.
+ */
+static inline int usb_device_write(usb_device_connection_t *instance,
+    usb_endpoint_t ep, const void *data, size_t size)
+{
+	return usb_device_control_write(instance, ep, 0, data, size);
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdev/src/altiface.c
===================================================================
--- uspace/lib/usbdev/src/altiface.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/altiface.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -167,9 +167,13 @@
 }
 
-void usb_alternate_interfaces_deinit(usb_alternate_interfaces_t *alternate)
+/** Clean initialized structure.
+ * @param instance structure do deinitialize.
+ */
+void usb_alternate_interfaces_deinit(usb_alternate_interfaces_t *instance)
 {
-	if (!alternate)
+	if (!instance)
 		return;
-	free(alternate->alternatives);
+	free(instance->alternatives);
+	instance->alternatives = NULL;
 }
 /**
Index: uspace/lib/usbdev/src/devdrv.c
===================================================================
--- uspace/lib/usbdev/src/devdrv.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/devdrv.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,5 +27,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusbdev
  * @{
@@ -36,5 +36,5 @@
 #include <usb/dev/request.h>
 #include <usb/debug.h>
-#include <usb/dev/dp.h>
+#include <usb/dev.h>
 #include <errno.h>
 #include <str_error.h>
@@ -56,5 +56,4 @@
 static const usb_driver_t *driver = NULL;
 
-
 /** Main routine of USB device driver.
  *
@@ -75,5 +74,5 @@
 	return ddf_driver_main(&generic_driver);
 }
-
+/*----------------------------------------------------------------------------*/
 /** Count number of pipes the driver expects.
  *
@@ -85,40 +84,6 @@
 {
 	size_t count;
-	for (count = 0; endpoints && endpoints[count] != NULL; ++count);
+	for (count = 0; endpoints != NULL && 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(const usb_endpoint_description_t **endpoints,
-    usb_device_t *dev, int alternate_setting)
-{
-	assert(dev);
-
-	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;
 }
 /*----------------------------------------------------------------------------*/
@@ -136,4 +101,5 @@
 	assert(driver->ops->device_add);
 
+	/* Get place for driver data. */
 	usb_device_t *dev = ddf_dev_data_alloc(gen_dev, sizeof(usb_device_t));
 	if (dev == NULL) {
@@ -142,4 +108,6 @@
 		return ENOMEM;
 	}
+
+	/* Initialize generic USB driver data. */
 	const char *err_msg = NULL;
 	int rc = usb_device_init(dev, gen_dev, driver->endpoints, &err_msg);
@@ -150,4 +118,5 @@
 	}
 
+	/* Start USB driver specific initialization. */
 	rc = driver->ops->device_add(dev);
 	if (rc != EOK)
@@ -169,6 +138,11 @@
 	if (driver->ops->device_rem == NULL)
 		return ENOTSUP;
-	/* Just tell the driver to stop whatever it is doing, keep structures */
-	return driver->ops->device_rem(gen_dev->driver_data);
+	/* Just tell the driver to stop whatever it is doing */
+	usb_device_t *usb_dev = gen_dev->driver_data;
+	const int ret = driver->ops->device_rem(usb_dev);
+	if (ret != EOK)
+		return ret;
+	usb_device_deinit(usb_dev);
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -197,20 +171,12 @@
  *
  * @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;
-	}
-
+ */
+static void destroy_current_pipes(usb_device_t *dev)
+{
+	usb_device_destroy_pipes(dev->pipes, dev->pipes_count);
 	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
@@ -242,14 +208,9 @@
 	}
 
-	int rc;
-
 	/* Destroy existing pipes. */
-	rc = destroy_current_pipes(dev);
-	if (rc != EOK) {
-		return rc;
-	}
+	destroy_current_pipes(dev);
 
 	/* Change the interface itself. */
-	rc = usb_request_set_interface(&dev->ctrl_pipe, dev->interface_no,
+	int rc = usb_request_set_interface(&dev->ctrl_pipe, dev->interface_no,
 	    alternate_setting);
 	if (rc != EOK) {
@@ -258,5 +219,8 @@
 
 	/* Create new pipes. */
-	rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
+	rc = usb_device_create_pipes(&dev->wire, endpoints,
+	    dev->descriptors.configuration, dev->descriptors.configuration_size,
+	    dev->interface_no, (int)alternate_setting,
+	    &dev->pipes, &dev->pipes_count);
 
 	return rc;
@@ -316,5 +280,4 @@
  * - 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.
@@ -329,5 +292,5 @@
  * @return Error code.
  */
-int usb_device_create_pipes(const ddf_dev_t *dev, usb_device_connection_t *wire,
+int usb_device_create_pipes(usb_device_connection_t *wire,
     const usb_endpoint_description_t **endpoints,
     const uint8_t *config_descr, size_t config_descr_size,
@@ -335,7 +298,5 @@
     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);
@@ -359,5 +320,5 @@
 	}
 
-	/* Now allocate and fully initialize. */
+	/* Now initialize. */
 	for (i = 0; i < pipe_count; i++) {
 		pipes[i].description = endpoints[i];
@@ -370,23 +331,13 @@
 	    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;
-	}
-
+		free(pipes);
+		return rc;
+	}
+
+	/* Register created pipes. */
 	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);
+			    pipes[i].descriptor->poll_interval);
 			if (rc != EOK) {
 				goto rollback_unregister_endpoints;
@@ -394,8 +345,4 @@
 		}
 	}
-
-	if (usb_hc_connection_close(&hc_conn) != EOK)
-		usb_log_warning("%s: Failed to close connection.\n",
-		    __FUNCTION__);
 
 	*pipes_ptr = pipes;
@@ -415,20 +362,9 @@
 	for (i = 0; i < pipe_count; i++) {
 		if (pipes[i].present) {
-			usb_pipe_unregister(&pipes[i].pipe, &hc_conn);
+			usb_pipe_unregister(&pipes[i].pipe);
 		}
 	}
 
-	if (usb_hc_connection_close(&hc_conn) != EOK)
-		usb_log_warning("usb_device_create_pipes(): "
-		    "Failed to close connection.\n");
-
-	/*
-	 * 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:
 	free(pipes);
-
 	return rc;
 }
@@ -436,48 +372,18 @@
 /** 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(const ddf_dev_t *dev,
-    usb_endpoint_mapping_t *pipes, size_t pipes_count)
-{
-	assert(dev != NULL);
-
-	if (pipes_count == 0) {
-		assert(pipes == NULL);
-		return EOK;
-	}
-	assert(pipes != NULL);
-
-	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;
-	}
-
+void usb_device_destroy_pipes(usb_endpoint_mapping_t *pipes, size_t pipes_count)
+{
 	/* Destroy the pipes. */
-	size_t i;
-	for (i = 0; i < pipes_count; i++) {
-		usb_log_debug2("Unregistering pipe %zu (%spresent).\n",
+	for (size_t i = 0; i < pipes_count; ++i) {
+		assert(pipes);
+		usb_log_debug2("Unregistering pipe %zu: %spresent.\n",
 		    i, pipes[i].present ? "" : "not ");
 		if (pipes[i].present)
-			usb_pipe_unregister(&pipes[i].pipe, &hc_conn);
-	}
-
-	if (usb_hc_connection_close(&hc_conn) != EOK)
-		usb_log_warning("usb_device_destroy_pipes(): "
-		    "Failed to close connection.\n");
-
+			usb_pipe_unregister(&pipes[i].pipe);
+	}
 	free(pipes);
-
-	return EOK;
 }
 
@@ -505,7 +411,21 @@
 	usb_dev->pipes = NULL;
 
+	/* Get assigned params */
+	devman_handle_t hc_handle;
+	usb_address_t address;
+
+	int rc = usb_get_info_by_handle(ddf_dev->handle,
+	    &hc_handle, &address, &usb_dev->interface_no);
+	if (rc != EOK) {
+		*errstr_ptr = "device parameters retrieval";
+		return rc;
+	}
+
+	/* Initialize hc connection. */
+	usb_hc_connection_initialize(&usb_dev->hc_conn, hc_handle);
+
 	/* Initialize backing wire and control pipe. */
-	int rc = usb_device_connection_initialize_from_device(
-	    &usb_dev->wire, ddf_dev);
+	rc = usb_device_connection_initialize(
+	    &usb_dev->wire, &usb_dev->hc_conn, address);
 	if (rc != EOK) {
 		*errstr_ptr = "device connection initialization";
@@ -515,6 +435,6 @@
 	/* This pipe was registered by the hub driver,
 	 * during device initialization. */
-	rc = usb_pipe_initialize_default_control(&usb_dev->ctrl_pipe,
-	    &usb_dev->wire);
+	rc = usb_pipe_initialize_default_control(
+	    &usb_dev->ctrl_pipe, &usb_dev->wire);
 	if (rc != EOK) {
 		*errstr_ptr = "default control pipe initialization";
@@ -522,12 +442,17 @@
 	}
 
-	/* Get our interface. */
-	usb_dev->interface_no = usb_device_get_assigned_interface(ddf_dev);
+	/* Open hc connection for pipe registration. */
+	rc = usb_hc_connection_open(&usb_dev->hc_conn);
+	if (rc != EOK) {
+		*errstr_ptr = "hc connection open";
+		return rc;
+	}
 
 	/* Retrieve standard descriptors. */
-	rc = usb_device_retrieve_descriptors(&usb_dev->ctrl_pipe,
-	    &usb_dev->descriptors);
+	rc = usb_device_retrieve_descriptors(
+	    &usb_dev->ctrl_pipe, &usb_dev->descriptors);
 	if (rc != EOK) {
 		*errstr_ptr = "descriptor retrieval";
+		usb_hc_connection_close(&usb_dev->hc_conn);
 		return rc;
 	}
@@ -543,7 +468,12 @@
 	    (rc == EOK) ? usb_dev->alternate_interfaces.current : 0;
 
-	/* TODO Add comment here. */
-	rc = initialize_other_pipes(endpoints, usb_dev, alternate_iface);
-	if (rc != EOK) {
+	/* Create and register other pipes than default control (EP 0) */
+	rc = usb_device_create_pipes(&usb_dev->wire, endpoints,
+	    usb_dev->descriptors.configuration,
+	    usb_dev->descriptors.configuration_size,
+	    usb_dev->interface_no, (int)alternate_iface,
+	    &usb_dev->pipes, &usb_dev->pipes_count);
+	if (rc != EOK) {
+		usb_hc_connection_close(&usb_dev->hc_conn);
 		/* Full configuration descriptor is allocated. */
 		usb_device_release_descriptors(&usb_dev->descriptors);
@@ -554,4 +484,5 @@
 	}
 
+	usb_hc_connection_close(&usb_dev->hc_conn);
 	return EOK;
 }
@@ -566,13 +497,20 @@
 {
 	if (dev) {
+		/* Destroy existing pipes. */
+		destroy_current_pipes(dev);
 		/* Ignore errors and hope for the best. */
-		destroy_current_pipes(dev);
-
+		usb_hc_connection_deinitialize(&dev->hc_conn);
 		usb_alternate_interfaces_deinit(&dev->alternate_interfaces);
 		usb_device_release_descriptors(&dev->descriptors);
 		free(dev->driver_data);
-	}
-}
-
+		dev->driver_data = NULL;
+	}
+}
+
+/** Allocate driver specific data.
+ * @param usb_dev usb_device structure.
+ * @param size requested data size.
+ * @return Pointer to the newly allocated space, NULL on failure.
+ */
 void * usb_device_data_alloc(usb_device_t *usb_dev, size_t size)
 {
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/devpoll.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -46,11 +46,15 @@
 /** Data needed for polling. */
 typedef struct {
+	/** Parameters for automated polling. */
 	usb_device_auto_polling_t auto_polling;
 
+	/** USB device to poll. */
 	usb_device_t *dev;
+	/** Device pipe to use for polling. */
 	size_t pipe_index;
+	/** Size of the recieved data. */
 	size_t request_size;
+	/** Data buffer. */
 	uint8_t *buffer;
-	void *custom_arg;
 } polling_data_t;
 
@@ -119,5 +123,5 @@
 			++failed_attempts;
 			const bool cont = (params->on_error == NULL) ? true :
-			    params->on_error(data->dev, rc, data->custom_arg);
+			    params->on_error(data->dev, rc, params->arg);
 			if (!cont) {
 				failed_attempts = params->max_failures;
@@ -129,5 +133,5 @@
 		assert(params->on_data);
 		const bool carry_on = params->on_data(
-		    data->dev, data->buffer, actual_size, data->custom_arg);
+		    data->dev, data->buffer, actual_size, params->arg);
 
 		if (!carry_on) {
@@ -149,5 +153,5 @@
 
 	if (params->on_polling_end != NULL) {
-		params->on_polling_end(data->dev, failed, data->custom_arg);
+		params->on_polling_end(data->dev, failed, params->arg);
 	}
 
@@ -199,8 +203,9 @@
 		.on_polling_end = terminated_callback,
 		.on_error = NULL,
+		.arg = arg,
 	};
 
 	return usb_device_auto_polling(dev, pipe_index, &auto_polling,
-	   request_size, arg);
+	   request_size);
 }
 
@@ -224,5 +229,5 @@
 int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
     const usb_device_auto_polling_t *polling,
-    size_t request_size, void *arg)
+    size_t request_size)
 {
 	if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) {
@@ -252,5 +257,4 @@
 	polling_data->dev = dev;
 	polling_data->pipe_index = pipe_index;
-	polling_data->custom_arg = arg;
 
 	/* Copy provided settings. */
Index: uspace/lib/usbdev/src/hub.c
===================================================================
--- uspace/lib/usbdev/src/hub.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/hub.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -38,5 +38,4 @@
 #include <usb/dev/recognise.h>
 #include <usb/debug.h>
-#include <usbhc_iface.h>
 #include <errno.h>
 #include <assert.h>
@@ -45,46 +44,8 @@
 #include <async.h>
 
-/** How much time to wait between attempts to register endpoint 0:0.
+/** How much time to wait between attempts to get the default address.
  * 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))) { \
-			usb_log_error("Connection not open.\n"); \
-			return ENOTCONN; \
-		} \
-	} while (false)
-
-/** Ask host controller for free address assignment.
- *
- * @param connection Opened connection to host controller.
- * @param preferred Preferred SUB address.
- * @param strict Fail if the preferred address is not avialable.
- * @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_address_t preferred, bool strict, usb_speed_t speed)
-{
-	CHECK_CONNECTION(connection);
-
-	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	if (!exch)
-		return (usb_address_t)ENOMEM;
-
-	usb_address_t address = preferred;
-	const int ret = usbhc_request_address(exch, &address, strict, speed);
-
-	async_exchange_end(exch);
-	return ret == EOK ? address : ret;
-}
+#define DEFAULT_ADDRESS_ATTEMPT_DELAY_USEC (1000 * (10 + 2))
 
 /** Inform host controller about new device.
@@ -94,39 +55,12 @@
  * @return Error code.
  */
-int usb_hc_register_device(usb_hc_connection_t *connection,
+int usb_hub_register_device(usb_hc_connection_t *connection,
     const usb_hub_attached_device_t *attached_device)
 {
-	CHECK_CONNECTION(connection);
+	assert(connection);
 	if (attached_device == NULL || attached_device->fun == NULL)
-		return EINVAL;
-
-	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	if (!exch)
-		return ENOMEM;
-	const int ret = usbhc_bind_address(exch,
+		return EBADMEM;
+	return usb_hc_bind_address(connection,
 	    attached_device->address, attached_device->fun->handle);
-	async_exchange_end(exch);
-
-	return ret;
-}
-
-/** 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);
-	if (!exch)
-		return ENOMEM;
-	const int ret = usbhc_release_address(exch, address);
-	async_exchange_end(exch);
-
-	return ret;
 }
 
@@ -145,6 +79,5 @@
  * @return Error code.
  */
-static int usb_request_set_address(usb_pipe_t *pipe, usb_address_t new_address,
-    usb_hc_connection_t *hc_conn)
+static int usb_request_set_address(usb_pipe_t *pipe, usb_address_t new_address)
 {
 	if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
@@ -152,5 +85,4 @@
 	}
 	assert(pipe);
-	assert(hc_conn);
 	assert(pipe->wire != NULL);
 
@@ -166,11 +98,15 @@
 
 	/* TODO: prevent others from accessing the wire now. */
-	if (usb_pipe_unregister(pipe, hc_conn) != EOK) {
+	if (usb_pipe_unregister(pipe) != EOK) {
 		usb_log_warning(
 		    "Failed to unregister the old pipe on address change.\n");
 	}
+	/* Address changed. We can release the old one, thus
+	 * allowing other to us it. */
+	usb_hc_release_address(pipe->wire->hc_connection, pipe->wire->address);
+
 	/* The address is already changed so set it in the wire */
 	pipe->wire->address = new_address;
-	rc = usb_pipe_register(pipe, 0, hc_conn);
+	rc = usb_pipe_register(pipe, 0);
 	if (rc != EOK)
 		return EADDRNOTAVAIL;
@@ -220,14 +156,10 @@
  */
 int usb_hc_new_device_wrapper(ddf_dev_t *parent,
-    usb_hc_connection_t *connection, usb_speed_t dev_speed,
+    usb_hc_connection_t *hc_conn, usb_speed_t dev_speed,
     int (*enable_port)(void *arg), void *arg, usb_address_t *assigned_address,
     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
 {
-	if (new_fun == NULL || connection == NULL)
+	if (new_fun == NULL || hc_conn == NULL)
 		return EINVAL;
-
-	// TODO: Why not use provided connection?
-	usb_hc_connection_t hc_conn;
-	usb_hc_connection_initialize(&hc_conn, connection->hc_handle);
 
 	int rc;
@@ -239,14 +171,13 @@
 	}
 
-	rc = usb_hc_connection_open(&hc_conn);
+	/* We are gona do a lot of communication better open it in advance. */
+	rc = usb_hc_connection_open(hc_conn);
 	if (rc != EOK) {
 		return rc;
 	}
 
-	/*
-	 * Request new address.
-	 */
+	/* Request a new address. */
 	usb_address_t dev_addr =
-	    usb_hc_request_address(&hc_conn, 0, false, dev_speed);
+	    usb_hc_request_address(hc_conn, 0, false, dev_speed);
 	if (dev_addr < 0) {
 		rc = EADDRNOTAVAIL;
@@ -254,31 +185,33 @@
 	}
 
+	/* Initialize connection to device. */
+	usb_device_connection_t dev_conn;
+	rc = usb_device_connection_initialize(
+	    &dev_conn, hc_conn, USB_ADDRESS_DEFAULT);
+	if (rc != EOK) {
+		rc = ENOTCONN;
+		goto leave_release_free_address;
+	}
+
+	/* Initialize control pipe on default address. Don't register yet. */
+	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;
+	}
+
 	/*
-	 * 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.
+	 * The default address request might fail.
+	 * That means that someone else is already using that address.
+	 * 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_hc_request_address(&hc_conn, USB_ADDRESS_DEFAULT,
+		rc = usb_hc_request_address(hc_conn, USB_ADDRESS_DEFAULT,
 		    true, dev_speed);
 		if (rc == ENOENT) {
 			/* Do not overheat the CPU ;-). */
-			async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
+			async_usleep(DEFAULT_ADDRESS_ATTEMPT_DELAY_USEC);
 		}
 	} while (rc == ENOENT);
@@ -287,6 +220,6 @@
 	}
 
-	/* Register control pipe on default address. */
-	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
+	/* Register control pipe on default address. 0 means no interval. */
+	rc = usb_pipe_register(&ctrl_pipe, 0);
 	if (rc != EOK) {
 		rc = ENOTCONN;
@@ -295,5 +228,4 @@
 
 	struct timeval end_time;
-
 	rc = gettimeofday(&end_time, NULL);
 	if (rc != EOK) {
@@ -330,5 +262,5 @@
 	}
 
-	rc = usb_request_set_address(&ctrl_pipe, dev_addr, &hc_conn);
+	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
 	if (rc != EOK) {
 		rc = ESTALL;
@@ -336,7 +268,4 @@
 	}
 
-	/* Address changed. We can release the default, thus
-	 * allowing other to access the default address. */
-	usb_hc_unregister_device(&hc_conn, USB_ADDRESS_DEFAULT);
 
 	/* Register the device with devman. */
@@ -356,5 +285,5 @@
 
 	/* Inform the host controller about the handle. */
-	rc = usb_hc_register_device(&hc_conn, &new_device);
+	rc = usb_hub_register_device(hc_conn, &new_device);
 	if (rc != EOK) {
 		/* We know nothing about that data. */
@@ -381,18 +310,20 @@
 	 */
 leave_release_default_address:
-	usb_hc_unregister_device(&hc_conn, USB_ADDRESS_DEFAULT);
+	if (usb_hc_release_address(hc_conn, USB_ADDRESS_DEFAULT) != EOK)
+		usb_log_warning("%s: Failed to release defaut address.\n",
+		    __FUNCTION__);
 
 leave_release_free_address:
 	/* This might be either 0:0 or dev_addr:0 */
-	if (usb_pipe_unregister(&ctrl_pipe, &hc_conn) != EOK)
+	if (usb_pipe_unregister(&ctrl_pipe) != EOK)
 		usb_log_warning("%s: Failed to unregister default pipe.\n",
 		    __FUNCTION__);
 
-	if (usb_hc_unregister_device(&hc_conn, dev_addr) != EOK)
-		usb_log_warning("%s: Failed to unregister device.\n",
-		    __FUNCTION__);
+	if (usb_hc_release_address(hc_conn, dev_addr) != EOK)
+		usb_log_warning("%s: Failed to release address: %d.\n",
+		    __FUNCTION__, dev_addr);
 
 close_connection:
-	if (usb_hc_connection_close(&hc_conn) != EOK)
+	if (usb_hc_connection_close(hc_conn) != EOK)
 		usb_log_warning("%s: Failed to close hc connection.\n",
 		    __FUNCTION__);
Index: pace/lib/usbdev/src/pipepriv.c
===================================================================
--- uspace/lib/usbdev/src/pipepriv.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ 	(revision )
@@ -1,148 +1,0 @@
-/*
- * 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) {
-		assert(pipe->hc_sess == NULL);
-		/* 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: pace/lib/usbdev/src/pipepriv.h
===================================================================
--- uspace/lib/usbdev/src/pipepriv.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/*
- * 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 cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/pipes.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -26,198 +27,313 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusbdev
  * @{
  */
 /** @file
- * USB endpoint pipes miscellaneous functions.
- */
-#include <usb/usb.h>
+ * USB endpoint pipes functions.
+ */
 #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 <usb/dev/request.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, const ddf_dev_t *dev)
-{
-	assert(sess);
-	async_exch_t *exch = async_exchange_begin(sess);
-	if (!exch)
-		return ENOMEM;
-
-	usb_address_t address;
-	const int ret = usb_get_my_address(exch, &address);
-
-	async_exchange_end(exch);
-
-	return (ret == EOK) ? address : ret;
-}
-
-/** Tell USB interface assigned to given device.
- *
- * @param device Device in question.
- * @return Error code (ENOTSUP means any).
- */
-int usb_device_get_assigned_interface(const ddf_dev_t *device)
-{
-	assert(device);
-	async_sess_t *parent_sess =
-	    devman_parent_device_connect(EXCHANGE_ATOMIC, device->handle,
-	    IPC_FLAG_BLOCKING);
-	if (!parent_sess)
-		return ENOMEM;
-
-	async_exch_t *exch = async_exchange_begin(parent_sess);
-	if (!exch) {
-		async_hangup(parent_sess);
-		return ENOMEM;
-	}
-
-	int iface_no;
-	const int ret = usb_get_my_interface(exch, &iface_no);
-
-	return ret == EOK ? iface_no : ret;
-}
-
-/** 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, const ddf_dev_t *dev)
-{
+
+/** Prepare pipe for a long transfer.
+ *
+ * Long transfer is transfer consisting of several requests to the HC.
+ * Calling this 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.
+ */
+int usb_pipe_start_long_transfer(usb_pipe_t *pipe)
+{
+	assert(pipe);
+	assert(pipe->wire);
+	assert(pipe->wire->hc_connection);
+	return usb_hc_connection_open(pipe->wire->hc_connection);
+}
+/*----------------------------------------------------------------------------*/
+/** Terminate a long transfer on a pipe.
+ * @param pipe Pipe where to end the long transfer.
+ * @return Error code.
+ * @see usb_pipe_start_long_transfer
+ */
+int usb_pipe_end_long_transfer(usb_pipe_t *pipe)
+{
+	assert(pipe);
+	assert(pipe->wire);
+	assert(pipe->wire->hc_connection);
+	return usb_hc_connection_close(pipe->wire->hc_connection);
+}
+/*----------------------------------------------------------------------------*/
+/** 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 infinite recursion. */
+	pipe->auto_reset_halt = false;
+	usb_request_clear_endpoint_halt(pipe, 0);
+	pipe->auto_reset_halt = true;
+}
+/*----------------------------------------------------------------------------*/
+/** 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,
+    const void *setup_buffer, size_t setup_buffer_size,
+    void *buffer, size_t buffer_size, size_t *transfered_size)
+{
+	assert(pipe);
+
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
+		return EINVAL;
+	}
+
+	if ((buffer == NULL) || (buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
+
+	size_t act_size = 0;
+	const int rc = usb_device_control_read(pipe->wire,
+	    pipe->endpoint_no, setup_packet, buffer, buffer_size, &act_size);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
+	if (rc == EOK && transfered_size != NULL) {
+		*transfered_size = act_size;
+	}
+
+	return 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,
+    const void *setup_buffer, size_t setup_buffer_size,
+    const void *buffer, size_t buffer_size)
+{
+	assert(pipe);
+
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
+		return EINVAL;
+	}
+
+	if ((buffer == NULL) && (buffer_size > 0)) {
+		return EINVAL;
+	}
+
+	if ((buffer != NULL) && (buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
+
+	const int rc = usb_device_control_write(pipe->wire,
+	    pipe->endpoint_no, setup_packet, buffer, buffer_size);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
+	return rc;
+}
+/*----------------------------------------------------------------------------*/
+/** 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;
+	}
+
+	/* Isochronous transfer are not supported (yet) */
+	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
+	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    return ENOTSUP;
+
+	size_t act_size = 0;
+	const int rc = usb_device_read(pipe->wire,
+	    pipe->endpoint_no, buffer, size, &act_size);
+
+	if (rc == EOK && size_transfered != NULL) {
+		*size_transfered = act_size;
+	}
+
+	return 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, const void *buffer, size_t size)
+{
+	assert(pipe);
+
+	if (buffer == NULL || size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_OUT) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	/* Isochronous transfer are not supported (yet) */
+	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
+	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    return ENOTSUP;
+
+	return usb_device_write(pipe->wire,
+	    pipe->endpoint_no, buffer, size);
+}
+/*----------------------------------------------------------------------------*/
+/** 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);
-	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_ATOMIC, 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);
+
+	pipe->wire = connection;
+	pipe->endpoint_no = endpoint_no;
+	pipe->transfer_type = transfer_type;
+	pipe->max_packet_size = max_packet_size;
+	pipe->direction = direction;
+	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;
 }
-
-/** 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);
+/*----------------------------------------------------------------------------*/
+/** Register endpoint with the host controller.
+ *
+ * @param pipe Pipe to be registered.
+ * @param interval Polling interval.
+ * @return Error code.
+ */
+int usb_pipe_register(usb_pipe_t *pipe, unsigned interval)
+{
+	assert(pipe);
+	assert(pipe->wire);
+
+	return usb_device_register_endpoint(pipe->wire,
+	   pipe->endpoint_no, pipe->transfer_type,
+	   pipe->direction, pipe->max_packet_size, interval);
+}
+/*----------------------------------------------------------------------------*/
+/** Revert endpoint registration with the host controller.
+ *
+ * @param pipe Pipe to be unregistered.
+ * @return Error code.
+ */
+int usb_pipe_unregister(usb_pipe_t *pipe)
+{
+	assert(pipe);
+	assert(pipe->wire);
+
+	return usb_device_unregister_endpoint(pipe->wire,
+	    pipe->endpoint_no, pipe->direction);
 }
 
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -31,5 +31,5 @@
  */
 /** @file
- * Initialization of endpoint pipes.
+ * Non trivial initialization of endpoint pipes.
  *
  */
@@ -38,11 +38,8 @@
 #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) \
@@ -327,59 +324,4 @@
 
 	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;
 }
 
@@ -435,57 +377,4 @@
 }
 
-/** 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 interval,
-    usb_hc_connection_t *hc_connection)
-{
-	assert(pipe);
-	assert(pipe->wire);
-	assert(hc_connection);
-
-	if (!usb_hc_connection_is_opened(hc_connection))
-		return EBADF;
-	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
-	if (!exch)
-		return ENOMEM;
-	const int ret = usbhc_register_endpoint(exch,
-	    pipe->wire->address, pipe->endpoint_no, pipe->transfer_type,
-	    pipe->direction, pipe->max_packet_size, interval);
-
-	async_exchange_end(exch);
-	return ret;
-}
-
-/** 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(pipe->wire);
-	assert(hc_connection);
-
-	if (!usb_hc_connection_is_opened(hc_connection))
-		return EBADF;
-
-	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
-	if (!exch)
-		return ENOMEM;
-	const int ret = usbhc_unregister_endpoint(exch,
-	    pipe->wire->address, pipe->endpoint_no, pipe->direction);
-	async_exchange_end(exch);
-
-	return ret;
-}
-
 /**
  * @}
Index: pace/lib/usbdev/src/pipesio.c
===================================================================
--- uspace/lib/usbdev/src/pipesio.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ 	(revision )
@@ -1,316 +1,0 @@
-/*
- * 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_check(usb_pipe_t *pipe, uint64_t setup,
-    void *buffer, size_t size, size_t *size_transfered)
-{
-	/* Isochronous transfer are not supported (yet) */
-	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK &&
-	    pipe->transfer_type != USB_TRANSFER_CONTROL)
-	    return ENOTSUP;
-
-	int ret = pipe_add_ref(pipe, false);
-	if (ret != EOK) {
-		return ret;
-	}
-
-	/* Ensure serialization over the phone. */
-	pipe_start_transaction(pipe);
-	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	if (!exch) {
-		pipe_end_transaction(pipe);
-		pipe_drop_ref(pipe);
-		return ENOMEM;
-	}
-
-	ret = usbhc_read(exch, pipe->wire->address, pipe->endpoint_no,
-	    setup, buffer, size, size_transfered);
-	async_exchange_end(exch);
-	pipe_end_transaction(pipe);
-	pipe_drop_ref(pipe);
-	return ret;
-}
-
-/** 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, uint64_t setup,
-    const void *buffer, size_t size)
-{
-	/* Only interrupt and bulk transfers are supported */
-	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK &&
-	    pipe->transfer_type != USB_TRANSFER_CONTROL)
-	    return ENOTSUP;
-
-	int ret = pipe_add_ref(pipe, false);
-	if (ret != EOK) {
-		return ret;
-	}
-
-	/* Ensure serialization over the phone. */
-	pipe_start_transaction(pipe);
-	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	if (!exch) {
-		pipe_end_transaction(pipe);
-		pipe_drop_ref(pipe);
-		return ENOMEM;
-	}
-	ret = usbhc_write(exch, pipe->wire->address, pipe->endpoint_no,
-	    setup, buffer, size);
-	async_exchange_end(exch);
-	pipe_end_transaction(pipe);
-	pipe_drop_ref(pipe);
-	return ret;
-}
-
-/** 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 infinite recursion. */
-	pipe->auto_reset_halt = false;
-	usb_request_clear_endpoint_halt(pipe, 0);
-	pipe->auto_reset_halt = true;
-}
-
-/** 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,
-    const 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 != 8)) {
-		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;
-	}
-
-	uint64_t setup_packet;
-	memcpy(&setup_packet, setup_buffer, 8);
-
-	size_t act_size = 0;
-	const int rc = usb_pipe_read_no_check(pipe, setup_packet,
-	    data_buffer, data_buffer_size, &act_size);
-
-	if (rc == ESTALL) {
-		clear_self_endpoint_halt(pipe);
-	}
-
-	if (rc == EOK && data_transfered_size != NULL) {
-		*data_transfered_size = act_size;
-	}
-
-	return 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,
-    const void *setup_buffer, size_t setup_buffer_size,
-    const void *data_buffer, size_t data_buffer_size)
-{
-	assert(pipe);
-
-	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
-		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;
-	}
-
-	uint64_t setup_packet;
-	memcpy(&setup_packet, setup_buffer, 8);
-
-	const int rc = usb_pipe_write_no_check(pipe, setup_packet,
-	    data_buffer, data_buffer_size);
-
-	if (rc == ESTALL) {
-		clear_self_endpoint_halt(pipe);
-	}
-
-	return rc;
-}
-
-/** 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;
-	}
-
-	size_t act_size = 0;
-	const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
-
-
-	if (rc == EOK && size_transfered != NULL) {
-		*size_transfered = act_size;
-	}
-
-	return 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, const void *buffer, size_t size)
-{
-	assert(pipe);
-
-	if (buffer == NULL || size == 0) {
-		return EINVAL;
-	}
-
-	if (pipe->direction != USB_DIRECTION_OUT) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
-		return EBADF;
-	}
-
-	return usb_pipe_write_no_check(pipe, 0, buffer, size);
-}
-
-/**
- * @}
- */
Index: uspace/lib/usbdev/src/recognise.c
===================================================================
--- uspace/lib/usbdev/src/recognise.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbdev/src/recognise.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -45,9 +45,4 @@
 #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. */
@@ -329,7 +324,8 @@
 	}
 
-	fibril_mutex_lock(&device_name_index_mutex);
-	const size_t this_device_name_index = device_name_index++;
-	fibril_mutex_unlock(&device_name_index_mutex);
+	/** Index to append after device name for uniqueness. */
+	static atomic_t device_name_index = {0};
+	const size_t this_device_name_index =
+	    (size_t) atomic_preinc(&device_name_index);
 
 	ddf_fun_t *child = NULL;
Index: uspace/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -32,5 +32,5 @@
 	-I$(LIBUSB_PREFIX)/include \
 	-I$(LIBDRV_PREFIX)/include \
-	-Iinclude 
+	-Iinclude
 
 SOURCES = \
Index: uspace/lib/usbhost/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -95,9 +95,9 @@
 /** list_get_instance wrapper.
  * @param item Pointer to link member.
- * @return Pointer to enpoint_t structure.
+ * @return Pointer to endpoint_t structure.
  */
 static inline endpoint_t * endpoint_get_instance(link_t *item)
 {
-	return list_get_instance(item, endpoint_t, link);
+	return item ? list_get_instance(item, endpoint_t, link) : NULL;
 }
 #endif
Index: uspace/lib/usbhost/include/usb/host/usb_device_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -59,5 +59,7 @@
 		devman_handle_t handle; /**< Devman handle of the device. */
 	} devices[USB_ADDRESS_COUNT];
+	/** Maximum speed allowed. */
 	usb_speed_t max_speed;
+	/** Protect access to members. */
 	fibril_mutex_t guard;
 	/** The last reserved address */
Index: uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -65,10 +65,17 @@
 	 */
 	size_t setup_size;
-	/** Actually used portion of the buffer */
-	size_t transfered_size;
-	/** Indicates success/failure of the communication */
-	int error;
 	/** Host controller function, passed to callback function */
 	ddf_fun_t *fun;
+
+	/** Actually used portion of the buffer
+	 * This member is never accessed by functions provided in this header,
+	 * with the exception of usb_transfer_batch_finish. For external use.
+	 */
+	size_t transfered_size;
+	/** Indicates success/failure of the communication
+	 * This member is never accessed by functions provided in this header,
+	 * with the exception of usb_transfer_batch_finish. For external use.
+	 */
+	int error;
 
 	/** Driver specific data */
@@ -106,20 +113,18 @@
 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance);
 
-void usb_transfer_batch_finish(const usb_transfer_batch_t *instance,
-    const void* data, size_t size);
+void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance,
+    const void* data, size_t size, int error);
 /*----------------------------------------------------------------------------*/
-/** Override error value and finishes transfer.
+/** Finish batch using stored error value and transferred size.
  *
  * @param[in] instance Batch structure to use.
  * @param[in] data Data to copy to the output buffer.
- * @param[in] size Size of @p data.
- * @param[in] error Set batch status to this error value.
  */
-static inline void usb_transfer_batch_finish_error(
-    usb_transfer_batch_t *instance, const void* data, size_t size, int error)
+static inline void usb_transfer_batch_finish(
+    const usb_transfer_batch_t *instance, const void* data)
 {
 	assert(instance);
-	instance->error = error;
-	usb_transfer_batch_finish(instance, data, size);
+	usb_transfer_batch_finish_error(
+	    instance, data, instance->transfered_size, instance->error);
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/src/iface.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -39,4 +39,14 @@
 #include <usb/host/hcd.h>
 
+/** Prepare generic usb_transfer_batch and schedule it.
+ * @param fun DDF fun
+ * @param target address and endpoint number.
+ * @param setup_data Data to use in setup stage (Control communication type)
+ * @param in Callback for device to host communication.
+ * @param out Callback for host to device communication.
+ * @param arg Callback parameter.
+ * @param name Communication identifier (for nicer output).
+ * @return Error code.
+ */
 static inline int send_batch(
     ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
@@ -89,4 +99,9 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Calls ep_add_hook upon endpoint registration.
+ * @param ep Endpoint to be registered.
+ * @param arg hcd_t in disguise.
+ * @return Error code.
+ */
 static int register_helper(endpoint_t *ep, void *arg)
 {
@@ -99,4 +114,8 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Calls ep_remove_hook upon endpoint removal.
+ * @param ep Endpoint to be unregistered.
+ * @param arg hcd_t in disguise.
+ */
 static void unregister_helper(endpoint_t *ep, void *arg)
 {
@@ -108,4 +127,8 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Calls ep_remove_hook upon endpoint removal. Prints warning.
+ * @param ep Endpoint to be unregistered.
+ * @param arg hcd_t in disguise.
+ */
 static void unregister_helper_warn(endpoint_t *ep, void *arg)
 {
@@ -119,9 +142,11 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Request address interface function
+/** Request address interface function.
  *
  * @param[in] fun DDF function that was called.
+ * @param[in] address Pointer to preferred USB address.
+ * @param[out] address Place to write a new address.
+ * @param[in] strict Fail if the preferred address is not available.
  * @param[in] speed Speed to associate with the new default address.
- * @param[out] address Place to write a new address.
  * @return Error code.
  */
@@ -140,5 +165,5 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Bind address interface function
+/** Bind address interface function.
  *
  * @param[in] fun DDF function that was called.
@@ -148,5 +173,5 @@
  */
 static int bind_address(
-  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
+    ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
 {
 	assert(fun);
@@ -176,5 +201,5 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Release address interface function
+/** Release address interface function.
  *
  * @param[in] fun DDF function that was called.
@@ -194,8 +219,18 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Register endpoint interface function.
+ * @param fun DDF function.
+ * @param address USB address of the device.
+ * @param endpoint USB endpoint number to be registered.
+ * @param transfer_type Endpoint's transfer type.
+ * @param direction USB communication direction the endpoint is capable of.
+ * @param max_packet_size Maximu size of packets the endpoint accepts.
+ * @param interval Preferred timeout between communication.
+ * @return Error code.
+ */
 static int register_endpoint(
     ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
     usb_transfer_type_t transfer_type, usb_direction_t direction,
-    size_t max_packet_size, unsigned int interval)
+    size_t max_packet_size, unsigned interval)
 {
 	assert(fun);
@@ -220,4 +255,11 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Unregister endpoint interface function.
+ * @param fun DDF function.
+ * @param address USB address of the endpoint.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction of the enpdoint to unregister.
+ * @return Error code.
+ */
 static int unregister_endpoint(
     ddf_fun_t *fun, usb_address_t address,
@@ -233,4 +275,14 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Inbound communication interface function.
+ * @param fun DDF function.
+ * @param target Communication target.
+ * @param setup_data Data to use in setup stage (control transfers).
+ * @param data Pointer to data buffer.
+ * @param size Size of the data buffer.
+ * @param callback Function to call on communication end.
+ * @param arg Argument passed to the callback function.
+ * @return Error code.
+ */
 static int usb_read(ddf_fun_t *fun, usb_target_t target, uint64_t setup_data,
     uint8_t *data, size_t size, usbhc_iface_transfer_in_callback_t callback,
@@ -241,4 +293,14 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Outbound communication interface function.
+ * @param fun DDF function.
+ * @param target Communication target.
+ * @param setup_data Data to use in setup stage (control transfers).
+ * @param data Pointer to data buffer.
+ * @param size Size of the data buffer.
+ * @param callback Function to call on communication end.
+ * @param arg Argument passed to the callback function.
+ * @return Error code.
+ */
 static int usb_write(ddf_fun_t *fun, usb_target_t target, uint64_t setup_data,
     const uint8_t *data, size_t size,
@@ -249,4 +311,5 @@
 }
 /*----------------------------------------------------------------------------*/
+/** usbhc Interface implementation using hcd_t from libusbhost library. */
 usbhc_iface_t hcd_iface = {
 	.request_address = request_address,
Index: uspace/lib/usbhost/src/usb_device_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_device_manager.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/src/usb_device_manager.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -26,5 +26,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup libusbhost
  * @{
@@ -41,5 +40,4 @@
  *
  * @param[in] instance Device manager structure to use.
- * @param[in] speed Speed of the device requiring address.
  * @return Free address, or error code.
  */
@@ -133,4 +131,5 @@
  * @param[in] handle Devman handle of the device.
  * @return Error code.
+ * @note Won't accept binding for default address.
  */
 int usb_device_manager_bind_address(usb_device_manager_t *instance,
@@ -184,5 +183,5 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Find USB address associated with the device
+/** Find USB address associated with the device.
  *
  * @param[in] instance Device manager structure to use.
@@ -208,5 +207,4 @@
 /*----------------------------------------------------------------------------*/
 /** Find devman handle and speed assigned to USB address.
- * Intentionally refuse to work on default address.
  *
  * @param[in] instance Device manager structure to use.
Index: uspace/lib/usbhost/src/usb_endpoint_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -26,4 +26,10 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+/**  @addtogroup libusbhost
+ * @{
+ */
+/** @file
+ * HC Endpoint management.
+ */
 
 #include <bool.h>
@@ -56,5 +62,5 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Get list that holds endpints for given address.
+/** Get list that holds endpoints for given address.
  * @param instance usb_endpoint_manager structure, non-null.
  * @param addr USB address, must be >= 0.
@@ -75,4 +81,5 @@
  * @return Pointer to endpoint_t structure representing given communication
  * target, NULL if there is no such endpoint registered.
+ * @note Assumes that the internal mutex is locked.
  */
 static endpoint_t * find_locked(usb_endpoint_manager_t *instance,
@@ -169,4 +176,5 @@
  *
  * Really ugly one. Resets toggle bit on all endpoints that need it.
+ * @TODO Use tools from libusbdev requests.h
  */
 void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
@@ -184,4 +192,5 @@
 	case 0x01: /* Clear Feature -- resets only cleared ep */
 		/* Recipient is endpoint, value is zero (ENDPOINT_STALL) */
+		// TODO Use macros in libusbdev requests.h
 		if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
 			fibril_mutex_lock(&instance->guard);
@@ -202,5 +211,7 @@
 		/* Recipient must be device, this resets all endpoints,
 		 * In fact there should be no endpoints but EP 0 registered
-		 * as different interfaces use different endpoints. */
+		 * as different interfaces use different endpoints,
+		 * unless you're changing configuration or alternative
+		 * interface of an already setup device. */
 		if ((data[0] & 0xf) == 0) {
 			fibril_mutex_lock(&instance->guard);
@@ -385,4 +396,13 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Unregister and destroy all endpoints using given address.
+ * @param instance usb_endpoint_manager structure, non-null.
+ * @param address USB address.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction.
+ * @param callback Function to call after unregister, before destruction.
+ * @arg Argument to pass to the callback function.
+ * @return Error code.
+ */
 void usb_endpoint_manager_remove_address(usb_endpoint_manager_t *instance,
     usb_address_t address, void (*callback)(endpoint_t *, void *), void *arg)
@@ -403,2 +423,5 @@
 	fibril_mutex_unlock(&instance->guard);
 }
+/**
+ * @}
+ */
Index: uspace/lib/usbhost/src/usb_transfer_batch.c
===================================================================
--- uspace/lib/usbhost/src/usb_transfer_batch.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -33,5 +33,5 @@
  */
 #include <errno.h>
-#include <str_error.h>
+#include <macros.h>
 
 #include <usb/usb.h>
@@ -48,4 +48,5 @@
  * @param func_in callback on IN transfer completion.
  * @param func_out callback on OUT transfer completion.
+ * @param fun DDF function (passed to callback function).
  * @param arg Argument to pass to the callback function.
  * @param private_data driver specific per batch data.
@@ -121,7 +122,8 @@
  * @param[in] data Data to copy to the output buffer.
  * @param[in] size Size of @p data.
+ * @param[in] error Error value to use.
  */
-void usb_transfer_batch_finish(
-    const usb_transfer_batch_t *instance, const void *data, size_t size)
+void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance,
+    const void *data, size_t size, int error)
 {
 	assert(instance);
@@ -133,5 +135,5 @@
 		/* Check for commands that reset toggle bit */
 		if (instance->ep->transfer_type == USB_TRANSFER_CONTROL
-		    && instance->error == EOK) {
+		    && error == EOK) {
 			const usb_target_t target =
 			    {{ instance->ep->address, instance->ep->endpoint }};
@@ -139,17 +141,15 @@
 			    instance->setup_buffer);
 		}
-		instance->callback_out(instance->fun,
-		    instance->error, instance->arg);
+		instance->callback_out(instance->fun, error, instance->arg);
 	}
 
         if (instance->callback_in) {
 		/* We care about the data and there are some to copy */
+		const size_t safe_size = min(size, instance->buffer_size);
 		if (data) {
-			const size_t min_size = size < instance->buffer_size
-			    ? size : instance->buffer_size;
-	                memcpy(instance->buffer, data, min_size);
+	                memcpy(instance->buffer, data, safe_size);
 		}
-		instance->callback_in(instance->fun, instance->error,
-		    instance->transfered_size, instance->arg);
+		instance->callback_in(instance->fun, error,
+		    safe_size, instance->arg);
 	}
 }
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -309,11 +309,9 @@
 	}
 
-	fs_va = as_get_mappable_page(comm_size);
-	if (fs_va == NULL) {
+	(void) async_share_out_finalize(callid, &fs_va);
+	if (fs_va == (void *) -1) {
 		async_answer_0(callid, EHANGUP);
 		return;
 	}
-
-	(void) async_share_out_finalize(callid, fs_va);
 
 	while (true) {
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -190,11 +190,9 @@
 	}
 
-	fs_va = as_get_mappable_page(comm_size);
-	if (fs_va == NULL) {
+	(void) async_share_out_finalize(callid, &fs_va);
+	if (fs_va == (void *) -1) {
 		async_answer_0(callid, EHANGUP);
 		return;
 	}
-
-	(void) async_share_out_finalize(callid, fs_va);
 
 	while (true) {
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -193,11 +193,9 @@
 	}
 
-	fs_va = as_get_mappable_page(comm_size);
-	if (fs_va == NULL) {
+	(void) async_share_out_finalize(callid, &fs_va);
+	if (fs_va == (void *) -1) {
 		async_answer_0(callid, EHANGUP);
 		return;
 	}
-
-	(void) async_share_out_finalize(callid, fs_va);
 
 	while (true) {
Index: uspace/srv/bd/part/guid_part/guid_part.c
===================================================================
--- uspace/srv/bd/part/guid_part/guid_part.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/bd/part/guid_part/guid_part.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -348,11 +348,9 @@
 	}
 
-	fs_va = as_get_mappable_page(comm_size);
-	if (fs_va == NULL) {
+	(void) async_share_out_finalize(callid, &fs_va);
+	if (fs_va == (void *) -1) {
 		async_answer_0(callid, EHANGUP);
 		return;
 	}
-
-	(void) async_share_out_finalize(callid, fs_va);
 
 	while (true) {
Index: uspace/srv/bd/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/bd/part/mbr_part/mbr_part.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -425,11 +425,9 @@
 	}
 
-	fs_va = as_get_mappable_page(comm_size);
-	if (fs_va == NULL) {
+	(void) async_share_out_finalize(callid, &fs_va);
+	if (fs_va == (void *) -1) {
 		async_answer_0(callid, EHANGUP);
 		return;
 	}
-
-	(void) async_share_out_finalize(callid, fs_va);
 
 	while (1) {
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/bd/rd/rd.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -105,8 +105,6 @@
 	unsigned int flags;
 	if (async_share_out_receive(&callid, &comm_size, &flags)) {
-		fs_va = as_get_mappable_page(comm_size);
-		if (fs_va) {
-			(void) async_share_out_finalize(callid, fs_va);
-		} else {
+		(void) async_share_out_finalize(callid, &fs_va);
+		if (fs_va == (void *) -1) {
 			async_answer_0(callid, EHANGUP);
 			return;
@@ -224,11 +222,10 @@
 	
 	rd_size = ALIGN_UP(size, block_size);
-	rd_addr = as_get_mappable_page(rd_size);
-	
 	unsigned int flags =
 	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
-	ret = physmem_map((void *) addr_phys, rd_addr,
-	    ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
-	if (ret < 0) {
+	
+	ret = physmem_map((void *) addr_phys,
+	    ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags, &rd_addr);
+	if (ret != EOK) {
 		printf("%s: Error mapping RAM disk\n", NAME);
 		return false;
Index: uspace/srv/fs/exfat/exfat_bitmap.c
===================================================================
--- uspace/srv/fs/exfat/exfat_bitmap.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/fs/exfat/exfat_bitmap.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -45,5 +45,4 @@
 #include <assert.h>
 #include <fibril_synch.h>
-#include <malloc.h>
 #include <mem.h>
 
Index: uspace/srv/fs/exfat/exfat_dentry.c
===================================================================
--- uspace/srv/fs/exfat/exfat_dentry.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/fs/exfat/exfat_dentry.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -101,11 +101,30 @@
 bool exfat_valid_char(wchar_t ch)
 {
-	/* TODO */
-	return true;
+	switch (ch) {
+	case 0x01 ... 0x1F:
+	case '/':
+	case '\\':
+	case '?':
+	case '|':
+	case '>':
+	case '<':
+	case '"':
+	case '*':
+	case ':':
+		return false;
+	default:
+		return true;
+	}
 }
 
 bool exfat_valid_name(const char *name)
 {
-	/* TODO */
+	size_t off = 0;
+	wchar_t ch;
+
+	while ((ch = str_decode(name, &off, STR_NO_LIMIT)) != 0) {
+		if (!exfat_valid_char(ch))
+			return false;
+	}
 	return true;
 }
Index: uspace/srv/fs/exfat/exfat_directory.c
===================================================================
--- uspace/srv/fs/exfat/exfat_directory.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/fs/exfat/exfat_directory.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -112,4 +112,6 @@
 		rc = block_put(di->b);
 		di->b = NULL;
+		if (rc != EOK)
+			return rc;
 	}
 	if (!di->b) {
@@ -266,5 +268,6 @@
 		if (idx == 2 || idx == 3)
 			continue;
-		checksum = ((checksum << 15) | (checksum >> 1)) + (uint16_t)bytes[idx];
+		checksum = ((checksum << 15) | (checksum >> 1)) +
+		    (uint16_t)bytes[idx];
 	}
 	return checksum;
@@ -310,5 +313,6 @@
 	array[1].stream.valid_data_size = host2uint64_t_le(ds->valid_data_size);
 	array[1].stream.data_size = host2uint64_t_le(ds->data_size);
-	array[0].file.checksum = host2uint16_t_le(exfat_directory_set_checksum((uint8_t *)array,
+	array[0].file.checksum =
+	    host2uint16_t_le(exfat_directory_set_checksum((uint8_t *)array,
 	    count * sizeof(exfat_dentry_t)));
 
@@ -352,5 +356,6 @@
 	uctablep = EXFAT_NODE(fn);
 
-	uctable_chars = ALIGN_DOWN(uctablep->size, sizeof(uint16_t)) / sizeof(uint16_t); 
+	uctable_chars = ALIGN_DOWN(uctablep->size,
+	    sizeof(uint16_t)) / sizeof(uint16_t); 
 	uctable = (uint16_t *) malloc(uctable_chars * sizeof(uint16_t));
 	rc = exfat_read_uctable(di->bs, uctablep, (uint8_t *)uctable);
@@ -417,6 +422,9 @@
 			return rc;
 
-		if (i == df.file.count - 2)
-			chars = ds.stream.name_size - EXFAT_NAME_PART_LEN*(df.file.count - 2);
+		if (i == df.file.count - 2) {
+			chars = ds.stream.name_size -
+			    EXFAT_NAME_PART_LEN*(df.file.count - 2);
+		}
+
 		rc = exfat_directory_get(di, &de);
 		if (rc != EOK)
Index: uspace/srv/fs/exfat/exfat_fat.c
===================================================================
--- uspace/srv/fs/exfat/exfat_fat.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/fs/exfat/exfat_fat.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -50,4 +50,5 @@
 #include <malloc.h>
 #include <mem.h>
+#include <str.h>
 
 
@@ -322,9 +323,9 @@
 			    (found == 0) ?  EXFAT_CLST_EOF : lifo[found - 1]);
 			if (rc != EOK)
-				break;
+				goto exit_error;
 			found++;
 			rc = bitmap_set_cluster(bs, service_id, clst);
 			if (rc != EOK)
-				break;
+				goto exit_error;
 
 		}
@@ -339,4 +340,8 @@
 	}
 
+	rc = ENOSPC;
+
+exit_error:
+
 	/* If something wrong - free the clusters */
 	while (found--) {
@@ -347,5 +352,5 @@
 	free(lifo);
 	fibril_mutex_unlock(&exfat_alloc_lock);
-	return ENOSPC;
+	return rc;
 }
 
@@ -537,5 +542,18 @@
 int exfat_sanity_check(exfat_bs_t *bs, service_id_t service_id)
 {
-	/* TODO */
+	if (str_cmp((char const *)bs->oem_name, "EXFAT   "))
+		return ENOTSUP;
+	else if (uint16_t_le2host(bs->signature) != 0xAA55)
+		return ENOTSUP;
+	else if (uint32_t_le2host(bs->fat_sector_count) == 0)
+		return ENOTSUP;
+	else if (uint32_t_le2host(bs->data_clusters) == 0)
+		return ENOTSUP;
+	else if (bs->fat_count != 1)
+		return ENOTSUP;
+	else if ((bs->bytes_per_sector + bs->sec_per_cluster) > 25) {
+		/* exFAT does not support cluster size > 32 Mb */
+		return ENOTSUP;
+	}
 	return EOK;
 }
Index: uspace/srv/fs/exfat/exfat_ops.c
===================================================================
--- uspace/srv/fs/exfat/exfat_ops.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/fs/exfat/exfat_ops.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -657,4 +657,11 @@
 			return rc;
 		}
+
+		rc = exfat_zero_cluster(bs, service_id, nodep->firstc);
+		if (rc != EOK) {
+			(void) exfat_node_put(FS_NODE(nodep));
+			return rc;
+		}
+
 		nodep->size = BPC(bs);
 	} else {
@@ -739,9 +746,14 @@
 	 */
 	rc = exfat_directory_write_file(&di, name);
-	if (rc != EOK)
-		return rc;
+	if (rc != EOK) {
+		(void) exfat_directory_close(&di);
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
 	rc = exfat_directory_close(&di);
-	if (rc != EOK)
-		return rc;
+	if (rc != EOK) {
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
 
 	fibril_mutex_unlock(&parentp->idx->lock);
@@ -1258,5 +1270,7 @@
 		exfat_directory_t di;
 		rc = exfat_directory_open(nodep, &di);
-		if (rc != EOK) goto err;
+		if (rc != EOK)
+			goto err;
+
 		rc = exfat_directory_seek(&di, pos);
 		if (rc != EOK) {
@@ -1268,7 +1282,9 @@
 		    &df, &ds);
 		if (rc == EOK)
-		    goto hit;
-		if (rc == ENOENT)
-		    goto miss;
+			goto hit;
+		else if (rc == ENOENT)
+			goto miss;
+
+		(void) exfat_directory_close(&di);
 
 err:
@@ -1279,5 +1295,5 @@
 miss:
 		rc = exfat_directory_close(&di);
-		if (rc!=EOK)
+		if (rc != EOK)
 			goto err;
 		rc = exfat_node_put(fn);
@@ -1397,5 +1413,5 @@
 
 	(void) async_data_write_finalize(callid,
-		b->data + pos % BPS(bs), bytes);
+	    b->data + pos % BPS(bs), bytes);
 	b->dirty = true;		/* need to sync block */
 	rc = block_put(b);
Index: uspace/srv/hid/fb/fb.c
===================================================================
--- uspace/srv/hid/fb/fb.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/fb/fb.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -304,7 +304,6 @@
 	}
 	
-	frontbuf->data = as_get_mappable_page(frontbuf->size);
-	int rc = async_answer_1(callid, EOK, (sysarg_t) frontbuf->data);
-	if (rc != EOK) {
+	int rc = async_share_out_finalize(callid, &frontbuf->data);
+	if ((rc != EOK) || (frontbuf->data == (void *) -1)) {
 		free(frontbuf);
 		async_answer_0(iid, ENOMEM);
@@ -348,7 +347,6 @@
 	}
 	
-	imagemap->data = as_get_mappable_page(imagemap->size);
-	int rc = async_answer_1(callid, EOK, (sysarg_t) imagemap->data);
-	if (rc != EOK) {
+	int rc = async_share_out_finalize(callid, &imagemap->data);
+	if ((rc != EOK) || (imagemap->data == (void *) -1)) {
 		free(imagemap);
 		async_answer_0(iid, ENOMEM);
Index: uspace/srv/hid/fb/port/ega.c
===================================================================
--- uspace/srv/hid/fb/port/ega.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/fb/port/ega.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -280,10 +280,8 @@
 	
 	ega.size = (width * height) << 1;
-	ega.addr = as_get_mappable_page(ega.size);
-	if (ega.addr == NULL)
-		return ENOMEM;
-	
-	rc = physmem_map((void *) paddr, ega.addr,
-	    ALIGN_UP(ega.size, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
+	
+	rc = physmem_map((void *) paddr,
+	    ALIGN_UP(ega.size, PAGE_SIZE) >> PAGE_WIDTH,
+	    AS_AREA_READ | AS_AREA_WRITE, (void *) &ega.addr);
 	if (rc != EOK)
 		return rc;
Index: uspace/srv/hid/fb/port/kchar.c
===================================================================
--- uspace/srv/hid/fb/port/kchar.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/fb/port/kchar.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -83,10 +83,7 @@
 		return rc;
 	
-	kchar.addr = as_get_mappable_page(1);
-	if (kchar.addr == NULL)
-		return ENOMEM;
-	
-	rc = physmem_map((void *) paddr, kchar.addr,
-	    ALIGN_UP(1, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
+	rc = physmem_map((void *) paddr,
+	    ALIGN_UP(1, PAGE_SIZE) >> PAGE_WIDTH,
+	    AS_AREA_READ | AS_AREA_WRITE, (void *) &kchar.addr);
 	if (rc != EOK)
 		return rc;
Index: uspace/srv/hid/fb/port/kfb.c
===================================================================
--- uspace/srv/hid/fb/port/kfb.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/fb/port/kfb.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -756,12 +756,8 @@
 	
 	kfb.size = scanline * height;
-	kfb.addr = as_get_mappable_page(kfb.size);
-	if (kfb.addr == NULL) {
-		free(kfb.glyphs);
-		return ENOMEM;
-	}
-	
-	rc = physmem_map((void *) paddr + offset, kfb.addr,
-	    ALIGN_UP(kfb.size, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
+	
+	rc = physmem_map((void *) paddr + offset,
+	    ALIGN_UP(kfb.size, PAGE_SIZE) >> PAGE_WIDTH,
+	    AS_AREA_READ | AS_AREA_WRITE, (void *) &kfb.addr);
 	if (rc != EOK) {
 		free(kfb.glyphs);
Index: uspace/srv/hid/fb/port/niagara.c
===================================================================
--- uspace/srv/hid/fb/port/niagara.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/fb/port/niagara.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -103,11 +103,6 @@
 		return rc;
 	
-	niagara.fifo =
-	    (output_fifo_t *) as_get_mappable_page(sizeof(output_fifo_t));
-	if (niagara.fifo == NULL)
-		return ENOMEM;
-	
-	rc = physmem_map((void *) paddr, (void *) niagara.fifo, 1,
-	    AS_AREA_READ | AS_AREA_WRITE);
+	rc = physmem_map((void *) paddr, 1,
+	    AS_AREA_READ | AS_AREA_WRITE, (void *) &niagara.fifo);
 	if (rc != EOK)
 		return rc;
Index: uspace/srv/hid/input/port/gxemul.c
===================================================================
--- uspace/srv/hid/input/port/gxemul.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/input/port/gxemul.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -90,5 +90,5 @@
 	async_set_interrupt_received(gxemul_irq_handler);
 	gxemul_cmds[0].addr = (void *) addr;
-	register_irq(inr, device_assign_devno(), 0, &gxemul_kbd);
+	irq_register(inr, device_assign_devno(), 0, &gxemul_kbd);
 	return 0;
 }
Index: uspace/srv/hid/input/port/msim.c
===================================================================
--- uspace/srv/hid/input/port/msim.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/input/port/msim.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -89,5 +89,5 @@
 	msim_cmds[0].addr = (void *) vaddr;
 	async_set_interrupt_received(msim_irq_handler);
-	register_irq(inr, device_assign_devno(), 0, &msim_kbd);
+	irq_register(inr, device_assign_devno(), 0, &msim_kbd);
 	
 	return 0;
Index: uspace/srv/hid/input/port/niagara.c
===================================================================
--- uspace/srv/hid/input/port/niagara.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/input/port/niagara.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -63,9 +63,4 @@
 #define POLL_INTERVAL  10000
 
-/**
- * Virtual address mapped to the buffer shared with the kernel counterpart.
- */
-static uintptr_t input_buffer_addr;
-
 /*
  * Kernel counterpart of the driver pushes characters (it has read) here.
@@ -102,8 +97,6 @@
 		return -1;
 	
-	input_buffer_addr = (uintptr_t) as_get_mappable_page(PAGE_SIZE);
-	int rc = physmem_map((void *) paddr, (void *) input_buffer_addr,
-	    1, AS_AREA_READ | AS_AREA_WRITE);
-	
+	int rc = physmem_map((void *) paddr, 1,
+	    AS_AREA_READ | AS_AREA_WRITE, (void *) &input_buffer);
 	if (rc != 0) {
 		printf("Niagara: uspace driver couldn't map physical memory: %d\n",
@@ -111,6 +104,4 @@
 		return rc;
 	}
-	
-	input_buffer = (input_buffer_t) input_buffer_addr;
 	
 	thread_id_t tid;
Index: uspace/srv/hid/input/port/ns16550.c
===================================================================
--- uspace/srv/hid/input/port/ns16550.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/input/port/ns16550.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -135,5 +135,5 @@
 	
 	async_set_interrupt_received(ns16550_irq_handler);
-	register_irq(inr, device_assign_devno(), inr, &ns16550_kbd);
+	irq_register(inr, device_assign_devno(), inr, &ns16550_kbd);
 	
 	return pio_enable((void *) ns16550_physical, 8, &vaddr);
Index: uspace/srv/hid/input/port/pl050.c
===================================================================
--- uspace/srv/hid/input/port/pl050.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/input/port/pl050.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -117,5 +117,5 @@
 	
 	async_set_interrupt_received(pl050_irq_handler);
-	register_irq(inr, device_assign_devno(), 0, &pl050_kbd);
+	irq_register(inr, device_assign_devno(), 0, &pl050_kbd);
 	
 	return 0;
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -139,5 +139,5 @@
 
 	async_set_interrupt_received(s3c24xx_ts_irq_handler);
-	register_irq(inr, device_assign_devno(), 0, &ts_irq_code);
+	irq_register(inr, device_assign_devno(), 0, &ts_irq_code);
 
 	s3c24xx_ts_wait_for_int_mode(ts, updn_down);
Index: uspace/srv/hw/bus/cuda_adb/cuda_adb.c
===================================================================
--- uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -275,5 +275,5 @@
 	cuda_irq_code.cmds[0].addr = (void *) &((cuda_t *) instance->cuda_kernel)->ifr;
 	async_set_interrupt_received(cuda_irq_handler);
-	register_irq(10, device_assign_devno(), 0, &cuda_irq_code);
+	irq_register(10, device_assign_devno(), 0, &cuda_irq_code);
 
 	/* Enable SR interrupt. */
Index: uspace/srv/hw/char/i8042/i8042.c
===================================================================
--- uspace/srv/hw/char/i8042/i8042.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hw/char/i8042/i8042.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -197,6 +197,6 @@
 	i8042_kbd.cmds[0].addr = (void *) &((i8042_t *) i8042_kernel)->status;
 	i8042_kbd.cmds[3].addr = (void *) &((i8042_t *) i8042_kernel)->data;
-	register_irq(inr_a, device_assign_devno(), 0, &i8042_kbd);
-	register_irq(inr_b, device_assign_devno(), 0, &i8042_kbd);
+	irq_register(inr_a, device_assign_devno(), 0, &i8042_kbd);
+	irq_register(inr_b, device_assign_devno(), 0, &i8042_kbd);
 	printf("%s: registered for interrupts %" PRIun " and %" PRIun "\n",
 	    NAME, inr_a, inr_b);
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -194,5 +194,5 @@
 	async_set_interrupt_received(s3c24xx_uart_irq_handler);
 
-	register_irq(inr, device_assign_devno(), 0, &uart_irq_code);
+	irq_register(inr, device_assign_devno(), 0, &uart_irq_code);
 
 	/* Enable FIFO, Tx trigger level: empty, Rx trigger level: 1 byte. */
Index: uspace/srv/hw/irc/obio/obio.c
===================================================================
--- uspace/srv/hw/irc/obio/obio.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/hw/irc/obio/obio.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -124,9 +124,9 @@
 	
 	base_phys = (void *) paddr;
-	base_virt = as_get_mappable_page(OBIO_SIZE);
 	
 	int flags = AS_AREA_READ | AS_AREA_WRITE;
-	int retval = physmem_map(base_phys, (void *) base_virt,
-	    ALIGN_UP(OBIO_SIZE, PAGE_SIZE) >> PAGE_WIDTH, flags);
+	int retval = physmem_map(base_phys,
+	    ALIGN_UP(OBIO_SIZE, PAGE_SIZE) >> PAGE_WIDTH, flags,
+	    (void *) &base_virt);
 	
 	if (retval < 0) {
Index: uspace/srv/net/cfg/e1k.nic
===================================================================
--- uspace/srv/net/cfg/e1k.nic	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/cfg/e1k.nic	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,21 @@
+# E1000 configuration
+
+NAME=e1k
+
+HWPATH=/hw/pci0/00:03.0/port0
+NIL=eth
+IL=ip
+
+# 8023_2_LSAP, 8023_2_SNAP
+ETH_MODE=DIX
+ETH_DUMMY=no
+
+IP_CONFIG=static
+IP_ADDR=10.0.2.15
+IP_ROUTING=yes
+IP_NETMASK=255.255.255.240
+IP_BROADCAST=10.0.2.255
+IP_GATEWAY=10.0.2.2
+ARP=arp
+
+MTU=1500
Index: uspace/srv/net/net/packet_server.c
===================================================================
--- uspace/srv/net/net/packet_server.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/net/net/packet_server.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -304,15 +304,14 @@
 static int packet_reply(packet_t *packet)
 {
+	if (!packet_is_valid(packet))
+		return EINVAL;
+	
 	ipc_callid_t callid;
 	size_t size;
-
-	if (!packet_is_valid(packet))
-		return EINVAL;
-
 	if (!async_share_in_receive(&callid, &size)) {
 		async_answer_0(callid, EINVAL);
 		return EINVAL;
 	}
-
+	
 	if (size != packet->length) {
 		async_answer_0(callid, ENOMEM);
@@ -375,7 +374,7 @@
 	case NET_PACKET_GET:
 		packet = pm_find(IPC_GET_ID(*call));
-		if (!packet_is_valid(packet)) {
+		if (!packet_is_valid(packet))
 			return ENOENT;
-		}
+		
 		return packet_reply(packet);
 	
Index: uspace/srv/net/tl/tcp/Makefile
===================================================================
--- uspace/srv/net/tl/tcp/Makefile	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/net/tl/tcp/Makefile	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,5 +1,4 @@
 #
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2011 Jiri Svoboda
 # All rights reserved.
 #
@@ -34,5 +33,16 @@
 
 SOURCES = \
-	tcp.c
+	conn.c \
+	iqueue.c \
+	ncsim.c \
+	pdu.c \
+	rqueue.c \
+	segment.c \
+	seq_no.c \
+	sock.c \
+	tcp.c \
+	test.c \
+	tqueue.c \
+	ucall.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/conn.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,1270 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP connection processing and state machine
+ */
+
+#include <adt/list.h>
+#include <bool.h>
+#include <errno.h>
+#include <io/log.h>
+#include <macros.h>
+#include <stdlib.h>
+#include "conn.h"
+#include "iqueue.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "tcp_type.h"
+#include "tqueue.h"
+#include "ucall.h"
+
+#define RCV_BUF_SIZE 4096/*2*/
+#define SND_BUF_SIZE 4096
+
+#define MAX_SEGMENT_LIFETIME	(15*1000*1000) //(2*60*1000*1000)
+#define TIME_WAIT_TIMEOUT	(2*MAX_SEGMENT_LIFETIME)
+
+LIST_INITIALIZE(conn_list);
+FIBRIL_MUTEX_INITIALIZE(conn_list_lock);
+
+static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg);
+static void tcp_conn_tw_timer_set(tcp_conn_t *conn);
+static void tcp_conn_tw_timer_clear(tcp_conn_t *conn);
+
+/** Create new connection structure.
+ *
+ * @param lsock		Local socket (will be deeply copied)
+ * @param fsock		Foreign socket (will be deeply copied)
+ * @return		New connection or NULL
+ */
+tcp_conn_t *tcp_conn_new(tcp_sock_t *lsock, tcp_sock_t *fsock)
+{
+	tcp_conn_t *conn = NULL;
+	bool tqueue_inited = false;
+
+	/* Allocate connection structure */
+	conn = calloc(1, sizeof(tcp_conn_t));
+	if (conn == NULL)
+		goto error;
+
+	conn->tw_timer = fibril_timer_create();
+	if (conn->tw_timer == NULL)
+		goto error;
+
+	fibril_mutex_initialize(&conn->lock);
+
+	/* One for the user, one for not being in closed state */
+	atomic_set(&conn->refcnt, 2);
+
+	/* Allocate receive buffer */
+	fibril_condvar_initialize(&conn->rcv_buf_cv);
+	conn->rcv_buf_size = RCV_BUF_SIZE;
+	conn->rcv_buf_used = 0;
+	conn->rcv_buf_fin = false;
+
+	conn->rcv_buf = calloc(1, conn->rcv_buf_size);
+	if (conn->rcv_buf == NULL)
+		goto error;
+
+	/** Allocate send buffer */
+	fibril_condvar_initialize(&conn->snd_buf_cv);
+	conn->snd_buf_size = SND_BUF_SIZE;
+	conn->snd_buf_used = 0;
+	conn->snd_buf_fin = false;
+	conn->snd_buf = calloc(1, conn->snd_buf_size);
+	if (conn->snd_buf == NULL)
+		goto error;
+
+	/* Set up receive window. */
+	conn->rcv_wnd = conn->rcv_buf_size;
+
+	/* Initialize incoming segment queue */
+	tcp_iqueue_init(&conn->incoming, conn);
+
+	/* Initialize retransmission queue */
+	if (tcp_tqueue_init(&conn->retransmit, conn) != EOK)
+		goto error;
+
+	tqueue_inited = true;
+
+	/* Connection state change signalling */
+	fibril_condvar_initialize(&conn->cstate_cv);
+
+	conn->cstate = st_listen;
+	conn->reset = false;
+	conn->deleted = false;
+	conn->ap = ap_passive;
+	conn->fin_is_acked = false;
+	conn->ident.local = *lsock;
+	if (fsock != NULL)
+		conn->ident.foreign = *fsock;
+
+	return conn;
+
+error:
+	if (tqueue_inited)
+		tcp_tqueue_fini(&conn->retransmit);
+	if (conn != NULL && conn->rcv_buf != NULL)
+		free(conn->rcv_buf);
+	if (conn != NULL && conn->snd_buf != NULL)
+		free(conn->snd_buf);
+	if (conn != NULL && conn->tw_timer != NULL)
+		fibril_timer_destroy(conn->tw_timer);
+	if (conn != NULL)
+		free(conn);
+
+	return NULL;
+}
+
+/** Destroy connection structure.
+ *
+ * Connection structure should be destroyed when the folowing condtitions
+ * are met:
+ * (1) user has deleted the connection
+ * (2) the connection has entered closed state
+ * (3) nobody is holding references to the connection
+ *
+ * This happens when @a conn->refcnt is zero as we count (1) and (2)
+ * as special references.
+ *
+ * @param conn		Connection
+ */
+static void tcp_conn_free(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_free(%p)", conn->name, conn);
+	tcp_tqueue_fini(&conn->retransmit);
+
+	if (conn->rcv_buf != NULL)
+		free(conn->rcv_buf);
+	if (conn->snd_buf != NULL)
+		free(conn->snd_buf);
+	if (conn->tw_timer != NULL)
+		fibril_timer_destroy(conn->tw_timer);
+	free(conn);
+}
+
+/** Add reference to connection.
+ *
+ * Increase connection reference count by one.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_addref(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_addref(%p)", conn->name, conn);
+	atomic_inc(&conn->refcnt);
+}
+
+/** Remove reference from connection.
+ *
+ * Decrease connection reference count by one.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_delref(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_delref(%p)", conn->name, conn);
+
+	if (atomic_predec(&conn->refcnt) == 0)
+		tcp_conn_free(conn);
+}
+
+/** Delete connection.
+ *
+ * The caller promises not make no further references to @a conn.
+ * TCP will free @a conn eventually.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_delete(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
+
+	assert(conn->deleted == false);
+	tcp_conn_delref(conn);
+}
+
+/** Enlist connection.
+ *
+ * Add connection to the connection map.
+ */
+void tcp_conn_add(tcp_conn_t *conn)
+{
+	tcp_conn_addref(conn);
+	fibril_mutex_lock(&conn_list_lock);
+	list_append(&conn->link, &conn_list);
+	fibril_mutex_unlock(&conn_list_lock);
+}
+
+/** Delist connection.
+ *
+ * Remove connection from the connection map.
+ */
+void tcp_conn_remove(tcp_conn_t *conn)
+{
+	fibril_mutex_lock(&conn_list_lock);
+	list_remove(&conn->link);
+	fibril_mutex_unlock(&conn_list_lock);
+	tcp_conn_delref(conn);
+}
+
+static void tcp_conn_state_set(tcp_conn_t *conn, tcp_cstate_t nstate)
+{
+	tcp_cstate_t old_state;
+
+	old_state = conn->cstate;
+	conn->cstate = nstate;
+	fibril_condvar_broadcast(&conn->cstate_cv);
+
+	assert(old_state != st_closed);
+	if (nstate == st_closed) {
+		/* Drop one reference for now being in closed state */
+		tcp_conn_delref(conn);
+	}
+}
+
+/** Synchronize connection.
+ *
+ * This is the first step of an active connection attempt,
+ * sends out SYN and sets up ISS and SND.xxx.
+ */
+void tcp_conn_sync(tcp_conn_t *conn)
+{
+	/* XXX select ISS */
+	conn->iss = 1;
+	conn->snd_nxt = conn->iss;
+	conn->snd_una = conn->iss;
+	conn->ap = ap_active;
+
+	tcp_tqueue_ctrl_seg(conn, CTL_SYN);
+	tcp_conn_state_set(conn, st_syn_sent);
+}
+
+/** FIN has been sent.
+ *
+ * This function should be called when FIN is sent over the connection,
+ * as a result the connection state is changed appropriately.
+ */
+void tcp_conn_fin_sent(tcp_conn_t *conn)
+{
+	switch (conn->cstate) {
+	case st_syn_received:
+	case st_established:
+		log_msg(LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
+		tcp_conn_state_set(conn, st_fin_wait_1);
+		break;
+	case st_close_wait:
+		log_msg(LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
+		tcp_conn_state_set(conn, st_last_ack);
+		break;
+	default:
+		log_msg(LVL_ERROR, "%s: Connection state %d", conn->name,
+		    conn->cstate);
+		assert(false);
+	}
+
+	conn->fin_is_acked = false;
+}
+
+/** Compare two sockets.
+ *
+ * Two sockets are equal if the address is equal and the port number
+ * is equal.
+ */
+static bool tcp_socket_match(tcp_sock_t *sock, tcp_sock_t *patt)
+{
+	log_msg(LVL_DEBUG, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
+
+	if (patt->addr.ipv4 != TCP_IPV4_ANY &&
+	    patt->addr.ipv4 != sock->addr.ipv4)
+		return false;
+
+	if (patt->port != TCP_PORT_ANY &&
+	    patt->port != sock->port)
+		return false;
+
+	log_msg(LVL_DEBUG, " -> match");
+
+	return true;
+}
+
+/** Match socket with pattern. */
+static bool tcp_sockpair_match(tcp_sockpair_t *sp, tcp_sockpair_t *pattern)
+{
+	log_msg(LVL_DEBUG, "tcp_sockpair_match(%p, %p)", sp, pattern);
+
+	if (!tcp_socket_match(&sp->local, &pattern->local))
+		return false;
+
+	if (!tcp_socket_match(&sp->foreign, &pattern->foreign))
+		return false;
+
+	return true;
+}
+
+/** Find connection structure for specified socket pair.
+ *
+ * A connection is uniquely identified by a socket pair. Look up our
+ * connection map and return connection structure based on socket pair.
+ * The connection reference count is bumped by one.
+ *
+ * @param sp	Socket pair
+ * @return	Connection structure or NULL if not found.
+ */
+tcp_conn_t *tcp_conn_find_ref(tcp_sockpair_t *sp)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_find(%p)", sp);
+
+	fibril_mutex_lock(&conn_list_lock);
+
+	list_foreach(conn_list, link) {
+		tcp_conn_t *conn = list_get_instance(link, tcp_conn_t, link);
+		tcp_sockpair_t *csp = &conn->ident;
+		log_msg(LVL_DEBUG, "compare with conn (f:(%x,%u), l:(%x,%u))",
+		    csp->foreign.addr.ipv4, csp->foreign.port,
+		    csp->local.addr.ipv4, csp->local.port);
+		if (tcp_sockpair_match(sp, csp)) {
+			tcp_conn_addref(conn);
+			fibril_mutex_unlock(&conn_list_lock);
+			return conn;
+		}
+	}
+
+	fibril_mutex_unlock(&conn_list_lock);
+	return NULL;
+}
+
+/** Reset connection.
+ *
+ * @param conn	Connection
+ */
+static void tcp_conn_reset(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
+	tcp_conn_state_set(conn, st_closed);
+	conn->reset = true;
+
+	tcp_conn_tw_timer_clear(conn);
+	tcp_tqueue_clear(&conn->retransmit);
+
+	fibril_condvar_broadcast(&conn->rcv_buf_cv);
+	fibril_condvar_broadcast(&conn->snd_buf_cv);
+}
+
+/** Signal to the user that connection has been reset.
+ *
+ * Send an out-of-band signal to the user.
+ */
+static void tcp_reset_signal(tcp_conn_t *conn)
+{
+	/* TODO */
+	log_msg(LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
+}
+
+/** Determine if SYN has been received.
+ *
+ * @param conn	Connection
+ * @return	@c true if SYN has been received, @c false otherwise.
+ */
+bool tcp_conn_got_syn(tcp_conn_t *conn)
+{
+	switch (conn->cstate) {
+	case st_listen:
+	case st_syn_sent:
+		return false;
+	case st_syn_received:
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+	case st_close_wait:
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		return true;
+	case st_closed:
+		log_msg(LVL_WARN, "state=%d", (int) conn->cstate);
+		assert(false);
+	}
+
+	assert(false);
+}
+
+/** Segment arrived in Listen state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_sa_listen(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
+
+	if ((seg->ctrl & CTL_RST) != 0) {
+		log_msg(LVL_DEBUG, "Ignoring incoming RST.");
+		return;
+	}
+
+	if ((seg->ctrl & CTL_ACK) != 0) {
+		log_msg(LVL_DEBUG, "Incoming ACK, send acceptable RST.");
+		tcp_reply_rst(&conn->ident, seg);
+		return;
+	}
+
+	if ((seg->ctrl & CTL_SYN) == 0) {
+		log_msg(LVL_DEBUG, "SYN not present. Ignoring segment.");
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "Got SYN, sending SYN, ACK.");
+
+	conn->rcv_nxt = seg->seq + 1;
+	conn->irs = seg->seq;
+
+
+	log_msg(LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
+
+	if (seg->len > 1)
+		log_msg(LVL_WARN, "SYN combined with data, ignoring data.");
+
+	/* XXX select ISS */
+	conn->iss = 1;
+	conn->snd_nxt = conn->iss;
+	conn->snd_una = conn->iss;
+
+	/*
+	 * Surprisingly the spec does not deal with initial window setting.
+	 * Set SND.WND = SEG.WND and set SND.WL1 so that next segment
+	 * will always be accepted as new window setting.
+	 */
+	conn->snd_wnd = seg->wnd;
+	conn->snd_wl1 = seg->seq;
+	conn->snd_wl2 = seg->seq;
+
+	tcp_conn_state_set(conn, st_syn_received);
+
+	tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
+
+	tcp_segment_delete(seg);
+}
+
+/** Segment arrived in Syn-Sent state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_sa_syn_sent(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
+
+	if ((seg->ctrl & CTL_ACK) != 0) {
+		log_msg(LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
+		    conn->snd_una, seg->ack, conn->snd_nxt);
+		if (!seq_no_ack_acceptable(conn, seg->ack)) {
+			if ((seg->ctrl & CTL_RST) == 0) {
+				log_msg(LVL_WARN, "ACK not acceptable, send RST");
+				tcp_reply_rst(&conn->ident, seg);
+			} else {
+				log_msg(LVL_WARN, "RST,ACK not acceptable, drop");
+			}
+			return;
+		}
+	}
+
+	if ((seg->ctrl & CTL_RST) != 0) {
+		/* If we get here, we have either an acceptable ACK or no ACK */
+		if ((seg->ctrl & CTL_ACK) != 0) {
+			log_msg(LVL_DEBUG, "%s: Connection reset. -> Closed",
+			    conn->name);
+			/* Reset connection */
+			tcp_conn_reset(conn);
+			return;
+		} else {
+			log_msg(LVL_DEBUG, "%s: RST without ACK, drop",
+			    conn->name);
+			return;
+		}
+	}
+
+	/* XXX precedence */
+
+	if ((seg->ctrl & CTL_SYN) == 0) {
+		log_msg(LVL_DEBUG, "No SYN bit, ignoring segment.");
+		return;
+	}
+
+	conn->rcv_nxt = seg->seq + 1;
+	conn->irs = seg->seq;
+
+	if ((seg->ctrl & CTL_ACK) != 0) {
+		conn->snd_una = seg->ack;
+
+		/*
+		 * Prune acked segments from retransmission queue and
+		 * possibly transmit more data.
+		 */
+		tcp_tqueue_ack_received(conn);
+	}
+
+	log_msg(LVL_DEBUG, "Sent SYN, got SYN.");
+
+	/*
+	 * Surprisingly the spec does not deal with initial window setting.
+	 * Set SND.WND = SEG.WND and set SND.WL1 so that next segment
+	 * will always be accepted as new window setting.
+	 */
+	log_msg(LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
+	    "SND.WL2 = %" PRIu32, seg->wnd, seg->seq, seg->seq);
+	conn->snd_wnd = seg->wnd;
+	conn->snd_wl1 = seg->seq;
+	conn->snd_wl2 = seg->seq;
+
+	if (seq_no_syn_acked(conn)) {
+		log_msg(LVL_DEBUG, "%s: syn acked -> Established", conn->name);
+		tcp_conn_state_set(conn, st_established);
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK /* XXX */);
+	} else {
+		log_msg(LVL_DEBUG, "%s: syn not acked -> Syn-Received",
+		    conn->name);
+		tcp_conn_state_set(conn, st_syn_received);
+		tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
+	}
+
+	tcp_segment_delete(seg);
+}
+
+/** Segment arrived in state where segments are processed in sequence order.
+ *
+ * Queue segment in incoming segments queue for processing.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_sa_queue(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	tcp_segment_t *pseg;
+
+	log_msg(LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
+
+	/* Discard unacceptable segments ("old duplicates") */
+	if (!seq_no_segment_acceptable(conn, seg)) {
+		log_msg(LVL_DEBUG, "Replying ACK to unacceptable segment.");
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+		tcp_segment_delete(seg);
+		return;
+	}
+
+	/* Queue for processing */
+	tcp_iqueue_insert_seg(&conn->incoming, seg);
+
+	/*
+	 * Process all segments from incoming queue that are ready.
+	 * Unacceptable segments are discarded by tcp_iqueue_get_ready_seg().
+	 *
+	 * XXX Need to return ACK for unacceptable segments
+	 */
+	while (tcp_iqueue_get_ready_seg(&conn->incoming, &pseg) == EOK)
+		tcp_conn_seg_process(conn, pseg);
+}
+
+/** Process segment RST field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_rst(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if ((seg->ctrl & CTL_RST) == 0)
+		return cp_continue;
+
+	switch (conn->cstate) {
+	case st_syn_received:
+		/* XXX In case of passive open, revert to Listen state */
+		if (conn->ap == ap_passive) {
+			tcp_conn_state_set(conn, st_listen);
+			/* XXX Revert conn->ident */
+			tcp_conn_tw_timer_clear(conn);
+			tcp_tqueue_clear(&conn->retransmit);
+		} else {
+			tcp_conn_reset(conn);
+		}
+		break;
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+	case st_close_wait:
+		/* General "connection reset" signal */
+		tcp_reset_signal(conn);
+		tcp_conn_reset(conn);
+		break;
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		tcp_conn_reset(conn);
+		break;
+	case st_listen:
+	case st_syn_sent:
+	case st_closed:
+		assert(false);
+	}
+
+	return cp_done;
+}
+
+/** Process segment security and precedence fields.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_sp(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/* TODO */
+	return cp_continue;
+}
+
+/** Process segment SYN field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_syn(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if ((seg->ctrl & CTL_SYN) == 0)
+		return cp_continue;
+
+	/*
+	 * Assert SYN is in receive window, otherwise this step should not
+	 * be reached.
+	 */
+	assert(seq_no_in_rcv_wnd(conn, seg->seq));
+
+	log_msg(LVL_WARN, "SYN is in receive window, should send reset. XXX");
+
+	/*
+	 * TODO
+	 *
+	 * Send a reset, resond "reset" to all outstanding RECEIVEs and SEND,
+	 * flush segment queues. Send unsolicited "connection reset" signal
+	 * to user, connection -> closed state, delete TCB, return.
+	 */
+	return cp_done;
+}
+
+/** Process segment ACK field in Syn-Received state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_sr(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (!seq_no_ack_acceptable(conn, seg->ack)) {
+		/* ACK is not acceptable, send RST. */
+		log_msg(LVL_WARN, "Segment ACK not acceptable, sending RST.");
+		tcp_reply_rst(&conn->ident, seg);
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	log_msg(LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
+
+	tcp_conn_state_set(conn, st_established);
+
+	/* XXX Not mentioned in spec?! */
+	conn->snd_una = seg->ack;
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Established state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
+
+	log_msg(LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
+	    (unsigned)seg->ack, (unsigned)conn->snd_una,
+	    (unsigned)conn->snd_nxt);
+
+	if (!seq_no_ack_acceptable(conn, seg->ack)) {
+		log_msg(LVL_DEBUG, "ACK not acceptable.");
+		if (!seq_no_ack_duplicate(conn, seg->ack)) {
+			log_msg(LVL_WARN, "Not acceptable, not duplicate. "
+			    "Send ACK and drop.");
+			/* Not acceptable, not duplicate. Send ACK and drop. */
+			tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+			tcp_segment_delete(seg);
+			return cp_done;
+		} else {
+			log_msg(LVL_DEBUG, "Ignoring duplicate ACK.");
+		}
+	} else {
+		/* Update SND.UNA */
+		conn->snd_una = seg->ack;
+	}
+
+	if (seq_no_new_wnd_update(conn, seg)) {
+		conn->snd_wnd = seg->wnd;
+		conn->snd_wl1 = seg->seq;
+		conn->snd_wl2 = seg->ack;
+
+		log_msg(LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
+		    ", SND.WL1=%" PRIu32 ", SND.WL2=%" PRIu32,
+		    conn->snd_wnd, conn->snd_wl1, conn->snd_wl2);
+	}
+
+	/*
+	 * Prune acked segments from retransmission queue and
+	 * possibly transmit more data.
+	 */
+	tcp_tqueue_ack_received(conn);
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Fin-Wait-1 state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_fw1(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	if (conn->fin_is_acked) {
+		log_msg(LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
+		tcp_conn_state_set(conn, st_fin_wait_2);
+	}
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Fin-Wait-2 state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_fw2(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	/* TODO */
+	return cp_continue;
+}
+
+/** Process segment ACK field in Close-Wait state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_cw(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/* The same processing as in Established state */
+	return tcp_conn_seg_proc_ack_est(conn, seg);
+}
+
+/** Process segment ACK field in Closing state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_cls(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	/* TODO */
+	return cp_continue;
+}
+
+/** Process segment ACK field in Last-Ack state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_la(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	if (conn->fin_is_acked) {
+		log_msg(LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
+		tcp_conn_remove(conn);
+		tcp_conn_state_set(conn, st_closed);
+		return cp_done;
+	}
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Time-Wait state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_tw(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/* Nothing to do */
+	return cp_continue;
+}
+
+/** Process segment ACK field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
+	    conn->name, conn, seg);
+
+	if ((seg->ctrl & CTL_ACK) == 0) {
+		log_msg(LVL_WARN, "Segment has no ACK. Dropping.");
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	switch (conn->cstate) {
+	case st_syn_received:
+		return tcp_conn_seg_proc_ack_sr(conn, seg);
+	case st_established:
+		return tcp_conn_seg_proc_ack_est(conn, seg);
+	case st_fin_wait_1:
+		return tcp_conn_seg_proc_ack_fw1(conn, seg);
+	case st_fin_wait_2:
+		return tcp_conn_seg_proc_ack_fw2(conn, seg);
+	case st_close_wait:
+		return tcp_conn_seg_proc_ack_cw(conn, seg);
+	case st_closing:
+		return tcp_conn_seg_proc_ack_cls(conn, seg);
+	case st_last_ack:
+		return tcp_conn_seg_proc_ack_la(conn, seg);
+	case st_time_wait:
+		return tcp_conn_seg_proc_ack_tw(conn, seg);
+	case st_listen:
+	case st_syn_sent:
+	case st_closed:
+		assert(false);
+	}
+
+	assert(false);
+}
+
+/** Process segment URG field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_urg(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	return cp_continue;
+}
+
+/** Process segment text.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_text(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	size_t text_size;
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
+	    conn->name, conn, seg);
+
+	switch (conn->cstate) {
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+		/* OK */
+		break;
+	case st_close_wait:
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		/* Invalid since FIN has been received. Ignore text. */
+		return cp_continue;
+	case st_listen:
+	case st_syn_sent:
+	case st_syn_received:
+	case st_closed:
+		assert(false);
+	}
+
+	/*
+	 * Process segment text
+	 */
+	assert(seq_no_segment_ready(conn, seg));
+
+	/* Trim anything outside our receive window */
+	tcp_conn_trim_seg_to_wnd(conn, seg);
+
+	/* Determine how many bytes to copy */
+	text_size = tcp_segment_text_size(seg);
+	xfer_size = min(text_size, conn->rcv_buf_size - conn->rcv_buf_used);
+
+	/* Copy data to receive buffer */
+	tcp_segment_text_copy(seg, conn->rcv_buf + conn->rcv_buf_used,
+	    xfer_size);
+	conn->rcv_buf_used += xfer_size;
+
+	/* Signal to the receive function that new data has arrived */
+	fibril_condvar_broadcast(&conn->rcv_buf_cv);
+
+	log_msg(LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
+
+	/* Advance RCV.NXT */
+	conn->rcv_nxt += xfer_size;
+
+	/* Update receive window. XXX Not an efficient strategy. */
+	conn->rcv_wnd -= xfer_size;
+
+	/* Send ACK */
+	if (xfer_size > 0)
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+	if (xfer_size < seg->len) {
+		/* Trim part of segment which we just received */
+		tcp_conn_trim_seg_to_wnd(conn, seg);
+	} else {
+		log_msg(LVL_DEBUG, "%s: Nothing left in segment, dropping "
+		    "(xfer_size=%zu, SEG.LEN=%zu, seg->ctrl=%u)",
+		    conn->name, xfer_size, seg->len, (unsigned)seg->ctrl);
+		/* Nothing left in segment */
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	return cp_continue;
+}
+
+/** Process segment FIN field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_fin(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
+	    conn->name, conn, seg);
+	log_msg(LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
+	    (unsigned) seg->ctrl);
+
+	/* Only process FIN if no text is left in segment. */
+	if (tcp_segment_text_size(seg) == 0 && (seg->ctrl & CTL_FIN) != 0) {
+		log_msg(LVL_DEBUG, " - FIN found in segment.");
+
+		/* Send ACK */
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+		conn->rcv_nxt++;
+		conn->rcv_wnd--;
+
+		/* Change connection state */
+		switch (conn->cstate) {
+		case st_listen:
+		case st_syn_sent:
+		case st_closed:
+			/* Connection not synchronized */
+			assert(false);
+		case st_syn_received:
+		case st_established:
+			log_msg(LVL_DEBUG, "%s: FIN received -> Close-Wait",
+			    conn->name);
+			tcp_conn_state_set(conn, st_close_wait);
+			break;
+		case st_fin_wait_1:
+			log_msg(LVL_DEBUG, "%s: FIN received -> Closing",
+			    conn->name);
+			tcp_conn_state_set(conn, st_closing);
+			break;
+		case st_fin_wait_2:
+			log_msg(LVL_DEBUG, "%s: FIN received -> Time-Wait",
+			    conn->name);
+			tcp_conn_state_set(conn, st_time_wait);
+			/* Start the Time-Wait timer */
+			tcp_conn_tw_timer_set(conn);
+			break;
+		case st_close_wait:
+		case st_closing:
+		case st_last_ack:
+			/* Do nothing */
+			break;
+		case st_time_wait:
+			/* Restart the Time-Wait timer */
+			tcp_conn_tw_timer_set(conn);
+			break;
+		}
+
+		/* Add FIN to the receive buffer */
+		conn->rcv_buf_fin = true;
+		fibril_condvar_broadcast(&conn->rcv_buf_cv);
+
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	return cp_continue;
+}
+
+/** Process incoming segment.
+ *
+ * We are in connection state where segments are processed in order
+ * of sequence number. This processes one segment taken from the
+ * connection incoming segments queue.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
+	tcp_segment_dump(seg);
+
+	/* Check whether segment is acceptable */
+	/* XXX Permit valid ACKs, URGs and RSTs */
+/*	if (!seq_no_segment_acceptable(conn, seg)) {
+		log_msg(LVL_WARN, "Segment not acceptable, dropping.");
+		if ((seg->ctrl & CTL_RST) == 0) {
+			tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+		}
+		return;
+	}
+*/
+
+	if (tcp_conn_seg_proc_rst(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_sp(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_syn(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_ack(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_urg(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_text(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_fin(conn, seg) == cp_done)
+		return;
+
+	/*
+	 * If anything is left from the segment, insert it back into the
+	 * incoming segments queue.
+	 */
+	if (seg->len > 0) {
+		log_msg(LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
+		    seg, (size_t) seg->len);
+		tcp_iqueue_insert_seg(&conn->incoming, seg);
+	} else {
+		tcp_segment_delete(seg);
+	}
+}
+
+/** Segment arrived on a connection.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+void tcp_conn_segment_arrived(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%c: tcp_conn_segment_arrived(%p)",
+	    conn->name, seg);
+
+	switch (conn->cstate) {
+	case st_listen:
+		tcp_conn_sa_listen(conn, seg); break;
+	case st_syn_sent:
+		tcp_conn_sa_syn_sent(conn, seg); break;
+	case st_syn_received:
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+	case st_close_wait:
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		/* Process segments in order of sequence number */
+		tcp_conn_sa_queue(conn, seg); break;
+	case st_closed:
+		log_msg(LVL_DEBUG, "state=%d", (int) conn->cstate);
+		assert(false);
+	}
+}
+
+/** Time-Wait timeout handler.
+ *
+ * @param arg	Connection
+ */
+static void tw_timeout_func(void *arg)
+{
+	tcp_conn_t *conn = (tcp_conn_t *) arg;
+
+	log_msg(LVL_DEBUG, "tw_timeout_func(%p)", conn);
+
+	fibril_mutex_lock(&conn->lock);
+
+	if (conn->cstate == st_closed) {
+		log_msg(LVL_DEBUG, "Connection already closed.");
+		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_delref(conn);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
+	tcp_conn_remove(conn);
+	tcp_conn_state_set(conn, st_closed);
+
+	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_delref(conn);
+}
+
+/** Start or restart the Time-Wait timeout.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_tw_timer_set(tcp_conn_t *conn)
+{
+	tcp_conn_addref(conn);
+	fibril_timer_set(conn->tw_timer, TIME_WAIT_TIMEOUT, tw_timeout_func,
+	    (void *)conn);
+}
+
+/** Clear the Time-Wait timeout.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_tw_timer_clear(tcp_conn_t *conn)
+{
+	if (fibril_timer_clear(conn->tw_timer) == fts_active)
+		tcp_conn_delref(conn);
+}
+
+/** Trim segment to the receive window.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	uint32_t left, right;
+
+	seq_no_seg_trim_calc(conn, seg, &left, &right);
+	tcp_segment_trim(seg, left, right);
+}
+
+/** Handle unexpected segment received on a socket pair.
+ *
+ * We reply with an RST unless the received segment has RST.
+ *
+ * @param sp		Socket pair which received the segment
+ * @param seg		Unexpected segment
+ */
+void tcp_unexpected_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", sp, seg);
+
+	if ((seg->ctrl & CTL_RST) == 0)
+		tcp_reply_rst(sp, seg);
+}
+
+/** Compute flipped socket pair for response.
+ *
+ * Flipped socket pair has local and foreign sockets exchanged.
+ *
+ * @param sp		Socket pair
+ * @param fsp		Place to store flipped socket pair
+ */
+void tcp_sockpair_flipped(tcp_sockpair_t *sp, tcp_sockpair_t *fsp)
+{
+	fsp->local = sp->foreign;
+	fsp->foreign = sp->local;
+}
+
+/** Send RST in response to an incoming segment.
+ *
+ * @param sp		Socket pair which received the segment
+ * @param seg		Incoming segment
+ */
+void tcp_reply_rst(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_segment_t *rseg;
+
+	log_msg(LVL_DEBUG, "tcp_reply_rst(%p, %p)", sp, seg);
+
+	rseg = tcp_segment_make_rst(seg);
+	tcp_transmit_segment(sp, rseg);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/conn.h
===================================================================
--- uspace/srv/net/tl/tcp/conn.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/conn.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP connection processing and state machine
+ */
+
+#ifndef CONN_H
+#define CONN_H
+
+#include <bool.h>
+#include "tcp_type.h"
+
+extern tcp_conn_t *tcp_conn_new(tcp_sock_t *, tcp_sock_t *);
+extern void tcp_conn_delete(tcp_conn_t *);
+extern void tcp_conn_add(tcp_conn_t *);
+extern void tcp_conn_remove(tcp_conn_t *);
+extern void tcp_conn_sync(tcp_conn_t *);
+extern void tcp_conn_fin_sent(tcp_conn_t *);
+extern void tcp_conn_ack_of_fin_rcvd(tcp_conn_t *);
+extern tcp_conn_t *tcp_conn_find_ref(tcp_sockpair_t *);
+extern void tcp_conn_addref(tcp_conn_t *);
+extern void tcp_conn_delref(tcp_conn_t *);
+extern bool tcp_conn_got_syn(tcp_conn_t *);
+extern void tcp_conn_segment_arrived(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_conn_trim_seg_to_wnd(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_unexpected_segment(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_sockpair_flipped(tcp_sockpair_t *, tcp_sockpair_t *);
+extern void tcp_reply_rst(tcp_sockpair_t *, tcp_segment_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/iqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/iqueue.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/iqueue.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Connection incoming segments queue
+ *
+ * Segments are sorted in order of their sequence number.
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <io/log.h>
+#include <stdlib.h>
+#include "iqueue.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "tcp_type.h"
+
+/** Initialize incoming segments queue.
+ *
+ * @param iqueue	Incoming queue
+ * @param conn		Connection the queue is associated with
+ */
+void tcp_iqueue_init(tcp_iqueue_t *iqueue, tcp_conn_t *conn)
+{
+	list_initialize(&iqueue->list);
+	iqueue->conn = conn;
+}
+
+/** Insert segment into incoming queue.
+ *
+ * @param iqueue	Incoming queue
+ * @param seg		Segment
+ */
+void tcp_iqueue_insert_seg(tcp_iqueue_t *iqueue, tcp_segment_t *seg)
+{
+	tcp_iqueue_entry_t *iqe;
+	tcp_iqueue_entry_t *qe;
+	link_t *link;
+	log_msg(LVL_DEBUG, "tcp_iqueue_insert_seg()");
+
+	iqe = calloc(1, sizeof(tcp_iqueue_entry_t));
+	if (iqe == NULL) {
+		log_msg(LVL_ERROR, "Failed allocating IQE.");
+		return;
+	}
+
+	iqe->seg = seg;
+
+	/* Sort by sequence number */
+
+	link = list_first(&iqueue->list);
+	while (link != NULL) {
+		qe = list_get_instance(link,
+		    tcp_iqueue_entry_t, link);
+
+		if (seq_no_seg_cmp(iqueue->conn, iqe->seg, qe->seg) >= 0)
+			break;
+	}
+
+	if (link != NULL)
+		list_insert_before(&iqe->link, &qe->link);
+	else
+		list_append(&iqe->link, &iqueue->list);
+}
+
+/** Get next ready segment from incoming queue.
+ *
+ * Return the segment with the earliest sequence number if it is ready.
+ * A segment is ready if its SEG.SEQ is earlier or equal to RCV.NXT.
+ *
+ * @param iqueue	Incoming queue
+ * @param seg		Place to store pointer to segment
+ * @return		EOK on success, ENOENT if no segment is ready
+ */
+int tcp_iqueue_get_ready_seg(tcp_iqueue_t *iqueue, tcp_segment_t **seg)
+{
+	tcp_iqueue_entry_t *iqe;
+	link_t *link;
+
+	log_msg(LVL_DEBUG, "tcp_get_ready_seg()");
+
+	link = list_first(&iqueue->list);
+	if (link == NULL) {
+		log_msg(LVL_DEBUG, "iqueue is empty");
+		return ENOENT;
+	}
+
+	iqe = list_get_instance(link, tcp_iqueue_entry_t, link);
+
+	while (!seq_no_segment_acceptable(iqueue->conn, iqe->seg)) {
+		log_msg(LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%"
+		    PRIu32 ", RCV.NXT+RCV.WND=%" PRIu32 ", SEG.SEQ=%" PRIu32
+		    ", SEG.LEN=%" PRIu32 ")", iqueue->conn->rcv_nxt,
+		    iqueue->conn->rcv_nxt + iqueue->conn->rcv_wnd,
+		    iqe->seg->seq, iqe->seg->len);
+
+		list_remove(&iqe->link);
+		tcp_segment_delete(iqe->seg);
+
+         	link = list_first(&iqueue->list);
+		if (link == NULL) {
+			log_msg(LVL_DEBUG, "iqueue is empty");
+			return ENOENT;
+		}
+
+		iqe = list_get_instance(link, tcp_iqueue_entry_t, link);
+	}
+
+	/* Do not return segments that are not ready for processing */
+	if (!seq_no_segment_ready(iqueue->conn, iqe->seg)) {
+		log_msg(LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, "
+		    "RCV.NXT=%u, SEG.LEN=%u", iqe->seg->seq,
+		    iqueue->conn->rcv_nxt, iqe->seg->len);
+		return ENOENT;
+	}
+
+	log_msg(LVL_DEBUG, "Returning ready segment %p", iqe->seg);
+	list_remove(&iqe->link);
+	*seg = iqe->seg;
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/iqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/iqueue.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/iqueue.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Connection incoming segments queue
+ */
+
+#ifndef IQUEUE_H
+#define IQUEUE_H
+
+#include "tcp_type.h"
+
+extern void tcp_iqueue_init(tcp_iqueue_t *, tcp_conn_t *);
+extern void tcp_iqueue_insert_seg(tcp_iqueue_t *, tcp_segment_t *);
+extern int tcp_iqueue_get_ready_seg(tcp_iqueue_t *, tcp_segment_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/ncsim.c
===================================================================
--- uspace/srv/net/tl/tcp/ncsim.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/ncsim.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Network condition simulator
+ *
+ * Simulate network conditions for testing the reliability implementation:
+ *    - variable latency
+ *    - frame drop
+ */
+
+#include <adt/list.h>
+#include <async.h>
+#include <errno.h>
+#include <io/log.h>
+#include <stdlib.h>
+#include <thread.h>
+#include "conn.h"
+#include "ncsim.h"
+#include "rqueue.h"
+#include "segment.h"
+#include "tcp_type.h"
+
+static list_t sim_queue;
+static fibril_mutex_t sim_queue_lock;
+static fibril_condvar_t sim_queue_cv;
+
+/** Initialize segment receive queue. */
+void tcp_ncsim_init(void)
+{
+	list_initialize(&sim_queue);
+	fibril_mutex_initialize(&sim_queue_lock);
+	fibril_condvar_initialize(&sim_queue_cv);
+}
+
+/** Bounce segment through simulator into receive queue.
+ *
+ * @param sp	Socket pair, oriented for transmission
+ * @param seg	Segment
+ */
+void tcp_ncsim_bounce_seg(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_squeue_entry_t *sqe;
+	tcp_squeue_entry_t *old_qe;
+	link_t *link;
+
+	log_msg(LVL_DEBUG, "tcp_ncsim_bounce_seg()");
+	tcp_rqueue_bounce_seg(sp, seg);
+	return;
+
+	if (0 /*random() % 4 == 3*/) {
+		/* Drop segment */
+		log_msg(LVL_ERROR, "NCSim dropping segment");
+		tcp_segment_delete(seg);
+		return;
+	}
+
+	sqe = calloc(1, sizeof(tcp_squeue_entry_t));
+	if (sqe == NULL) {
+		log_msg(LVL_ERROR, "Failed allocating SQE.");
+		return;
+	}
+
+	sqe->delay = random() % (1000 * 1000);
+	sqe->sp = *sp;
+	sqe->seg = seg;
+
+	fibril_mutex_lock(&sim_queue_lock);
+
+	link = list_first(&sim_queue);
+	while (link != NULL && sqe->delay > 0) {
+		old_qe = list_get_instance(link, tcp_squeue_entry_t, link);
+		if (sqe->delay < old_qe->delay)
+			break;
+
+		sqe->delay -= old_qe->delay;
+
+		link = link->next;
+		if (link == &sim_queue.head)
+			link = NULL;
+	}
+
+	if (link != NULL)
+		list_insert_after(&sqe->link, link);
+	else
+		list_append(&sqe->link, &sim_queue);
+
+	fibril_condvar_broadcast(&sim_queue_cv);
+	fibril_mutex_unlock(&sim_queue_lock);
+}
+
+/** Network condition simulator handler thread. */
+static void tcp_ncsim_thread(void *arg)
+{
+	link_t *link;
+	tcp_squeue_entry_t *sqe;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_ncsim_thread()");
+
+
+	while (true) {
+		fibril_mutex_lock(&sim_queue_lock);
+
+		while (list_empty(&sim_queue))
+			fibril_condvar_wait(&sim_queue_cv, &sim_queue_lock);
+
+		do {
+			link = list_first(&sim_queue);
+			sqe = list_get_instance(link, tcp_squeue_entry_t, link);
+
+			log_msg(LVL_DEBUG, "NCSim - Sleep");
+			rc = fibril_condvar_wait_timeout(&sim_queue_cv,
+			    &sim_queue_lock, sqe->delay);
+		} while (rc != ETIMEOUT);
+
+		list_remove(link);
+		fibril_mutex_unlock(&sim_queue_lock);
+
+		log_msg(LVL_DEBUG, "NCSim - End Sleep");
+		tcp_rqueue_bounce_seg(&sqe->sp, sqe->seg);
+		free(sqe);
+	}
+}
+
+/** Start simulator handler thread. */
+void tcp_ncsim_thread_start(void)
+{
+	thread_id_t tid;
+        int rc;
+
+	log_msg(LVL_DEBUG, "tcp_ncsim_thread_start()");
+
+	rc = thread_create(tcp_ncsim_thread, NULL, "ncsim", &tid);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed creating ncsim thread.");
+		return;
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/ncsim.h
===================================================================
--- uspace/srv/net/tl/tcp/ncsim.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/ncsim.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Network condition simulator
+ */
+
+#ifndef NCSIM_H
+#define NCSIM_H
+
+#include "tcp_type.h"
+
+extern void tcp_ncsim_init(void);
+extern void tcp_ncsim_bounce_seg(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_ncsim_thread_start(void);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/pdu.c
===================================================================
--- uspace/srv/net/tl/tcp/pdu.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/pdu.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP header encoding and decoding
+ */
+
+#include <bitops.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "pdu.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "std.h"
+#include "tcp_type.h"
+
+#define TCP_CHECKSUM_INIT 0xffff
+
+/** One's complement addition.
+ *
+ * Result is a + b + carry.
+ */
+static uint16_t tcp_ocadd16(uint16_t a, uint16_t b)
+{
+	uint32_t s;
+
+	s = (uint32_t)a + (uint32_t)b;
+	return (s & 0xffff) + (s >> 16);
+}
+
+static uint16_t tcp_checksum_calc(uint16_t ivalue, void *data, size_t size)
+{
+	uint16_t sum;
+	uint16_t w;
+	size_t words, i;
+	uint8_t *bdata;
+
+	sum = ~ivalue;
+	words = size / 2;
+	bdata = (uint8_t *)data;
+
+	for (i = 0; i < words; i++) {
+		w = ((uint16_t)bdata[2*i] << 8) | bdata[2*i + 1];
+		sum = tcp_ocadd16(sum, w);
+	}
+
+	if (size % 2 != 0) {
+		w = ((uint16_t)bdata[2*words] << 8);
+		sum = tcp_ocadd16(sum, w);
+	}
+
+	return ~sum;
+}
+
+static void tcp_header_decode_flags(uint16_t doff_flags, tcp_control_t *rctl)
+{
+	tcp_control_t ctl;
+
+	ctl = 0;
+
+	if ((doff_flags & BIT_V(uint16_t, DF_URG)) != 0)
+		ctl |= 0 /* XXX */;
+	if ((doff_flags & BIT_V(uint16_t, DF_ACK)) != 0)
+		ctl |= CTL_ACK;
+	if ((doff_flags & BIT_V(uint16_t, DF_PSH)) != 0)
+		ctl |= 0 /* XXX */;
+	if ((doff_flags & BIT_V(uint16_t, DF_RST)) != 0)
+		ctl |= CTL_RST;
+	if ((doff_flags & BIT_V(uint16_t, DF_SYN)) != 0)
+		ctl |= CTL_SYN;
+	if ((doff_flags & BIT_V(uint16_t, DF_FIN)) != 0)
+		ctl |= CTL_FIN;
+
+	*rctl = ctl;
+}
+
+static void tcp_header_encode_flags(tcp_control_t ctl, uint16_t doff_flags0,
+    uint16_t *rdoff_flags)
+{
+	uint16_t doff_flags;
+
+	doff_flags = doff_flags0;
+
+	if ((ctl & CTL_ACK) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_ACK);
+	if ((ctl & CTL_RST) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_RST);
+	if ((ctl & CTL_SYN) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_SYN);
+	if ((ctl & CTL_FIN) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_FIN);
+
+	*rdoff_flags = doff_flags;
+}
+
+static void tcp_header_setup(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_header_t *hdr)
+{
+	uint16_t doff_flags;
+	uint16_t doff;
+
+	hdr->src_port = host2uint16_t_be(sp->local.port);
+	hdr->dest_port = host2uint16_t_be(sp->foreign.port);
+	hdr->seq = host2uint32_t_be(seg->seq);
+	hdr->ack = host2uint32_t_be(seg->ack);
+
+	doff = (sizeof(tcp_header_t) / sizeof(uint32_t)) << DF_DATA_OFFSET_l;
+	tcp_header_encode_flags(seg->ctrl, doff, &doff_flags);
+
+	hdr->doff_flags = host2uint16_t_be(doff_flags);
+	hdr->window = host2uint16_t_be(seg->wnd);
+	hdr->checksum = 0;
+	hdr->urg_ptr = host2uint16_t_be(seg->up);
+}
+
+static void tcp_phdr_setup(tcp_pdu_t *pdu, tcp_phdr_t *phdr)
+{
+	phdr->src_addr = host2uint32_t_be(pdu->src_addr.ipv4);
+	phdr->dest_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
+	phdr->zero = 0;
+	phdr->protocol = 6; /* XXX Magic number */
+	phdr->tcp_length = host2uint16_t_be(pdu->header_size + pdu->text_size);
+}
+
+static void tcp_header_decode(tcp_header_t *hdr, tcp_segment_t *seg)
+{
+	tcp_header_decode_flags(uint16_t_be2host(hdr->doff_flags), &seg->ctrl);
+	seg->seq = uint32_t_be2host(hdr->seq);
+	seg->ack = uint32_t_be2host(hdr->ack);
+	seg->wnd = uint16_t_be2host(hdr->window);
+	seg->up = uint16_t_be2host(hdr->urg_ptr);
+}
+
+static int tcp_header_encode(tcp_sockpair_t *sp, tcp_segment_t *seg,
+    void **header, size_t *size)
+{
+	tcp_header_t *hdr;
+
+	hdr = calloc(1, sizeof(tcp_header_t));
+	if (hdr == NULL)
+		return ENOMEM;
+
+	tcp_header_setup(sp, seg, hdr);
+	*header = hdr;
+	*size = sizeof(tcp_header_t);
+
+	return EOK;
+}
+
+static tcp_pdu_t *tcp_pdu_new(void)
+{
+	return calloc(1, sizeof(tcp_pdu_t));
+}
+
+/** Create PDU with the specified header and text data.
+ *
+ * Note that you still need to set addresses in the returned PDU.
+ *
+ * @param hdr		Header data
+ * @param hdr_size      Header size in bytes
+ * @param text		Text data
+ * @param text_size	Text size in bytes
+ * @return		New PDU
+ */
+tcp_pdu_t *tcp_pdu_create(void *hdr, size_t hdr_size, void *text,
+    size_t text_size)
+{
+	tcp_pdu_t *pdu;
+
+	pdu = tcp_pdu_new();
+	if (pdu == NULL)
+		return NULL;
+
+	pdu->header = malloc(hdr_size);
+	pdu->text = malloc(text_size);
+	if (pdu->header == NULL || pdu->text == NULL)
+		goto error;
+
+	memcpy(pdu->header, hdr, hdr_size);
+	memcpy(pdu->text, text, text_size);
+
+	pdu->header_size = hdr_size;
+	pdu->text_size = text_size;
+
+	return pdu;
+
+error:
+	if (pdu->header != NULL)
+		free(pdu->header);
+	if (pdu->text != NULL)
+		free(pdu->text);
+
+	return NULL;
+}
+
+void tcp_pdu_delete(tcp_pdu_t *pdu)
+{
+	free(pdu->header);
+	free(pdu->text);
+	free(pdu);
+}
+
+static uint16_t tcp_pdu_checksum_calc(tcp_pdu_t *pdu)
+{
+	uint16_t cs_phdr;
+	uint16_t cs_headers;
+	uint16_t cs_all;
+	tcp_phdr_t phdr;
+
+	tcp_phdr_setup(pdu, &phdr);
+	cs_phdr = tcp_checksum_calc(TCP_CHECKSUM_INIT, (void *)&phdr,
+	    sizeof(tcp_phdr_t));
+	cs_headers = tcp_checksum_calc(cs_phdr, pdu->header, pdu->header_size);
+	cs_all = tcp_checksum_calc(cs_headers, pdu->text, pdu->text_size);
+
+	return cs_all;
+}
+
+static void tcp_pdu_set_checksum(tcp_pdu_t *pdu, uint16_t checksum)
+{
+	tcp_header_t *hdr;
+
+	hdr = (tcp_header_t *)pdu->header;
+	hdr->checksum = host2uint16_t_be(checksum);
+}
+
+/** Encode outgoing PDU */
+int tcp_pdu_decode(tcp_pdu_t *pdu, tcp_sockpair_t *sp, tcp_segment_t **seg)
+{
+	tcp_segment_t *nseg;
+	tcp_header_t *hdr;
+
+	nseg = tcp_segment_make_data(0, pdu->text, pdu->text_size);
+	if (nseg == NULL)
+		return ENOMEM;
+
+	tcp_header_decode(pdu->header, nseg);
+	nseg->len += seq_no_control_len(nseg->ctrl);
+
+	hdr = (tcp_header_t *)pdu->header;
+
+	sp->local.port = uint16_t_be2host(hdr->dest_port);
+	sp->local.addr = pdu->dest_addr;
+	sp->foreign.port = uint16_t_be2host(hdr->src_port);
+	sp->foreign.addr = pdu->src_addr;
+
+	*seg = nseg;
+	return EOK;
+}
+
+/** Decode incoming PDU */
+int tcp_pdu_encode(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_pdu_t **pdu)
+{
+	tcp_pdu_t *npdu;
+	size_t text_size;
+	uint16_t checksum;
+
+	npdu = tcp_pdu_new();
+	if (npdu == NULL)
+		return ENOMEM;
+
+	npdu->src_addr = sp->local.addr;
+	npdu->dest_addr = sp->foreign.addr;
+	tcp_header_encode(sp, seg, &npdu->header, &npdu->header_size);
+
+	text_size = tcp_segment_text_size(seg);
+	npdu->text = calloc(1, text_size);
+	if (npdu->text == NULL)
+		return ENOMEM;
+
+	npdu->text_size = text_size;
+	memcpy(npdu->text, seg->data, text_size);
+
+	/* Checksum calculation */
+	checksum = tcp_pdu_checksum_calc(npdu);
+	tcp_pdu_set_checksum(npdu, checksum);
+
+	*pdu = npdu;
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/pdu.h
===================================================================
--- uspace/srv/net/tl/tcp/pdu.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/pdu.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP PDU (encoded Protocol Data Unit) handling
+ */
+
+#ifndef PDU_H
+#define PDU_H
+
+#include <sys/types.h>
+#include "std.h"
+#include "tcp_type.h"
+
+extern tcp_pdu_t *tcp_pdu_create(void *, size_t, void *, size_t);
+extern void tcp_pdu_delete(tcp_pdu_t *);
+extern int tcp_pdu_decode(tcp_pdu_t *, tcp_sockpair_t *, tcp_segment_t **);
+extern int tcp_pdu_encode(tcp_sockpair_t *, tcp_segment_t *, tcp_pdu_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/rqueue.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/rqueue.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Global segment receive queue
+ */
+
+#include <adt/prodcons.h>
+#include <errno.h>
+#include <io/log.h>
+#include <stdlib.h>
+#include <thread.h>
+#include "conn.h"
+#include "pdu.h"
+#include "rqueue.h"
+#include "segment.h"
+#include "tcp_type.h"
+#include "ucall.h"
+
+/** Transcode bounced segments.
+ *
+ * If defined, segments bounced via the internal debugging loopback will
+ * be encoded to a PDU and the decoded. Otherwise they will be bounced back
+ * directly without passing the encoder-decoder.
+ */
+#define BOUNCE_TRANSCODE
+
+static prodcons_t rqueue;
+
+/** Initialize segment receive queue. */
+void tcp_rqueue_init(void)
+{
+	prodcons_initialize(&rqueue);
+}
+
+/** Bounce segment directy into receive queue without constructing the PDU.
+ *
+ * This is for testing purposes only.
+ *
+ * @param sp	Socket pair, oriented for transmission
+ * @param seg	Segment
+ */
+void tcp_rqueue_bounce_seg(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_sockpair_t rident;
+
+	log_msg(LVL_DEBUG, "tcp_rqueue_bounce_seg()");
+
+#ifdef BOUNCE_TRANSCODE
+	tcp_pdu_t *pdu;
+	tcp_segment_t *dseg;
+
+	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		return;
+	}
+
+	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		return;
+	}
+
+	tcp_pdu_delete(pdu);
+
+	/** Insert decoded segment into rqueue */
+	tcp_rqueue_insert_seg(&rident, dseg);
+	tcp_segment_delete(seg);
+#else
+	/* Reverse the identification */
+	tcp_sockpair_flipped(sp, &rident);
+
+	/* Insert segment back into rqueue */
+	tcp_rqueue_insert_seg(&rident, seg);
+#endif
+}
+
+/** Insert segment into receive queue.
+ *
+ * @param sp	Socket pair, oriented for reception
+ * @param seg	Segment
+ */
+void tcp_rqueue_insert_seg(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_rqueue_entry_t *rqe;
+	log_msg(LVL_DEBUG, "tcp_rqueue_insert_seg()");
+
+	tcp_segment_dump(seg);
+
+	rqe = calloc(1, sizeof(tcp_rqueue_entry_t));
+	if (rqe == NULL) {
+		log_msg(LVL_ERROR, "Failed allocating RQE.");
+		return;
+	}
+
+	rqe->sp = *sp;
+	rqe->seg = seg;
+
+	prodcons_produce(&rqueue, &rqe->link);
+}
+
+/** Receive queue handler thread. */
+static void tcp_rqueue_thread(void *arg)
+{
+	link_t *link;
+	tcp_rqueue_entry_t *rqe;
+
+	log_msg(LVL_DEBUG, "tcp_rqueue_thread()");
+
+	while (true) {
+		link = prodcons_consume(&rqueue);
+		rqe = list_get_instance(link, tcp_rqueue_entry_t, link);
+
+		tcp_as_segment_arrived(&rqe->sp, rqe->seg);
+	}
+}
+
+/** Start receive queue handler thread. */
+void tcp_rqueue_thread_start(void)
+{
+	thread_id_t tid;
+        int rc;
+
+	log_msg(LVL_DEBUG, "tcp_rqueue_thread_start()");
+
+	rc = thread_create(tcp_rqueue_thread, NULL, "rqueue", &tid);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed creating rqueue thread.");
+		return;
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/rqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/rqueue.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/rqueue.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Global segment receive queue
+ */
+
+#ifndef RQUEUE_H
+#define RQUEUE_H
+
+#include "tcp_type.h"
+
+extern void tcp_rqueue_init(void);
+extern void tcp_rqueue_bounce_seg(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_rqueue_insert_seg(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_rqueue_handler(void *);
+extern void tcp_rqueue_thread_start(void);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/segment.c
===================================================================
--- uspace/srv/net/tl/tcp/segment.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/segment.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Segment processing
+ */
+
+#include <io/log.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "segment.h"
+#include "seq_no.h"
+#include "tcp_type.h"
+
+/** Alocate new segment structure. */
+tcp_segment_t *tcp_segment_new(void)
+{
+	return calloc(1, sizeof(tcp_segment_t));
+}
+
+/** Delete segment. */
+void tcp_segment_delete(tcp_segment_t *seg)
+{
+	free(seg);
+}
+
+/** Create duplicate of segment.
+ *
+ * @param seg	Segment
+ * @return 	Duplicate segment
+ */
+tcp_segment_t *tcp_segment_dup(tcp_segment_t *seg)
+{
+	tcp_segment_t *scopy;
+	size_t tsize;
+
+	scopy = tcp_segment_new();
+	if (scopy == NULL)
+		return NULL;
+
+	scopy->ctrl = seg->ctrl;
+	scopy->seq = seg->seq;
+	scopy->ack = seg->ack;
+	scopy->len = seg->len;
+	scopy->wnd = seg->wnd;
+	scopy->up = seg->up;
+
+	tsize = tcp_segment_text_size(seg);
+	scopy->data = calloc(tsize, 1);
+	if (scopy->data == NULL) {
+		free(scopy);
+		return NULL;
+	}
+
+	memcpy(scopy->data, seg->data, tsize);
+	scopy->dfptr = scopy->data;
+
+	return scopy;
+}
+
+/** Create a control-only segment.
+ *
+  * @return	Segment
+ */
+tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t ctrl)
+{
+	tcp_segment_t *seg;
+
+	seg = tcp_segment_new();
+	if (seg == NULL)
+		return NULL;
+
+	seg->ctrl = ctrl;
+	seg->len = seq_no_control_len(ctrl);
+
+	return seg;
+}
+
+/** Create an RST segment.
+ *
+ * @param seg	Segment we are replying to
+ * @return	RST segment
+ */
+tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *seg)
+{
+	tcp_segment_t *rseg;
+
+	rseg = tcp_segment_new();
+	if (rseg == NULL)
+		return NULL;
+
+	if ((seg->ctrl & CTL_ACK) == 0) {
+		rseg->ctrl = CTL_RST | CTL_ACK;
+		rseg->seq = 0;
+		rseg->ack = seg->seq + seg->len;
+	} else {
+		rseg->ctrl = CTL_RST;
+		rseg->seq = seg->ack;
+	}
+
+	return rseg;
+}
+
+/** Create a control segment.
+ *
+  * @return	Segment
+ */
+tcp_segment_t *tcp_segment_make_data(tcp_control_t ctrl, void *data,
+    size_t size)
+{
+	tcp_segment_t *seg;
+
+	seg = tcp_segment_new();
+	if (seg == NULL)
+		return NULL;
+
+	seg->ctrl = ctrl;
+	seg->len = seq_no_control_len(ctrl) + size;
+
+	seg->dfptr = seg->data = malloc(size);
+	if (seg->dfptr == NULL) {
+		free(seg);
+		return NULL;
+	}
+
+	memcpy(seg->data, data, size);
+
+	return seg;
+}
+
+
+/** Trim segment from left and right by the specified amount.
+ *
+ * Trim any text or control to remove the specified amount of sequence
+ * numbers from the left (lower sequence numbers) and right side
+ * (higher sequence numbers) of the segment.
+ *
+ * @param seg		Segment, will be modified in place
+ * @param left		Amount of sequence numbers to trim from the left
+ * @param right		Amount of sequence numbers to trim from the right
+ */
+void tcp_segment_trim(tcp_segment_t *seg, uint32_t left, uint32_t right)
+{
+	uint32_t t_size;
+
+	assert(left + right <= seg->len);
+
+	/* Special case, entire segment trimmed from left */
+	if (left == seg->len) {
+		seg->seq = seg->seq + seg->len;
+		seg->len = 0;
+		return;
+	}
+
+	/* Special case, entire segment trimmed from right */
+	if (right == seg->len) {
+		seg->len = 0;
+		return;
+	}
+
+	/* General case */
+
+	t_size = tcp_segment_text_size(seg);
+
+	if (left > 0 && (seg->ctrl & CTL_SYN) != 0) {
+		/* Trim SYN */
+		seg->ctrl &= ~CTL_SYN;
+		seg->seq++;
+		seg->len--;
+		left--;
+	}
+
+	if (right > 0 && (seg->ctrl & CTL_FIN) != 0) {
+		/* Trim FIN */
+		seg->ctrl &= ~CTL_FIN;
+		seg->len--;
+		right--;
+	}
+
+	if (left > 0 || right > 0) {
+		/* Trim segment text */
+		assert(left + right <= t_size);
+
+		seg->data += left;
+		seg->len -= left + right;
+	}
+}
+
+/** Copy out text data from segment.
+ *
+ * Data is copied from the beginning of the segment text up to @a size bytes.
+ * @a size must not be greater than the size of the segment text, but
+ * it can be less.
+ *
+ * @param seg	Segment
+ * @param buf	Destination buffer
+ * @param size	Size of destination buffer
+ */
+void tcp_segment_text_copy(tcp_segment_t *seg, void *buf, size_t size)
+{
+	assert(size <= tcp_segment_text_size(seg));
+	memcpy(buf, seg->data, size);
+}
+
+/** Return number of bytes in segment text.
+ *
+ * @param seg	Segment
+ * @return	Number of bytes in segment text
+ */
+size_t tcp_segment_text_size(tcp_segment_t *seg)
+{
+	return seg->len - seq_no_control_len(seg->ctrl);
+}
+
+/** Dump segment contents to log.
+ *
+ * @param seg	Segment
+ */
+void tcp_segment_dump(tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "Segment dump:");
+	log_msg(LVL_DEBUG, " - ctrl = %u", (unsigned)seg->ctrl);
+	log_msg(LVL_DEBUG, " - seq = % " PRIu32, seg->seq);
+	log_msg(LVL_DEBUG, " - ack = % " PRIu32, seg->ack);
+	log_msg(LVL_DEBUG, " - len = % " PRIu32, seg->len);
+	log_msg(LVL_DEBUG, " - wnd = % " PRIu32, seg->wnd);
+	log_msg(LVL_DEBUG, " - up = % " PRIu32, seg->up);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/segment.h
===================================================================
--- uspace/srv/net/tl/tcp/segment.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/segment.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Segment processing
+ */
+
+#ifndef SEGMENT_H
+#define SEGMENT_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+extern tcp_segment_t *tcp_segment_new(void);
+extern void tcp_segment_delete(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_dup(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t);
+extern tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_make_data(tcp_control_t, void *, size_t);
+extern void tcp_segment_trim(tcp_segment_t *, uint32_t, uint32_t);
+extern void tcp_segment_text_copy(tcp_segment_t *, void *, size_t);
+extern size_t tcp_segment_text_size(tcp_segment_t *);
+extern void tcp_segment_dump(tcp_segment_t *);
+
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/seq_no.c
===================================================================
--- uspace/srv/net/tl/tcp/seq_no.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/seq_no.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Sequence number computations
+ */
+
+#include <assert.h>
+#include <bool.h>
+#include <sys/types.h>
+#include "seq_no.h"
+#include "tcp_type.h"
+
+/** a <= b < c modulo sequence space */
+static bool seq_no_le_lt(uint32_t a, uint32_t b, uint32_t c)
+{
+	if (a <= c) {
+		return (a <= b) && (b < c);
+	} else {
+		return (b < c) || (a <= b);
+	}
+}
+
+/** a < b <= c modulo sequence space */
+static bool seq_no_lt_le(uint32_t a, uint32_t b, uint32_t c)
+{
+	if (a <= c) {
+		return (a < b) && (b <= c);
+	} else {
+		return (b <= c) || (a < b);
+	}
+}
+
+/** Determine wheter ack is acceptable (new acknowledgement) */
+bool seq_no_ack_acceptable(tcp_conn_t *conn, uint32_t seg_ack)
+{
+	/* SND.UNA < SEG.ACK <= SND.NXT */
+	return seq_no_lt_le(conn->snd_una, seg_ack, conn->snd_nxt);
+}
+
+/** Determine wheter ack is duplicate.
+ *
+ * ACK is duplicate if it refers to a sequence number that has
+ * aleady been acked (SEG.ACK <= SND.UNA).
+ */
+bool seq_no_ack_duplicate(tcp_conn_t *conn, uint32_t seg_ack)
+{
+	uint32_t diff;
+
+	/*
+	 * There does not seem to be a three-point comparison
+	 * equivalent of SEG.ACK < SND.UNA. Thus we do it
+	 * on a best-effort basis, based on the difference.
+	 * [-2^31, 0) means less-than, 0 means equal, [0, 2^31)
+	 * means greater-than. Less-than or equal means duplicate.
+	 */
+	diff = seg_ack - conn->snd_una;
+	return diff == 0 || (diff & (0x1 << 31)) != 0;
+}
+
+/** Determine if sequence number is in receive window. */
+bool seq_no_in_rcv_wnd(tcp_conn_t *conn, uint32_t sn)
+{
+	return seq_no_le_lt(conn->rcv_nxt, sn, conn->rcv_nxt + conn->rcv_wnd);
+}
+
+/** Determine segment has new window update.
+ *
+ * Window update is new if either SND.WL1 < SEG.SEQ or
+ * (SND.WL1 = SEG.SEQ and SND.WL2 <= SEG.ACK).
+ */
+bool seq_no_new_wnd_update(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	bool n_seq, n_ack;
+
+	assert(seq_no_segment_acceptable(conn, seg));
+
+	/*
+	 * We make use of the fact that the peer should not ACK anything
+	 * beyond our send window (we surely haven't sent that yet)
+	 * as we should have filtered those acks out.
+	 * We use SND.UNA+SND.WND as the third point of comparison.
+	 */
+
+	n_seq = seq_no_lt_le(conn->snd_wl1, seg->seq,
+	    conn->snd_una + conn->snd_wnd);
+
+	n_ack = conn->snd_wl1 == seg->seq &&
+	    seq_no_le_lt(conn->snd_wl2, seg->ack,
+	    conn->snd_una + conn->snd_wnd + 1);
+
+	return n_seq || n_ack;
+}
+
+/** Determine if segment is ready for processing.
+ *
+ * Assuming segment is acceptable, a segment is ready if it intersects
+ * RCV.NXT, that is we can process it immediately.
+ */
+bool seq_no_segment_ready(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	assert(seq_no_segment_acceptable(conn, seg));
+
+	return seq_no_le_lt(seg->seq, conn->rcv_nxt, seg->seq + seg->len + 1);
+}
+
+/** Determine whether segment is fully acked */
+bool seq_no_segment_acked(tcp_conn_t *conn, tcp_segment_t *seg, uint32_t ack)
+{
+	assert(seg->len > 0);
+	return seq_no_lt_le(seg->seq, seg->seq + seg->len, ack);
+}
+
+/** Determine whether initial SYN is acked */
+bool seq_no_syn_acked(tcp_conn_t *conn)
+{
+	return seq_no_lt_le(conn->iss, conn->snd_una, conn->snd_nxt);
+}
+
+/** Determine whether segment overlaps the receive window */
+bool seq_no_segment_acceptable(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	bool b_in, e_in;
+
+	b_in = seq_no_le_lt(conn->rcv_nxt, seg->seq, conn->rcv_nxt
+	    + conn->rcv_wnd);
+
+	e_in = seq_no_le_lt(conn->rcv_nxt, seg->seq + seg->len - 1,
+	    conn->rcv_nxt + conn->rcv_wnd);
+
+	if (seg->len == 0 && conn->rcv_wnd == 0) {
+		return seg->seq == conn->rcv_nxt;
+	} else if (seg->len == 0 && conn->rcv_wnd != 0) {
+		return b_in;
+	} else if (seg->len > 0 && conn->rcv_wnd == 0) {
+		return false;
+	} else {
+		return b_in || e_in;
+	}
+}
+
+/** Determine size that control bits occupy in sequence space. */
+uint32_t seq_no_control_len(tcp_control_t ctrl)
+{
+	uint32_t len = 0;
+
+	if ((ctrl & CTL_SYN) != 0)
+		++len;
+
+	if ((ctrl & CTL_FIN) != 0)
+		++len;
+
+	return len;
+}
+
+/** Calculate the amount of trim needed to fit segment in receive window. */
+void seq_no_seg_trim_calc(tcp_conn_t *conn, tcp_segment_t *seg,
+    uint32_t *left, uint32_t *right)
+{
+	assert(seq_no_segment_acceptable(conn, seg));
+
+	/*
+	 * If RCV.NXT is between SEG.SEQ and RCV.NXT+RCV.WND, then
+	 * left trim amount is positive
+	 */
+	if (seq_no_lt_le(seg->seq, conn->rcv_nxt,
+	    conn->rcv_nxt + conn->rcv_wnd)) {
+		*left = conn->rcv_nxt - seg->seq;
+	} else {
+		*left = 0;
+	}
+
+	/*
+	 * If SEG.SEQ+SEG.LEN is between SEG.SEQ and RCV.NXT+RCV.WND,
+	 * then right trim is zero.
+	 */
+	if (seq_no_lt_le(seg->seq - 1, seg->seq + seg->len,
+	    conn->rcv_nxt + conn->rcv_wnd)) {
+		*right = 0;
+	} else {
+		*right = (seg->seq + seg->len) -
+		    (conn->rcv_nxt + conn->rcv_wnd);
+	}
+}
+
+/** Segment order comparison.
+ *
+ * Compare sequence order of two acceptable segments.
+ *
+ * @param conn		Connection
+ * @param sa		Segment A
+ * @param sb		Segment B
+ *
+ * @return		-1, 0, 1, resp. if A < B, A == B, A > B in terms
+ *			of sequence order of the beginning of the segment.
+ */
+int seq_no_seg_cmp(tcp_conn_t *conn, tcp_segment_t *sa, tcp_segment_t *sb)
+{
+	assert(seq_no_segment_acceptable(conn, sa));
+	assert(seq_no_segment_acceptable(conn, sb));
+
+	if (seq_no_lt_le(sa->seq, sb->seq, conn->rcv_nxt + conn->rcv_wnd))
+		return -1;
+
+	if (seq_no_lt_le(sb->seq, sa->seq, conn->rcv_nxt + conn->rcv_wnd))
+		return +1;
+
+	assert(sa->seq == sb->seq);
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/seq_no.h
===================================================================
--- uspace/srv/net/tl/tcp/seq_no.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/seq_no.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Sequence number computations
+ */
+
+#ifndef SEQ_NO_H
+#define SEQ_NO_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+extern bool seq_no_ack_acceptable(tcp_conn_t *, uint32_t);
+extern bool seq_no_ack_duplicate(tcp_conn_t *, uint32_t);
+extern bool seq_no_in_rcv_wnd(tcp_conn_t *, uint32_t);
+extern bool seq_no_new_wnd_update(tcp_conn_t *, tcp_segment_t *);
+extern bool seq_no_segment_acked(tcp_conn_t *, tcp_segment_t *, uint32_t);
+extern bool seq_no_syn_acked(tcp_conn_t *);
+extern bool seq_no_segment_ready(tcp_conn_t *, tcp_segment_t *);
+extern bool seq_no_segment_acceptable(tcp_conn_t *, tcp_segment_t *);
+extern void seq_no_seg_trim_calc(tcp_conn_t *, tcp_segment_t *, uint32_t *,
+    uint32_t *);
+extern int seq_no_seg_cmp(tcp_conn_t *, tcp_segment_t *, tcp_segment_t *);
+
+extern uint32_t seq_no_control_len(tcp_control_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/sock.c
===================================================================
--- uspace/srv/net/tl/tcp/sock.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/sock.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2008 Lukas Mejdrech
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Socket provider
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <io/log.h>
+#include <ip_client.h>
+#include <ipc/socket.h>
+#include <net/modules.h>
+#include <net/socket.h>
+
+#include "sock.h"
+#include "std.h"
+#include "tcp.h"
+#include "tcp_type.h"
+#include "ucall.h"
+
+#define FRAGMENT_SIZE 1024
+
+/** Free ports pool start. */
+#define TCP_FREE_PORTS_START		1025
+
+/** Free ports pool end. */
+#define TCP_FREE_PORTS_END		65535
+
+static int last_used_port = TCP_FREE_PORTS_START - 1;
+static socket_ports_t gsock;
+
+void tcp_sock_init(void)
+{
+	socket_ports_initialize(&gsock);
+}
+
+static void tcp_free_sock_data(socket_core_t *sock_core)
+{
+	tcp_sockdata_t *socket;
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	(void)socket;
+}
+
+static void tcp_sock_notify_data(socket_core_t *sock_core)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
+	async_exch_t *exch = async_exchange_begin(sock_core->sess);
+	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
+	    FRAGMENT_SIZE, 0, 0, 1);
+	async_exchange_end(exch);
+}
+
+static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
+	async_exch_t *exch = async_exchange_begin(lsock_core->sess);
+	async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
+	    FRAGMENT_SIZE, 0, 0, 0);
+	async_exchange_end(exch);
+}
+
+static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	tcp_sockdata_t *sock;
+	int sock_id;
+	int rc;
+	ipc_call_t answer;
+
+	log_msg(LVL_DEBUG, "tcp_sock_socket()");
+	sock = calloc(sizeof(tcp_sockdata_t), 1);
+	if (sock == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	sock->client = client;
+	sock->laddr.ipv4 = TCP_IPV4_ANY;
+
+	sock_id = SOCKET_GET_SOCKET_ID(call);
+	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	refresh_answer(&answer, NULL);
+	SOCKET_SET_SOCKET_ID(answer, sock_id);
+
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
+	answer_call(callid, EOK, &answer, 3);
+}
+
+static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int rc;
+	struct sockaddr *addr;
+	size_t addr_len;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+
+	log_msg(LVL_DEBUG, "tcp_sock_bind()");
+	log_msg(LVL_DEBUG, " - async_data_write_accept");
+	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - call socket_bind");
+	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
+	    addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
+	    last_used_port);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - call socket_cores_find");
+	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
+	if (sock_core != NULL) {
+		socket = (tcp_sockdata_t *)sock_core->specific_data;
+		/* XXX Anything to do? */
+		(void) socket;
+	}
+
+	log_msg(LVL_DEBUG, " - success");
+	async_answer_0(callid, EOK);
+}
+
+static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	int backlog;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+
+	log_msg(LVL_DEBUG, "tcp_sock_listen()");
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	backlog = SOCKET_GET_BACKLOG(call);
+
+	if (backlog < 0) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+
+	/*
+	 * XXX We do not do anything and defer action to accept().
+	 * This is a slight difference in semantics, but most servers
+	 * would just listen() and immediately accept() in a loop.
+	 *
+	 * The only difference is that there is a window between
+	 * listen() and accept() or two accept()s where we refuse
+	 * connections.
+	 */
+	(void)backlog;
+	(void)socket;
+
+	async_answer_0(callid, EOK);
+	log_msg(LVL_DEBUG, "tcp_sock_listen(): notify data\n");
+	/* Push one accept notification to client's queue */
+	tcp_sock_notify_aconn(sock_core);
+}
+
+static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int rc;
+	struct sockaddr_in *addr;
+	int socket_id;
+	size_t addr_len;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	tcp_error_t trc;
+	tcp_sock_t lsocket;
+	tcp_sock_t fsocket;
+	nic_device_id_t dev_id;
+	tcp_phdr_t *phdr;
+	size_t phdr_len;
+
+	log_msg(LVL_DEBUG, "tcp_sock_connect()");
+
+	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
+	if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	if (sock_core->port <= 0) {
+		rc = socket_bind_free_port(&gsock, sock_core,
+		    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
+		    last_used_port);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			return;
+		}
+
+		last_used_port = sock_core->port;
+	}
+
+	if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
+		/* Find route to determine local IP address. */
+		rc = ip_get_route_req(ip_sess, IPPROTO_TCP,
+		    (struct sockaddr *)addr, sizeof(*addr), &dev_id,
+		    (void **)&phdr, &phdr_len);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			log_msg(LVL_DEBUG, "tcp_transmit_connect: Failed to find route.");
+			return;
+		}
+
+		socket->laddr.ipv4 = uint32_t_be2host(phdr->src_addr);
+		log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
+		free(phdr);
+	}
+
+	lsocket.addr.ipv4 = socket->laddr.ipv4;
+	lsocket.port = sock_core->port;
+	fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
+	fsocket.port = uint16_t_be2host(addr->sin_port);
+
+	trc = tcp_uc_open(&lsocket, &fsocket, ap_active, &socket->conn);
+
+	if (socket->conn != NULL)
+		socket->conn->name = (char *)"C";
+
+	switch (trc) {
+	case TCP_EOK:
+		rc = EOK;
+		break;
+	case TCP_ERESET:
+		rc = ECONNREFUSED;
+		break;
+	default:
+		assert(false);
+	}
+
+	async_answer_0(callid, rc);
+
+	/* Push one fragment notification to client's queue */
+	tcp_sock_notify_data(sock_core);
+	log_msg(LVL_DEBUG, "tcp_sock_connect(): notify conn\n");
+}
+
+static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	ipc_call_t answer;
+	int socket_id;
+	int asock_id;
+	socket_core_t *sock_core;
+	socket_core_t *asock_core;
+	tcp_sockdata_t *socket;
+	tcp_sockdata_t *asocket;
+	tcp_error_t trc;
+	tcp_sock_t lsocket;
+	tcp_sock_t fsocket;
+	tcp_conn_t *conn;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_sock_accept()");
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+
+	log_msg(LVL_DEBUG, " - verify socket->conn");
+	if (socket->conn != NULL) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - open connection");
+
+	lsocket.addr.ipv4 = TCP_IPV4_ANY;
+	lsocket.port = sock_core->port;
+	fsocket.addr.ipv4 = TCP_IPV4_ANY;
+	fsocket.port = TCP_PORT_ANY;
+
+	trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, &conn);
+	if (conn != NULL)
+		conn->name = (char *)"S";
+
+	log_msg(LVL_DEBUG, " - decode TCP return code");
+
+	switch (trc) {
+	case TCP_EOK:
+		rc = EOK;
+		break;
+	case TCP_ERESET:
+		rc = ECONNABORTED;
+		break;
+	default:
+		assert(false);
+	}
+
+	log_msg(LVL_DEBUG, " - check TCP return code");
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
+	asocket = calloc(sizeof(tcp_sockdata_t), 1);
+	if (asocket == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	asocket->client = client;
+	asocket->conn = conn;
+	log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
+
+	rc = socket_create(&client->sockets, client->sess, asocket, &asock_id);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
+
+	asock_core = socket_cores_find(&client->sockets, asock_id);
+	assert(asock_core != NULL);
+
+	refresh_answer(&answer, NULL);
+
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_SOCKET_ID(answer, asock_id);
+	SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
+
+	answer_call(callid, asock_core->socket_id, &answer, 3);
+
+	/* Push one accept notification to client's queue */
+	tcp_sock_notify_aconn(sock_core);
+
+	/* Push one fragment notification to client's queue */
+	tcp_sock_notify_data(asock_core);
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify aconn\n");
+}
+
+static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	int fragments;
+	int index;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	ipc_call_t answer;
+	ipc_callid_t wcallid;
+	size_t length;
+	uint8_t buffer[FRAGMENT_SIZE];
+	tcp_error_t trc;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_sock_send()");
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
+	SOCKET_GET_FLAGS(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	if (socket->conn == NULL) {
+		async_answer_0(callid, ENOTCONN);
+		return;
+	}
+
+	for (index = 0; index < fragments; index++) {
+		if (!async_data_write_receive(&wcallid, &length)) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+
+		if (length > FRAGMENT_SIZE)
+			length = FRAGMENT_SIZE;
+
+		rc = async_data_write_finalize(wcallid, buffer, length);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			return;
+		}
+
+		trc = tcp_uc_send(socket->conn, buffer, length, 0);
+
+		switch (trc) {
+		case TCP_EOK:
+			rc = EOK;
+			break;
+		case TCP_ENOTEXIST:
+			rc = ENOTCONN;
+			break;
+		case TCP_ECLOSING:
+			rc = ENOTCONN;
+			break;
+		case TCP_ERESET:
+			rc = ECONNABORTED;
+			break;
+		default:
+			assert(false);
+		}
+
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			return;
+		}
+	}
+
+	refresh_answer(&answer, NULL);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	answer_call(callid, EOK, &answer, 2);
+}
+
+static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_sendto()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	int flags;
+	size_t addr_length, length;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	ipc_call_t answer;
+	ipc_callid_t rcallid;
+	uint8_t buffer[FRAGMENT_SIZE];
+	size_t data_len;
+	xflags_t xflags;
+	tcp_error_t trc;
+	struct sockaddr_in addr;
+	tcp_sock_t *rsock;
+	int rc;
+
+	log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	flags = SOCKET_GET_FLAGS(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	if (socket->conn == NULL) {
+		async_answer_0(callid, ENOTCONN);
+		return;
+	}
+
+	(void)flags;
+
+	trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
+	    &xflags);
+	log_msg(LVL_DEBUG, "**** tcp_uc_receive done");
+
+	switch (trc) {
+	case TCP_EOK:
+		rc = EOK;
+		break;
+	case TCP_ENOTEXIST:
+	case TCP_ECLOSING:
+		rc = ENOTCONN;
+		break;
+	case TCP_ERESET:
+		rc = ECONNABORTED;
+		break;
+	default:
+		assert(false);
+	}
+
+	log_msg(LVL_DEBUG, "**** tcp_uc_receive -> %d", rc);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
+		/* Fill addr */
+		rsock = &socket->conn->ident.foreign;
+		addr.sin_family = AF_INET;
+		addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
+		addr.sin_port = host2uint16_t_be(rsock->port);
+
+		log_msg(LVL_DEBUG, "addr read receive");
+		if (!async_data_read_receive(&rcallid, &addr_length)) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+
+		if (addr_length > sizeof(addr))
+			addr_length = sizeof(addr);
+
+		log_msg(LVL_DEBUG, "addr read finalize");
+		rc = async_data_read_finalize(rcallid, &addr, addr_length);
+		if (rc != EOK) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+	}
+
+	log_msg(LVL_DEBUG, "data read receive");
+	if (!async_data_read_receive(&rcallid, &length)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (length > data_len)
+		length = data_len;
+
+	log_msg(LVL_DEBUG, "data read finalize");
+	rc = async_data_read_finalize(rcallid, buffer, length);
+
+	if (length < data_len && rc == EOK)
+		rc = EOVERFLOW;
+
+	SOCKET_SET_READ_DATA_LENGTH(answer, length);
+	answer_call(callid, EOK, &answer, 1);
+
+	/* Push one fragment notification to client's queue */
+	tcp_sock_notify_data(sock_core);
+}
+
+static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	tcp_error_t trc;
+	int rc;
+	uint8_t buffer[FRAGMENT_SIZE];
+	size_t data_len;
+	xflags_t xflags;
+
+	log_msg(LVL_DEBUG, "tcp_sock_close()");
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+
+	if (socket->conn != NULL) {
+		trc = tcp_uc_close(socket->conn);
+		if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
+			async_answer_0(callid, EBADF);
+			return;
+		}
+
+		/* Drain incoming data. This should really be done in the background. */
+		do {
+			trc = tcp_uc_receive(socket->conn, buffer,
+			    FRAGMENT_SIZE, &data_len, &xflags);
+		} while (trc == TCP_EOK);
+
+		tcp_uc_delete(socket->conn);
+	}
+
+	rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
+	    tcp_free_sock_data);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_answer_0(callid, EOK);
+}
+
+static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+int tcp_sock_connection(async_sess_t *sess, ipc_callid_t iid, ipc_call_t icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	tcp_client_t client;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	client.sess = sess;
+	socket_cores_initialize(&client.sockets);
+
+	while (true) {
+		callid = async_get_call(&call);
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
+		    (int)IPC_GET_IMETHOD(call));
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case NET_SOCKET:
+			tcp_sock_socket(&client, callid, call);
+			break;
+		case NET_SOCKET_BIND:
+			tcp_sock_bind(&client, callid, call);
+			break;
+		case NET_SOCKET_LISTEN:
+			tcp_sock_listen(&client, callid, call);
+			break;
+		case NET_SOCKET_CONNECT:
+			tcp_sock_connect(&client, callid, call);
+			break;
+		case NET_SOCKET_ACCEPT:
+			tcp_sock_accept(&client, callid, call);
+			break;
+		case NET_SOCKET_SEND:
+			tcp_sock_send(&client, callid, call);
+			break;
+		case NET_SOCKET_SENDTO:
+			tcp_sock_sendto(&client, callid, call);
+			break;
+		case NET_SOCKET_RECV:
+		case NET_SOCKET_RECVFROM:
+			tcp_sock_recvfrom(&client, callid, call);
+			break;
+		case NET_SOCKET_CLOSE:
+			tcp_sock_close(&client, callid, call);
+			break;
+		case NET_SOCKET_GETSOCKOPT:
+			tcp_sock_getsockopt(&client, callid, call);
+			break;
+		case NET_SOCKET_SETSOCKOPT:
+			tcp_sock_setsockopt(&client, callid, call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/sock.h
===================================================================
--- uspace/srv/net/tl/tcp/sock.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/sock.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Socket provider
+ */
+
+#ifndef SOCK_H
+#define SOCK_H
+
+#include <async.h>
+
+extern void tcp_sock_init(void);
+extern int tcp_sock_connection(async_sess_t *, ipc_callid_t, ipc_call_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/std.h
===================================================================
--- uspace/srv/net/tl/tcp/std.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/std.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP header definitions
+ *
+ * Based on IETF RFC 793
+ */
+
+#ifndef STD_H
+#define STD_H
+
+#include <sys/types.h>
+
+/** TCP Header (fixed part) */
+typedef struct {
+	/** Source port */
+	uint16_t src_port;
+	/** Destination port */
+	uint16_t dest_port;
+	/** Sequence number */
+	uint32_t seq;
+	/** Acknowledgement number */
+	uint32_t ack;
+	/** Data Offset, Reserved, Flags */
+	uint16_t doff_flags;
+	/** Window */
+	uint16_t window;
+	/* Checksum */
+	uint16_t checksum;
+	/** Urgent pointer */
+	uint16_t urg_ptr;
+} tcp_header_t;
+
+/** Bits in tcp_header_t.doff_flags */
+enum doff_flags_bits {
+	DF_DATA_OFFSET_h	= 15,
+	DF_DATA_OFFSET_l	= 12,
+	DF_URG			= 5,
+	DF_ACK			= 4,
+	DF_PSH			= 3,
+	DF_RST			= 2,
+	DF_SYN			= 1,
+	DF_FIN			= 0
+};
+
+/** TCP pseudo header */
+typedef struct {
+	/** Source address */
+	uint32_t src_addr;
+	/** Destination address */
+	uint32_t dest_addr;
+	/** Zero */
+	uint8_t zero;
+	/** Protocol */
+	uint8_t protocol;
+	/** TCP length */
+	uint16_t tcp_length;
+} tcp_phdr_t;
+
+/** Option kind */
+enum opt_kind {
+	/** End of option list */
+	OPT_END_LIST		= 0,
+	/** No-operation */
+	OPT_NOP			= 1,
+	/** Maximum segment size */
+	OPT_MAX_SEG_SIZE	= 2
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2008 Lukas Mejdrech
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,229 +31,99 @@
  */
 
-/** @file
- * TCP module implementation.
- * @see tcp.h
+/**
+ * @file TCP (Transmission Control Protocol) network module
  */
 
-#include <assert.h>
 #include <async.h>
-#include <fibril_synch.h>
-#include <malloc.h>
-/* TODO remove stdio */
+#include <bitops.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <io/log.h>
 #include <stdio.h>
-#include <errno.h>
-
+#include <task.h>
+
+#include <icmp_remote.h>
+#include <ip_client.h>
+#include <ip_interface.h>
 #include <ipc/services.h>
-#include <ipc/net.h>
 #include <ipc/tl.h>
-#include <ipc/socket.h>
-
-#include <net/socket_codes.h>
-#include <net/ip_protocols.h>
-#include <net/in.h>
-#include <net/in6.h>
-#include <net/inet.h>
-#include <net/modules.h>
-
-#include <adt/dynamic_fifo.h>
+#include <tl_common.h>
+#include <tl_skel.h>
 #include <packet_client.h>
 #include <packet_remote.h>
-#include <net_checksum.h>
-#include <ip_client.h>
-#include <ip_interface.h>
-#include <icmp_client.h>
-#include <icmp_remote.h>
-#include <net_interface.h>
-#include <socket_core.h>
-#include <tl_common.h>
-#include <tl_remote.h>
-#include <tl_skel.h>
-
+
+#include "ncsim.h"
+#include "pdu.h"
+#include "rqueue.h"
+#include "sock.h"
+#include "std.h"
 #include "tcp.h"
-#include "tcp_header.h"
-
-/** TCP module name. */
-#define NAME  "tcp"
-
-/** The TCP window default value. */
-#define NET_DEFAULT_TCP_WINDOW		10240
-
-/** Initial timeout for new connections. */
-#define NET_DEFAULT_TCP_INITIAL_TIMEOUT	3000000L
-
-/** Default timeout for closing. */
-#define NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT 2000L
-
-/** The initial outgoing sequence number. */
-#define TCP_INITIAL_SEQUENCE_NUMBER	2999
-
-/** Maximum TCP fragment size. */
-#define MAX_TCP_FRAGMENT_SIZE		65535
-
-/** Free ports pool start. */
-#define TCP_FREE_PORTS_START		1025
-
-/** Free ports pool end. */
-#define TCP_FREE_PORTS_END		65535
-
-/** Timeout for connection initialization, SYN sent. */
-#define TCP_SYN_SENT_TIMEOUT		1000000L
-
-/** The maximum number of timeouts in a row before singaling connection lost. */
-#define TCP_MAX_TIMEOUTS		8
-
-/** The number of acknowledgements before retransmit. */
-#define TCP_FAST_RETRANSMIT_COUNT	3
-
-/** Returns a value indicating whether the value is in the interval respecting
- * the possible overflow.
- *
- * The high end and/or the value may overflow, be lower than the low value.
- *
- * @param[in] lower	The last value before the interval.
- * @param[in] value	The value to be checked.
- * @param[in] higher_equal The last value in the interval.
- */
-#define IS_IN_INTERVAL_OVERFLOW(lower, value, higher_equal) \
-	((((lower) < (value)) && (((value) <= (higher_equal)) || \
-	((higher_equal) < (lower)))) || (((value) <= (higher_equal)) && \
-	((higher_equal) < (lower))))
-
-/** Type definition of the TCP timeout.
- *  @see tcp_timeout
- */
-typedef struct tcp_timeout tcp_timeout_t;
-
-/** TCP reply timeout data.
- *  Used as a timeouting fibril argument.
- *  @see tcp_timeout()
- */
-struct tcp_timeout {
-	/** TCP global data are going to be read only. */
-	int globals_read_only;
-
-	/** Socket port. */
-	int port;
-
-	/** Local sockets. */
-	socket_cores_t *local_sockets;
-
-	/** Socket identifier. */
-	int socket_id;
-
-	/** Socket state. */
-	tcp_socket_state_t state;
-
-	/** Sent packet sequence number. */
-	int sequence_number;
-
-	/** Timeout in microseconds. */
-	suseconds_t timeout;
-
-	/** Port map key. */
-	uint8_t *key;
-
-	/** Port map key length. */
-	size_t key_length;
-};
-
-static int tcp_release_and_return(packet_t *, int);
-static void tcp_prepare_operation_header(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, int synchronize, int);
-static int tcp_prepare_timeout(int (*)(void *), socket_core_t *,
-    tcp_socket_data_t *, size_t, tcp_socket_state_t, suseconds_t, int);
-static void tcp_free_socket_data(socket_core_t *);
-
-static int tcp_timeout(void *);
-
-static int tcp_release_after_timeout(void *);
-
-static int tcp_process_packet(nic_device_id_t, packet_t *, services_t);
-static int tcp_connect_core(socket_core_t *, socket_cores_t *,
-    struct sockaddr *, socklen_t);
-static int tcp_queue_prepare_packet(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, size_t);
-static int tcp_queue_packet(socket_core_t *, tcp_socket_data_t *, packet_t *,
-    size_t);
-static packet_t *tcp_get_packets_to_send(socket_core_t *, tcp_socket_data_t *);
-static void tcp_send_packets(nic_device_id_t, packet_t *);
-
-static void tcp_process_acknowledgement(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *);
-static packet_t *tcp_send_prepare_packet(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, size_t, size_t);
-static packet_t *tcp_prepare_copy(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, size_t, size_t);
-/* static */ void tcp_retransmit_packet(socket_core_t *, tcp_socket_data_t *,
-    size_t);
-static int tcp_create_notification_packet(packet_t **, socket_core_t *,
-    tcp_socket_data_t *, int, int);
-static void tcp_refresh_socket_data(tcp_socket_data_t *);
-
-static void tcp_initialize_socket_data(tcp_socket_data_t *);
-
-static int tcp_process_listen(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *, struct sockaddr *, struct sockaddr *, size_t);
-static int tcp_process_syn_sent(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *);
-static int tcp_process_syn_received(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *);
-static int tcp_process_established(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *, int, size_t);
-static int tcp_queue_received_packet(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, int, size_t);
-static void tcp_queue_received_end_of_data(socket_core_t *socket);
-
-static int tcp_received_msg(nic_device_id_t, packet_t *, services_t, services_t);
-static int tcp_process_client_messages(async_sess_t *, ipc_callid_t,
-    ipc_call_t);
-
-static int tcp_listen_message(socket_cores_t *, int, int);
-static int tcp_connect_message(socket_cores_t *, int, struct sockaddr *,
-    socklen_t);
-static int tcp_recvfrom_message(socket_cores_t *, int, int, size_t *);
-static int tcp_send_message(socket_cores_t *, int, int, size_t *, int);
-static int tcp_accept_message(socket_cores_t *, int, int, size_t *, size_t *);
-static int tcp_close_message(socket_cores_t *, int);
-
-/** TCP global data. */
-tcp_globals_t tcp_globals;
-
-int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
-    services_t receiver, services_t error)
+#include "test.h"
+
+#define NAME       "tcp"
+
+async_sess_t *net_sess;
+static async_sess_t *icmp_sess;
+async_sess_t *ip_sess;
+packet_dimensions_t pkt_dims;
+
+static void tcp_received_pdu(tcp_pdu_t *pdu);
+
+/* Pull up packets into a single memory block. */
+static int pq_pullup(packet_t *packet, void **data, size_t *dsize)
+{
+	packet_t *npacket;
+	size_t tot_len;
+	int length;
+
+	npacket = packet;
+	tot_len = 0;
+	do {
+		length = packet_get_data_length(packet);
+		if (length <= 0)
+			return EINVAL;
+
+		tot_len += length;
+	} while ((npacket = pq_next(npacket)) != NULL);
+
+	uint8_t *buf;
+	uint8_t *dp;
+
+	buf = calloc(tot_len, 1);
+	if (buf == NULL) {
+		free(buf);
+		return ENOMEM;
+	}
+
+	npacket = packet;
+	dp = buf;
+	do {
+		length = packet_get_data_length(packet);
+		if (length <= 0) {
+			free(buf);
+			return EINVAL;
+		}
+
+		memcpy(dp, packet_get_data(packet), length);
+		dp += length;
+	} while ((npacket = pq_next(npacket)) != NULL);
+
+	*data = buf;
+	*dsize = tot_len;
+	return EOK;
+}
+
+/** Process packet received from network layer. */
+static int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
+    services_t error)
 {
 	int rc;
-
-	if (receiver != SERVICE_TCP)
-		return EREFUSED;
-
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-	rc = tcp_process_packet(device_id, packet, error);
-	if (rc != EOK)
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	printf("receive %d \n", rc);
-
-	return rc;
-}
-
-int tcp_process_packet(nic_device_id_t device_id, packet_t *packet, services_t error)
-{
-	size_t length;
 	size_t offset;
-	int result;
-	tcp_header_t *header;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_t *next_packet;
-	size_t total_length;
-	uint32_t checksum;
-	int fragments;
-	icmp_type_t type;
-	icmp_code_t code;
-	struct sockaddr *src;
-	struct sockaddr *dest;
-	size_t addrlen;
-	int rc;
+	int length;
+	struct sockaddr_in *src_addr;
+	struct sockaddr_in *dest_addr;
+	size_t addr_len;
+
+	log_msg(LVL_DEBUG, "tcp_received_msg()");
 
 	switch (error) {
@@ -261,2256 +131,316 @@
 		break;
 	case SERVICE_ICMP:
-		/* Process error */
-		result = icmp_client_process_packet(packet, &type, &code, NULL,
-		    NULL);
-		if (result < 0)
-			return tcp_release_and_return(packet, result);
-
-		length = (size_t) result;
-		rc = packet_trim(packet, length, 0);
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-		break;
 	default:
-		return tcp_release_and_return(packet, ENOTSUP);
-	}
-
-	/* TODO process received ipopts? */
-	result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
-	if (result < 0)
-		return tcp_release_and_return(packet, result);
-
-	offset = (size_t) result;
-
+		log_msg(LVL_WARN, "Unsupported service number %u",
+		    (unsigned)error);
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return ENOTSUP;
+	}
+
+	/* Process and trim off IP header */
+	log_msg(LVL_DEBUG, "tcp_received_msg() - IP header");
+
+	rc = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
+	if (rc < 0) {
+		log_msg(LVL_WARN, "ip_client_process_packet() failed");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return rc;
+	}
+
+	offset = (size_t)rc;
 	length = packet_get_data_length(packet);
-	if (length <= 0)
-		return tcp_release_and_return(packet, EINVAL);
-
-	if (length < TCP_HEADER_SIZE + offset)
-		return tcp_release_and_return(packet, NO_DATA);
-
-	/* Trim all but TCP header */
+
+	if (length < 0 || (size_t)length < offset) {
+		log_msg(LVL_WARN, "length=%d, dropping.", length);
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	addr_len = packet_get_addr(packet, (uint8_t **)&src_addr,
+	    (uint8_t **)&dest_addr);
+	if (addr_len <= 0) {
+		log_msg(LVL_WARN, "Failed to get packet address.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	if (addr_len != sizeof(struct sockaddr_in)) {
+		log_msg(LVL_WARN, "Unsupported address size %zu (!= %zu)",
+		    addr_len, sizeof(struct sockaddr_in));
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
 	rc = packet_trim(packet, offset, 0);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-
-	/* Get tcp header */
-	header = (tcp_header_t *) packet_get_data(packet);
-	if (!header)
-		return tcp_release_and_return(packet, NO_DATA);
-
-#if 0
-	printf("header len %d, port %d \n", TCP_HEADER_LENGTH(header),
-	    ntohs(header->destination_port));
-#endif
-	result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
-	if (result <= 0)
-		return tcp_release_and_return(packet, result);
-
-	addrlen = (size_t) result;
-
-	rc = tl_set_address_port(src, addrlen, ntohs(header->source_port));
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-	
-	/* Find the destination socket */
-	socket = socket_port_find(&tcp_globals.sockets,
-	    ntohs(header->destination_port), (uint8_t *) src, addrlen);
-	if (!socket) {
-		/* Find the listening destination socket */
-		socket = socket_port_find(&tcp_globals.sockets,
-		    ntohs(header->destination_port),
-		    (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
-	}
-
-	if (!socket) {
-		if (tl_prepare_icmp_packet(tcp_globals.net_sess,
-		    tcp_globals.icmp_sess, packet, error) == EOK) {
-			icmp_destination_unreachable_msg(tcp_globals.icmp_sess,
-			    ICMP_PORT_UNREACH, 0, packet);
-		}
-		return EADDRNOTAVAIL;
-	}
-
-	printf("socket id %d\n", socket->socket_id);
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Some data received, clear the timeout counter */
-	socket_data->timeout_count = 0;
-
-	/* Count the received packet fragments */
-	next_packet = packet;
-	fragments = 0;
-	checksum = 0;
-	total_length = 0;
-	do {
-		fragments++;
-		length = packet_get_data_length(next_packet);
-		if (length <= 0)
-			return tcp_release_and_return(packet, NO_DATA);
-
-		total_length += length;
-
-		/* Add partial checksum if set */
-		if (!error) {
-			checksum = compute_checksum(checksum,
-			    packet_get_data(packet),
-			    packet_get_data_length(packet));
-		}
-
-	} while ((next_packet = pq_next(next_packet)));
-
-	fibril_rwlock_write_lock(socket_data->local_lock);
-
-	if (error)
-		goto has_error_service;
-	
-	if (socket_data->state == TCP_SOCKET_LISTEN) {
-		if (socket_data->pseudo_header) {
-			free(socket_data->pseudo_header);
-			socket_data->pseudo_header = NULL;
-			socket_data->headerlen = 0;
-		}
-
-		rc = ip_client_get_pseudo_header(IPPROTO_TCP, src, addrlen,
-		    dest, addrlen, total_length, &socket_data->pseudo_header,
-		    &socket_data->headerlen);
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			return tcp_release_and_return(packet, rc);
-		}
-	} else {
-		rc = ip_client_set_pseudo_header_data_length(
-		    socket_data->pseudo_header, socket_data->headerlen,
-		    total_length);
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			return tcp_release_and_return(packet, rc);
-		}
-	}
-	
-	checksum = compute_checksum(checksum, socket_data->pseudo_header,
-	    socket_data->headerlen);
-	if (flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO) {
-		printf("checksum err %x -> %x\n", header->checksum,
-		    flip_checksum(compact_checksum(checksum)));
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-
-		rc = tl_prepare_icmp_packet(tcp_globals.net_sess,
-		    tcp_globals.icmp_sess, packet, error);
-		if (rc == EOK) {
-			/* Checksum error ICMP */
-			icmp_parameter_problem_msg(tcp_globals.icmp_sess,
-			    ICMP_PARAM_POINTER,
-			    ((size_t) ((void *) &header->checksum)) -
-			    ((size_t) ((void *) header)), packet);
-		}
-
-		return EINVAL;
-	}
-
-has_error_service:
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	/* TODO error reporting/handling */
-	switch (socket_data->state) {
-	case TCP_SOCKET_LISTEN:
-		rc = tcp_process_listen(socket, socket_data, header, packet,
-		    src, dest, addrlen);
-		break;
-	case TCP_SOCKET_SYN_RECEIVED:
-		rc = tcp_process_syn_received(socket, socket_data, header,
-		    packet);
-		break;
-	case TCP_SOCKET_SYN_SENT:
-		rc = tcp_process_syn_sent(socket, socket_data, header, packet);
-		break;
-	case TCP_SOCKET_FIN_WAIT_1:
-		/* ack changing the state to FIN_WAIT_2 gets processed later */
-	case TCP_SOCKET_FIN_WAIT_2:
-		/* fin changing state to LAST_ACK gets processed later */
-	case TCP_SOCKET_LAST_ACK:
-		/* ack releasing the socket get processed later */
-	case TCP_SOCKET_CLOSING:
-		/* ack releasing the socket gets processed later */
-	case TCP_SOCKET_ESTABLISHED:
-		rc = tcp_process_established(socket, socket_data, header,
-		    packet, fragments, total_length);
-		break;
-	default:
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-	}
-
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-		printf("process %d\n", rc);
-	}
+	if (rc != EOK) {
+		log_msg(LVL_WARN, "Failed to trim packet.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return rc;
+	}
+
+	/* Pull up packets into a single memory block, pdu_raw. */
+	log_msg(LVL_DEBUG, "tcp_received_msg() - pull up");
+	uint8_t *pdu_raw;
+	size_t pdu_raw_size = 0;
+
+	pq_pullup(packet, (void **)&pdu_raw, &pdu_raw_size);
+
+	/* Split into header and payload. */
+
+	log_msg(LVL_DEBUG, "tcp_received_msg() - split header/payload");
+
+	tcp_pdu_t *pdu;
+	size_t hdr_size;
+	tcp_header_t *hdr;
+	uint32_t data_offset;
+
+	if (pdu_raw_size < sizeof(tcp_header_t)) {
+		log_msg(LVL_WARN, "pdu_raw_size = %zu < sizeof(tcp_header_t) = %zu",
+		    pdu_raw_size, sizeof(tcp_header_t));
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	hdr = (tcp_header_t *)pdu_raw;
+	data_offset = BIT_RANGE_EXTRACT(uint32_t, DF_DATA_OFFSET_h, DF_DATA_OFFSET_l,
+	    uint16_t_be2host(hdr->doff_flags));
+
+	hdr_size = sizeof(uint32_t) * data_offset;
+
+	if (pdu_raw_size < hdr_size) {
+		log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
+		    pdu_raw_size, hdr_size);
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	if (hdr_size < sizeof(tcp_header_t)) {
+		log_msg(LVL_WARN, "hdr_size = %zu < sizeof(tcp_header_t) = %zu",
+		    hdr_size, sizeof(tcp_header_t));
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	log_msg(LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
+	    pdu_raw_size, hdr_size);
+	pdu = tcp_pdu_create(pdu_raw, hdr_size, pdu_raw + hdr_size,
+	    pdu_raw_size - hdr_size);
+	if (pdu == NULL) {
+		log_msg(LVL_WARN, "Failed creating PDU. Dropped.");
+		return ENOMEM;
+	}
+
+	free(pdu_raw);
+
+	pdu->src_addr.ipv4 = uint32_t_be2host(src_addr->sin_addr.s_addr);
+	pdu->dest_addr.ipv4 = uint32_t_be2host(dest_addr->sin_addr.s_addr);
+	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
+	    pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
+
+	tcp_received_pdu(pdu);
+	tcp_pdu_delete(pdu);
 
 	return EOK;
 }
 
-int tcp_process_established(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, tcp_header_t *header, packet_t *packet, int fragments,
-    size_t total_length)
-{
-	packet_t *next_packet;
-	packet_t *tmp_packet;
-	uint32_t old_incoming;
-	size_t order;
-	uint32_t sequence_number;
-	size_t length;
-	size_t offset;
-	uint32_t new_sequence_number;
-	bool forced_ack;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-	assert(packet);
-
-	forced_ack = false;
-
-	new_sequence_number = ntohl(header->sequence_number);
-	old_incoming = socket_data->next_incoming;
-
-	if (GET_TCP_HEADER_FINALIZE(header)) {
-		socket_data->fin_incoming = new_sequence_number +
-		    total_length - TCP_HEADER_LENGTH(header);
-	}
-
-	/* Trim begining if containing expected data */
-	if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
-	    socket_data->next_incoming, new_sequence_number + total_length)) {
-
-		/* Get the acknowledged offset */
-		if (socket_data->next_incoming < new_sequence_number) {
-			offset = new_sequence_number -
-			    socket_data->next_incoming;
-		} else {
-			offset = socket_data->next_incoming -
-			    new_sequence_number;
-		}
-
-		new_sequence_number += offset;
-		total_length -= offset;
-		length = packet_get_data_length(packet);
-
-		/* Trim the acknowledged data */
-		while (length <= offset) {
-			/* Release the acknowledged packets */
-			next_packet = pq_next(packet);
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(packet));
-			packet = next_packet;
-			offset -= length;
-			length = packet_get_data_length(packet);
-		}
-
-		if (offset > 0) {
-			rc = packet_trim(packet, offset, 0);
-			if (rc != EOK)
-				return tcp_release_and_return(packet, rc);
-		}
-
-		assert(new_sequence_number == socket_data->next_incoming);
-	}
-
-	/* Release if overflowing the window */
-/*
-	if (IS_IN_INTERVAL_OVERFLOW(socket_data->next_incoming +
-	    socket_data->window, new_sequence_number, new_sequence_number +
-	    total_length)) {
-		return tcp_release_and_return(packet, EOVERFLOW);
-	}
-
-	// trim end if overflowing the window
-	if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
-	    socket_data->next_incoming + socket_data->window,
-	    new_sequence_number + total_length)) {
-		// get the allowed data length
-		if (socket_data->next_incoming + socket_data->window <
-		    new_sequence_number) {
-			offset = new_sequence_number -
-			    socket_data->next_incoming + socket_data->window;
-		} else {
-			offset = socket_data->next_incoming +
-			    socket_data->window - new_sequence_number;
-		}
-		next_packet = packet;
-		// trim the overflowing data
-		while (next_packet && (offset > 0)) {
-			length = packet_get_data_length(packet);
-			if (length <= offset)
-				next_packet = pq_next(next_packet);
-			else {
-				rc = packet_trim(next_packet, 0,
-				    length - offset));
-				if (rc != EOK)
-					return tcp_release_and_return(packet,
-					    rc);
-			}
-			offset -= length;
-			total_length -= length - offset;
-		}
-		// release the overflowing packets
-		next_packet = pq_next(next_packet);
-		if (next_packet) {
-			tmp_packet = next_packet;
-			next_packet = pq_next(next_packet);
-			pq_insert_after(tmp_packet, next_packet);
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(tmp_packet));
-		}
-		assert(new_sequence_number + total_length ==
-		    socket_data->next_incoming + socket_data->window);
-	}
-*/
-	/* The expected one arrived? */
-	if (new_sequence_number == socket_data->next_incoming) {
-		printf("expected\n");
-		/* Process acknowledgement */
-		tcp_process_acknowledgement(socket, socket_data, header);
-
-		/* Remove the header */
-		total_length -= TCP_HEADER_LENGTH(header);
-		rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-
-		if (total_length) {
-			rc = tcp_queue_received_packet(socket, socket_data,
-			    packet, fragments, total_length);
-			if (rc != EOK)
-				return rc;
-		} else {
-			total_length = 1;
-		}
-
-		socket_data->next_incoming = old_incoming + total_length;
-		packet = socket_data->incoming;
-		while (packet) {
-			rc = pq_get_order(socket_data->incoming, &order, NULL);
-			if (rc != EOK) {
-				/* Remove the corrupted packet */
-				next_packet = pq_detach(packet);
-				if (packet == socket_data->incoming)
-					socket_data->incoming = next_packet;
-				pq_release_remote(tcp_globals.net_sess,
-				    packet_get_id(packet));
-				packet = next_packet;
-				continue;
-			}
-
-			sequence_number = (uint32_t) order;
-			if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
-			    old_incoming, socket_data->next_incoming)) {
-				/* Move to the next */
-				packet = pq_next(packet);
-				/* Coninual data? */
-			} else if (IS_IN_INTERVAL_OVERFLOW(old_incoming,
-			    sequence_number, socket_data->next_incoming)) {
-				/* Detach the packet */
-				next_packet = pq_detach(packet);
-				if (packet == socket_data->incoming)
-					socket_data->incoming = next_packet;
-				/* Get data length */
-				length = packet_get_data_length(packet);
-				new_sequence_number = sequence_number + length;
-				if (length <= 0) {
-					/* Remove the empty packet */
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(packet));
-					packet = next_packet;
-					continue;
-				}
-				/* Exactly following */
-				if (sequence_number ==
-				    socket_data->next_incoming) {
-					/* Queue received data */
-					rc = tcp_queue_received_packet(socket,
-					    socket_data, packet, 1,
-					    packet_get_data_length(packet));
-					if (rc != EOK)
-						return rc;
-					socket_data->next_incoming =
-					    new_sequence_number;
-					packet = next_packet;
-					continue;
-					/* At least partly following data? */
-				}
-				if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
-				    socket_data->next_incoming, new_sequence_number)) {
-					if (socket_data->next_incoming <
-					    new_sequence_number) {
-						length = new_sequence_number -
-						    socket_data->next_incoming;
-					} else {
-						length =
-						    socket_data->next_incoming -
-						    new_sequence_number;
-					}
-					rc = packet_trim(packet,length, 0);
-					if (rc == EOK) {
-						/* Queue received data */
-						rc = tcp_queue_received_packet(
-						    socket, socket_data, packet,
-						    1, packet_get_data_length(
-						    packet));
-						if (rc != EOK)
-							return rc;
-						socket_data->next_incoming =
-						    new_sequence_number;
-						packet = next_packet;
-						continue;
-					}
-				}
-				/* Remove the duplicit or corrupted packet */
-				pq_release_remote(tcp_globals.net_sess,
-				    packet_get_id(packet));
-				packet = next_packet;
-				continue;
-			} else {
-				break;
-			}
-		}
-	} else if (IS_IN_INTERVAL(socket_data->next_incoming,
-	    new_sequence_number,
-	    socket_data->next_incoming + socket_data->window)) {
-		printf("in window\n");
-		/* Process acknowledgement */
-		tcp_process_acknowledgement(socket, socket_data, header);
-
-		/* Remove the header */
-		total_length -= TCP_HEADER_LENGTH(header);
-		rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-
-		next_packet = pq_detach(packet);
-		length = packet_get_data_length(packet);
-		rc = pq_add(&socket_data->incoming, packet, new_sequence_number,
-		    length);
-		if (rc != EOK) {
-			/* Remove the corrupted packets */
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(packet));
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(next_packet));
-		} else {
-			while (next_packet) {
-				new_sequence_number += length;
-				tmp_packet = pq_detach(next_packet);
-				length = packet_get_data_length(next_packet);
-
-				rc = pq_set_order(next_packet,
-				    new_sequence_number, length);
-				if (rc != EOK) {
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(next_packet));
-				}
-				rc = pq_insert_after(packet, next_packet);
-				if (rc != EOK) {
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(next_packet));
-				}
-				next_packet = tmp_packet;
-			}
-		}
-	} else {
-		printf("unexpected\n");
-		/* Release duplicite or restricted */
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		forced_ack = true;
-	}
-
-	/* If next in sequence is an incoming FIN */
-	if (socket_data->next_incoming == socket_data->fin_incoming) {
-		/* Advance sequence number */
-		socket_data->next_incoming += 1;
-
-		/* Handle FIN */
-		switch (socket_data->state) {
-		case TCP_SOCKET_FIN_WAIT_1:
-		case TCP_SOCKET_FIN_WAIT_2:
-		case TCP_SOCKET_CLOSING:
-			socket_data->state = TCP_SOCKET_CLOSING;
-			break;
-		case TCP_SOCKET_ESTABLISHED:
-			/* Queue end-of-data marker on the socket. */
-			tcp_queue_received_end_of_data(socket);
-			socket_data->state = TCP_SOCKET_CLOSE_WAIT;
-			break;
-		default:
-			socket_data->state = TCP_SOCKET_CLOSE_WAIT;
-			break;
-		}
-	}
-
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	if (!packet && (socket_data->next_incoming != old_incoming || forced_ack)) {
-		/* Create the notification packet */
-		rc = tcp_create_notification_packet(&packet, socket,
-		    socket_data, 0, 0);
-		if (rc != EOK)
-			return rc;
-		rc = tcp_queue_prepare_packet(socket, socket_data, packet, 1);
-		if (rc != EOK)
-			return rc;
-		packet = tcp_send_prepare_packet(socket, socket_data, packet, 1,
-		    socket_data->last_outgoing + 1);
-	}
-
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-
-	/* Send the packet */
-	tcp_send_packets(socket_data->device_id, packet);
-
-	return EOK;
-}
-
-int tcp_queue_received_packet(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, packet_t *packet, int fragments,
-    size_t total_length)
-{
-	packet_dimension_t *packet_dimension;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(packet);
-	assert(fragments >= 1);
-	assert(socket_data->window > total_length);
-
-	/* Queue the received packet */
-	rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
-	    SOCKET_MAX_RECEIVED_SIZE);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-	rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-	    &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-
-	/* Decrease the window size */
-	socket_data->window -= total_length;
-
-	/* Notify the destination socket */
-	async_exch_t *exch = async_exchange_begin(socket->sess);
-	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t) socket->socket_id,
-	    ((packet_dimension->content < socket_data->data_fragment_size) ?
-	    packet_dimension->content : socket_data->data_fragment_size), 0, 0,
-	    (sysarg_t) fragments);
-	async_exchange_end(exch);
-
-	return EOK;
-}
-
-/** Queue end-of-data marker on the socket.
- *
- * Next element in the sequence space is FIN. Queue end-of-data marker
- * on the socket.
- *
- * @param socket	Socket
- */
-static void tcp_queue_received_end_of_data(socket_core_t *socket)
-{
-	assert(socket != NULL);
-
-	/* Notify the destination socket */
-	async_exch_t *exch = async_exchange_begin(socket->sess);
-	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t) socket->socket_id,
-	    0, 0, 0, (sysarg_t) 0 /* 0 fragments == no more data */);
-	async_exchange_end(exch);
-}
-
-int tcp_process_syn_sent(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, tcp_header_t *header, packet_t *packet)
-{
-	packet_t *next_packet;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-	assert(packet);
-
-	if (!GET_TCP_HEADER_SYNCHRONIZE(header))
-		return tcp_release_and_return(packet, EINVAL);
-	
-	/* Process acknowledgement */
-	tcp_process_acknowledgement(socket, socket_data, header);
-
-	socket_data->next_incoming = ntohl(header->sequence_number) + 1;
-
-	/* Release additional packets */
-	next_packet = pq_detach(packet);
-	if (next_packet) {
-		pq_release_remote(tcp_globals.net_sess,
-		    packet_get_id(next_packet));
-	}
-
-	/* Trim if longer than the header */
-	if (packet_get_data_length(packet) > sizeof(*header)) {
-		rc = packet_trim(packet, 0,
-		    packet_get_data_length(packet) - sizeof(*header));
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-	}
-
-	tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
-	fibril_mutex_lock(&socket_data->operation.mutex);
-	socket_data->operation.result = tcp_queue_packet(socket, socket_data,
-	    packet, 1);
-
-	if (socket_data->operation.result == EOK) {
-		socket_data->state = TCP_SOCKET_ESTABLISHED;
-		packet = tcp_get_packets_to_send(socket, socket_data);
-		if (packet) {
-			fibril_rwlock_write_unlock( socket_data->local_lock);
-			/* Send the packet */
-			tcp_send_packets(socket_data->device_id, packet);
-			/* Signal the result */
-			fibril_condvar_signal( &socket_data->operation.condvar);
-			fibril_mutex_unlock( &socket_data->operation.mutex);
-			return EOK;
-		}
-	}
-
-	fibril_mutex_unlock(&socket_data->operation.mutex);
-	return tcp_release_and_return(packet, EINVAL);
-}
-
-int tcp_process_listen(socket_core_t *listening_socket,
-    tcp_socket_data_t *listening_socket_data, tcp_header_t *header,
-    packet_t *packet, struct sockaddr *src, struct sockaddr *dest,
-    size_t addrlen)
-{
-	packet_t *next_packet;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	int socket_id;
-	int listening_socket_id = listening_socket->socket_id;
-	int listening_port = listening_socket->port;
-	int rc;
-
-	assert(listening_socket);
-	assert(listening_socket_data);
-	assert(listening_socket->specific_data == listening_socket_data);
-	assert(header);
-	assert(packet);
-
-	if (!GET_TCP_HEADER_SYNCHRONIZE(header))
-		return tcp_release_and_return(packet, EINVAL);
-
-	socket_data = (tcp_socket_data_t *) malloc(sizeof(*socket_data));
-	if (!socket_data)
-		return tcp_release_and_return(packet, ENOMEM);
-
-	tcp_initialize_socket_data(socket_data);
-	socket_data->local_lock = listening_socket_data->local_lock;
-	socket_data->local_sockets = listening_socket_data->local_sockets;
-	socket_data->listening_socket_id = listening_socket->socket_id;
-	socket_data->next_incoming = ntohl(header->sequence_number);
-	socket_data->treshold = socket_data->next_incoming +
-	    ntohs(header->window);
-	socket_data->addrlen = addrlen;
-	socket_data->addr = malloc(socket_data->addrlen);
-	if (!socket_data->addr) {
-		free(socket_data);
-		return tcp_release_and_return(packet, ENOMEM);
-	}
-
-	memcpy(socket_data->addr, src, socket_data->addrlen);
-	socket_data->dest_port = ntohs(header->source_port);
-	rc = tl_set_address_port(socket_data->addr, socket_data->addrlen,
-	    socket_data->dest_port);
-	if (rc != EOK) {
-		free(socket_data->addr);
-		free(socket_data);
-		return tcp_release_and_return(packet, rc);
-	}
-
-	/* Create a socket */
-	socket_id = -1;
-	rc = socket_create(socket_data->local_sockets, listening_socket->sess,
-	    socket_data, &socket_id);
-	if (rc != EOK) {
-		free(socket_data->addr);
-		free(socket_data);
-		return tcp_release_and_return(packet, rc);
-	}
-
-	printf("new_sock %d\n", socket_id);
-	socket_data->pseudo_header = listening_socket_data->pseudo_header;
-	socket_data->headerlen = listening_socket_data->headerlen;
-	listening_socket_data->pseudo_header = NULL;
-	listening_socket_data->headerlen = 0;
-
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-
-	/* Find the destination socket */
-	listening_socket = socket_port_find(&tcp_globals.sockets,
-	    listening_port, (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
-	if (!listening_socket ||
-	    (listening_socket->socket_id != listening_socket_id)) {
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-		/* A shadow may remain until app hangs up */
-		return tcp_release_and_return(packet, EOK /*ENOTSOCK*/);
-	}
-	listening_socket_data =
-	    (tcp_socket_data_t *) listening_socket->specific_data;
-	assert(listening_socket_data);
-
-	fibril_rwlock_write_lock(listening_socket_data->local_lock);
-
-	socket = socket_cores_find(listening_socket_data->local_sockets,
-	    socket_id);
-	if (!socket) {
-		/* Where is the socket?!? */
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-		return ENOTSOCK;
-	}
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	rc = socket_port_add(&tcp_globals.sockets, listening_port, socket,
-	    (uint8_t *) socket_data->addr, socket_data->addrlen);
-	assert(socket == socket_port_find(&tcp_globals.sockets, listening_port,
-	    (uint8_t *) socket_data->addr, socket_data->addrlen));
-
-//	rc = socket_bind_free_port(&tcp_globals.sockets, socket,
-//	    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
-//	    tcp_globals.last_used_port);
-//	tcp_globals.last_used_port = socket->port;
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-	if (rc != EOK) {
-		socket_destroy(tcp_globals.net_sess, socket->socket_id,
-		    socket_data->local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		return tcp_release_and_return(packet, rc);
-	}
-
-	socket_data->state = TCP_SOCKET_LISTEN;
-	socket_data->next_incoming = ntohl(header->sequence_number) + 1;
-
-	/* Release additional packets */
-	next_packet = pq_detach(packet);
-	if (next_packet) {
-		pq_release_remote(tcp_globals.net_sess,
-		    packet_get_id(next_packet));
-	}
-
-	/* Trim if longer than the header */
-	if (packet_get_data_length(packet) > sizeof(*header)) {
-		rc = packet_trim(packet, 0,
-		    packet_get_data_length(packet) - sizeof(*header));
-		if (rc != EOK) {
-			socket_destroy(tcp_globals.net_sess, socket->socket_id,
-			    socket_data->local_sockets, &tcp_globals.sockets,
-			    tcp_free_socket_data);
-			return tcp_release_and_return(packet, rc);
-		}
-	}
-
-	tcp_prepare_operation_header(socket, socket_data, header, 1, 0);
-
-	rc = tcp_queue_packet(socket, socket_data, packet, 1);
-	if (rc != EOK) {
-		socket_destroy(tcp_globals.net_sess, socket->socket_id,
-		    socket_data->local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		return rc;
-	}
-
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	if (!packet) {
-		socket_destroy(tcp_globals.net_sess, socket->socket_id,
-		    socket_data->local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		return EINVAL;
-	}
-
-	socket_data->state = TCP_SOCKET_SYN_RECEIVED;
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-
-	/* Send the packet */
-	tcp_send_packets(socket_data->device_id, packet);
-
-	return EOK;
-}
-
-int tcp_process_syn_received(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, tcp_header_t *header, packet_t *packet)
-{
-	socket_core_t *listening_socket;
-	tcp_socket_data_t *listening_socket_data;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-	assert(packet);
-
-	if (!GET_TCP_HEADER_ACKNOWLEDGE(header))
-		return tcp_release_and_return(packet, EINVAL);
-
-	/* Process acknowledgement */
-	tcp_process_acknowledgement(socket, socket_data, header);
-
-	socket_data->next_incoming = ntohl(header->sequence_number); /* + 1; */
-	pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-	socket_data->state = TCP_SOCKET_ESTABLISHED;
-	listening_socket = socket_cores_find(socket_data->local_sockets,
-	    socket_data->listening_socket_id);
-	if (listening_socket) {
-		listening_socket_data =
-		    (tcp_socket_data_t *) listening_socket->specific_data;
-		assert(listening_socket_data);
-
-		/* Queue the received packet */
-		rc = dyn_fifo_push(&listening_socket->accepted,
-		    (-1 * socket->socket_id), listening_socket_data->backlog);
-		if (rc == EOK) {
-			/* Notify the destination socket */
-			async_exch_t *exch = async_exchange_begin(socket->sess);
-			async_msg_5(exch, NET_SOCKET_ACCEPTED,
-			    (sysarg_t) listening_socket->socket_id,
-			    socket_data->data_fragment_size, TCP_HEADER_SIZE,
-			    0, (sysarg_t) socket->socket_id);
-			async_exchange_end(exch);
-
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			return EOK;
-		}
-	}
-	/* Send FIN */
-	socket_data->state = TCP_SOCKET_FIN_WAIT_1;
-
-	/* Create the notification packet */
-	rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Send the packet */
-	rc = tcp_queue_packet(socket, socket_data, packet, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Flush packets */
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	if (packet) {
-		/* Send the packet */
-		tcp_send_packets(socket_data->device_id, packet);
-	}
-
-	return EOK;
-}
-
-void tcp_process_acknowledgement(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, tcp_header_t *header)
-{
-	size_t number;
-	size_t length;
-	packet_t *packet;
-	packet_t *next;
-	packet_t *acknowledged = NULL;
-	uint32_t old;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-
-	if (!GET_TCP_HEADER_ACKNOWLEDGE(header))
-		return;
-
-	number = ntohl(header->acknowledgement_number);
-
-	/* If more data acknowledged */
-	if (number != socket_data->expected) {
-		old = socket_data->expected;
-		if (IS_IN_INTERVAL_OVERFLOW(old, socket_data->fin_outgoing,
-		    number)) {
-			switch (socket_data->state) {
-			case TCP_SOCKET_FIN_WAIT_1:
-				socket_data->state = TCP_SOCKET_FIN_WAIT_2;
-				break;
-			case TCP_SOCKET_LAST_ACK:
-			case TCP_SOCKET_CLOSING:
-				/*
-				 * FIN acknowledged - release the socket in
-				 * another fibril.
-				 */
-				tcp_prepare_timeout(tcp_release_after_timeout,
-				    socket, socket_data, 0,
-				    TCP_SOCKET_TIME_WAIT,
-				    NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT, true);
-				break;
-			default:
-				break;
-			}
-		}
-
-		/* Update the treshold if higher than set */
-		if (number + ntohs(header->window) >
-		    socket_data->expected + socket_data->treshold) {
-			socket_data->treshold = number + ntohs(header->window) -
-			    socket_data->expected;
-		}
-
-		/* Set new expected sequence number */
-		socket_data->expected = number;
-		socket_data->expected_count = 1;
-		packet = socket_data->outgoing;
-		while (pq_get_order(packet, &number, &length) == EOK) {
-			if (IS_IN_INTERVAL_OVERFLOW((uint32_t) old,
-			    (uint32_t) (number + length),
-			    (uint32_t) socket_data->expected)) {
-				next = pq_detach(packet);
-				if (packet == socket_data->outgoing)
-					socket_data->outgoing = next;
-
-				/* Add to acknowledged or release */
-				if (pq_add(&acknowledged, packet, 0, 0) != EOK)
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(packet));
-				packet = next;
-			} else if (old < socket_data->expected)
-				break;
-		}
-
-		/* Release acknowledged */
-		if (acknowledged) {
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(acknowledged));
-		}
-		return;
-		/* If the same as the previous time */
-	}
-
-	if (number == socket_data->expected) {
-		/* Increase the counter */
-		socket_data->expected_count++;
-		if (socket_data->expected_count == TCP_FAST_RETRANSMIT_COUNT) {
-			socket_data->expected_count = 1;
-			/* TODO retransmit lock */
-			//tcp_retransmit_packet(socket, socket_data, number);
-		}
-	}
-}
-
-/** Per-connection initialization
- *
- */
-void tl_connection(void)
-{
-}
-
-/** Processes the TCP message.
- *
- * @param[in] callid	The message identifier.
- * @param[in] call	The message parameters.
- * @param[out] answer	The message answer parameters.
- * @param[out] answer_count The last parameter for the actual answer in the
- *			answer parameter.
- * @return		EOK on success.
- * @return		ENOTSUP if the message is not known.
- *
- * @see tcp_interface.h
- * @see IS_NET_TCP_MESSAGE()
- */
-int tl_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *answer_count)
-{
-	assert(call);
-	assert(answer);
-	assert(answer_count);
-	
-	*answer_count = 0;
-	
-	async_sess_t *callback =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, call);
-	if (callback)
-		return tcp_process_client_messages(callback, callid, *call);
-	
-	return ENOTSUP;
-}
-
-void tcp_refresh_socket_data(tcp_socket_data_t *socket_data)
-{
-	assert(socket_data);
-
-	bzero(socket_data, sizeof(*socket_data));
-	socket_data->state = TCP_SOCKET_INITIAL;
-	socket_data->device_id = NIC_DEVICE_INVALID_ID;
-	socket_data->window = NET_DEFAULT_TCP_WINDOW;
-	socket_data->treshold = socket_data->window;
-	socket_data->last_outgoing = TCP_INITIAL_SEQUENCE_NUMBER;
-	socket_data->timeout = NET_DEFAULT_TCP_INITIAL_TIMEOUT;
-	socket_data->acknowledged = socket_data->last_outgoing;
-	socket_data->next_outgoing = socket_data->last_outgoing + 1;
-	socket_data->expected = socket_data->next_outgoing;
-}
-
-void tcp_initialize_socket_data(tcp_socket_data_t *socket_data)
-{
-	assert(socket_data);
-
-	tcp_refresh_socket_data(socket_data);
-	fibril_mutex_initialize(&socket_data->operation.mutex);
-	fibril_condvar_initialize(&socket_data->operation.condvar);
-	socket_data->data_fragment_size = MAX_TCP_FRAGMENT_SIZE;
-}
-
-int tcp_process_client_messages(async_sess_t *sess, ipc_callid_t callid,
-    ipc_call_t call)
-{
-	int res;
-	socket_cores_t local_sockets;
-	struct sockaddr *addr;
-	int socket_id;
-	size_t addrlen;
-	size_t size;
-	fibril_rwlock_t lock;
-	ipc_call_t answer;
-	size_t answer_count;
-	tcp_socket_data_t *socket_data;
-	socket_core_t *socket;
-	packet_dimension_t *packet_dimension;
-
-	/*
-	 * Accept the connection
-	 *  - Answer the first IPC_M_CONNECT_ME_TO call.
-	 */
-	res = EOK;
-	answer_count = 0;
-
-	socket_cores_initialize(&local_sockets);
-	fibril_rwlock_initialize(&lock);
-
-	while (true) {
-
-		/* Answer the call */
-		answer_call(callid, res, &answer, answer_count);
-		/* Refresh data */
-		refresh_answer(&answer, &answer_count);
-		/* 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 NET_SOCKET:
-			socket_data =
-			    (tcp_socket_data_t *) malloc(sizeof(*socket_data));
-			if (!socket_data) {
-				res = ENOMEM;
-				break;
-			}
-			
-			tcp_initialize_socket_data(socket_data);
-			socket_data->local_lock = &lock;
-			socket_data->local_sockets = &local_sockets;
-			fibril_rwlock_write_lock(&lock);
-			socket_id = SOCKET_GET_SOCKET_ID(call);
-			res = socket_create(&local_sockets, sess,
-			    socket_data, &socket_id);
-			SOCKET_SET_SOCKET_ID(answer, socket_id);
-			fibril_rwlock_write_unlock(&lock);
-			if (res != EOK) {
-				free(socket_data);
-				break;
-			}
-			if (tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-			    &tcp_globals.dimensions, NIC_DEVICE_INVALID_ID,
-			    &packet_dimension) == EOK) {
-				SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
-				    ((packet_dimension->content <
-				    socket_data->data_fragment_size) ?
-				    packet_dimension->content :
-				    socket_data->data_fragment_size));
-			}
-//                      SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_TCP_FRAGMENT_SIZE);
-			SOCKET_SET_HEADER_SIZE(answer, TCP_HEADER_SIZE);
-			answer_count = 3;
-			break;
-
-		case NET_SOCKET_BIND:
-			res = async_data_write_accept((void **) &addr, false,
-			    0, 0, 0, &addrlen);
-			if (res != EOK)
-				break;
-			fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = socket_bind(&local_sockets, &tcp_globals.sockets,
-			    SOCKET_GET_SOCKET_ID(call), addr, addrlen,
-			    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
-			    tcp_globals.last_used_port);
-			if (res == EOK) {
-				socket = socket_cores_find(&local_sockets,
-				    SOCKET_GET_SOCKET_ID(call));
-				if (socket) {
-					socket_data = (tcp_socket_data_t *)
-					    socket->specific_data;
-					assert(socket_data);
-					socket_data->state = TCP_SOCKET_LISTEN;
-				}
-			}
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_write_unlock(&tcp_globals.lock);
-			free(addr);
-			break;
-
-		case NET_SOCKET_LISTEN:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-//                      fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_listen_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_BACKLOG(call));
-			fibril_rwlock_write_unlock(&lock);
-//                      fibril_rwlock_write_unlock(&tcp_globals.lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			break;
-
-		case NET_SOCKET_CONNECT:
-			res = async_data_write_accept((void **) &addr, false,
-			    0, 0, 0, &addrlen);
-			if (res != EOK)
-				break;
-			/*
-			 * The global lock may be released in the
-			 * tcp_connect_message() function.
-			 */
-			fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_connect_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call), addr, addrlen);
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_write_unlock(&tcp_globals.lock);
-				free(addr);
-			}
-			break;
-
-		case NET_SOCKET_ACCEPT:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_accept_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_NEW_SOCKET_ID(call), &size, &addrlen);
-			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			if (res > 0) {
-				SOCKET_SET_SOCKET_ID(answer, res);
-				SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
-				answer_count = 3;
-			}
-			break;
-
-		case NET_SOCKET_SEND:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_send_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_DATA_FRAGMENTS(call), &size,
-			    SOCKET_GET_FLAGS(call));
-			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_read_unlock(&tcp_globals.lock);
-			} else {
-				answer_count = 2;
-			}
-			break;
-
-		case NET_SOCKET_SENDTO:
-			res = async_data_write_accept((void **) &addr, false,
-			    0, 0, 0, &addrlen);
-			if (res != EOK)
-				break;
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_send_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_DATA_FRAGMENTS(call), &size,
-			    SOCKET_GET_FLAGS(call));
-			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_read_unlock(&tcp_globals.lock);
-			} else {
-				answer_count = 2;
-			}
-			free(addr);
-			break;
-
-		case NET_SOCKET_RECV:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_recvfrom_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
-			    NULL);
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			if (res > 0) {
-				SOCKET_SET_READ_DATA_LENGTH(answer, res);
-				answer_count = 1;
-				res = EOK;
-			}
-			break;
-
-		case NET_SOCKET_RECVFROM:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_recvfrom_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
-			    &addrlen);
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			if (res > 0) {
-				SOCKET_SET_READ_DATA_LENGTH(answer, res);
-				SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
-				answer_count = 3;
-				res = EOK;
-			}
-			break;
-
-		case NET_SOCKET_CLOSE:
-			fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_close_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call));
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_write_unlock(&tcp_globals.lock);
-			}
-			break;
-
-		case NET_SOCKET_GETSOCKOPT:
-		case NET_SOCKET_SETSOCKOPT:
-		default:
-			res = ENOTSUP;
-			break;
-		}
-	}
-
-	/* Release the application session */
-	async_hangup(sess);
-
-	printf("release\n");
-	/* Release all local sockets */
-	socket_cores_release(tcp_globals.net_sess, &local_sockets,
-	    &tcp_globals.sockets, tcp_free_socket_data);
-
-	return EOK;
-}
-
-int tcp_timeout(void *data)
-{
-	tcp_timeout_t *timeout = data;
-	int keep_write_lock = false;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-
-	assert(timeout);
-
-	/* Sleep the given timeout */
-	async_usleep(timeout->timeout);
-	/* Lock the globals */
-	if (timeout->globals_read_only) 
-		fibril_rwlock_read_lock(&tcp_globals.lock);
-	else 
-		fibril_rwlock_write_lock(&tcp_globals.lock);
-
-	/* Find the pending operation socket */
-	socket = socket_port_find(&tcp_globals.sockets, timeout->port,
-	    timeout->key, timeout->key_length);
-	if (!socket || (socket->socket_id != timeout->socket_id))
-		goto out;
-	
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-	if (socket_data->local_sockets != timeout->local_sockets)
-		goto out;
-	
-	fibril_rwlock_write_lock(socket_data->local_lock);
-	if (timeout->sequence_number) {
-		/* Increase the timeout counter */
-		socket_data->timeout_count++;
-		if (socket_data->timeout_count == TCP_MAX_TIMEOUTS) {
-			/* TODO release as connection lost */
-			//tcp_refresh_socket_data(socket_data);
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-		} else {
-			/* Retransmit */
-//                      tcp_retransmit_packet(socket,
-//			    socket_data, timeout->sequence_number);
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-		}
-	} else {
-		fibril_mutex_lock(&socket_data->operation.mutex);
-		/* Set the timeout operation result if state not changed */
-		if (socket_data->state == timeout->state) {
-			socket_data->operation.result = ETIMEOUT;
-
-			/* Notify the main fibril */
-			fibril_condvar_signal(&socket_data->operation.condvar);
-
-			/* Keep the global write lock */
-			keep_write_lock = true;
-		} else {
-			/*
-			 * Operation is ok, do nothing.
-			 * Unlocking from now on, so the unlocking
-			 * order does not matter.
-			 */
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-		}
-		fibril_mutex_unlock(&socket_data->operation.mutex);
-	}
-
-out:
-	/* Unlock only if no socket */
-	if (timeout->globals_read_only)
-		fibril_rwlock_read_unlock(&tcp_globals.lock);
-	else if (!keep_write_lock)
-		/* Release if not desired */
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-	
-	/* Release the timeout structure */
-	free(timeout);
-	return EOK;
-}
-
-int tcp_release_after_timeout(void *data)
-{
-	tcp_timeout_t *timeout = data;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	fibril_rwlock_t *local_lock;
-
-	assert(timeout);
-
-	/* Sleep the given timeout */
-	async_usleep(timeout->timeout);
-
-	/* Lock the globals */
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-
-	/* Find the pending operation socket */
-	socket = socket_port_find(&tcp_globals.sockets, timeout->port,
-	    timeout->key, timeout->key_length);
-
-	if (socket && (socket->socket_id == timeout->socket_id)) {
-		socket_data = (tcp_socket_data_t *) socket->specific_data;
-		assert(socket_data);
-		if (socket_data->local_sockets == timeout->local_sockets) {
-			local_lock = socket_data->local_lock;
-			fibril_rwlock_write_lock(local_lock);
-			socket_destroy(tcp_globals.net_sess,
-			    timeout->socket_id, timeout->local_sockets,
-			    &tcp_globals.sockets, tcp_free_socket_data);
-			fibril_rwlock_write_unlock(local_lock);
-		}
-	}
-
-	/* Unlock the globals */
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	/* Release the timeout structure */
-	free(timeout);
-
-	return EOK;
-}
-
-void tcp_retransmit_packet(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, size_t sequence_number)
-{
-	packet_t *packet;
-	packet_t *copy;
-	size_t data_length;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Sent packet? */
-	packet = pq_find(socket_data->outgoing, sequence_number);
-	if (packet) {
-		pq_get_order(packet, NULL, &data_length);
-		copy = tcp_prepare_copy(socket, socket_data, packet,
-		    data_length, sequence_number);
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-//              printf("r send %d\n", packet_get_id(packet));
-		if (copy) 
-			tcp_send_packets(socket_data->device_id, copy);
-	} else {
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-	}
-}
-
-int tcp_listen_message(socket_cores_t *local_sockets, int socket_id,
-    int backlog)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-
-	assert(local_sockets);
-
-	if (backlog < 0) 
-		return EINVAL;
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket) 
-		return ENOTSOCK;
-	
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Set the backlog */
-	socket_data->backlog = backlog;
-
-	return EOK;
-}
-
-int tcp_connect_message(socket_cores_t *local_sockets, int socket_id,
-    struct sockaddr *addr, socklen_t addrlen)
-{
-	socket_core_t *socket;
-	int rc;
-
-	assert(local_sockets);
-	assert(addr);
-	assert(addrlen > 0);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-	
-	rc = tcp_connect_core(socket, local_sockets, addr, addrlen);
-	if (rc != EOK) {
-		tcp_free_socket_data(socket);
-		/* Unbind if bound */
-		if (socket->port > 0) {
-			socket_ports_exclude(&tcp_globals.sockets,
-			    socket->port, free);
-			socket->port = 0;
-		}
-	}
-	return rc;
-}
-
-int tcp_connect_core(socket_core_t *socket, socket_cores_t *local_sockets,
-    struct sockaddr *addr, socklen_t addrlen)
-{
-	tcp_socket_data_t *socket_data;
+/** Receive packets from network layer. */
+static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
 	packet_t *packet;
 	int rc;
 
-	assert(socket);
-	assert(addr);
-	assert(addrlen > 0);
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	if ((socket_data->state != TCP_SOCKET_INITIAL) &&
-	    ((socket_data->state != TCP_SOCKET_LISTEN) ||
-	    (socket->port <= 0)))
-		return EINVAL;
-
-	/* Get the destination port */
-	rc = tl_get_address_port(addr, addrlen, &socket_data->dest_port);
-	if (rc != EOK)
-		return rc;
-	
-	if (socket->port <= 0) {
-		/* Try to find a free port */
-		rc = socket_bind_free_port(&tcp_globals.sockets, socket,
-		    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
-		    tcp_globals.last_used_port);
-		if (rc != EOK)
-			return rc;
-		/* Set the next port as the search starting port number */
-		tcp_globals.last_used_port = socket->port;
-	}
-
-	rc = ip_get_route_req(tcp_globals.ip_sess, IPPROTO_TCP,
-	    addr, addrlen, &socket_data->device_id,
-	    &socket_data->pseudo_header, &socket_data->headerlen);
-	if (rc != EOK)
-		return rc;
-
-	/* Create the notification packet */
-	rc = tcp_create_notification_packet(&packet, socket, socket_data, 1, 0);
-	if (rc != EOK)
-		return rc;
-
-	/* Unlock the globals and wait for an operation */
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	socket_data->addr = addr;
-	socket_data->addrlen = addrlen;
-
-	/* Send the packet */
-
-	if (((rc = tcp_queue_packet(socket, socket_data, packet, 1)) != EOK) ||
-	    ((rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data, 0,
-	    TCP_SOCKET_INITIAL, NET_DEFAULT_TCP_INITIAL_TIMEOUT, false)) !=
-	    EOK)) {
-		socket_data->addr = NULL;
-		socket_data->addrlen = 0;
-		fibril_rwlock_write_lock(&tcp_globals.lock);
-	} else {
-		packet = tcp_get_packets_to_send(socket, socket_data);
-		if (packet) {
-			fibril_mutex_lock(&socket_data->operation.mutex);
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-
-			socket_data->state = TCP_SOCKET_SYN_SENT;
-
-			/* Send the packet */
-			tcp_send_packets(socket_data->device_id, packet);
-
-			/* Wait for a reply */
-			fibril_condvar_wait(&socket_data->operation.condvar,
-			    &socket_data->operation.mutex);
-			rc = socket_data->operation.result;
-			if (rc != EOK) {
-				socket_data->addr = NULL;
-				socket_data->addrlen = 0;
-			}
-		} else {
-			socket_data->addr = NULL;
-			socket_data->addrlen = 0;
-			rc = EINTR;
-		}
-	}
-
-	fibril_mutex_unlock(&socket_data->operation.mutex);
-	return rc;
-}
-
-int tcp_queue_prepare_packet(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, packet_t *packet, size_t data_length)
-{
-	tcp_header_t *header;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Get TCP header */
-	header = (tcp_header_t *) packet_get_data(packet);
-	if (!header)
-		return NO_DATA;
-	
-	header->destination_port = htons(socket_data->dest_port);
-	header->source_port = htons(socket->port);
-	header->sequence_number = htonl(socket_data->next_outgoing);
-
-	rc = packet_set_addr(packet, NULL, (uint8_t *) socket_data->addr,
-	    socket_data->addrlen);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, EINVAL);
-
-	/* Remember the outgoing FIN */
-	if (GET_TCP_HEADER_FINALIZE(header))
-		socket_data->fin_outgoing = socket_data->next_outgoing;
-	
-	return EOK;
-}
-
-int tcp_queue_packet(socket_core_t *socket, tcp_socket_data_t *socket_data,
-    packet_t *packet, size_t data_length)
-{
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	rc = tcp_queue_prepare_packet(socket, socket_data, packet, data_length);
-	if (rc != EOK)
-		return rc;
-
-	rc = pq_add(&socket_data->outgoing, packet, socket_data->next_outgoing,
-	    data_length);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-
-	socket_data->next_outgoing += data_length;
-	return EOK;
-}
-
-packet_t *tcp_get_packets_to_send(socket_core_t *socket, tcp_socket_data_t *
-    socket_data)
-{
-	packet_t *packet;
-	packet_t *copy;
-	packet_t *sending = NULL;
-	packet_t *previous = NULL;
-	size_t data_length;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	packet = pq_find(socket_data->outgoing, socket_data->last_outgoing + 1);
-	while (packet) {
-		pq_get_order(packet, NULL, &data_length);
-
-		/*
-		 * Send only if fits into the window, respecting the possible
-		 * overflow.
-		 */
-		if (!IS_IN_INTERVAL_OVERFLOW(
-		    (uint32_t) socket_data->last_outgoing,
-		    (uint32_t) (socket_data->last_outgoing + data_length),
-		    (uint32_t) (socket_data->expected + socket_data->treshold)))
-			break;
-
-		copy = tcp_prepare_copy(socket, socket_data, packet,
-		    data_length, socket_data->last_outgoing + 1);
-		if (!copy) 
-			return sending;
-			
-		if (!sending) {
-			sending = copy;
-		} else {
-			rc = pq_insert_after(previous, copy);
-			if (rc != EOK) {
-				pq_release_remote(tcp_globals.net_sess,
-				    packet_get_id(copy));
-				return sending;
-			}
-		}
-
-		previous = copy;
-		packet = pq_next(packet);
-
-		/* Overflow occurred? */
-		if (!packet &&
-		    (socket_data->last_outgoing > socket_data->next_outgoing)) {
-			printf("gpts overflow\n");
-			/* Continue from the beginning */
-			packet = socket_data->outgoing;
-		}
-		socket_data->last_outgoing += data_length;
-	}
-
-	return sending;
-}
-
-packet_t *tcp_send_prepare_packet(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
-{
-	tcp_header_t *header;
-	uint32_t checksum;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Adjust the pseudo header */
-	rc = ip_client_set_pseudo_header_data_length(socket_data->pseudo_header,
-	    socket_data->headerlen, packet_get_data_length(packet));
-	if (rc != EOK) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-
-	/* Get the header */
-	header = (tcp_header_t *) packet_get_data(packet);
-	if (!header) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-	assert(ntohl(header->sequence_number) == sequence_number);
-
-	/* Adjust the header */
-	if (socket_data->next_incoming) {
-		header->acknowledgement_number =
-		    htonl(socket_data->next_incoming);
-		SET_TCP_HEADER_ACKNOWLEDGE(header, 1);
-	}
-	header->window = htons(socket_data->window);
-
-	/* Checksum */
-	header->checksum = 0;
-	checksum = compute_checksum(0, socket_data->pseudo_header,
-	    socket_data->headerlen);
-	checksum = compute_checksum(checksum,
-	    (uint8_t *) packet_get_data(packet),
-	    packet_get_data_length(packet));
-	header->checksum = htons(flip_checksum(compact_checksum(checksum)));
-
-	/* Prepare the packet */
-	rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
-	if (rc != EOK) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-
-	rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data,
-	    sequence_number, socket_data->state, socket_data->timeout, true);
-	if (rc != EOK) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-
-	return packet;
-}
-
-packet_t *tcp_prepare_copy(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
-{
-	packet_t *copy;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Make a copy of the packet */
-	copy = packet_get_copy(tcp_globals.net_sess, packet);
-	if (!copy)
-		return NULL;
-
-	return tcp_send_prepare_packet(socket, socket_data, copy, data_length,
-	    sequence_number);
-}
-
-void tcp_send_packets(nic_device_id_t device_id, packet_t *packet)
-{
-	packet_t *next;
-
-	while (packet) {
-		next = pq_detach(packet);
-		ip_send_msg(tcp_globals.ip_sess, device_id, packet,
-		    SERVICE_TCP, 0);
-		packet = next;
-	}
-}
-
-void tcp_prepare_operation_header(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, tcp_header_t *header, int synchronize,
-    int finalize)
-{
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-
-	bzero(header, sizeof(*header));
-	header->source_port = htons(socket->port);
-	header->source_port = htons(socket_data->dest_port);
-	SET_TCP_HEADER_LENGTH(header,
-	    TCP_COMPUTE_HEADER_LENGTH(sizeof(*header)));
-	SET_TCP_HEADER_SYNCHRONIZE(header, synchronize);
-	SET_TCP_HEADER_FINALIZE(header, finalize);
-}
-
-int tcp_prepare_timeout(int (*timeout_function)(void *tcp_timeout_t),
-    socket_core_t *socket, tcp_socket_data_t *socket_data,
-    size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout,
-    int globals_read_only)
-{
-	tcp_timeout_t *operation_timeout;
-	fid_t fibril;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Prepare the timeout with key bundle structure */
-	operation_timeout = malloc(sizeof(*operation_timeout) +
-	    socket->key_length + 1);
-	if (!operation_timeout)
-		return ENOMEM;
-
-	bzero(operation_timeout, sizeof(*operation_timeout));
-	operation_timeout->globals_read_only = globals_read_only;
-	operation_timeout->port = socket->port;
-	operation_timeout->local_sockets = socket_data->local_sockets;
-	operation_timeout->socket_id = socket->socket_id;
-	operation_timeout->timeout = timeout;
-	operation_timeout->sequence_number = sequence_number;
-	operation_timeout->state = state;
-
-	/* Copy the key */
-	operation_timeout->key = ((uint8_t *) operation_timeout) +
-	    sizeof(*operation_timeout);
-	operation_timeout->key_length = socket->key_length;
-	memcpy(operation_timeout->key, socket->key, socket->key_length);
-	operation_timeout->key[operation_timeout->key_length] = '\0';
-
-	/* Prepare the timeouting thread */
-	fibril = fibril_create(timeout_function, operation_timeout);
-	if (!fibril) {
-		free(operation_timeout);
-		return ENOMEM;
-	}
-
-//      fibril_mutex_lock(&socket_data->operation.mutex);
-	/* Start the timeout fibril */
-	fibril_add_ready(fibril);
-	//socket_data->state = state;
-	return EOK;
-}
-
-int tcp_recvfrom_message(socket_cores_t *local_sockets, int socket_id,
-    int flags, size_t *addrlen)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	int packet_id;
-	packet_t *packet;
-	size_t length;
-	int rc;
-
-	assert(local_sockets);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	if (!socket->specific_data)
-		return NO_DATA;
-
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-
-	/* Check state */
-	if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
-	    (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
-		return ENOTCONN;
-
-	/* Send the source address if desired */
-	if (addrlen) {
-		rc = data_reply(socket_data->addr, socket_data->addrlen);
-		if (rc != EOK)
-			return rc;
-		*addrlen = socket_data->addrlen;
-	}
-
-	/* Get the next received packet */
-	packet_id = dyn_fifo_value(&socket->received);
-	if (packet_id < 0)
-		return NO_DATA;
-
-	rc = packet_translate_remote(tcp_globals.net_sess, &packet, packet_id);
-	if (rc != EOK)
-		return rc;
-
-	/* Reply the packets */
-	rc = socket_reply_packets(packet, &length);
-	if (rc != EOK)
-		return rc;
-
-	/* Release the packet */
-	dyn_fifo_pop(&socket->received);
-	pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-
-	/* Return the total length */
-	return (int) length;
-}
-
-int tcp_send_message(socket_cores_t *local_sockets, int socket_id,
-    int fragments, size_t *data_fragment_size, int flags)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_dimension_t *packet_dimension;
-	packet_t *packet;
-	size_t total_length;
-	tcp_header_t *header;
-	int index;
-	int result;
-	int rc;
-
-	assert(local_sockets);
-	assert(data_fragment_size);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	if (!socket->specific_data)
-		return NO_DATA;
-
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-
-	/* Check state */
-	if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
-	    (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
-		return ENOTCONN;
-
-	rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-	    &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
-	if (rc != EOK)
-		return rc;
-
-	*data_fragment_size =
-	    ((packet_dimension->content < socket_data->data_fragment_size) ?
-	    packet_dimension->content : socket_data->data_fragment_size);
-
-	for (index = 0; index < fragments; index++) {
-		/* Read the data fragment */
-		result = tl_socket_read_packet_data(tcp_globals.net_sess,
-		    &packet, TCP_HEADER_SIZE, packet_dimension,
-		    socket_data->addr, socket_data->addrlen);
-		if (result < 0)
-			return result;
-
-		total_length = (size_t) result;
-
-		/* Prefix the TCP header */
-		header = PACKET_PREFIX(packet, tcp_header_t);
-		if (!header)
-			return tcp_release_and_return(packet, ENOMEM);
-
-		tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
-		rc = tcp_queue_packet(socket, socket_data, packet, total_length);
-		if (rc != EOK)
-			return rc;
-	}
-
-	/* Flush packets */
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	fibril_rwlock_read_unlock(&tcp_globals.lock);
-
-	if (packet) {
-		/* Send the packet */
-		tcp_send_packets(socket_data->device_id, packet);
-	}
-
-	return EOK;
-}
-
-int
-tcp_close_message(socket_cores_t *local_sockets, int socket_id)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_t *packet;
-	int rc;
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Check state */
-	switch (socket_data->state) {
-	case TCP_SOCKET_ESTABLISHED:
-		socket_data->state = TCP_SOCKET_FIN_WAIT_1;
-		break;
-
-	case TCP_SOCKET_CLOSE_WAIT:
-		socket_data->state = TCP_SOCKET_LAST_ACK;
-		break;
-
-//      case TCP_SOCKET_LISTEN:
-
-	default:
-		/* Just destroy */
-		rc = socket_destroy(tcp_globals.net_sess, socket_id,
-		    local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		if (rc == EOK) {
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			fibril_rwlock_write_unlock(&tcp_globals.lock);
-		}
-		return rc;
-	}
-
-	/*
-	 * Send FIN.
-	 * TODO should I wait to complete?
-	 */
-
-	/* Create the notification packet */
-	rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Send the packet */
-	rc = tcp_queue_packet(socket, socket_data, packet, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Flush packets */
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	if (packet) {
-		/* Send the packet */
-		tcp_send_packets(socket_data->device_id, packet);
-	}
-
-	return EOK;
-}
-
-int tcp_create_notification_packet(packet_t **packet, socket_core_t *socket,
-    tcp_socket_data_t *socket_data, int synchronize, int finalize)
-{
-	packet_dimension_t *packet_dimension;
-	tcp_header_t *header;
-	int rc;
-
-	assert(packet);
-
-	/* Get the device packet dimension */
-	rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-	    &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
-	if (rc != EOK)
-		return rc;
-
-	/* Get a new packet */
-	*packet = packet_get_4_remote(tcp_globals.net_sess, TCP_HEADER_SIZE,
-	    packet_dimension->addr_len, packet_dimension->prefix,
-	    packet_dimension->suffix);
-	
-	if (!*packet) 
-		return ENOMEM;
-
-	/* Allocate space in the packet */
-	header = PACKET_SUFFIX(*packet, tcp_header_t);
-	if (!header)
-		tcp_release_and_return(*packet, ENOMEM);
-
-	tcp_prepare_operation_header(socket, socket_data, header, synchronize,
-	    finalize);
-
-	return EOK;
-}
-
-int tcp_accept_message(socket_cores_t *local_sockets, int socket_id,
-    int new_socket_id, size_t *data_fragment_size, size_t *addrlen)
-{
-	socket_core_t *accepted;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_dimension_t *packet_dimension;
-	int rc;
-
-	assert(local_sockets);
-	assert(data_fragment_size);
-	assert(addrlen);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Check state */
-	if (socket_data->state != TCP_SOCKET_LISTEN)
-		return EINVAL;
-
-	do {
-		socket_id = dyn_fifo_value(&socket->accepted);
-		if (socket_id < 0)
-			return ENOTSOCK;
-		socket_id *= -1;
-
-		accepted = socket_cores_find(local_sockets, socket_id);
-		if (!accepted)
-			return ENOTSOCK;
-
-		/* Get the socket specific data */
-		socket_data = (tcp_socket_data_t *) accepted->specific_data;
-		assert(socket_data);
-		/* TODO can it be in another state? */
-		if (socket_data->state == TCP_SOCKET_ESTABLISHED) {
-			rc = data_reply(socket_data->addr,
-			    socket_data->addrlen);
-			if (rc != EOK)
-				return rc;
-			rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-			    &tcp_globals.dimensions, socket_data->device_id,
-			    &packet_dimension);
-			if (rc != EOK)
-				return rc;
-			*addrlen = socket_data->addrlen;
-
-			*data_fragment_size =
-			    ((packet_dimension->content <
-			    socket_data->data_fragment_size) ?
-			    packet_dimension->content :
-			    socket_data->data_fragment_size);
-	
-			if (new_socket_id > 0) {
-				rc = socket_cores_update(local_sockets,
-				    accepted->socket_id, new_socket_id);
-				if (rc != EOK)
-					return rc;
-				accepted->socket_id = new_socket_id;
-			}
-		}
-		dyn_fifo_pop(&socket->accepted);
-	} while (socket_data->state != TCP_SOCKET_ESTABLISHED);
-
-	printf("ret accept %d\n", accepted->socket_id);
-	return accepted->socket_id;
-}
-
-void tcp_free_socket_data(socket_core_t *socket)
-{
-	tcp_socket_data_t *socket_data;
-
-	assert(socket);
-
-	printf("destroy_socket %d\n", socket->socket_id);
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Free the pseudo header */
-	if (socket_data->pseudo_header) {
-		if (socket_data->headerlen) {
-			printf("d pseudo\n");
-			free(socket_data->pseudo_header);
-			socket_data->headerlen = 0;
-		}
-		socket_data->pseudo_header = NULL;
-	}
-
-	socket_data->headerlen = 0;
-
-	/* Free the address */
-	if (socket_data->addr) {
-		if (socket_data->addrlen) {
-			printf("d addr\n");
-			free(socket_data->addr);
-			socket_data->addrlen = 0;
-		}
-		socket_data->addr = NULL;
-	}
-	socket_data->addrlen = 0;
-}
-
-/** Releases the packet and returns the result.
- *
- * @param[in] packet	The packet queue to be released.
- * @param[in] result	The result to be returned.
- * @return		The result parameter.
- */
-int tcp_release_and_return(packet_t *packet, int result)
-{
-	pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-	return result;
-}
-
-/** Process IPC messages from the IP module
- *
- * @param[in]     iid   Message identifier.
- * @param[in,out] icall Message parameters.
- * @param[in]     arg   Local argument.
- *
- */
-static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	packet_t *packet;
-	int rc;
-	
+	log_msg(LVL_DEBUG, "tcp_receiver()");
+
 	while (true) {
 		switch (IPC_GET_IMETHOD(*icall)) {
 		case NET_TL_RECEIVED:
-			rc = packet_translate_remote(tcp_globals.net_sess, &packet,
+			log_msg(LVL_DEBUG, "method = NET_TL_RECEIVED");
+			rc = packet_translate_remote(net_sess, &packet,
 			    IPC_GET_PACKET(*icall));
-			if (rc == EOK)
-				rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
-				    SERVICE_TCP, IPC_GET_ERROR(*icall));
-			
-			async_answer_0(iid, (sysarg_t) rc);
+			if (rc != EOK) {
+				log_msg(LVL_DEBUG, "Error %d translating packet.", rc);
+				async_answer_0(iid, (sysarg_t)rc);
+				break;
+			}
+			rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
+			    IPC_GET_ERROR(*icall));
+			async_answer_0(iid, (sysarg_t)rc);
 			break;
 		default:
-			async_answer_0(iid, (sysarg_t) ENOTSUP);
+			log_msg(LVL_DEBUG, "method = %u",
+			    (unsigned)IPC_GET_IMETHOD(*icall));
+			async_answer_0(iid, ENOTSUP);
+			break;
 		}
-		
+
 		iid = async_get_call(icall);
 	}
 }
 
-/** Initialize the TCP module.
- *
- * @param[in] sess Network module session.
- *
- * @return EOK on success.
- * @return ENOMEM if there is not enough memory left.
- *
+/** Transmit PDU over network layer. */
+void tcp_transmit_pdu(tcp_pdu_t *pdu)
+{
+	struct sockaddr_in dest;
+	nic_device_id_t dev_id;
+	void *phdr;
+	size_t phdr_len;
+	packet_dimension_t *pkt_dim;
+	int rc;
+	packet_t *packet;
+	void *pkt_data;
+	size_t pdu_size;
+
+	dest.sin_family = AF_INET;
+	dest.sin_port = 0; /* not needed */
+	dest.sin_addr.s_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
+
+	/* Find route. Obtained pseudo-header is not used. */
+	rc = ip_get_route_req(ip_sess, IPPROTO_TCP, (struct sockaddr *)&dest,
+	    sizeof(dest), &dev_id, &phdr, &phdr_len);
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to find route.");
+		return;
+	}
+
+	rc = tl_get_ip_packet_dimension(ip_sess, &pkt_dims, dev_id, &pkt_dim);
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get dimension.");
+		return;
+	}
+
+	pdu_size = pdu->header_size + pdu->text_size;
+
+	packet = packet_get_4_remote(net_sess, pdu_size, pkt_dim->addr_len,
+	    pkt_dim->prefix, pkt_dim->suffix);
+	if (!packet) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get packet.");
+		return;
+	}
+
+	pkt_data = packet_suffix(packet, pdu_size);
+	if (!pkt_data) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get pkt_data ptr.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return;
+	}
+
+	rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to prepare IP packet part.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return;
+	}
+
+	rc = packet_set_addr(packet, NULL, (uint8_t *)&dest, sizeof(dest));
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to set packet address.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return;
+	}
+
+	/* Copy PDU data to packet */
+	memcpy(pkt_data, pdu->header, pdu->header_size);
+	memcpy((uint8_t *)pkt_data + pdu->header_size, pdu->text,
+	    pdu->text_size);
+
+	/* Transmit packet. XXX Transfers packet ownership to IP? */
+	ip_send_msg(ip_sess, dev_id, packet, SERVICE_TCP, 0);
+}
+
+/** Process received PDU. */
+static void tcp_received_pdu(tcp_pdu_t *pdu)
+{
+	tcp_segment_t *dseg;
+	tcp_sockpair_t rident;
+
+	log_msg(LVL_DEBUG, "tcp_received_pdu()");
+
+	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
+		return;
+	}
+
+	/* Insert decoded segment into rqueue */
+	tcp_rqueue_insert_seg(&rident, dseg);
+}
+
+/* Called from libnet */
+void tl_connection(void)
+{
+	log_msg(LVL_DEBUG, "tl_connection()");
+}
+
+/* Called from libnet */
+int tl_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
+    size_t *answer_count)
+{
+	async_sess_t *callback;
+
+	log_msg(LVL_DEBUG, "tl_message()");
+
+	*answer_count = 0;
+	callback = async_callback_receive_start(EXCHANGE_SERIALIZE, call);
+	if (callback)
+		return tcp_sock_connection(callback, callid, *call);
+
+	return ENOTSUP;
+}
+
+/* Called from libnet */
+int tl_initialize(async_sess_t *sess)
+{
+	int rc;
+
+	net_sess = sess;
+	icmp_sess = icmp_connect_module();
+
+	log_msg(LVL_DEBUG, "tl_initialize()");
+
+	tcp_sock_init();
+
+	ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP, SERVICE_TCP,
+	    tcp_receiver);
+	if (ip_sess == NULL)
+		return ENOENT;
+
+	rc = packet_dimensions_initialize(&pkt_dims);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+int main(int argc, char **argv)
+{
+	int rc;
+
+	printf(NAME ": TCP (Transmission Control Protocol) network module\n");
+
+	rc = log_init(NAME, LVL_ERROR);
+	if (rc != EOK) {
+		printf(NAME ": Failed to initialize log.\n");
+		return 1;
+	}
+
+//	printf(NAME ": Accepting connections\n");
+//	task_retval(0);
+
+	tcp_rqueue_init();
+	tcp_rqueue_thread_start();
+
+	tcp_ncsim_init();
+	tcp_ncsim_thread_start();
+
+	if (0) tcp_test();
+/*
+	async_manager();
+*/
+	tl_module_start(SERVICE_TCP);
+
+	/* Not reached */
+	return 0;
+}
+
+/**
+ * @}
  */
-int tl_initialize(async_sess_t *sess)
-{
-	fibril_rwlock_initialize(&tcp_globals.lock);
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-	
-	tcp_globals.net_sess = sess;
-	
-	tcp_globals.icmp_sess = icmp_connect_module();
-	tcp_globals.ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP,
-	    SERVICE_TCP, tcp_receiver);
-	if (tcp_globals.ip_sess == NULL) {
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-		return ENOENT;
-	}
-	
-	int rc = socket_ports_initialize(&tcp_globals.sockets);
-	if (rc != EOK)
-		goto out;
-
-	rc = packet_dimensions_initialize(&tcp_globals.dimensions);
-	if (rc != EOK) {
-		socket_ports_destroy(&tcp_globals.sockets, free);
-		goto out;
-	}
-
-	tcp_globals.last_used_port = TCP_FREE_PORTS_START - 1;
-
-out:
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-	return rc;
-}
-
-int main(int argc, char *argv[])
-{
-	return tl_module_start(SERVICE_TCP);
-}
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/tcp.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/net/tl/tcp/tcp.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2008 Lukas Mejdrech
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -30,277 +30,17 @@
  * @{
  */
-
-/** @file
- * TCP module.
+/** @file TCP (Transmission Control Protocol) network module
  */
 
-#ifndef NET_TCP_H_
-#define NET_TCP_H_
+#ifndef TCP_H
+#define TCP_H
 
 #include <async.h>
-#include <fibril_synch.h>
-#include <net/packet.h>
-#include <net/device.h>
-#include <socket_core.h>
-#include <tl_common.h>
+#include <packet_remote.h>
+#include "tcp_type.h"
 
-/** Type definition of the TCP global data.
- * @see tcp_globals
- */
-typedef struct tcp_globals tcp_globals_t;
-
-/** Type definition of the TCP socket specific data.
- * @see tcp_socket_data
- */
-typedef struct tcp_socket_data tcp_socket_data_t;
-
-/** Type definition of the TCP operation data.
- * @see tcp_operation
- */
-typedef struct tcp_operation tcp_operation_t;
-
-/** TCP socket state type definition.
- * @see tcp_socket_state
- */
-typedef enum tcp_socket_state tcp_socket_state_t;
-
-/** TCP socket state. */
-enum tcp_socket_state {
-	/** Initial.
-	 *
-	 * Not connected or bound.
-	 */
-	TCP_SOCKET_INITIAL,
-	
-	/** Listening.
-	 *
-	 * Awaiting a connection request from another TCP layer.
-	 * When SYN is received a new bound socket in the
-	 * TCP_SOCKET_SYN_RECEIVED state should be created.
-	 */
-	TCP_SOCKET_LISTEN,
-	
-	/** Connecting issued.
-	 *
-	 * A SYN has been sent, and TCP is awaiting the response SYN.
-	 * Should continue to the TCP_SOCKET_ESTABLISHED state.
-	 */
-	TCP_SOCKET_SYN_SENT,
-	
-	/** Connecting received.
-	 *
-	 * A SYN has been received, a SYN has been sent, and TCP is awaiting an
-	 * ACK. Should continue to the TCP_SOCKET_ESTABLISHED state.
-	 */
-	TCP_SOCKET_SYN_RECEIVED,
-	
-	/** Connected.
-	 *
-	 * The three-way handshake has been completed.
-	 */
-	TCP_SOCKET_ESTABLISHED,
-	
-	/** Closing started.
-	 *
-	 * The local application has issued a CLOSE.
-	 * TCP has sent a FIN, and is awaiting an ACK or a FIN.
-	 * Should continue to the TCP_SOCKET_FIN_WAIT_2 state when an ACK is
-	 * received.
-	 * Should continue to the TCP_SOCKET_CLOSING state when a FIN is
-	 * received.
-	 */
-	TCP_SOCKET_FIN_WAIT_1,
-	
-	/** Closing confirmed.
-	 *
-	 * A FIN has been sent, and an ACK received.
-	 * TCP is awaiting a~FIN from the remote TCP layer.
-	 * Should continue to the TCP_SOCKET_CLOSING state.
-	 */
-	TCP_SOCKET_FIN_WAIT_2,
-	
-	/** Closing.
-	 *
-	 * A FIN has been sent, a FIN has been received, and an ACK has been
-	 * sent.
-	 * TCP is awaiting an ACK for the FIN that was sent.
-	 * Should continue to the TCP_SOCKET_TIME_WAIT state.
-	 */
-	TCP_SOCKET_CLOSING,
-	
-	/** Closing received.
-	 *
-	 * TCP has received a FIN, and has sent an ACK.
-	 * It is awaiting a close request from the local application before
-	 * sending a FIN.
-	 * Should continue to the TCP_SOCKET_SOCKET_LAST_ACK state.
-	 */
-	TCP_SOCKET_CLOSE_WAIT,
-	
-	/**
-	 * A FIN has been received, and an ACK and a FIN have been sent.
-	 * TCP is awaiting an ACK.
-	 * Should continue to the TCP_SOCKET_TIME_WAIT state.
-	 */
-	TCP_SOCKET_LAST_ACK,
-	
-	/** Closing finished.
-	 *
-	 * FINs have been received and ACK’d, and TCP is waiting two MSLs to
-	 * remove the connection from the table.
-	 */
-	TCP_SOCKET_TIME_WAIT,
-	
-	/** Closed.
-	 *
-	 * Imaginary, this indicates that a connection has been removed from
-	 * the connection table.
-	 */
-	TCP_SOCKET_CLOSED
-};
-
-/** TCP operation data. */
-struct tcp_operation {
-	/** Operation result. */
-	int result;
-	/** Safety lock. */
-	fibril_mutex_t mutex;
-	/** Operation result signaling. */
-	fibril_condvar_t condvar;
-};
-
-/** TCP socket specific data. */
-struct tcp_socket_data {
-	/** TCP socket state. */
-	tcp_socket_state_t state;
-	
-	/**
-	 * Data fragment size.
-	 * Sending optimalization.
-	 */
-	size_t data_fragment_size;
-	
-	/** Device identifier. */
-	nic_device_id_t device_id;
-	
-	/**
-	 * Listening backlog.
-	 * The maximal number of connected but not yet accepted sockets.
-	 */
-	int backlog;
-	
-	/**
-	 * Parent listening socket identifier.
-	 * Set if this socket is an accepted one.
-	 */
-	int listening_socket_id;
-	
-	/** Treshold size in bytes. */
-	size_t treshold;
-	/** Window size in bytes. */
-	size_t window;
-	/** Acknowledgement timeout. */
-	suseconds_t timeout;
-	/** Last acknowledged byte. */
-	uint32_t acknowledged;
-	/** Next incoming sequence number. */
-	uint32_t next_incoming;
-	/** Incoming FIN. */
-	uint32_t fin_incoming;
-	/** Next outgoing sequence number. */
-	uint32_t next_outgoing;
-	/** Last outgoing sequence number. */
-	uint32_t last_outgoing;
-	/** Outgoing FIN. */
-	uint32_t fin_outgoing;
-	
-	/**
-	 * Expected sequence number by the remote host.
-	 * The sequence number the other host expects.
-	 * The notification is sent only upon a packet reecival.
-	 */
-	uint32_t expected;
-	
-	/**
-	 * Expected sequence number counter.
-	 * Counts the number of received notifications for the same sequence
-	 * number.
-	 */
-	int expected_count;
-	
-	/** Incoming packet queue.
-	 *
-	 * Packets are buffered until received in the right order.
-	 * The packets are excluded after successfully read.
-	 * Packets are sorted by their starting byte.
-	 * Packets metric is set as their data length.
-	 */
-	packet_t *incoming;
-	
-	/** Outgoing packet queue.
-	 *
-	 * Packets are buffered until acknowledged by the remote host in the
-	 * right order.
-	 * The packets are excluded after acknowledged.
-	 * Packets are sorted by their starting byte.
-	 * Packets metric is set as their data length.
-	 */
-	packet_t *outgoing;
-	
-	/** IP pseudo header. */
-	void *pseudo_header;
-	/** IP pseudo header length. */
-	size_t headerlen;
-	/** Remote host address. */
-	struct sockaddr *addr;
-	/** Remote host address length. */
-	socklen_t addrlen;
-	/** Remote host port. */
-	uint16_t dest_port;
-	/** Parent local sockets. */
-	socket_cores_t *local_sockets;
-	
-	/** Local sockets safety lock.
-	 *
-	 * May be locked for writing while holding the global lock for reading
-	 * when changing the local sockets only.
-	 * The global lock may be locked only before locking the local lock.
-	 * The global lock may be locked more weakly than the local lock.
-	 * The global lock may be released before releasing the local lock.
-	 * @see tcp_globals:lock
-	 */
-	fibril_rwlock_t *local_lock;
-	
-	/** Pending operation data. */
-	tcp_operation_t operation;
-	
-	/**
-	 * Timeouts in a row counter.
-	 * If TCP_MAX_TIMEOUTS is reached, the connection is lost.
-	 */
-	int timeout_count;
-};
-
-/** TCP global data. */
-struct tcp_globals {
-	/** Networking module session. */
-	async_sess_t *net_sess;
-	/** IP module session. */
-	async_sess_t *ip_sess;
-	/** ICMP module session. */
-	async_sess_t *icmp_sess;
-	/** Last used free port. */
-	int last_used_port;
-	/** Active sockets. */
-	socket_ports_t sockets;
-	/** Device packet dimensions. */
-	packet_dimensions_t dimensions;
-	
-	/**
-	 * Safety lock.
-	 * Write lock is used only for adding or removing socket ports.
-	 */
-	fibril_rwlock_t lock;
-};
+extern async_sess_t *net_sess;
+extern async_sess_t *ip_sess;
+extern void tcp_transmit_pdu(tcp_pdu_t *);
 
 #endif
Index: pace/srv/net/tl/tcp/tcp_header.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_header.h	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ 	(revision )
@@ -1,163 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup tcp
- * @{
- */
-
-/** @file
- * TCP header definition.
- * Based on the RFC 793.
- */
-
-#ifndef NET_TCP_HEADER_H_
-#define NET_TCP_HEADER_H_
-
-#include <sys/types.h>
-
-/** TCP header size in bytes. */
-#define TCP_HEADER_SIZE				sizeof(tcp_header_t)
-
-/** Returns the actual TCP header length in bytes.
- * @param[in] header The TCP packet header.
- */
-#define TCP_HEADER_LENGTH(header)		(GET_TCP_HEADER_LENGTH(header) * 4U)
-
-/** Returns the TCP header length.
- * @param[in] length The TCP header length in bytes.
- */
-#define TCP_COMPUTE_HEADER_LENGTH(length)	((uint8_t) ((length) / 4U))
-
-/** Type definition of the transmission datagram header.
- * @see tcp_header
- */
-typedef struct tcp_header tcp_header_t;
-
-/** Type definition of the transmission datagram header option.
- * @see tcp_option
- */
-typedef struct tcp_option tcp_option_t;
-
-/** Type definition of the Maximum segment size TCP option. */
-typedef struct tcp_max_segment_size_option tcp_max_segment_size_option_t;
-
-/** Transmission datagram header. */
-struct tcp_header {
-	uint16_t source_port;
-	uint16_t destination_port;
-	uint32_t sequence_number;
-	uint32_t acknowledgement_number;
-
-	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;
-	uint16_t checksum;
-	uint16_t urgent_pointer;
-} __attribute__ ((packed));
-
-/** Transmission datagram header option. */
-struct tcp_option {
-	/** Option type. */
-	uint8_t type;
-	/** Option length. */
-	uint8_t length;
-};
-
-/** Maximum segment size TCP option. */
-struct tcp_max_segment_size_option {
-	/** TCP option.
-	 * @see TCPOPT_MAX_SEGMENT_SIZE
-	 * @see TCPOPT_MAX_SEGMENT_SIZE_LENGTH
-	 */
-	tcp_option_t option;
-	
-	/** Maximum segment size in bytes. */
-	uint16_t max_segment_size;
-} __attribute__ ((packed));
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_type.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/tcp_type.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP type definitions
+ */
+
+#ifndef TCP_TYPE_H
+#define TCP_TYPE_H
+
+#include <adt/list.h>
+#include <async.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <socket_core.h>
+#include <sys/types.h>
+
+struct tcp_conn;
+
+typedef enum {
+	/** Listen */
+	st_listen,
+	/** Syn-sent */
+	st_syn_sent,
+	/** Syn-received */
+	st_syn_received,
+	/** Established */
+	st_established,
+	/** Fin-wait-1 */
+	st_fin_wait_1,
+	/** Fin-wait-2 */
+	st_fin_wait_2,
+	/** Close-wait */
+	st_close_wait,
+	/** Closing */
+	st_closing,
+	/** Last-ack */
+	st_last_ack,
+	/** Time-wait */
+	st_time_wait,
+	/** Closed */
+	st_closed
+} tcp_cstate_t;
+
+/** Error codes returned by TCP user calls (per the spec). */
+typedef enum {
+	/* OK */
+	TCP_EOK,
+	/* Connection aborted due to user timeout */
+	TCP_EABORTED,
+	/* Connection already exists */
+	TCP_EEXISTS,
+	/* Connection closing */
+	TCP_ECLOSING,
+	/* Connection does not exist */
+	TCP_ENOTEXIST,
+	/* Connection illegal for this process */
+	TCP_EILLEGAL,
+	/* Connection not open */
+	TCP_ENOTOPEN,
+	/* Connection reset */
+	TCP_ERESET,
+	/* Foreign socket unspecified */
+	TCP_EUNSPEC,
+	/* Insufficient resources */
+	TCP_ENORES,
+	/* Precedence not allowed */
+	TCP_EINVPREC,
+	/* Security/compartment not allowed */
+	TCP_EINVCOMP
+} tcp_error_t;
+
+typedef enum {
+	XF_PUSH		= 0x1,
+	XF_URGENT	= 0x2
+} xflags_t;
+
+typedef enum {
+	CTL_SYN		= 0x1,
+	CTL_FIN		= 0x2,
+	CTL_RST		= 0x4,
+	CTL_ACK		= 0x8
+} tcp_control_t;
+
+typedef struct {
+	uint32_t ipv4;
+} netaddr_t;
+
+typedef struct {
+	netaddr_t addr;
+	uint16_t port;
+} tcp_sock_t;
+
+enum netaddr {
+	TCP_IPV4_ANY = 0
+};
+
+enum tcp_port {
+	TCP_PORT_ANY = 0
+};
+
+typedef struct {
+	tcp_sock_t local;
+	tcp_sock_t foreign;
+} tcp_sockpair_t;
+
+/** Connection incoming segments queue */
+typedef struct {
+	struct tcp_conn *conn;
+	list_t list;
+} tcp_iqueue_t;
+
+/** Retransmission queue */
+typedef struct {
+	struct tcp_conn *conn;
+	list_t list;
+
+	/** Retransmission timer */
+	fibril_timer_t *timer;
+} tcp_tqueue_t;
+
+typedef enum {
+	ap_active,
+	ap_passive
+} acpass_t;
+
+typedef struct tcp_conn {
+	char *name;
+	link_t link;
+
+	/** Connection identification (local and foreign socket) */
+	tcp_sockpair_t ident;
+
+	/** Active or passive connection */
+	acpass_t ap;
+
+	/** Protects access to connection structure */
+	fibril_mutex_t lock;
+	/** Reference count */
+	atomic_t refcnt;
+
+	/** Connection state */
+	tcp_cstate_t cstate;
+	/** True if connection was reset */
+	bool reset;
+	/** True if connection was deleted by user */
+	bool deleted;
+	/** Signalled when @c cstate changes */
+	fibril_condvar_t cstate_cv;
+
+	/** Set when FIN is removed from the retransmission queue */
+	bool fin_is_acked;
+
+	/** Queue of incoming segments */
+	tcp_iqueue_t incoming;
+
+	/** Retransmission queue */
+	tcp_tqueue_t retransmit;
+
+	/** Time-Wait timeout timer */
+	fibril_timer_t *tw_timer;
+
+	/** Receive buffer */
+	uint8_t *rcv_buf;
+	/** Receive buffer size */
+	size_t rcv_buf_size;
+	/** Receive buffer number of bytes used */
+	size_t rcv_buf_used;
+	/** Receive buffer contains FIN */
+	bool rcv_buf_fin;
+	/** Receive buffer CV. Broadcast when new data is inserted */
+	fibril_condvar_t rcv_buf_cv;
+
+	/** Send buffer */
+	uint8_t *snd_buf;
+	/** Send buffer size */
+	size_t snd_buf_size;
+	/** Send buffer number of bytes used */
+	size_t snd_buf_used;
+	/** Send buffer contains FIN */
+	bool snd_buf_fin;
+	/** Send buffer CV. Broadcast when space is made available in buffer */
+	fibril_condvar_t snd_buf_cv;
+
+	/** Send unacknowledged */
+	uint32_t snd_una;
+	/** Send next */
+	uint32_t snd_nxt;
+	/** Send window */
+	uint32_t snd_wnd;
+	/** Send urgent pointer */
+	uint32_t snd_up;
+	/** Segment sequence number used for last window update */
+	uint32_t snd_wl1;
+	/** Segment acknowledgement number used for last window update */
+	uint32_t snd_wl2;
+	/** Initial send sequence number */
+	uint32_t iss;
+
+	/** Receive next */
+	uint32_t rcv_nxt;
+	/** Receive window */
+	uint32_t rcv_wnd;
+	/** Receive urgent pointer */
+	uint32_t rcv_up;
+	/** Initial receive sequence number */
+	uint32_t irs;
+} tcp_conn_t;
+
+typedef struct {
+	unsigned dummy;
+} tcp_conn_status_t;
+
+typedef struct {
+	/** SYN, FIN */
+	tcp_control_t ctrl;
+
+	/** Segment sequence number */
+	uint32_t seq;
+	/** Segment acknowledgement number */
+	uint32_t ack;
+	/** Segment length in sequence space */
+	uint32_t len;
+	/** Segment window */
+	uint32_t wnd;
+	/** Segment urgent pointer */
+	uint32_t up;
+
+	/** Segment data, may be moved when trimming segment */
+	void *data;
+	/** Segment data, original pointer used to free data */
+	void *dfptr;
+} tcp_segment_t;
+
+
+typedef struct {
+	link_t link;
+	tcp_sockpair_t sp;
+	tcp_segment_t *seg;
+} tcp_rqueue_entry_t;
+
+/** NCSim queue entry */
+typedef struct {
+	link_t link;
+	suseconds_t delay;
+	tcp_sockpair_t sp;
+	tcp_segment_t *seg;
+} tcp_squeue_entry_t;
+
+typedef struct {
+	link_t link;
+	tcp_segment_t *seg;
+} tcp_iqueue_entry_t;
+
+/** Retransmission queue entry */
+typedef struct {
+	link_t link;
+	tcp_conn_t *conn;
+	tcp_segment_t *seg;
+} tcp_tqueue_entry_t;
+
+typedef enum {
+	cp_continue,
+	cp_done
+} cproc_t;
+
+/** Encoded PDU */
+typedef struct {
+	/** Source address */
+	netaddr_t src_addr;
+	/** Destination address */
+	netaddr_t dest_addr;
+
+	/** Encoded header */
+	void *header;
+	/** Encoded header size */
+	size_t header_size;
+	/** Text */
+	void *text;
+	/** Text size */
+	size_t text_size;
+} tcp_pdu_t;
+
+typedef struct {
+	async_sess_t *sess;
+	socket_cores_t sockets;
+} tcp_client_t;
+
+typedef struct {
+	/** Client */
+	tcp_client_t *client;
+	/** Connection */
+	tcp_conn_t *conn;
+	/** Local address */
+	netaddr_t laddr;
+} tcp_sockdata_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/test.c
===================================================================
--- uspace/srv/net/tl/tcp/test.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/test.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Internal TCP test
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <stdio.h>
+#include <thread.h>
+#include <str.h>
+#include "tcp_type.h"
+#include "ucall.h"
+
+#include "test.h"
+
+#define RCV_BUF_SIZE 64
+
+static void test_srv(void *arg)
+{
+	tcp_conn_t *conn;
+	tcp_sock_t lsock;
+	tcp_sock_t fsock;
+	char rcv_buf[RCV_BUF_SIZE + 1];
+	size_t rcvd;
+	xflags_t xflags;
+
+	printf("test_srv()\n");
+	lsock.port = 80;
+	lsock.addr.ipv4 = 0x7f000001;
+	fsock.port = 1024;
+	fsock.addr.ipv4 = 0x7f000001;
+	printf("S: User open...\n");
+	tcp_uc_open(&lsock, &fsock, ap_passive, &conn);
+	conn->name = (char *) "S";
+
+	while (true) {
+		printf("S: User receive...\n");
+		tcp_uc_receive(conn, rcv_buf, RCV_BUF_SIZE, &rcvd, &xflags);
+		if (rcvd == 0) {
+			printf("S: End of data reached.\n");
+			break;
+		}
+		rcv_buf[rcvd] = '\0';
+		printf("S: User received %zu bytes '%s'.\n", rcvd, rcv_buf);
+
+		async_usleep(1000*1000*2);
+	}
+
+	async_usleep(/*10**/1000*1000);
+
+	printf("S: User close...\n");
+	tcp_uc_close(conn);
+
+	printf("test_srv() terminating\n");
+}
+
+static void test_cli(void *arg)
+{
+	tcp_conn_t *conn;
+	tcp_sock_t lsock;
+	tcp_sock_t fsock;
+	const char *msg = "Hello World!";
+
+	printf("test_cli()\n");
+
+	lsock.port = 1024;
+	lsock.addr.ipv4 = 0x7f000001;
+	fsock.port = 80;
+	fsock.addr.ipv4 = 0x7f000001;
+
+	async_usleep(1000*1000*3);
+	printf("C: User open...\n");
+	tcp_uc_open(&lsock, &fsock, ap_active, &conn);
+	conn->name = (char *) "C";
+
+	async_usleep(1000*1000*10);
+	printf("C: User send...\n");
+	tcp_uc_send(conn, (void *)msg, str_size(msg), 0);
+
+	async_usleep(1000*1000*20/**20*2*/);
+	printf("C: User close...\n");
+	tcp_uc_close(conn);
+}
+
+void tcp_test(void)
+{
+	thread_id_t srv_tid;
+	thread_id_t cli_tid;
+	int rc;
+
+	printf("tcp_test()\n");
+
+	async_usleep(1000*1000);
+
+	if (0) {
+		rc = thread_create(test_srv, NULL, "test_srv", &srv_tid);
+		if (rc != EOK) {
+			printf("Failed to create server thread.\n");
+			return;
+		}
+	}
+
+	if (0) {
+		rc = thread_create(test_cli, NULL, "test_cli", &cli_tid);
+		if (rc != EOK) {
+			printf("Failed to create client thread.\n");
+			return;
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/test.h
===================================================================
--- uspace/srv/net/tl/tcp/test.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/test.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Internal TCP test
+ */
+
+#ifndef TEST_H
+#define TEST_H
+
+extern void tcp_test(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP transmission queue
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <byteorder.h>
+#include <io/log.h>
+#include <macros.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "conn.h"
+#include "ncsim.h"
+#include "pdu.h"
+#include "rqueue.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "tqueue.h"
+#include "tcp.h"
+#include "tcp_type.h"
+
+#define RETRANSMIT_TIMEOUT	(2*1000*1000)
+
+static void retransmit_timeout_func(void *arg);
+static void tcp_tqueue_timer_set(tcp_conn_t *conn);
+static void tcp_tqueue_timer_clear(tcp_conn_t *conn);
+
+int tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
+{
+	tqueue->conn = conn;
+	tqueue->timer = fibril_timer_create();
+	if (tqueue->timer == NULL)
+		return ENOMEM;
+
+	list_initialize(&tqueue->list);
+
+	return EOK;
+}
+
+void tcp_tqueue_clear(tcp_tqueue_t *tqueue)
+{
+	tcp_tqueue_timer_clear(tqueue->conn);
+}
+
+void tcp_tqueue_fini(tcp_tqueue_t *tqueue)
+{
+	if (tqueue->timer != NULL) {
+		fibril_timer_destroy(tqueue->timer);
+		tqueue->timer = NULL;
+	}
+}
+
+void tcp_tqueue_ctrl_seg(tcp_conn_t *conn, tcp_control_t ctrl)
+{
+	tcp_segment_t *seg;
+
+	log_msg(LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
+
+	seg = tcp_segment_make_ctrl(ctrl);
+	tcp_tqueue_seg(conn, seg);
+}
+
+void tcp_tqueue_seg(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	tcp_segment_t *rt_seg;
+	tcp_tqueue_entry_t *tqe;
+
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
+	    seg);
+
+	/*
+	 * Add segment to retransmission queue
+	 */
+
+	if (seg->len > 0) {
+		rt_seg = tcp_segment_dup(seg);
+		if (rt_seg == NULL) {
+			log_msg(LVL_ERROR, "Memory allocation failed.");
+			/* XXX Handle properly */
+			return;
+		}
+
+		tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
+		if (tqe == NULL) {
+			log_msg(LVL_ERROR, "Memory allocation failed.");
+			/* XXX Handle properly */
+			return;
+		}
+
+		tqe->conn = conn;
+		tqe->seg = rt_seg;
+		rt_seg->seq = conn->snd_nxt;
+
+		list_append(&tqe->link, &conn->retransmit.list);
+
+		/* Set retransmission timer */
+		tcp_tqueue_timer_set(conn);
+	}
+
+	tcp_prepare_transmit_segment(conn, seg);
+}
+
+void tcp_prepare_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/*
+	 * Always send ACK once we have received SYN, except for RST segments.
+	 * (Spec says we should always send ACK once connection has been
+	 * established.)
+	 */
+	if (tcp_conn_got_syn(conn) && (seg->ctrl & CTL_RST) == 0)
+		seg->ctrl |= CTL_ACK;
+
+	seg->seq = conn->snd_nxt;
+	conn->snd_nxt += seg->len;
+
+	tcp_conn_transmit_segment(conn, seg);
+}
+
+/** Transmit data from the send buffer.
+ *
+ * @param conn	Connection
+ */
+void tcp_tqueue_new_data(tcp_conn_t *conn)
+{
+	size_t avail_wnd;
+	size_t xfer_seqlen;
+	size_t snd_buf_seqlen;
+	size_t data_size;
+	tcp_control_t ctrl;
+	bool send_fin;
+
+	tcp_segment_t *seg;
+
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
+
+	/* Number of free sequence numbers in send window */
+	avail_wnd = (conn->snd_una + conn->snd_wnd) - conn->snd_nxt;
+	snd_buf_seqlen = conn->snd_buf_used + (conn->snd_buf_fin ? 1 : 0);
+
+	xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
+	log_msg(LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
+	    "xfer_seqlen = %zu", conn->name, snd_buf_seqlen, conn->snd_wnd,
+	    xfer_seqlen);
+
+	if (xfer_seqlen == 0)
+		return;
+
+	/* XXX Do not always send immediately */
+
+	send_fin = conn->snd_buf_fin && xfer_seqlen == snd_buf_seqlen;
+	data_size = xfer_seqlen - (send_fin ? 1 : 0);
+
+	if (send_fin) {
+		log_msg(LVL_DEBUG, "%s: Sending out FIN.", conn->name);
+		/* We are sending out FIN */
+		ctrl = CTL_FIN;
+	} else {
+		ctrl = 0;
+	}
+
+	seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
+	if (seg == NULL) {
+		log_msg(LVL_ERROR, "Memory allocation failure.");
+		return;
+	}
+
+	/* Remove data from send buffer */
+	memmove(conn->snd_buf, conn->snd_buf + data_size,
+	    conn->snd_buf_used - data_size);
+	conn->snd_buf_used -= data_size;
+
+	if (send_fin)
+		conn->snd_buf_fin = false;
+
+	fibril_condvar_broadcast(&conn->snd_buf_cv);
+
+	if (send_fin)
+		tcp_conn_fin_sent(conn);
+
+	tcp_tqueue_seg(conn, seg);
+}
+
+/** Remove ACKed segments from retransmission queue and possibly transmit
+ * more data.
+ *
+ * This should be called when SND.UNA is updated due to incoming ACK.
+ */
+void tcp_tqueue_ack_received(tcp_conn_t *conn)
+{
+	link_t *cur, *next;
+
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_ack_received(%p)", conn->name,
+	    conn);
+
+	cur = conn->retransmit.list.head.next;
+
+	while (cur != &conn->retransmit.list.head) {
+		next = cur->next;
+
+		tcp_tqueue_entry_t *tqe = list_get_instance(cur,
+		    tcp_tqueue_entry_t, link);
+
+		if (seq_no_segment_acked(conn, tqe->seg, conn->snd_una)) {
+			/* Remove acknowledged segment */
+			list_remove(cur);
+
+			if ((tqe->seg->ctrl & CTL_FIN) != 0) {
+				log_msg(LVL_DEBUG, "Fin has been acked");
+				log_msg(LVL_DEBUG, "SND.UNA=%" PRIu32
+				    " SEG.SEQ=%" PRIu32 " SEG.LEN=%" PRIu32,
+				    conn->snd_una, tqe->seg->seq, tqe->seg->len);
+				/* Our FIN has been acked */
+				conn->fin_is_acked = true;
+			}
+
+			tcp_segment_delete(tqe->seg);
+			free(tqe);
+
+			/* Reset retransmission timer */
+			tcp_tqueue_timer_set(conn);
+		}
+
+		cur = next;
+	}
+
+	/* Clear retransmission timer if the queue is empty. */
+	if (list_empty(&conn->retransmit.list))
+		tcp_tqueue_timer_clear(conn);
+
+	/* Possibly transmit more data */
+	tcp_tqueue_new_data(conn);
+}
+
+void tcp_conn_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_transmit_segment(%p, %p)",
+	    conn->name, conn, seg);
+
+	seg->wnd = conn->rcv_wnd;
+
+	if ((seg->ctrl & CTL_ACK) != 0)
+		seg->ack = conn->rcv_nxt;
+	else
+		seg->ack = 0;
+
+	tcp_transmit_segment(&conn->ident, seg);
+}
+
+void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
+	    sp->foreign.addr.ipv4, sp->foreign.port,
+	    sp->local.addr.ipv4, sp->local.port, seg);
+
+	log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
+	    seg->seq, seg->wnd);
+
+	tcp_segment_dump(seg);
+/*
+	tcp_pdu_prepare(conn, seg, &data, &len);
+	tcp_pdu_transmit(data, len);
+*/
+//	tcp_rqueue_bounce_seg(sp, seg);
+//	tcp_ncsim_bounce_seg(sp, seg);
+
+	tcp_pdu_t *pdu;
+
+	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		return;
+	}
+
+	tcp_transmit_pdu(pdu);
+	tcp_pdu_delete(pdu);
+}
+
+static void retransmit_timeout_func(void *arg)
+{
+	tcp_conn_t *conn = (tcp_conn_t *) arg;
+	tcp_tqueue_entry_t *tqe;
+	tcp_segment_t *rt_seg;
+	link_t *link;
+
+	log_msg(LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
+
+	fibril_mutex_lock(&conn->lock);
+
+	if (conn->cstate == st_closed) {
+		log_msg(LVL_DEBUG, "Connection already closed.");
+		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_delref(conn);
+		return;
+	}
+
+	link = list_first(&conn->retransmit.list);
+	if (link == NULL) {
+		log_msg(LVL_DEBUG, "Nothing to retransmit");
+		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_delref(conn);
+		return;
+	}
+
+	tqe = list_get_instance(link, tcp_tqueue_entry_t, link);
+
+	rt_seg = tcp_segment_dup(tqe->seg);
+	if (rt_seg == NULL) {
+		log_msg(LVL_ERROR, "Memory allocation failed.");
+		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_delref(conn);
+		/* XXX Handle properly */
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "### %s: retransmitting segment", conn->name);
+	tcp_conn_transmit_segment(tqe->conn, rt_seg);
+
+	/* Reset retransmission timer */
+	tcp_tqueue_timer_set(tqe->conn);
+
+	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_delref(conn);
+}
+
+/** Set or re-set retransmission timer */
+static void tcp_tqueue_timer_set(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
+
+	/* Clear first to make sure we update refcnt correctly */
+	tcp_tqueue_timer_clear(conn);
+
+	tcp_conn_addref(conn);
+	fibril_timer_set(conn->retransmit.timer, RETRANSMIT_TIMEOUT,
+	    retransmit_timeout_func, (void *) conn);
+}
+
+/** Clear retransmission timer */
+static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
+
+	if (fibril_timer_clear(conn->retransmit.timer) == fts_active)
+		tcp_conn_delref(conn);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/tqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/tqueue.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP transmission queue
+ */
+
+#ifndef TQUEUE_H
+#define TQUEUE_H
+
+#include "std.h"
+#include "tcp_type.h"
+
+extern int tcp_tqueue_init(tcp_tqueue_t *, tcp_conn_t *);
+extern void tcp_tqueue_clear(tcp_tqueue_t *);
+extern void tcp_tqueue_fini(tcp_tqueue_t *);
+extern void tcp_tqueue_ctrl_seg(tcp_conn_t *, tcp_control_t);
+extern void tcp_tqueue_seg(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_tqueue_new_data(tcp_conn_t *);
+extern void tcp_tqueue_ack_received(tcp_conn_t *);
+extern void tcp_prepare_transmit_segment(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_conn_transmit_segment(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_transmit_segment(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_header_setup(tcp_conn_t *, tcp_segment_t *, tcp_header_t *);
+extern void tcp_phdr_setup(tcp_conn_t *, tcp_segment_t *, tcp_phdr_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/ucall.c
===================================================================
--- uspace/srv/net/tl/tcp/ucall.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/ucall.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP entry points (close to those defined in the RFC)
+ */
+
+#include <fibril_synch.h>
+#include <io/log.h>
+#include <macros.h>
+#include <mem.h>
+#include "conn.h"
+#include "tcp_type.h"
+#include "tqueue.h"
+#include "ucall.h"
+
+/*
+ * User calls
+ */
+
+/** OPEN user call
+ *
+ * @param lsock		Local socket
+ * @param fsock		Foreign socket
+ * @param acpass	Active/passive
+ * @param conn		Connection
+ *
+ * Unlike in the spec we allow specifying the local address. This means
+ * the implementation does not need to magically guess it, especially
+ * considering there can be more than one local address.
+ *
+ * XXX We should be able to call active open on an existing listening
+ * connection.
+ * XXX We should be able to get connection structure immediately, before
+ * establishment.
+ */
+tcp_error_t tcp_uc_open(tcp_sock_t *lsock, tcp_sock_t *fsock, acpass_t acpass,
+    tcp_conn_t **conn)
+{
+	tcp_conn_t *nconn;
+
+	log_msg(LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %p)",
+	    lsock, fsock, acpass == ap_active ? "active" : "passive",
+	    conn);
+
+	nconn = tcp_conn_new(lsock, fsock);
+	tcp_conn_add(nconn);
+
+	if (acpass == ap_active) {
+		/* Synchronize (initiate) connection */
+		tcp_conn_sync(nconn);
+	}
+
+	/* Wait for connection to be established or reset */
+	log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
+	fibril_mutex_lock(&nconn->lock);
+	while (nconn->cstate == st_listen ||
+	    nconn->cstate == st_syn_sent ||
+	    nconn->cstate == st_syn_received) {
+		fibril_condvar_wait(&nconn->cstate_cv, &nconn->lock);
+	}
+
+	if (nconn->cstate != st_established) {
+		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
+		assert(nconn->cstate == st_closed);
+		fibril_mutex_unlock(&nconn->lock);
+		return TCP_ERESET;
+	}
+
+	fibril_mutex_unlock(&nconn->lock);
+	log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
+
+	*conn = nconn;
+	return TCP_EOK;
+}
+
+/** SEND user call */
+tcp_error_t tcp_uc_send(tcp_conn_t *conn, void *data, size_t size,
+    xflags_t flags)
+{
+	size_t buf_free;
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
+
+	fibril_mutex_lock(&conn->lock);
+
+	if (conn->cstate == st_closed) {
+		fibril_mutex_unlock(&conn->lock);
+		return TCP_ENOTEXIST;
+	}
+
+	if (conn->cstate == st_listen) {
+		/* Change connection to active */
+		tcp_conn_sync(conn);
+	}
+
+
+	if (conn->snd_buf_fin) {
+		fibril_mutex_unlock(&conn->lock);
+		return TCP_ECLOSING;
+	}
+
+	while (size > 0) {
+		buf_free = conn->snd_buf_size - conn->snd_buf_used;
+		while (buf_free == 0 && !conn->reset) {
+			log_msg(LVL_DEBUG, "%s: buf_free == 0, waiting.",
+			    conn->name);
+			fibril_condvar_wait(&conn->snd_buf_cv, &conn->lock);
+			buf_free = conn->snd_buf_size - conn->snd_buf_used;
+		}
+
+		if (conn->reset) {
+			fibril_mutex_unlock(&conn->lock);
+			return TCP_ERESET;
+		}
+
+		xfer_size = min(size, buf_free);
+
+		/* Copy data to buffer */
+		memcpy(conn->snd_buf + conn->snd_buf_used, data, xfer_size);
+		data += xfer_size;
+		conn->snd_buf_used += xfer_size;
+		size -= xfer_size;
+
+		tcp_tqueue_new_data(conn);
+	}
+
+	tcp_tqueue_new_data(conn);
+	fibril_mutex_unlock(&conn->lock);
+
+	return TCP_EOK;
+}
+
+/** RECEIVE user call */
+tcp_error_t tcp_uc_receive(tcp_conn_t *conn, void *buf, size_t size,
+    size_t *rcvd, xflags_t *xflags)
+{
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
+
+	fibril_mutex_lock(&conn->lock);
+
+	if (conn->cstate == st_closed) {
+		fibril_mutex_unlock(&conn->lock);
+		return TCP_ENOTEXIST;
+	}
+
+	/* Wait for data to become available */
+	while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin && !conn->reset) {
+		log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
+		fibril_condvar_wait(&conn->rcv_buf_cv, &conn->lock);
+	}
+
+	if (conn->rcv_buf_used == 0) {
+		*rcvd = 0;
+		*xflags = 0;
+
+		if (conn->rcv_buf_fin) {
+			/* End of data, peer closed connection */
+			fibril_mutex_unlock(&conn->lock);
+			return TCP_ECLOSING;
+		} else {
+			/* Connection was reset */
+			assert(conn->reset);
+			fibril_mutex_unlock(&conn->lock);
+			return TCP_ERESET;
+		}
+	}
+
+	/* Copy data from receive buffer to user buffer */
+	xfer_size = min(size, conn->rcv_buf_used);
+	memcpy(buf, conn->rcv_buf, xfer_size);
+	*rcvd = xfer_size;
+
+	/* Remove data from receive buffer */
+	memmove(conn->rcv_buf, conn->rcv_buf + xfer_size, conn->rcv_buf_used -
+	    xfer_size);
+	conn->rcv_buf_used -= xfer_size;
+	conn->rcv_wnd += xfer_size;
+
+	/* TODO */
+	*xflags = 0;
+
+	/* Send new size of receive window */
+	tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+	log_msg(LVL_DEBUG, "%s: tcp_uc_receive() - returning %zu bytes",
+	    conn->name, xfer_size);
+
+	fibril_mutex_unlock(&conn->lock);
+
+	return TCP_EOK;
+}
+
+/** CLOSE user call */
+tcp_error_t tcp_uc_close(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
+
+	fibril_mutex_lock(&conn->lock);
+
+	if (conn->cstate == st_closed) {
+		fibril_mutex_unlock(&conn->lock);
+		return TCP_ENOTEXIST;
+	}
+
+	if (conn->snd_buf_fin) {
+		fibril_mutex_unlock(&conn->lock);
+		return TCP_ECLOSING;
+	}
+
+	conn->snd_buf_fin = true;
+	tcp_tqueue_new_data(conn);
+
+	fibril_mutex_unlock(&conn->lock);
+	return TCP_EOK;
+}
+
+/** ABORT user call */
+void tcp_uc_abort(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_abort()");
+}
+
+/** STATUS user call */
+void tcp_uc_status(tcp_conn_t *conn, tcp_conn_status_t *cstatus)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_status()");
+}
+
+/** Delete connection user call.
+ *
+ * (Not in spec.) Inform TCP that the user is done with this connection
+ * and will not make any further calls/references to it. TCP can deallocate
+ * the connection from now on.
+ */
+void tcp_uc_delete(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_delete()");
+	tcp_conn_delete(conn);
+}
+
+/*
+ * Arriving segments
+ */
+
+/** Segment arrived */
+void tcp_as_segment_arrived(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_conn_t *conn;
+
+	log_msg(LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))",
+	    sp->foreign.addr.ipv4, sp->foreign.port,
+	    sp->local.addr.ipv4, sp->local.port);
+
+	conn = tcp_conn_find_ref(sp);
+	if (conn == NULL) {
+		log_msg(LVL_WARN, "No connection found.");
+		tcp_unexpected_segment(sp, seg);
+		return;
+	}
+
+	fibril_mutex_lock(&conn->lock);
+
+	if (conn->cstate == st_closed) {
+		log_msg(LVL_WARN, "Connection is closed.");
+		tcp_unexpected_segment(sp, seg);
+		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_delref(conn);
+		return;
+	}
+
+	if (conn->ident.foreign.addr.ipv4 == TCP_IPV4_ANY)
+		conn->ident.foreign.addr.ipv4 = sp->foreign.addr.ipv4;
+	if (conn->ident.foreign.port == TCP_PORT_ANY)
+		conn->ident.foreign.port = sp->foreign.port;
+	if (conn->ident.local.addr.ipv4 == TCP_IPV4_ANY)
+		conn->ident.local.addr.ipv4 = sp->local.addr.ipv4;
+
+	tcp_conn_segment_arrived(conn, seg);
+
+	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_delref(conn);
+}
+
+/*
+ * Timeouts
+ */
+
+/** User timeout */
+void tcp_to_user(void)
+{
+	log_msg(LVL_DEBUG, "tcp_to_user()");
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/ucall.h
===================================================================
--- uspace/srv/net/tl/tcp/ucall.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
+++ uspace/srv/net/tl/tcp/ucall.h	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP user calls (close to those defined in the RFC)
+ */
+
+#ifndef UCALL_H
+#define UCALL_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+/*
+ * User calls
+ */
+extern tcp_error_t tcp_uc_open(tcp_sock_t *, tcp_sock_t *, acpass_t, tcp_conn_t **);
+extern tcp_error_t tcp_uc_send(tcp_conn_t *, void *, size_t, xflags_t);
+extern tcp_error_t tcp_uc_receive(tcp_conn_t *, void *, size_t, size_t *, xflags_t *);
+extern tcp_error_t tcp_uc_close(tcp_conn_t *);
+extern void tcp_uc_abort(tcp_conn_t *);
+extern void tcp_uc_status(tcp_conn_t *, tcp_conn_status_t *);
+extern void tcp_uc_delete(tcp_conn_t *);
+
+/*
+ * Arriving segments
+ */
+extern void tcp_as_segment_arrived(tcp_sockpair_t *, tcp_segment_t *);
+
+/*
+ * Timeouts
+ */
+extern void tcp_to_user(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision cf5c05c0d7db41eddaceef9f32c5f35a3fd89289)
+++ uspace/srv/vfs/vfs.c	(revision b39eb797516ad8a55b8d1e661c09436f7633cbaf)
@@ -172,12 +172,7 @@
 	 * Allocate and initialize the Path Lookup Buffer.
 	 */
-	plb = as_get_mappable_page(PLB_SIZE);
-	if (!plb) {
-		printf(NAME ": Cannot allocate a mappable piece of address space\n");
-		return ENOMEM;
-	}
-	
-	if (as_area_create(plb, PLB_SIZE, AS_AREA_READ | AS_AREA_WRITE |
-	    AS_AREA_CACHEABLE) != plb) {
+	plb = as_area_create((void *) -1, PLB_SIZE,
+	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
+	if (plb == (void *) -1) {
 		printf(NAME ": Cannot create address space area\n");
 		return ENOMEM;
