Index: abi/include/ddi/arg.h
===================================================================
--- abi/include/ddi/arg.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ abi/include/ddi/arg.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ abi/include/ipc/methods.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ abi/include/syscall.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ boot/Makefile.common	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -105,4 +105,5 @@
 	$(USPACE_PATH)/srv/fs/exfat/exfat \
 	$(USPACE_PATH)/srv/fs/ext2fs/ext2fs \
+	$(USPACE_PATH)/srv/hid/remcons/remcons \
 	$(USPACE_PATH)/srv/taskmon/taskmon \
 	$(USPACE_PATH)/srv/net/nil/eth/eth \
@@ -123,5 +124,7 @@
 	test/test3 \
 	nic/lo \
-	nic/ne2k
+	nic/ne2k \
+	nic/e1k \
+	nic/rtl8139
 
 RD_DRV_CFG =
@@ -174,4 +177,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 +206,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: boot/Makefile.grub
===================================================================
--- boot/Makefile.grub	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ boot/Makefile.grub	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -52,8 +52,8 @@
 $(BOOT_OUTPUT): build_dist
 ifeq ($(GRUB_ARCH),pc)
-	mkisofs -J -r -input-charset utf-8 -V "HelenOS boot ISO" -eltorito-boot $(ELTORITO) -no-emul-boot -boot-load-size 64 -boot-info-table -o $@ $(DISTROOT)/
+	$(GENISOIMAGE) -J -r -input-charset utf-8 -V "HelenOS boot ISO" -eltorito-boot $(ELTORITO) -no-emul-boot -boot-load-size 64 -boot-info-table -o $@ $(DISTROOT)/
 endif
 ifeq ($(GRUB_ARCH),efi)
-	mkisofs -J -r -input-charset utf-8 -V "HelenOS boot ISO" -efi-boot $(ELTORITO) -o $@ $(DISTROOT)/
+	$(GENISOIMAGE) -J -r -input-charset utf-8 -V "HelenOS boot ISO" -efi-boot $(ELTORITO) -o $@ $(DISTROOT)/
 endif
 
@@ -89,5 +89,5 @@
 			echo "	$(MULTIBOOT_CMD) /boot/$$module" >> $(BOOT_CONFIG) ; \
 		else \
-			echo "	$(MODULE_CMD) /boot/$$module" >> $(BOOT_CONFIG) ; \
+			echo "	$(MODULE_CMD) /boot/$$module /boot/$$module" >> $(BOOT_CONFIG) ; \
 		fi \
 	done
Index: boot/Makefile.silo
===================================================================
--- boot/Makefile.silo	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ boot/Makefile.silo	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,5 +41,5 @@
 
 $(POST_OUTPUT): build_dist
-	mkisofs -f -G $(ISOFS_B_IN) -B ... -r -o $@ $(DISTROOT)/
+	$(GENISOIMAGE) -f -G $(ISOFS_B_IN) -B ... -r -o $@ $(DISTROOT)/
 
 build_dist: clean
Index: boot/Makefile.yaboot
===================================================================
--- boot/Makefile.yaboot	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ boot/Makefile.yaboot	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,5 +40,5 @@
 
 $(POST_OUTPUT): build_dist
-	mkisofs -hfs -part -map $(MAPS) -no-desktop -hfs-volid "HelenOS" -hfs-bless $(DISTROOT)/boot -r -o $@ $(DISTROOT)/
+	$(GENISOIMAGE) -hfs -part -map $(MAPS) -no-desktop -hfs-volid "HelenOS" -hfs-bless $(DISTROOT)/boot -r -o $@ $(DISTROOT)/
 
 build_dist: clean
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ boot/arch/amd64/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -28,5 +28,4 @@
 
 RD_SRVS_ESSENTIAL += \
-	$(USPACE_PATH)/srv/hw/char/i8042/i8042 \
 	$(USPACE_PATH)/srv/hw/irc/apic/apic \
 	$(USPACE_PATH)/srv/hw/irc/i8259/i8259
@@ -39,5 +38,8 @@
 	bus/pci/pciintel \
 	bus/isa \
+	char/i8042 \
 	char/ns8250 \
+	char/ps2mouse \
+	char/xtkbd \
 	bus/usb/ehci\
 	bus/usb/ohci \
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ boot/arch/ia64/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -37,6 +37,5 @@
 RD_SRVS_NON_ESSENTIAL +=
 
-RD_SRVS_ESSENTIAL += \
-	$(USPACE_PATH)/srv/hw/char/i8042/i8042
+RD_SRVS_ESSENTIAL +=
 
 SOURCES = \
Index: contrib/conf/net-qe.sh
===================================================================
--- contrib/conf/net-qe.sh	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ contrib/conf/net-qe.sh	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,12 +1,18 @@
 #!/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
+		;;
+	rtl8139)
+		shift
+		qemu $@ -device rtl8139,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|rtl8139}"
+esac
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -229,4 +229,5 @@
 	generic/src/syscall/syscall.c \
 	generic/src/syscall/copy.c \
+	generic/src/mm/km.c \
 	generic/src/mm/reserve.c \
 	generic/src/mm/buddy.c \
@@ -245,4 +246,5 @@
 	generic/src/lib/str.c \
 	generic/src/lib/elf.c \
+	generic/src/lib/ra.c \
 	generic/src/lib/rd.c \
 	generic/src/printf/printf_core.c \
Index: kernel/arch/abs32le/Makefile.inc
===================================================================
--- kernel/arch/abs32le/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/abs32le/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -57,4 +57,5 @@
 	arch/$(KARCH)/src/smp/smp.c \
 	arch/$(KARCH)/src/smp/ipi.c \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/as.c \
 	arch/$(KARCH)/src/mm/frame.c \
Index: kernel/arch/abs32le/include/mm/frame.h
===================================================================
--- kernel/arch/abs32le/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/abs32le/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,5 +41,6 @@
 #include <typedefs.h>
 
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void physmem_print(void);
 
Index: kernel/arch/abs32le/include/mm/km.h
===================================================================
--- kernel/arch/abs32le/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/abs32le/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup abs32lemm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_abs32le_KM_H_
+#define KERN_abs32le_KM_H_
+
+#include <typedefs.h>
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/abs32le/src/abs32le.c
===================================================================
--- kernel/arch/abs32le/src/abs32le.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/abs32le/src/abs32le.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -49,5 +49,4 @@
 #include <syscall/syscall.h>
 #include <console/console.h>
-#include <sysinfo/sysinfo.h>
 #include <memstr.h>
 
@@ -86,5 +85,5 @@
 }
 
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	return EOK;
Index: kernel/arch/abs32le/src/mm/frame.c
===================================================================
--- kernel/arch/abs32le/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/abs32le/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -50,5 +50,9 @@
 
 
-void frame_arch_init(void)
+void frame_low_arch_init(void)
+{
+}
+
+void frame_high_arch_init(void)
 {
 }
Index: kernel/arch/abs32le/src/mm/km.c
===================================================================
--- kernel/arch/abs32le/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/abs32le/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup abs32lemm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <typedefs.h>
+
+void km_identity_arch_init(void)
+{
+}
+
+void km_non_identity_arch_init(void)
+{
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return false;
+}
+
+/** @}
+ */
Index: kernel/arch/abs32le/src/mm/page.c
===================================================================
--- kernel/arch/abs32le/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/abs32le/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -56,10 +56,4 @@
 }
 
-
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	return physaddr;
-}
-
 void page_fault(unsigned int n __attribute__((unused)), istate_t *istate)
 {
Index: kernel/arch/amd64/Makefile.inc
===================================================================
--- kernel/arch/amd64/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/amd64/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -86,4 +86,5 @@
 	arch/$(KARCH)/src/bios/bios.c \
 	arch/$(KARCH)/src/interrupt.c \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/as.c \
 	arch/$(KARCH)/src/mm/frame.c \
Index: kernel/arch/amd64/include/interrupt.h
===================================================================
--- kernel/arch/amd64/include/interrupt.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/amd64/include/interrupt.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -55,5 +55,4 @@
 #define IRQ_PIC_SPUR  7
 #define IRQ_MOUSE     12
-#define IRQ_NE2000    9
 
 /* This one must have four least significant bits set to ones */
Index: kernel/arch/amd64/include/mm/frame.h
===================================================================
--- kernel/arch/amd64/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/amd64/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,6 +43,6 @@
 #include <typedefs.h>
 
-extern uintptr_t last_frame;
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void physmem_print(void);
 
Index: kernel/arch/amd64/include/mm/km.h
===================================================================
--- kernel/arch/amd64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/amd64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup amd64mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_amd64_KM_H_
+#define KERN_amd64_KM_H_
+
+#include <typedefs.h>
+
+#define KM_AMD64_IDENTITY_START		UINT64_C(0xffff800000000000)
+#define KM_AMD64_IDENTITY_SIZE		UINT64_C(0x0000400000000000)
+
+#define KM_AMD64_NON_IDENTITY_START	UINT64_C(0xffffc00000000000)
+#define KM_AMD64_NON_IDENTITY_SIZE	UINT64_C(0x0000400000000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/amd64/src/amd64.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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
@@ -224,22 +214,8 @@
 		}
 	}
-	
-	/*
-	 * This is the necessary evil until the userspace driver is entirely
-	 * self-sufficient.
-	 */
-	sysinfo_set_item_val("i8042", NULL, true);
-	sysinfo_set_item_val("i8042.inr_a", NULL, IRQ_KBD);
-	sysinfo_set_item_val("i8042.inr_b", NULL, IRQ_MOUSE);
-	sysinfo_set_item_val("i8042.address.physical", NULL,
-	    (uintptr_t) I8042_BASE);
-	sysinfo_set_item_val("i8042.address.kernel", NULL,
-	    (uintptr_t) I8042_BASE);
 #endif
 	
 	if (irqs_info != NULL)
 		sysinfo_set_item_val(irqs_info, NULL, true);
-	
-	sysinfo_set_item_val("netif.ne2000.inr", NULL, IRQ_NE2000);
 }
 
@@ -264,10 +240,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/amd64/src/boot/multiboot2.S
===================================================================
--- kernel/arch/amd64/src/boot/multiboot2.S	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/amd64/src/boot/multiboot2.S	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -55,5 +55,7 @@
 		.long MULTIBOOT2_TAG_MODULE
 		.long MULTIBOOT2_TAG_MEMMAP
+#ifdef CONFIG_FB
 		.long MULTIBOOT2_TAG_FBINFO
+#endif
 	tag_info_req_end:
 	
@@ -85,4 +87,5 @@
 	tag_flags_end:
 	
+#ifdef CONFIG_FB
 	/* Framebuffer tag */
 	tag_framebuffer_start:
@@ -94,4 +97,5 @@
 		.long CONFIG_BFB_BPP
 	tag_framebuffer_end:
+#endif
 	
 	/* Module alignment tag */
Index: kernel/arch/amd64/src/mm/km.c
===================================================================
--- kernel/arch/amd64/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/amd64/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup amd64mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_AMD64_IDENTITY_START;
+	config.identity_size = KM_AMD64_IDENTITY_SIZE;	
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_AMD64_NON_IDENTITY_START,
+	    KM_AMD64_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_AMD64_NON_IDENTITY_START,
+	    KM_AMD64_NON_IDENTITY_SIZE, addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/amd64/src/mm/page.c
===================================================================
--- kernel/arch/amd64/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/amd64/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,28 +46,32 @@
 #include <panic.h>
 #include <align.h>
+#include <macros.h>
 
 void page_arch_init(void)
 {
-	if (config.cpu_active == 1) {
-		uintptr_t cur;
-		unsigned int identity_flags =
-		    PAGE_CACHEABLE | PAGE_EXEC | PAGE_GLOBAL | PAGE_WRITE;
+	if (config.cpu_active > 1) {
+		write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
+		return;
+	}
+
+	uintptr_t cur;
+	unsigned int identity_flags =
+	    PAGE_CACHEABLE | PAGE_EXEC | PAGE_GLOBAL | PAGE_WRITE;
 		
-		page_mapping_operations = &pt_mapping_operations;
+	page_mapping_operations = &pt_mapping_operations;
 		
-		page_table_lock(AS_KERNEL, true);
+	page_table_lock(AS_KERNEL, true);
 		
-		/*
-		 * PA2KA(identity) mapping for all frames.
-		 */
-		for (cur = 0; cur < last_frame; cur += FRAME_SIZE)
-			page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, identity_flags);
+	/*
+	 * PA2KA(identity) mapping for all low-memory frames.
+	 */
+	for (cur = 0; cur < min(config.identity_size, config.physmem_end);
+	    cur += FRAME_SIZE)
+		page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, identity_flags);
 		
-		page_table_unlock(AS_KERNEL, true);
+	page_table_unlock(AS_KERNEL, true);
 		
-		exc_register(14, "page_fault", true, (iroutine_t) page_fault);
-		write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
-	} else
-		write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
+	exc_register(14, "page_fault", true, (iroutine_t) page_fault);
+	write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
 }
 
@@ -94,25 +98,4 @@
 }
 
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
-		panic("Unable to map physical memory %p (%zu bytes).",
-		    (void *) physaddr, size);
-	
-	uintptr_t virtaddr = PA2KA(last_frame);
-	pfn_t i;
-	
-	page_table_lock(AS_KERNEL, true);
-	
-	for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
-		page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_WRITE);
-	
-	page_table_unlock(AS_KERNEL, true);
-	
-	last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
-	
-	return virtaddr;
-}
-
 /** @}
  */
Index: kernel/arch/arm32/Makefile.inc
===================================================================
--- kernel/arch/arm32/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -53,4 +53,5 @@
 	arch/$(KARCH)/src/debug/stacktrace.c \
 	arch/$(KARCH)/src/debug/stacktrace_asm.S \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/as.c \
 	arch/$(KARCH)/src/mm/frame.c \
Index: kernel/arch/arm32/include/mach/integratorcp/integratorcp.h
===================================================================
--- kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -103,5 +103,5 @@
 extern void icp_cpu_halt(void);
 extern void icp_irq_exception(unsigned int, istate_t *);
-extern void icp_get_memory_extents(uintptr_t *, uintptr_t *);
+extern void icp_get_memory_extents(uintptr_t *, size_t *);
 extern void icp_frame_init(void);
 extern size_t icp_get_irq_count(void);
Index: kernel/arch/arm32/include/mach/testarm/testarm.h
===================================================================
--- kernel/arch/arm32/include/mach/testarm/testarm.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/include/mach/testarm/testarm.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -71,5 +71,5 @@
 extern void gxemul_cpu_halt(void);
 extern void gxemul_irq_exception(unsigned int, istate_t *);
-extern void gxemul_get_memory_extents(uintptr_t *, uintptr_t *);
+extern void gxemul_get_memory_extents(uintptr_t *, size_t *);
 extern void gxemul_frame_init(void);
 extern size_t gxemul_get_irq_count(void);
Index: kernel/arch/arm32/include/machine_func.h
===================================================================
--- kernel/arch/arm32/include/machine_func.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/include/machine_func.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -50,5 +50,5 @@
 	void (*machine_timer_irq_start)(void);
 	void (*machine_cpu_halt)(void);
-	void (*machine_get_memory_extents)(uintptr_t *, uintptr_t *);
+	void (*machine_get_memory_extents)(uintptr_t *, size_t *);
 	void (*machine_irq_exception)(unsigned int, istate_t *);
 	void (*machine_frame_init)(void);
@@ -81,5 +81,5 @@
  * @param size		Place to store memory size.
  */
-extern void machine_get_memory_extents(uintptr_t *start, uintptr_t *size);
+extern void machine_get_memory_extents(uintptr_t *start, size_t *size);
 
 /** Interrupt exception handler.
Index: kernel/arch/arm32/include/mm/frame.h
===================================================================
--- kernel/arch/arm32/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -61,7 +61,6 @@
 #endif
 
-extern uintptr_t last_frame;
-
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void boot_page_table_free(void);
 #define physmem_print()
Index: kernel/arch/arm32/include/mm/km.h
===================================================================
--- kernel/arch/arm32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/arm32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup arm32mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_arm32_KM_H_
+#define KERN_arm32_KM_H_
+
+#include <typedefs.h>
+
+#define KM_ARM32_IDENTITY_START		UINT32_C(0x80000000)
+#define KM_ARM32_IDENTITY_SIZE		UINT32_C(0x70000000)
+
+#define KM_ARM32_NON_IDENTITY_START	UINT32_C(0xf0000000)
+/*
+ * The last virtual megabyte contains the high exception vectors (0xFFFF0000).
+ * Do not include this range into kernel non-identity.
+ */
+#define KM_ARM32_NON_IDENTITY_SIZE	UINT32_C(0x0ff00000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/arm32/include/mm/page.h
===================================================================
--- kernel/arch/arm32/include/mm/page.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/include/mm/page.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -54,9 +54,9 @@
 
 /* Number of entries in each level. */
-#define PTL0_ENTRIES_ARCH 	(2 << 12)	/* 4096 */
+#define PTL0_ENTRIES_ARCH 	(1 << 12)	/* 4096 */
 #define PTL1_ENTRIES_ARCH 	0
 #define PTL2_ENTRIES_ARCH 	0
 /* coarse page tables used (256 * 4 = 1KB per page) */
-#define PTL3_ENTRIES_ARCH 	(2 << 8)	/* 256 */
+#define PTL3_ENTRIES_ARCH 	(1 << 8)	/* 256 */
 
 /* Page table sizes for each level. */
Index: kernel/arch/arm32/src/arm32.c
===================================================================
--- kernel/arch/arm32/src/arm32.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/arm32.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -38,5 +38,4 @@
 #include <genarch/fb/fb.h>
 #include <abi/fb/visuals.h>
-#include <sysinfo/sysinfo.h>
 #include <console/console.h>
 #include <ddi/irq.h>
@@ -58,5 +57,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr = (uintptr_t) bootinfo->tasks[i].addr;
+		init.tasks[i].paddr = KA2PA(bootinfo->tasks[i].addr);
 		init.tasks[i].size = bootinfo->tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
Index: kernel/arch/arm32/src/mach/gta02/gta02.c
===================================================================
--- kernel/arch/arm32/src/mach/gta02/gta02.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/mach/gta02/gta02.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -38,4 +38,5 @@
 #include <arch/mm/page.h>
 #include <mm/page.h>
+#include <mm/km.h>
 #include <genarch/fb/fb.h>
 #include <abi/fb/visuals.h>
@@ -65,5 +66,5 @@
 static void gta02_timer_irq_start(void);
 static void gta02_cpu_halt(void);
-static void gta02_get_memory_extents(uintptr_t *start, uintptr_t *size);
+static void gta02_get_memory_extents(uintptr_t *start, size_t *size);
 static void gta02_irq_exception(unsigned int exc_no, istate_t *istate);
 static void gta02_frame_init(void);
@@ -101,6 +102,8 @@
 	s3c24xx_irqc_regs_t *irqc_regs;
 
-	gta02_timer = (void *) hw_map(S3C24XX_TIMER_ADDRESS, PAGE_SIZE);
-	irqc_regs = (void *) hw_map(S3C24XX_IRQC_ADDRESS, PAGE_SIZE);
+	gta02_timer = (void *) km_map(S3C24XX_TIMER_ADDRESS, PAGE_SIZE,
+	    PAGE_NOT_CACHEABLE);
+	irqc_regs = (void *) km_map(S3C24XX_IRQC_ADDRESS, PAGE_SIZE,
+	    PAGE_NOT_CACHEABLE);
 
 	/* Initialize interrupt controller. */
@@ -123,5 +126,5 @@
  * @param size		Place to store memory size.
  */
-static void gta02_get_memory_extents(uintptr_t *start, uintptr_t *size)
+static void gta02_get_memory_extents(uintptr_t *start, size_t *size)
 {
 	*start = GTA02_MEMORY_START + GTA02_MEMORY_SKIP;
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -45,4 +45,5 @@
 #include <mm/page.h>
 #include <mm/frame.h>
+#include <mm/km.h>
 #include <arch/mm/frame.h>
 #include <arch/mach/integratorcp/integratorcp.h>
@@ -128,10 +129,12 @@
 void icp_init(void)
 {
-	icp_hw_map.uart = hw_map(ICP_UART, PAGE_SIZE);
-	icp_hw_map.kbd_ctrl = hw_map(ICP_KBD, PAGE_SIZE);
+	icp_hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	icp_hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
 	icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
 	icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
 	icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
-	icp_hw_map.rtc = hw_map(ICP_RTC, PAGE_SIZE);
+	icp_hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
 	icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
@@ -141,10 +144,13 @@
 	icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
 
-	icp_hw_map.irqc = hw_map(ICP_IRQC, PAGE_SIZE);
+	icp_hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
 	icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
-	icp_hw_map.cmcr = hw_map(ICP_CMCR, PAGE_SIZE);
+	icp_hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
-	icp_hw_map.vga = hw_map(ICP_VGA, PAGE_SIZE);
+	icp_hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 
 	hw_map_init_called = true;
@@ -220,5 +226,5 @@
  * @param size		Place to store memory size.
  */
-void icp_get_memory_extents(uintptr_t *start, uintptr_t *size)
+void icp_get_memory_extents(uintptr_t *start, size_t *size)
 {
 	*start = 0;
Index: kernel/arch/arm32/src/mach/testarm/testarm.c
===================================================================
--- kernel/arch/arm32/src/mach/testarm/testarm.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/mach/testarm/testarm.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -37,4 +37,5 @@
 #include <arch/mach/testarm/testarm.h>
 #include <mm/page.h>
+#include <mm/km.h>
 #include <genarch/fb/fb.h>
 #include <abi/fb/visuals.h>
@@ -71,7 +72,10 @@
 void gxemul_init(void)
 {
-	gxemul_kbd = (void *) hw_map(GXEMUL_KBD_ADDRESS, PAGE_SIZE);
-	gxemul_rtc = (void *) hw_map(GXEMUL_RTC_ADDRESS, PAGE_SIZE);
-	gxemul_irqc = (void *) hw_map(GXEMUL_IRQC_ADDRESS, PAGE_SIZE);
+	gxemul_kbd = (void *) km_map(GXEMUL_KBD_ADDRESS, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	gxemul_rtc = (void *) km_map(GXEMUL_RTC_ADDRESS, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	gxemul_irqc = (void *) km_map(GXEMUL_IRQC_ADDRESS, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 }
 
@@ -202,8 +206,8 @@
  * @param size		Place to store memory size.
  */
-void gxemul_get_memory_extents(uintptr_t *start, uintptr_t *size)
+void gxemul_get_memory_extents(uintptr_t *start, size_t *size)
 {
 	*start = 0;
-        *size = *((uintptr_t *) (GXEMUL_MP_ADDRESS + GXEMUL_MP_MEMSIZE_OFFSET));
+	*size = *((uintptr_t *) (GXEMUL_MP_ADDRESS + GXEMUL_MP_MEMSIZE_OFFSET));
 }
 
Index: kernel/arch/arm32/src/machine_func.c
===================================================================
--- kernel/arch/arm32/src/machine_func.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/machine_func.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -85,5 +85,5 @@
  * @param size		Place to store memory size.
  */
-void machine_get_memory_extents(uintptr_t *start, uintptr_t *size)
+void machine_get_memory_extents(uintptr_t *start, size_t *size)
 {
 	(machine_ops->machine_get_memory_extents)(start, size);
Index: kernel/arch/arm32/src/mm/frame.c
===================================================================
--- kernel/arch/arm32/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,24 +39,37 @@
 #include <config.h>
 #include <align.h>
+#include <macros.h>
 
-/** Address of the last frame in the memory. */
-uintptr_t last_frame = 0;
+static void frame_common_arch_init(bool low)
+{
+	uintptr_t base;
+	size_t size;
 
-/** Creates memory zones. */
-void frame_arch_init(void)
+	machine_get_memory_extents(&base, &size);
+	base = ALIGN_UP(base, FRAME_SIZE);
+	size = ALIGN_DOWN(size, FRAME_SIZE);
+	
+	if (!frame_adjust_zone_bounds(low, &base, &size))
+		return;
+
+	if (low) {
+		zone_create(ADDR2PFN(base), SIZE2FRAMES(size),
+		    BOOT_PAGE_TABLE_START_FRAME +
+		    BOOT_PAGE_TABLE_SIZE_IN_FRAMES,
+		    ZONE_AVAILABLE | ZONE_LOWMEM);
+	} else {
+		pfn_t conf = zone_external_conf_alloc(SIZE2FRAMES(size));
+		if (conf != 0)
+			zone_create(ADDR2PFN(base), SIZE2FRAMES(size), conf,
+			    ZONE_AVAILABLE | ZONE_HIGHMEM);
+	}
+	
+}
+
+/** Create low memory zones. */
+void frame_low_arch_init(void)
 {
-	uintptr_t mem_start, mem_size;
-	uintptr_t first_frame;
-	uintptr_t num_frames;
+	frame_common_arch_init(true);
 
-	machine_get_memory_extents(&mem_start, &mem_size);
-	first_frame = ALIGN_UP(mem_start, FRAME_SIZE);
-	last_frame = ALIGN_DOWN(mem_start + mem_size, FRAME_SIZE);
-	num_frames = (last_frame - first_frame) >> FRAME_WIDTH;
-	
-	/* All memory as one zone */
-	zone_create(first_frame >> FRAME_WIDTH, num_frames,
-	    BOOT_PAGE_TABLE_START_FRAME + BOOT_PAGE_TABLE_SIZE_IN_FRAMES, 0);
-	
 	/* blacklist boot page table */
 	frame_mark_unavailable(BOOT_PAGE_TABLE_START_FRAME,
@@ -64,4 +77,10 @@
 
 	machine_frame_init();
+}
+
+/** Create high memory zones. */
+void frame_high_arch_init(void)
+{
+	frame_common_arch_init(false);
 }
 
Index: kernel/arch/arm32/src/mm/km.c
===================================================================
--- kernel/arch/arm32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/arm32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup arm32mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_ARM32_IDENTITY_START;
+	config.identity_size = KM_ARM32_IDENTITY_SIZE;
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_ARM32_NON_IDENTITY_START,
+	    KM_ARM32_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_ARM32_NON_IDENTITY_START,
+	    KM_ARM32_NON_IDENTITY_SIZE, addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/arm32/src/mm/page.c
===================================================================
--- kernel/arch/arm32/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -37,4 +37,5 @@
 #include <genarch/mm/page_pt.h>
 #include <mm/page.h>
+#include <arch/mm/frame.h>
 #include <align.h>
 #include <config.h>
@@ -42,5 +43,5 @@
 #include <typedefs.h>
 #include <interrupt.h>
-#include <arch/mm/frame.h>
+#include <macros.h>
 
 /** Initializes page tables.
@@ -57,17 +58,18 @@
 	
 	uintptr_t cur;
+
 	/* Kernel identity mapping */
-	for (cur = PHYSMEM_START_ADDR; cur < last_frame; cur += FRAME_SIZE)
+	for (cur = PHYSMEM_START_ADDR;
+	    cur < min(config.identity_size, config.physmem_end);
+	    cur += FRAME_SIZE)
 		page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
 	
+#ifdef HIGH_EXCEPTION_VECTORS
 	/* Create mapping for exception table at high offset */
-#ifdef HIGH_EXCEPTION_VECTORS
-	void *virtaddr = frame_alloc(ONE_FRAME, FRAME_KA);
-	page_mapping_insert(AS_KERNEL, EXC_BASE_ADDRESS, KA2PA(virtaddr), flags);
+	uintptr_t ev_frame = (uintptr_t) frame_alloc(ONE_FRAME, FRAME_NONE);
+	page_mapping_insert(AS_KERNEL, EXC_BASE_ADDRESS, ev_frame, flags);
 #else
 #error "Only high exception vector supported now"
 #endif
-	cur = ALIGN_DOWN(0x50008010, FRAME_SIZE);
-	page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
 
 	page_table_unlock(AS_KERNEL, true);
@@ -78,37 +80,4 @@
 }
 
-/** Maps device into the kernel space.
- *
- * Maps physical address of device into kernel virtual address space (so it can
- * be accessed only by kernel through virtual address).
- *
- * @param physaddr Physical address where device is connected.
- * @param size Length of area where device is present.
- *
- * @return Virtual address where device will be accessible.
- */
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	if (last_frame + ALIGN_UP(size, PAGE_SIZE) >
-	    KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH)) {
-		panic("Unable to map physical memory %p (%d bytes).",
-		    (void *) physaddr, size);
-	}
-	
-	uintptr_t virtaddr = PA2KA(last_frame);
-	pfn_t i;
-
-	page_table_lock(AS_KERNEL, true);
-	for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++) {
-		page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i),
-		    physaddr + PFN2ADDR(i),
-		    PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL);
-	}
-	page_table_unlock(AS_KERNEL, true);
-	
-	last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
-	return virtaddr;
-}
-
 /** @}
  */
Index: kernel/arch/arm32/src/ras.c
===================================================================
--- kernel/arch/arm32/src/ras.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/arm32/src/ras.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -38,4 +38,5 @@
 #include <mm/frame.h>
 #include <mm/page.h>
+#include <mm/km.h>
 #include <mm/tlb.h>
 #include <mm/asid.h>
@@ -50,18 +51,16 @@
 void ras_init(void)
 {
-	ras_page = frame_alloc(ONE_FRAME, FRAME_KA);
-	memsetb(ras_page, FRAME_SIZE, 0); 
+	uintptr_t frame;
+
+	frame = (uintptr_t) frame_alloc(ONE_FRAME,
+	    FRAME_ATOMIC | FRAME_HIGHMEM);
+	if (!frame)
+		frame = (uintptr_t) frame_alloc(ONE_FRAME, FRAME_LOWMEM);
+	ras_page = (uintptr_t *) km_map(frame,
+	    PAGE_SIZE, PAGE_READ | PAGE_WRITE | PAGE_USER | PAGE_CACHEABLE);
+
+	memsetb(ras_page, PAGE_SIZE, 0); 
 	ras_page[RAS_START] = 0;
 	ras_page[RAS_END] = 0xffffffff;
-	/*
-	 * Userspace needs to be able to write to this page. The page is 
-	 * cached in TLB as PAGE_KERNEL. Purge it from TLB and map it
-	 * read/write PAGE_USER.
-	 */
-	tlb_invalidate_pages(ASID_KERNEL, (uintptr_t)ras_page, 1);
-	page_table_lock(AS, true);
-	page_mapping_insert(AS, (uintptr_t)ras_page, (uintptr_t)KA2PA(ras_page),
-	    PAGE_READ | PAGE_WRITE | PAGE_USER);
-	page_table_unlock(AS, true);
 }
 
Index: kernel/arch/ia32/Makefile.inc
===================================================================
--- kernel/arch/ia32/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -99,4 +99,5 @@
 	arch/$(KARCH)/src/userspace.c \
 	arch/$(KARCH)/src/cpu/cpu.c \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/as.c \
 	arch/$(KARCH)/src/mm/frame.c \
Index: kernel/arch/ia32/include/interrupt.h
===================================================================
--- kernel/arch/ia32/include/interrupt.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/include/interrupt.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -55,5 +55,4 @@
 #define IRQ_PIC_SPUR  7
 #define IRQ_MOUSE     12
-#define IRQ_NE2000    5
 
 /* This one must have four least significant bits set to ones */
Index: kernel/arch/ia32/include/mm/frame.h
===================================================================
--- kernel/arch/ia32/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,7 +43,6 @@
 #include <typedefs.h>
 
-extern uintptr_t last_frame;
-
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void physmem_print(void);
 
Index: kernel/arch/ia32/include/mm/km.h
===================================================================
--- kernel/arch/ia32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ia32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ia32mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_ia32_KM_H_
+#define KERN_ia32_KM_H_
+
+#include <typedefs.h>
+
+#define KM_IA32_IDENTITY_START		UINT32_C(0x80000000)
+#define KM_IA32_IDENTITY_SIZE		UINT32_C(0x40000000)
+
+#define KM_IA32_NON_IDENTITY_START	UINT32_C(0xc0000000)
+#define KM_IA32_NON_IDENTITY_SIZE	UINT32_C(0x40000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/ia32/src/boot/multiboot2.S
===================================================================
--- kernel/arch/ia32/src/boot/multiboot2.S	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/src/boot/multiboot2.S	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -53,5 +53,7 @@
 		.long MULTIBOOT2_TAG_MODULE
 		.long MULTIBOOT2_TAG_MEMMAP
+#ifdef CONFIG_FB
 		.long MULTIBOOT2_TAG_FBINFO
+#endif
 	tag_info_req_end:
 	
@@ -83,4 +85,5 @@
 	tag_flags_end:
 	
+#ifdef CONFIG_FB
 	/* Framebuffer tag */
 	tag_framebuffer_start:
@@ -92,4 +95,5 @@
 		.long CONFIG_BFB_BPP
 	tag_framebuffer_end:
+#endif
 	
 	/* Module alignment tag */
Index: kernel/arch/ia32/src/boot/vesa_real.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_real.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/src/boot/vesa_real.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/src/ia32.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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
@@ -182,22 +168,8 @@
 		}
 	}
-	
-	/*
-	 * This is the necessary evil until the userspace driver is entirely
-	 * self-sufficient.
-	 */
-	sysinfo_set_item_val("i8042", NULL, true);
-	sysinfo_set_item_val("i8042.inr_a", NULL, IRQ_KBD);
-	sysinfo_set_item_val("i8042.inr_b", NULL, IRQ_MOUSE);
-	sysinfo_set_item_val("i8042.address.physical", NULL,
-	    (uintptr_t) I8042_BASE);
-	sysinfo_set_item_val("i8042.address.kernel", NULL,
-	    (uintptr_t) I8042_BASE);
 #endif
 	
 	if (irqs_info != NULL)
 		sysinfo_set_item_val(irqs_info, NULL, true);
-	
-	sysinfo_set_item_val("netif.ne2000.inr", NULL, IRQ_NE2000);
 }
 
@@ -219,10 +191,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/ia32/src/mm/frame.c
===================================================================
--- kernel/arch/ia32/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,67 +46,33 @@
 #include <print.h>
 
-#define PHYSMEM_LIMIT32  UINT64_C(0x07c000000)
-#define PHYSMEM_LIMIT64  UINT64_C(0x200000000)
+#define PHYSMEM_LIMIT32  UINT64_C(0x100000000)
 
 size_t hardcoded_unmapped_ktext_size = 0;
 size_t hardcoded_unmapped_kdata_size = 0;
 
-uintptr_t last_frame = 0;
-
-static void init_e820_memory(pfn_t minconf)
+static void init_e820_memory(pfn_t minconf, bool low)
 {
 	unsigned int i;
 	
 	for (i = 0; i < e820counter; i++) {
-		uint64_t base = e820table[i].base_address;
-		uint64_t size = e820table[i].size;
+		uint64_t base64 = e820table[i].base_address;
+		uint64_t size64 = e820table[i].size;
 		
-#ifdef __32_BITS__
+#ifdef KARCH_ia32
 		/*
-		 * XXX FIXME:
-		 *
-		 * Ignore zones which start above PHYSMEM_LIMIT32
-		 * or clip zones which go beyond PHYSMEM_LIMIT32.
-		 *
-		 * The PHYSMEM_LIMIT32 (2 GB - 64 MB) is a rather
-		 * arbitrary constant which allows to have at
-		 * least 64 MB in the kernel address space to
-		 * map hardware resources.
-		 *
-		 * The kernel uses fixed 1:1 identity mapping
-		 * of the physical memory with 2:2 GB split.
-		 * This is a severe limitation of the current
-		 * kernel memory management.
-		 *
+		 * Restrict the e820 table entries to 32-bits.
 		 */
-		
-		if (base > PHYSMEM_LIMIT32)
+		if (base64 >= PHYSMEM_LIMIT32)
 			continue;
 		
-		if (base + size > PHYSMEM_LIMIT32)
-			size = PHYSMEM_LIMIT32 - base;
+		if (base64 + size64 > PHYSMEM_LIMIT32)
+			size64 = PHYSMEM_LIMIT32 - base64;
 #endif
 		
-#ifdef __64_BITS__
-		/*
-		 * XXX FIXME:
-		 *
-		 * Ignore zones which start above PHYSMEM_LIMIT64
-		 * or clip zones which go beyond PHYSMEM_LIMIT64.
-		 *
-		 * The PHYSMEM_LIMIT64 (8 GB) is the size of the
-		 * fixed 1:1 identically mapped physical memory
-		 * accessible during the bootstrap process.
-		 * This is a severe limitation of the current
-		 * kernel memory management.
-		 *
-		 */
+		uintptr_t base = (uintptr_t) base64;
+		size_t size = (size_t) size64;
 		
-		if (base > PHYSMEM_LIMIT64)
+		if (!frame_adjust_zone_bounds(low, &base, &size))
 			continue;
-		
-		if (base + size > PHYSMEM_LIMIT64)
-			size = PHYSMEM_LIMIT64 - base;
-#endif
 		
 		if (e820table[i].type == MEMMAP_MEMORY_AVAILABLE) {
@@ -116,18 +82,21 @@
 			    FRAME_SIZE);
 			
+			size_t count = SIZE2FRAMES(new_size);
 			pfn_t pfn = ADDR2PFN(new_base);
-			size_t count = SIZE2FRAMES(new_size);
+			pfn_t conf;
 			
-			pfn_t conf;
-			if ((minconf < pfn) || (minconf >= pfn + count))
-				conf = pfn;
-			else
-				conf = minconf;
-			
-			zone_create(pfn, count, conf, ZONE_AVAILABLE);
-			
-			// XXX this has to be removed
-			if (last_frame < ALIGN_UP(new_base + new_size, FRAME_SIZE))
-				last_frame = ALIGN_UP(new_base + new_size, FRAME_SIZE);
+			if (low) {
+				if ((minconf < pfn) || (minconf >= pfn + count))
+					conf = pfn;
+				else
+					conf = minconf;
+				zone_create(pfn, count, conf,
+				    ZONE_AVAILABLE | ZONE_LOWMEM);
+			} else {
+				conf = zone_external_conf_alloc(count);
+				if (conf != 0)
+					zone_create(pfn, count, conf,
+					    ZONE_AVAILABLE | ZONE_HIGHMEM);
+			}
 		} else if ((e820table[i].type == MEMMAP_MEMORY_ACPI) ||
 		    (e820table[i].type == MEMMAP_MEMORY_NVS)) {
@@ -179,5 +148,5 @@
 
 
-void frame_arch_init(void)
+void frame_low_arch_init(void)
 {
 	pfn_t minconf;
@@ -192,5 +161,5 @@
 #endif
 		
-		init_e820_memory(minconf);
+		init_e820_memory(minconf, true);
 		
 		/* Reserve frame 0 (BIOS data) */
@@ -206,4 +175,10 @@
 }
 
+void frame_high_arch_init(void)
+{
+	if (config.cpu_active == 1)
+		init_e820_memory(0, false);
+}
+
 /** @}
  */
Index: kernel/arch/ia32/src/mm/km.c
===================================================================
--- kernel/arch/ia32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ia32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ia32mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_IA32_IDENTITY_START;
+	config.identity_size = KM_IA32_IDENTITY_SIZE;
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_IA32_NON_IDENTITY_START,
+	    KM_IA32_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_IA32_NON_IDENTITY_START, KM_IA32_NON_IDENTITY_SIZE,
+	    addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/ia32/src/mm/page.c
===================================================================
--- kernel/arch/ia32/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -49,4 +49,5 @@
 #include <print.h>
 #include <interrupt.h>
+#include <macros.h>
 
 void page_arch_init(void)
@@ -55,46 +56,31 @@
 	int flags;
 	
-	if (config.cpu_active == 1) {
-		page_mapping_operations = &pt_mapping_operations;
+	if (config.cpu_active > 1) {
+		/* Fast path for non-boot CPUs */
+		write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
+		paging_on();
+		return;
+	}
+
+	page_mapping_operations = &pt_mapping_operations;
 	
-		/*
-		 * PA2KA(identity) mapping for all frames until last_frame.
-		 */
-		page_table_lock(AS_KERNEL, true);
-		for (cur = 0; cur < last_frame; cur += FRAME_SIZE) {
-			flags = PAGE_CACHEABLE | PAGE_WRITE;
-			if ((PA2KA(cur) >= config.base) && (PA2KA(cur) < config.base + config.kernel_size))
-				flags |= PAGE_GLOBAL;
-			page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
-		}
-		page_table_unlock(AS_KERNEL, true);
+	/*
+	 * PA2KA(identity) mapping for all low-memory frames.
+	 */
+	page_table_lock(AS_KERNEL, true);
+	for (cur = 0; cur < min(config.identity_size, config.physmem_end);
+	    cur += FRAME_SIZE) {
+		flags = PAGE_CACHEABLE | PAGE_WRITE;
+		if ((PA2KA(cur) >= config.base) &&
+		    (PA2KA(cur) < config.base + config.kernel_size))
+			flags |= PAGE_GLOBAL;
+		page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
+	}
+	page_table_unlock(AS_KERNEL, true);
 		
-		exc_register(14, "page_fault", true, (iroutine_t) page_fault);
-		write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
-	} else
-		write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
+	exc_register(14, "page_fault", true, (iroutine_t) page_fault);
+	write_cr3((uintptr_t) AS_KERNEL->genarch.page_table);
 	
 	paging_on();
-}
-
-
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
-		panic("Unable to map physical memory %p (%zu bytes).",
-		    (void *) physaddr, size);
-	
-	uintptr_t virtaddr = PA2KA(last_frame);
-	pfn_t i;
-	page_table_lock(AS_KERNEL, true);
-	for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++) {
-		uintptr_t addr = PFN2ADDR(i);
-		page_mapping_insert(AS_KERNEL, virtaddr + addr, physaddr + addr, PAGE_NOT_CACHEABLE | PAGE_WRITE);
-	}
-	page_table_unlock(AS_KERNEL, true);
-	
-	last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
-	
-	return virtaddr;
 }
 
Index: kernel/arch/ia32/src/smp/smp.c
===================================================================
--- kernel/arch/ia32/src/smp/smp.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia32/src/smp/smp.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -47,6 +47,7 @@
 #include <debug.h>
 #include <arch/asm.h>
+#include <mm/page.h>
 #include <mm/frame.h>
-#include <mm/page.h>
+#include <mm/km.h>
 #include <mm/slab.h>
 #include <mm/as.h>
@@ -72,6 +73,8 @@
 	
 	if (config.cpu_count > 1) {
-		l_apic = (uint32_t *) hw_map((uintptr_t) l_apic, PAGE_SIZE);
-		io_apic = (uint32_t *) hw_map((uintptr_t) io_apic, PAGE_SIZE);
+		l_apic = (uint32_t *) km_map((uintptr_t) l_apic, PAGE_SIZE,
+		    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+		io_apic = (uint32_t *) km_map((uintptr_t) io_apic, PAGE_SIZE,
+		    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	}
 }
Index: kernel/arch/ia64/Makefile.inc
===================================================================
--- kernel/arch/ia64/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -52,4 +52,5 @@
 	arch/$(KARCH)/src/ivt.S \
 	arch/$(KARCH)/src/interrupt.c \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/as.c \
 	arch/$(KARCH)/src/mm/frame.c \
Index: kernel/arch/ia64/include/arch.h
===================================================================
--- kernel/arch/ia64/include/arch.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/include/arch.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -36,6 +36,4 @@
 #define KERN_ia64_ARCH_H_
 
-#include <arch/drivers/ski.h>
-
 extern void arch_pre_main(void);
 
Index: kernel/arch/ia64/include/asm.h
===================================================================
--- kernel/arch/ia64/include/asm.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/include/asm.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -38,22 +38,24 @@
 #include <config.h>
 #include <typedefs.h>
-#include <typedefs.h>
 #include <arch/register.h>
+#include <arch/legacyio.h>
 #include <trace.h>
 
-#define IA64_IOSPACE_ADDRESS  0xE001000000000000ULL
-
 #define IO_SPACE_BOUNDARY       ((void *) (64 * 1024))
 
+/** Map the I/O port address to a legacy I/O address. */
+NO_TRACE static inline uintptr_t p2a(volatile void *p)
+{
+	uintptr_t prt = (uintptr_t) p;
+
+	return legacyio_virt_base + (((prt >> 2) << 12) | (prt & 0xfff));
+}
+	
 NO_TRACE static inline void pio_write_8(ioport8_t *port, uint8_t v)
 {
-	if (port < (ioport8_t *) IO_SPACE_BOUNDARY) {
-		uintptr_t prt = (uintptr_t) port;
-	
-		*((ioport8_t *) (IA64_IOSPACE_ADDRESS +
-		    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
-	} else {
+	if (port < (ioport8_t *) IO_SPACE_BOUNDARY)
+		*((ioport8_t *) p2a(port)) = v;
+	else
 		*port = v;
-	}
 	
 	asm volatile (
@@ -65,12 +67,8 @@
 NO_TRACE static inline void pio_write_16(ioport16_t *port, uint16_t v)
 {
-	if (port < (ioport16_t *) IO_SPACE_BOUNDARY) {
-		uintptr_t prt = (uintptr_t) port;
-	
-		*((ioport16_t *) (IA64_IOSPACE_ADDRESS +
-		    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
-	} else {
+	if (port < (ioport16_t *) IO_SPACE_BOUNDARY)
+		*((ioport16_t *) p2a(port)) = v;
+	else
 		*port = v;
-	}
 	
 	asm volatile (
@@ -82,12 +80,8 @@
 NO_TRACE static inline void pio_write_32(ioport32_t *port, uint32_t v)
 {
-	if (port < (ioport32_t *) IO_SPACE_BOUNDARY) {
-		uintptr_t prt = (uintptr_t) port;
-	
-		*((ioport32_t *) (IA64_IOSPACE_ADDRESS +
-		    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
-	} else {
+	if (port < (ioport32_t *) IO_SPACE_BOUNDARY)
+		*((ioport32_t *) p2a(port)) = v;
+	else
 		*port = v;
-	}
 	
 	asm volatile (
@@ -106,12 +100,8 @@
 	);
 
-	if (port < (ioport8_t *) IO_SPACE_BOUNDARY) {
-		uintptr_t prt = (uintptr_t) port;
-
-		v = *((ioport8_t *) (IA64_IOSPACE_ADDRESS +
-		    ((prt & 0xfff) | ((prt >> 2) << 12))));
-	} else {
+	if (port < (ioport8_t *) IO_SPACE_BOUNDARY)
+		v = *((ioport8_t *) p2a(port));
+	else
 		v = *port;
-	}
 	
 	return v;
@@ -127,12 +117,8 @@
 	);
 
-	if (port < (ioport16_t *) IO_SPACE_BOUNDARY) {
-		uintptr_t prt = (uintptr_t) port;
-
-		v = *((ioport16_t *) (IA64_IOSPACE_ADDRESS +
-		    ((prt & 0xfff) | ((prt >> 2) << 12))));
-	} else {
+	if (port < (ioport16_t *) IO_SPACE_BOUNDARY)
+		v = *((ioport16_t *) p2a(port));
+	else
 		v = *port;
-	}
 	
 	return v;
@@ -148,12 +134,8 @@
 	);
 	
-	if (port < (ioport32_t *) IO_SPACE_BOUNDARY) {
-		uintptr_t prt = (uintptr_t) port;
-		
-		v = *((ioport32_t *) (IA64_IOSPACE_ADDRESS +
-		    ((prt & 0xfff) | ((prt >> 2) << 12))));
-	} else {
+	if (port < (ioport32_t *) IO_SPACE_BOUNDARY)
+		v = *((ioport32_t *) p2a(port));
+	else
 		v = *port;
-	}
 
 	return v;
Index: kernel/arch/ia64/include/interrupt.h
===================================================================
--- kernel/arch/ia64/include/interrupt.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/include/interrupt.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -61,5 +61,4 @@
 #define IRQ_KBD    (0x01 + LEGACY_INTERRUPT_BASE)
 #define IRQ_MOUSE  (0x0c + LEGACY_INTERRUPT_BASE)
-#define IRQ_NE2000 (0x09 + LEGACY_INTERRUPT_BASE)
 
 /** General Exception codes. */
Index: kernel/arch/ia64/include/legacyio.h
===================================================================
--- kernel/arch/ia64/include/legacyio.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ia64/include/legacyio.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ia64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_ia64_LEGACYIO_H_
+#define KERN_ia64_LEGACYIO_H_
+
+#include <typedefs.h>
+
+#define LEGACYIO_PHYS_BASE	0x00000FFFFC000000ULL
+
+/* Legacy I/O space - static uspace address, FIXME */
+#define LEGACYIO_USER_BASE	0x0001000000000000ULL 
+
+#define LEGACYIO_PAGE_WIDTH		26	/* 64M */
+#define LEGACYIO_SINGLE_PAGE_WIDTH 	12 	/* 4K */
+
+#define LEGACYIO_SIZE	(1ULL << LEGACYIO_PAGE_WIDTH)
+
+extern uintptr_t legacyio_virt_base;
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/ia64/include/mm/frame.h
===================================================================
--- kernel/arch/ia64/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,7 +43,8 @@
 #include <typedefs.h>
 
-extern uintptr_t last_frame;
+extern uintptr_t end_of_identity;
 
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 #define physmem_print()
 
Index: kernel/arch/ia64/include/mm/km.h
===================================================================
--- kernel/arch/ia64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ia64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ia64mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_ia64_KM_H_
+#define KERN_ia64_KM_H_
+
+#include <typedefs.h>
+
+/*
+ * Be conservative and assume the minimal (3 + 51)-bit virtual address width
+ * of the Itanium CPU even if running on CPU with full 64-bit virtual
+ * address width, such as Itanium 2.
+ */
+
+#define KM_IA64_IDENTITY_START		UINT64_C(0xe000000000000000)
+#define KM_IA64_IDENTITY_SIZE		UINT64_C(0x0004000000000000)
+
+#define KM_IA64_NON_IDENTITY_START	UINT64_C(0xfffc000000000000)
+#define KM_IA64_NON_IDENTITY_SIZE	UINT64_C(0x0004000000000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/ia64/include/mm/page.h
===================================================================
--- kernel/arch/ia64/include/mm/page.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/include/mm/page.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,24 +43,5 @@
 
 /** Bit width of the TLB-locked portion of kernel address space. */
-#define KERNEL_PAGE_WIDTH  28  /* 256M */
-#define IO_PAGE_WIDTH      26  /* 64M */
-#define FW_PAGE_WIDTH      28  /* 256M */
-
-#define USPACE_IO_PAGE_WIDTH  12  /* 4K */
-
-
-/*
- * Statically mapped IO spaces - offsets to 0xe...00 of virtual addresses
- * because of "minimal virtual bits implemented is 51" it is possible to
- * have values up to 0x0007000000000000
- */
-
-/* Firmware area (bellow 4GB in phys mem) */
-#define FW_OFFSET   0x00000000F0000000
-/* Legacy IO space */
-#define IO_OFFSET   0x0001000000000000
-/* Videoram - now mapped to 0 as VGA text mode vram on 0xb8000 */
-#define VIO_OFFSET  0x0002000000000000
-
+#define KERNEL_PAGE_WIDTH 	28	/* 256M */
 
 #define PPN_SHIFT  12
Index: kernel/arch/ia64/src/ia64.c
===================================================================
--- kernel/arch/ia64/src/ia64.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/src/ia64.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -34,38 +34,28 @@
 
 #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 <arch/legacyio.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>
+#include <mm/page.h>
+#include <mm/km.h>
+
+#ifdef MACHINE_ski
+#include <arch/drivers/ski.h>
+#endif
 
 /* NS16550 as a COM 1 */
@@ -75,14 +65,16 @@
 
 static uint64_t iosapic_base = 0xfec00000;
+uintptr_t legacyio_virt_base = 0;
 
 /** Performs ia64-specific initialization before main_bsp() is called. */
 void arch_pre_main(void)
 {
-	init.cnt = min3(bootinfo->taskmap.cnt, TASKMAP_MAX_RECORDS, CONFIG_INIT_TASKS);
+	init.cnt = min3(bootinfo->taskmap.cnt, TASKMAP_MAX_RECORDS,
+	    CONFIG_INIT_TASKS);
 	size_t i;
+
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr =
-		    ((unsigned long) bootinfo->taskmap.tasks[i].addr) |
-		    VRN_MASK;
+		init.tasks[i].paddr =
+		    (uintptr_t) bootinfo->taskmap.tasks[i].addr;
 		init.tasks[i].size = bootinfo->taskmap.tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
@@ -97,5 +89,6 @@
 static void iosapic_init(void)
 {
-	uint64_t IOSAPIC = PA2KA((sysarg_t)(iosapic_base)) | FW_OFFSET;
+	uintptr_t IOSAPIC = km_map(iosapic_base, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	int i;
 	
@@ -124,4 +117,8 @@
 {
 	if (config.cpu_active == 1) {
+		/* Map the page with legacy I/O. */
+		legacyio_virt_base = km_map(LEGACYIO_PHYS_BASE, LEGACYIO_SIZE,
+		    PAGE_WRITE | PAGE_NOT_CACHEABLE);
+
 		iosapic_init();
 		irq_init(INR_COUNT, INR_COUNT);
@@ -196,5 +193,6 @@
 	
 #ifdef CONFIG_I8042
-	i8042_instance_t *i8042_instance = i8042_init((i8042_t *) I8042_BASE, IRQ_KBD);
+	i8042_instance_t *i8042_instance = i8042_init((i8042_t *) I8042_BASE,
+	    IRQ_KBD);
 	if (i8042_instance) {
 		kbrd_instance_t *kbrd_instance = kbrd_init();
@@ -205,19 +203,9 @@
 		}
 	}
-	
-	sysinfo_set_item_val("i8042", NULL, true);
-	sysinfo_set_item_val("i8042.inr_a", NULL, IRQ_KBD);
-	sysinfo_set_item_val("i8042.inr_b", NULL, IRQ_MOUSE);
-	sysinfo_set_item_val("i8042.address.physical", NULL,
-	    (uintptr_t) I8042_BASE);
-	sysinfo_set_item_val("i8042.address.kernel", NULL,
-	    (uintptr_t) I8042_BASE);
-#endif
-
-	sysinfo_set_item_val("netif.ne2000.inr", NULL, IRQ_NE2000);
-
+#endif
+	
 	sysinfo_set_item_val("ia64_iospace", NULL, true);
 	sysinfo_set_item_val("ia64_iospace.address", NULL, true);
-	sysinfo_set_item_val("ia64_iospace.address.virtual", NULL, IO_OFFSET);
+	sysinfo_set_item_val("ia64_iospace.address.virtual", NULL, LEGACYIO_USER_BASE);
 }
 
@@ -262,7 +250,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 +258,5 @@
 {
 	pio_write_8((ioport8_t *)0x64, 0xfe);
-	while (1)
-		;
+	while (1);
 }
 
Index: kernel/arch/ia64/src/mm/frame.c
===================================================================
--- kernel/arch/ia64/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -51,39 +51,67 @@
 #define MINCONF 1
 
-uintptr_t last_frame = 0;
+uintptr_t end_of_identity = -1ULL;
 
-void frame_arch_init(void)
+static void frame_common_arch_init(bool low)
 {
-	if (config.cpu_active == 1) {
-		unsigned int i;
-		for (i = 0; i < bootinfo->memmap_items; i++) {
-			if (bootinfo->memmap[i].type == MEMMAP_FREE_MEM) {
-				uint64_t base = bootinfo->memmap[i].base;
-				uint64_t size = bootinfo->memmap[i].size;
-				uint64_t abase = ALIGN_UP(base, FRAME_SIZE);
+	unsigned int i;
 
-				if (size > FRAME_SIZE)
-					size -= abase - base;
+	for (i = 0; i < bootinfo->memmap_items; i++) {
+		if (bootinfo->memmap[i].type != MEMMAP_FREE_MEM)
+			continue;
 
-				if (size > MIN_ZONE_SIZE) {
-					zone_create(abase >> FRAME_WIDTH,
-					    size >> FRAME_WIDTH,
-					    max(MINCONF, abase >> FRAME_WIDTH),
-					    0);
-				}
-				if (abase + size > last_frame)
-					last_frame = abase + size;
+		uintptr_t base = bootinfo->memmap[i].base;
+		size_t size = bootinfo->memmap[i].size;
+		uintptr_t abase = ALIGN_UP(base, FRAME_SIZE);
+
+		if (size > FRAME_SIZE)
+			size -= abase - base;
+
+		if (!frame_adjust_zone_bounds(low, &abase, &size))
+			continue;
+
+		if (size > MIN_ZONE_SIZE) {
+			pfn_t pfn = ADDR2PFN(abase);
+			size_t count = SIZE2FRAMES(size);
+
+			if (low) {
+				zone_create(pfn, count, max(MINCONF, pfn),
+				    ZONE_AVAILABLE | ZONE_LOWMEM);
+			} else {
+				pfn_t conf = zone_external_conf_alloc(count);
+				if (conf != 0)
+					zone_create(pfn, count, conf,
+					    ZONE_AVAILABLE | ZONE_HIGHMEM);
 			}
 		}
-		
-		/*
-		 * Blacklist ROM regions.
-		 */
-		frame_mark_unavailable(ADDR2PFN(ROM_BASE),
-		    SIZE2FRAMES(ROM_SIZE));
+	}
+}
 
-		frame_mark_unavailable(ADDR2PFN(KERNEL_RESERVED_AREA_BASE),
-		    SIZE2FRAMES(KERNEL_RESERVED_AREA_SIZE));
-	}	
+void frame_low_arch_init(void)
+{
+	if (config.cpu_active > 1)
+		return;
+	
+	frame_common_arch_init(true);
+	
+	/*
+	 * Blacklist ROM regions.
+	 */
+	frame_mark_unavailable(ADDR2PFN(ROM_BASE),
+	    SIZE2FRAMES(ROM_SIZE));
+
+	frame_mark_unavailable(ADDR2PFN(KERNEL_RESERVED_AREA_BASE),
+	    SIZE2FRAMES(KERNEL_RESERVED_AREA_SIZE));
+
+	/* PA2KA will work only on low-memory. */
+	end_of_identity = PA2KA(config.physmem_end - FRAME_SIZE) + PAGE_SIZE;
+}
+
+void frame_high_arch_init(void)
+{
+	if (config.cpu_active > 1)
+		return;
+	
+	frame_common_arch_init(false);
 }
 
Index: kernel/arch/ia64/src/mm/km.c
===================================================================
--- kernel/arch/ia64/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ia64/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ia64mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_IA64_IDENTITY_START;
+	config.identity_size = KM_IA64_IDENTITY_SIZE;	
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_IA64_NON_IDENTITY_START,
+	    KM_IA64_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_IA64_NON_IDENTITY_START, KM_IA64_NON_IDENTITY_SIZE,
+	    addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/ia64/src/mm/page.c
===================================================================
--- kernel/arch/ia64/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -255,10 +255,4 @@
 }
 
-uintptr_t hw_map(uintptr_t physaddr, size_t size __attribute__ ((unused)))
-{
-	/* THIS is a dirty hack. */
-	return (uintptr_t)((uint64_t)(PA2KA(physaddr)) + VIO_OFFSET);
-}
-
 /** @}
  */
Index: kernel/arch/ia64/src/mm/tlb.c
===================================================================
--- kernel/arch/ia64/src/mm/tlb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/src/mm/tlb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -52,6 +52,5 @@
 #include <arch.h>
 #include <interrupt.h>
-
-#define IO_FRAME_BASE 0xFFFFC000000
+#include <arch/legacyio.h>
 
 /** Invalidate all TLB entries. */
@@ -467,4 +466,13 @@
 }
 
+static bool is_kernel_fault(uintptr_t va)
+{
+	region_register_t rr;
+
+	rr.word = rr_read(VA2VRN(va));
+	rid_t rid = rr.map.rid;
+	return (RID2ASID(rid) == ASID_KERNEL) && (VA2VRN(va) == VRN_KERNEL);
+}
+
 /** Instruction TLB fault handler for faults with VHPT turned off.
  *
@@ -480,5 +488,6 @@
 	va = istate->cr_ifa; /* faulting address */
 	
-	page_table_lock(AS, true);
+	ASSERT(!is_kernel_fault(va));
+
 	t = page_mapping_find(AS, va, true);
 	if (t) {
@@ -488,10 +497,8 @@
 		 */
 		itc_pte_copy(t);
-		page_table_unlock(AS, true);
 	} else {
 		/*
 		 * Forward the page fault to address space page fault handler.
 		 */
-		page_table_unlock(AS, true);
 		if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.",
@@ -522,16 +529,16 @@
 static int try_memmap_io_insertion(uintptr_t va, istate_t *istate)
 {
-	if ((va >= IO_OFFSET ) && (va < IO_OFFSET + (1 << IO_PAGE_WIDTH))) {
+	if ((va >= LEGACYIO_USER_BASE) && (va < LEGACYIO_USER_BASE + (1 << LEGACYIO_PAGE_WIDTH))) {
 		if (TASK) {
-			uint64_t io_page = (va & ((1 << IO_PAGE_WIDTH) - 1)) >>
-			    USPACE_IO_PAGE_WIDTH;
+			uint64_t io_page = (va & ((1 << LEGACYIO_PAGE_WIDTH) - 1)) >>
+			    LEGACYIO_SINGLE_PAGE_WIDTH;
 			
 			if (is_io_page_accessible(io_page)) {
 				uint64_t page, frame;
 				
-				page = IO_OFFSET +
-				    (1 << USPACE_IO_PAGE_WIDTH) * io_page;
-				frame = IO_FRAME_BASE +
-				    (1 << USPACE_IO_PAGE_WIDTH) * io_page;
+				page = LEGACYIO_USER_BASE +
+				    (1 << LEGACYIO_SINGLE_PAGE_WIDTH) * io_page;
+				frame = LEGACYIO_PHYS_BASE +
+				    (1 << LEGACYIO_SINGLE_PAGE_WIDTH) * io_page;
 				
 				tlb_entry_t entry;
@@ -547,5 +554,5 @@
 				entry.ar = AR_READ | AR_WRITE;
 				entry.ppn = frame >> PPN_SHIFT;
-				entry.ps = USPACE_IO_PAGE_WIDTH;
+				entry.ps = LEGACYIO_SINGLE_PAGE_WIDTH;
 				
 				dtc_mapping_insert(page, TASK->as->asid, entry);
@@ -570,11 +577,11 @@
 {
 	if (istate->cr_isr.sp) {
-		/* Speculative load. Deffer the exception
-		   until a more clever approach can be used.
-		   
-		   Currently if we try to find the mapping
-		   for the speculative load while in the kernel,
-		   we might introduce a livelock because of
-		   the possibly invalid values of the address. */
+		/*
+		 * Speculative load. Deffer the exception until a more clever
+		 * approach can be used. Currently if we try to find the
+		 * mapping for the speculative load while in the kernel, we
+		 * might introduce a livelock because of the possibly invalid
+		 * values of the address.
+		 */
 		istate->cr_ipsr.ed = true;
 		return;
@@ -582,22 +589,20 @@
 	
 	uintptr_t va = istate->cr_ifa;  /* faulting address */
-	
-	region_register_t rr;
-	rr.word = rr_read(VA2VRN(va));
-	rid_t rid = rr.map.rid;
-	if (RID2ASID(rid) == ASID_KERNEL) {
-		if (VA2VRN(va) == VRN_KERNEL) {
+	as_t *as = AS;
+	
+	if (is_kernel_fault(va)) {
+		if (va < end_of_identity) {
 			/*
-			 * Provide KA2PA(identity) mapping for faulting piece of
-			 * kernel address space.
+			 * Create kernel identity mapping for low memory. 
 			 */
 			dtlb_kernel_mapping_insert(va, KA2PA(va), false, 0);
 			return;
+		} else {
+			as = AS_KERNEL;
 		}
 	}
 	
 	
-	page_table_lock(AS, true);
-	pte_t *entry = page_mapping_find(AS, va, true);
+	pte_t *entry = page_mapping_find(as, va, true);
 	if (entry) {
 		/*
@@ -606,7 +611,5 @@
 		 */
 		dtc_pte_copy(entry);
-		page_table_unlock(AS, true);
 	} else {
-		page_table_unlock(AS, true);
 		if (try_memmap_io_insertion(va, istate))
 			return;
@@ -647,9 +650,12 @@
 	uintptr_t va;
 	pte_t *t;
+	as_t *as = AS;
 	
 	va = istate->cr_ifa;  /* faulting address */
 	
-	page_table_lock(AS, true);
-	t = page_mapping_find(AS, va, true);
+	if (is_kernel_fault(va))
+		as = AS_KERNEL;
+
+	t = page_mapping_find(as, va, true);
 	ASSERT((t) && (t->p));
 	if ((t) && (t->p) && (t->w)) {
@@ -667,5 +673,4 @@
 		}
 	}
-	page_table_unlock(AS, true);
 }
 
@@ -682,6 +687,7 @@
 	
 	va = istate->cr_ifa;  /* faulting address */
-	
-	page_table_lock(AS, true);
+
+	ASSERT(!is_kernel_fault(va));
+	
 	t = page_mapping_find(AS, va, true);
 	ASSERT((t) && (t->p));
@@ -700,5 +706,4 @@
 		}
 	}
-	page_table_unlock(AS, true);
 }
 
@@ -713,9 +718,12 @@
 	uintptr_t va;
 	pte_t *t;
+	as_t *as = AS;
 	
 	va = istate->cr_ifa;  /* faulting address */
 	
-	page_table_lock(AS, true);
-	t = page_mapping_find(AS, va, true);
+	if (is_kernel_fault(va))
+		as = AS_KERNEL;
+
+	t = page_mapping_find(as, va, true);
 	ASSERT((t) && (t->p));
 	if ((t) && (t->p)) {
@@ -733,5 +741,4 @@
 		}
 	}
-	page_table_unlock(AS, true);
 }
 
@@ -748,9 +755,10 @@
 	
 	va = istate->cr_ifa;  /* faulting address */
+
+	ASSERT(!is_kernel_fault(va));
 	
 	/*
 	 * Assume a write to a read-only page.
 	 */
-	page_table_lock(AS, true);
 	t = page_mapping_find(AS, va, true);
 	ASSERT((t) && (t->p));
@@ -761,5 +769,4 @@
 		panic_memtrap(istate, PF_ACCESS_WRITE, va, NULL);
 	}
-	page_table_unlock(AS, true);
 }
 
@@ -777,5 +784,6 @@
 	va = istate->cr_ifa;  /* faulting address */
 	
-	page_table_lock(AS, true);
+	ASSERT(!is_kernel_fault(va));
+
 	t = page_mapping_find(AS, va, true);
 	ASSERT(t);
@@ -790,7 +798,5 @@
 		else
 			dtc_pte_copy(t);
-		page_table_unlock(AS, true);
 	} else {
-		page_table_unlock(AS, true);
 		if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.",
Index: kernel/arch/ia64/src/start.S
===================================================================
--- kernel/arch/ia64/src/start.S	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ia64/src/start.S	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -38,7 +38,4 @@
 #define KERNEL_TRANSLATION_I    0x0010000000000661
 #define KERNEL_TRANSLATION_D    0x0010000000000661
-#define KERNEL_TRANSLATION_VIO  0x0010000000000671
-#define KERNEL_TRANSLATION_IO   0x00100FFFFC000671
-#define KERNEL_TRANSLATION_FW   0x00100000F0000671
 
 .section K_TEXT_START, "ax"
@@ -88,39 +85,5 @@
 	itr.d dtr[r0] = r10
 	
-	movl r7 = 1
-	movl r8 = (VRN_KERNEL << VRN_SHIFT) | VIO_OFFSET
-	mov cr.ifa = r8
-	movl r10 = (KERNEL_TRANSLATION_VIO)
-	itr.d dtr[r7] = r10
-	
-	mov r11 = cr.itir
-	movl r10 = ~0xfc
-	and r10 = r10, r11
-	movl r11 = (IO_PAGE_WIDTH << PS_SHIFT)
-	or r10 = r10, r11
-	mov cr.itir = r10
-	
-	movl r7 = 2
-	movl r8 = (VRN_KERNEL << VRN_SHIFT) | IO_OFFSET
-	mov cr.ifa = r8
-	movl r10 = (KERNEL_TRANSLATION_IO)
-	itr.d dtr[r7] = r10
-	
-	# Setup mapping for firmware area (also SAPIC)
-	
-	mov r11 = cr.itir
-	movl r10 = ~0xfc
-	and r10 = r10, r11
-	movl r11 = (FW_PAGE_WIDTH << PS_SHIFT)
-	or r10 = r10, r11
-	mov cr.itir = r10
-	
-	movl r7 = 3
-	movl r8 = (VRN_KERNEL << VRN_SHIFT) | FW_OFFSET
-	mov cr.ifa = r8
-	movl r10 = (KERNEL_TRANSLATION_FW)
-	itr.d dtr[r7] = r10
-	
-	# Initialize DSR
+	# Initialize DCR
 	
 	movl r10 = (DCR_DP_MASK | DCR_DK_MASK | DCR_DX_MASK | DCR_DR_MASK | DCR_DA_MASK | DCR_DD_MASK | DCR_LC_MASK)
@@ -174,5 +137,5 @@
 	mov ar.bspstore = r8
 	loadrs
-
+	
 	#
 	# Initialize memory stack to some sane value and allocate a scratch area
@@ -196,5 +159,5 @@
 	srlz.i
 	srlz.d ;;
-
+	
 	br.call.sptk.many b0 = arch_pre_main
 0:
Index: kernel/arch/mips32/Makefile.inc
===================================================================
--- kernel/arch/mips32/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -63,4 +63,5 @@
 	arch/$(KARCH)/src/debug/stacktrace.c \
 	arch/$(KARCH)/src/debug/stacktrace_asm.S \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/frame.c \
 	arch/$(KARCH)/src/mm/page.c \
Index: kernel/arch/mips32/include/mm/as.h
===================================================================
--- kernel/arch/mips32/include/mm/as.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/include/mm/as.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,5 +39,5 @@
 
 #define KERNEL_ADDRESS_SPACE_START_ARCH  UINT32_C(0x80000000)
-#define KERNEL_ADDRESS_SPACE_END_ARCH    UINT32_C(0x9fffffff)
+#define KERNEL_ADDRESS_SPACE_END_ARCH    UINT32_C(0xffffffff)
 #define USER_ADDRESS_SPACE_START_ARCH    UINT32_C(0x00000000)
 #define USER_ADDRESS_SPACE_END_ARCH      UINT32_C(0x7fffffff)
Index: kernel/arch/mips32/include/mm/frame.h
===================================================================
--- kernel/arch/mips32/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,5 +41,6 @@
 #ifndef __ASM__
 
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void physmem_print(void);
 
Index: kernel/arch/mips32/include/mm/km.h
===================================================================
--- kernel/arch/mips32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/mips32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup mips32mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_mips32_KM_H_
+#define KERN_mips32_KM_H_
+
+#include <typedefs.h>
+
+#define KM_MIPS32_KSEG0_START	UINT32_C(0x80000000)
+#define KM_MIPS32_KSEG0_SIZE	UINT32_C(0x20000000)
+
+#define KM_MIPS32_KSSEG_START	UINT32_C(0xc0000000)
+#define KM_MIPS32_KSSEG_SIZE	UINT32_C(0x20000000)
+
+#define KM_MIPS32_KSEG3_START	UINT32_C(0xe0000000)
+#define KM_MIPS32_KSEG3_SIZE	UINT32_C(0x20000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/src/mips32.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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
@@ -88,5 +78,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr = (uintptr_t) bootinfo->tasks[i].addr;
+		init.tasks[i].paddr = KA2PA(bootinfo->tasks[i].addr);
 		init.tasks[i].size = bootinfo->tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
@@ -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/mips32/src/mm/frame.c
===================================================================
--- kernel/arch/mips32/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -123,5 +123,5 @@
 	for (i = 0; i < init.cnt; i++)
 		if (overlaps(frame << ZERO_PAGE_WIDTH, ZERO_PAGE_SIZE,
-		    KA2PA(init.tasks[i].addr), init.tasks[i].size)) {
+		    init.tasks[i].paddr, init.tasks[i].size)) {
 			safe = false;
 			break;
@@ -131,25 +131,38 @@
 }
 
-static void frame_add_region(pfn_t start_frame, pfn_t end_frame)
-{
-	if (end_frame > start_frame) {
-		/* Convert 1M frames to 16K frames */
-		pfn_t first = ADDR2PFN(start_frame << ZERO_PAGE_WIDTH);
-		pfn_t count = ADDR2PFN((end_frame - start_frame) << ZERO_PAGE_WIDTH);
-		
+static void frame_add_region(pfn_t start_frame, pfn_t end_frame, bool low)
+{
+	if (end_frame <= start_frame)
+		return;
+
+	uintptr_t base = start_frame << ZERO_PAGE_WIDTH;
+	size_t size = (end_frame - start_frame) << ZERO_PAGE_WIDTH;
+
+	if (!frame_adjust_zone_bounds(low, &base, &size))
+		return; 
+
+	pfn_t first = ADDR2PFN(base);
+	size_t count = SIZE2FRAMES(size);
+	pfn_t conf_frame;
+
+	if (low) {
 		/* Interrupt vector frame is blacklisted */
-		pfn_t conf_frame;
 		if (first == 0)
 			conf_frame = 1;
 		else
 			conf_frame = first;
-		
-		zone_create(first, count, conf_frame, 0);
-		
-		if (phys_regions_count < MAX_REGIONS) {
-			phys_regions[phys_regions_count].start = first;
-			phys_regions[phys_regions_count].count = count;
-			phys_regions_count++;
-		}
+		zone_create(first, count, conf_frame,
+		    ZONE_AVAILABLE | ZONE_LOWMEM);
+	} else {
+		conf_frame = zone_external_conf_alloc(count);
+		if (conf_frame != 0)
+			zone_create(first, count, conf_frame,
+			    ZONE_AVAILABLE | ZONE_HIGHMEM);
+	}
+	
+	if (phys_regions_count < MAX_REGIONS) {
+		phys_regions[phys_regions_count].start = first;
+		phys_regions[phys_regions_count].count = count;
+		phys_regions_count++;
 	}
 }
@@ -165,5 +178,5 @@
  *
  */
-void frame_arch_init(void)
+void frame_low_arch_init(void)
 {
 	ipl_t ipl = interrupts_disable();
@@ -224,5 +237,5 @@
 		
 		if (!avail) {
-			frame_add_region(start_frame, frame);
+			frame_add_region(start_frame, frame, true);
 			start_frame = frame + 1;
 			avail = true;
@@ -230,5 +243,5 @@
 	}
 	
-	frame_add_region(start_frame, frame);
+	frame_add_region(start_frame, frame, true);
 	
 	/* Blacklist interrupt vector frame */
@@ -246,4 +259,7 @@
 }
 
+void frame_high_arch_init(void)
+{
+}
 
 void physmem_print(void)
Index: kernel/arch/mips32/src/mm/km.c
===================================================================
--- kernel/arch/mips32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/mips32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup mips32mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_MIPS32_KSEG0_START;
+	config.identity_size = KM_MIPS32_KSEG0_SIZE;
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_MIPS32_KSSEG_START, KM_MIPS32_KSSEG_SIZE);
+	km_non_identity_span_add(KM_MIPS32_KSEG3_START, KM_MIPS32_KSEG3_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_MIPS32_KSSEG_START, KM_MIPS32_KSSEG_SIZE, addr, 1)
+	    || iswithin(KM_MIPS32_KSEG3_START, KM_MIPS32_KSEG3_SIZE, addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/mips32/src/mm/page.c
===================================================================
--- kernel/arch/mips32/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,13 +41,5 @@
 {
 	page_mapping_operations = &pt_mapping_operations;
-}
-
-/** Map device into kernel space
- * - on mips, all devices are already mapped into kernel space,
- *   translate the physical address to uncached area
- */
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	return physaddr + 0xa0000000;
+	as_switch(NULL, AS_KERNEL);
 }
 
Index: kernel/arch/mips32/src/mm/tlb.c
===================================================================
--- kernel/arch/mips32/src/mm/tlb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips32/src/mm/tlb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -95,8 +95,5 @@
 	
 	badvaddr = cp0_badvaddr_read();
-	
-	mutex_lock(&AS->lock);
 	asid = AS->asid;
-	mutex_unlock(&AS->lock);
 	
 	pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate, &pfrc);
Index: kernel/arch/mips64/Makefile.inc
===================================================================
--- kernel/arch/mips64/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips64/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -55,4 +55,5 @@
 	arch/$(KARCH)/src/debug/stacktrace.c \
 	arch/$(KARCH)/src/debug/stacktrace_asm.S \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/frame.c \
 	arch/$(KARCH)/src/mm/page.c \
Index: kernel/arch/mips64/include/mm/frame.h
===================================================================
--- kernel/arch/mips64/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips64/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,5 +41,6 @@
 #ifndef __ASM__
 
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void physmem_print(void);
 
Index: kernel/arch/mips64/include/mm/km.h
===================================================================
--- kernel/arch/mips64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/mips64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup mips64mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_mips64_KM_H_
+#define KERN_mips64_KM_H_
+
+#include <typedefs.h>
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/mips64/src/mips64.c
===================================================================
--- kernel/arch/mips64/src/mips64.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips64/src/mips64.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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
@@ -88,5 +78,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr = (uintptr_t) bootinfo->tasks[i].addr;
+		init.tasks[i].paddr = KA2PA(bootinfo->tasks[i].addr);
 		init.tasks[i].size = bootinfo->tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
@@ -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/arch/mips64/src/mm/frame.c
===================================================================
--- kernel/arch/mips64/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips64/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -115,5 +115,5 @@
 	for (i = 0; i < init.cnt; i++)
 		if (overlaps(frame << ZERO_PAGE_WIDTH, ZERO_PAGE_SIZE,
-		    KA2PA(init.tasks[i].addr), init.tasks[i].size)) {
+		    init.tasks[i].paddr, init.tasks[i].size)) {
 			safe = false;
 			break;
@@ -123,25 +123,38 @@
 }
 
-static void frame_add_region(pfn_t start_frame, pfn_t end_frame)
-{
-	if (end_frame > start_frame) {
-		/* Convert 1M frames to 16K frames */
-		pfn_t first = ADDR2PFN(start_frame << ZERO_PAGE_WIDTH);
-		pfn_t count = ADDR2PFN((end_frame - start_frame) << ZERO_PAGE_WIDTH);
-		
+static void frame_add_region(pfn_t start_frame, pfn_t end_frame, bool low)
+{
+	if (end_frame <= start_frame)
+		return;
+
+	uintptr_t base = start_frame << ZERO_PAGE_WIDTH;
+	size_t size = (end_frame - start_frame) << ZERO_PAGE_WIDTH;
+
+	if (!frame_adjust_zone_bounds(low, &base, &size))
+		return; 
+
+	pfn_t first = ADDR2PFN(base);
+	size_t count = SIZE2FRAMES(size);
+	pfn_t conf_frame;
+
+	if (low) {
 		/* Interrupt vector frame is blacklisted */
-		pfn_t conf_frame;
 		if (first == 0)
 			conf_frame = 1;
 		else
 			conf_frame = first;
-		
-		zone_create(first, count, conf_frame, 0);
-		
-		if (phys_regions_count < MAX_REGIONS) {
-			phys_regions[phys_regions_count].start = first;
-			phys_regions[phys_regions_count].count = count;
-			phys_regions_count++;
-		}
+		zone_create(first, count, conf_frame,
+		    ZONE_AVAILABLE | ZONE_LOWMEM);
+	} else {
+		conf_frame = zone_external_conf_alloc(count);
+		if (conf_frame != 0)
+			zone_create(first, count, conf_frame,
+			    ZONE_AVAILABLE | ZONE_HIGHMEM);
+	}
+	
+	if (phys_regions_count < MAX_REGIONS) {
+		phys_regions[phys_regions_count].start = first;
+		phys_regions[phys_regions_count].count = count;
+		phys_regions_count++;
 	}
 }
@@ -156,5 +169,5 @@
  *
  */
-void frame_arch_init(void)
+void frame_low_arch_init(void)
 {
 	ipl_t ipl = interrupts_disable();
@@ -207,5 +220,5 @@
 		
 		if (!avail) {
-			frame_add_region(start_frame, frame);
+			frame_add_region(start_frame, frame, true);
 			start_frame = frame + 1;
 			avail = true;
@@ -213,5 +226,5 @@
 	}
 	
-	frame_add_region(start_frame, frame);
+	frame_add_region(start_frame, frame, true);
 	
 	/* Blacklist interrupt vector frame */
@@ -229,4 +242,8 @@
 }
 
+void frame_high_arch_init(void)
+{
+}
+
 void physmem_print(void)
 {
Index: kernel/arch/mips64/src/mm/km.c
===================================================================
--- kernel/arch/mips64/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/mips64/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup mips64mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <typedefs.h>
+
+void km_identity_arch_init(void)
+{
+}
+
+void km_non_identity_arch_init(void)
+{
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return false;
+}
+
+/** @}
+ */
Index: kernel/arch/mips64/src/mm/page.c
===================================================================
--- kernel/arch/mips64/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/mips64/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,13 +43,4 @@
 }
 
-/** Map device into kernel space
- * - on mips, all devices are already mapped into kernel space,
- *   translate the physical address to uncached area
- */
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	return physaddr + 0xffffffffa0000000;
-}
-
 /** @}
  */
Index: kernel/arch/ppc32/Makefile.inc
===================================================================
--- kernel/arch/ppc32/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ppc32/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -52,4 +52,5 @@
 	arch/$(KARCH)/src/proc/scheduler.c \
 	arch/$(KARCH)/src/ddi/ddi.c \
+	arch/$(KARCH)/src/mm/km.c \
 	arch/$(KARCH)/src/mm/as.c \
 	arch/$(KARCH)/src/mm/frame.c \
Index: kernel/arch/ppc32/include/mm/frame.h
===================================================================
--- kernel/arch/ppc32/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ppc32/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -44,6 +44,4 @@
 #include <trace.h>
 
-extern uintptr_t last_frame;
-
 NO_TRACE static inline uint32_t physmem_top(void)
 {
@@ -58,5 +56,6 @@
 }
 
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 extern void physmem_print(void);
 
Index: kernel/arch/ppc32/include/mm/km.h
===================================================================
--- kernel/arch/ppc32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ppc32/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ppc32mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_ppc32_KM_H_
+#define KERN_ppc32_KM_H_
+
+#include <typedefs.h>
+
+#define KM_PPC32_IDENTITY_START		UINT32_C(0x80000000)
+#define KM_PPC32_IDENTITY_SIZE		UINT32_C(0x40000000)
+
+#define KM_PPC32_NON_IDENTITY_START	UINT32_C(0xc0000000)
+#define KM_PPC32_NON_IDENTITY_SIZE	UINT32_C(0x40000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/ppc32/src/drivers/pic.c
===================================================================
--- kernel/arch/ppc32/src/drivers/pic.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ppc32/src/drivers/pic.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -34,5 +34,5 @@
 
 #include <arch/drivers/pic.h>
-#include <mm/page.h>
+#include <mm/km.h>
 #include <byteorder.h>
 #include <bitops.h>
@@ -42,5 +42,5 @@
 void pic_init(uintptr_t base, size_t size, cir_t *cir, void **cir_arg)
 {
-	pic = (uint32_t *) hw_map(base, size);
+	pic = (uint32_t *) km_map(base, size, PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	*cir = pic_ack_interrupt;
 	*cir_arg = NULL;
Index: kernel/arch/ppc32/src/mm/frame.c
===================================================================
--- kernel/arch/ppc32/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ppc32/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,5 +40,4 @@
 #include <print.h>
 
-uintptr_t last_frame = 0;
 memmap_t memmap;
 
@@ -54,5 +53,5 @@
 }
 
-void frame_arch_init(void)
+static void frame_common_arch_init(bool low)
 {
 	pfn_t minconf = 2;
@@ -61,23 +60,36 @@
 	for (i = 0; i < memmap.cnt; i++) {
 		/* To be safe, make the available zone possibly smaller */
-		uintptr_t new_start = ALIGN_UP((uintptr_t) memmap.zones[i].start,
+		uintptr_t base = ALIGN_UP((uintptr_t) memmap.zones[i].start,
 		    FRAME_SIZE);
-		size_t new_size = ALIGN_DOWN(memmap.zones[i].size -
-		    (new_start - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
+		size_t size = ALIGN_DOWN(memmap.zones[i].size -
+		    (base - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
 		
-		pfn_t pfn = ADDR2PFN(new_start);
-		size_t count = SIZE2FRAMES(new_size);
-		
+		if (!frame_adjust_zone_bounds(low, &base, &size))
+			return;
+
+		pfn_t pfn = ADDR2PFN(base);
+		size_t count = SIZE2FRAMES(size);
 		pfn_t conf;
-		if ((minconf < pfn) || (minconf >= pfn + count))
-			conf = pfn;
-		else
-			conf = minconf;
-		
-		zone_create(pfn, count, conf, 0);
-		
-		if (last_frame < ALIGN_UP(new_start + new_size, FRAME_SIZE))
-			last_frame = ALIGN_UP(new_start + new_size, FRAME_SIZE);
+
+		if (low) {
+			if ((minconf < pfn) || (minconf >= pfn + count))
+				conf = pfn;
+			else
+				conf = minconf;
+			zone_create(pfn, count, conf,
+			    ZONE_AVAILABLE | ZONE_LOWMEM);
+		} else {
+			conf = zone_external_conf_alloc(count);
+			if (conf != 0)
+				zone_create(pfn, count, conf,
+				    ZONE_AVAILABLE | ZONE_HIGHMEM);
+		}
 	}
+	
+}
+
+void frame_low_arch_init(void)
+{
+	frame_common_arch_init(true);
 	
 	/* First is exception vector, second is 'implementation specific',
@@ -92,4 +104,9 @@
 }
 
+void frame_high_arch_init(void)
+{
+	frame_common_arch_init(false);
+}
+
 /** @}
  */
Index: kernel/arch/ppc32/src/mm/km.c
===================================================================
--- kernel/arch/ppc32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/ppc32/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup ppc32mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_PPC32_IDENTITY_START;
+	config.identity_size = KM_PPC32_IDENTITY_SIZE;
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_PPC32_NON_IDENTITY_START,
+	    KM_PPC32_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_PPC32_NON_IDENTITY_START,
+	    KM_PPC32_NON_IDENTITY_SIZE, addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/ppc32/src/mm/page.c
===================================================================
--- kernel/arch/ppc32/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ppc32/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,24 +46,4 @@
 }
 
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	if (last_frame + ALIGN_UP(size, PAGE_SIZE) >
-	    KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
-		panic("Unable to map physical memory %p (%zu bytes).",
-		    (void *) physaddr, size);
-	
-	uintptr_t virtaddr = PA2KA(last_frame);
-	pfn_t i;
-	page_table_lock(AS_KERNEL, true);
-	for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
-		page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i),
-		    physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_WRITE);
-	page_table_unlock(AS_KERNEL, true);
-	
-	last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
-	
-	return virtaddr;
-}
-
 /** @}
  */
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/ppc32/src/ppc32.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,4 +46,5 @@
 #include <userspace.h>
 #include <mm/page.h>
+#include <mm/km.h>
 #include <abi/proc/uarg.h>
 #include <console/console.h>
@@ -71,5 +72,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr = (uintptr_t) bootinfo->taskmap.tasks[i].addr;
+		init.tasks[i].paddr = KA2PA(bootinfo->taskmap.tasks[i].addr);
 		init.tasks[i].size = bootinfo->taskmap.tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
@@ -208,6 +209,6 @@
 		size_t size = 2 * PAGE_SIZE;
 		
-		cuda_t *cuda = (cuda_t *)
-		    (hw_map(aligned_addr, offset + size) + offset);
+		cuda_t *cuda = (cuda_t *) (km_map(aligned_addr, offset + size,
+		    PAGE_WRITE | PAGE_NOT_CACHEABLE) + offset);
 		
 		/* Initialize I/O controller */
Index: kernel/arch/sparc64/Makefile.inc
===================================================================
--- kernel/arch/sparc64/Makefile.inc	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/Makefile.inc	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -68,4 +68,5 @@
 	arch/$(KARCH)/src/fpu_context.c \
 	arch/$(KARCH)/src/dummy.s \
+	arch/$(KARCH)/src/mm/$(USARCH)/km.c \
 	arch/$(KARCH)/src/mm/$(USARCH)/as.c \
 	arch/$(KARCH)/src/mm/$(USARCH)/frame.c \
Index: kernel/arch/sparc64/include/mm/km.h
===================================================================
--- kernel/arch/sparc64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/sparc64/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64mm	
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_sparc64_KM_H_
+#define KERN_sparc64_KM_H_
+
+#if defined (SUN4U)
+#include <arch/mm/sun4u/km.h>
+#elif defined (SUN4V)
+#include <arch/mm/sun4v/km.h>
+#endif
+
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/sparc64/include/mm/sun4u/frame.h
===================================================================
--- kernel/arch/sparc64/include/mm/sun4u/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/include/mm/sun4u/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -72,8 +72,8 @@
 typedef union frame_address frame_address_t;
 
-extern uintptr_t last_frame;
 extern uintptr_t end_of_identity;
 
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 #define physmem_print()
 
Index: kernel/arch/sparc64/include/mm/sun4u/km.h
===================================================================
--- kernel/arch/sparc64/include/mm/sun4u/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/sparc64/include/mm/sun4u/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_sparc64_sun4u_KM_H_
+#define KERN_sparc64_sun4u_KM_H_
+
+#include <typedefs.h>
+
+/*
+ * Be conservative and assume the 44-bit virtual address width as found
+ * on the UltraSPARC CPU, even when running on a newer CPU, such as
+ * UltraSPARC III, which has the full 64-bit virtual address width.
+ *
+ * Do not use the 4 GiB area on either side of the VA hole to meet the
+ * limitations of the UltraSPARC CPU.
+ */
+
+#define KM_SPARC64_US_IDENTITY_START		UINT64_C(0x0000000000000000)
+#define KM_SPARC64_US_IDENTITY_SIZE		UINT64_C(0x000007ff00000000)
+
+#define KM_SPARC64_US_NON_IDENTITY_START	UINT64_C(0xfffff80100000000)
+#define KM_SPARC64_US_NON_IDENTITY_SIZE		UINT64_C(0x000007ff00000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/sparc64/include/mm/sun4v/frame.h
===================================================================
--- kernel/arch/sparc64/include/mm/sun4v/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/include/mm/sun4v/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,6 +46,6 @@
 #include <typedefs.h>
 
-extern uintptr_t last_frame;
-extern void frame_arch_init(void);
+extern void frame_low_arch_init(void);
+extern void frame_high_arch_init(void);
 #define physmem_print()
 
Index: kernel/arch/sparc64/include/mm/sun4v/km.h
===================================================================
--- kernel/arch/sparc64/include/mm/sun4v/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/sparc64/include/mm/sun4v/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64mm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_sparc64_sun4v_KM_H_
+#define KERN_sparc64_sun4v_KM_H_
+
+#include <typedefs.h>
+
+/*
+ * Do not use the 4 GiB area on either side of the VA hole to meet the
+ * limitations of the UltraSPARC T1 CPU.
+ */
+
+#define KM_SPARC64_T1_IDENTITY_START		UINT64_C(0x0000000000000000)
+#define KM_SPARC64_T1_IDENTITY_SIZE		UINT64_C(0x00007fff00000000)
+
+#define KM_SPARC64_T1_NON_IDENTITY_START	UINT64_C(0xffff800100000000)
+#define KM_SPARC64_T1_NON_IDENTITY_SIZE		UINT64_C(0x00007fff00000000)
+
+extern void km_identity_arch_init(void);
+extern void km_non_identity_arch_init(void);
+extern bool km_is_non_identity_arch(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/arch/sparc64/src/drivers/kbd.c
===================================================================
--- kernel/arch/sparc64/src/drivers/kbd.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/drivers/kbd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,4 +40,5 @@
 #include <mm/page.h>
 #include <arch/mm/page.h>
+#include <mm/km.h>
 #include <typedefs.h>
 #include <align.h>
@@ -113,6 +114,6 @@
 	size_t offset = pa - aligned_addr;
 	
-	ns16550_t *ns16550 = (ns16550_t *)
-	   (hw_map(aligned_addr, offset + size) + offset);
+	ns16550_t *ns16550 = (ns16550_t *) (km_map(aligned_addr, offset + size,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE) + offset);
 	
 	ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, inr, cir, cir_arg);
Index: kernel/arch/sparc64/src/drivers/pci.c
===================================================================
--- kernel/arch/sparc64/src/drivers/pci.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/drivers/pci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,5 +39,5 @@
 #include <genarch/ofw/upa.h>
 #include <arch/trap/interrupt.h>
-#include <mm/page.h>
+#include <mm/km.h>
 #include <mm/slab.h>
 #include <typedefs.h>
@@ -109,5 +109,6 @@
 	pci->model = PCI_SABRE;
 	pci->op = &pci_sabre_ops;
-	pci->reg = (uint64_t *) hw_map(paddr, reg[SABRE_INTERNAL_REG].size);
+	pci->reg = (uint64_t *) km_map(paddr, reg[SABRE_INTERNAL_REG].size,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 
 	/*
@@ -156,5 +157,6 @@
 	pci->model = PCI_PSYCHO;
 	pci->op = &pci_psycho_ops;
-	pci->reg = (uint64_t *) hw_map(paddr, reg[PSYCHO_INTERNAL_REG].size);
+	pci->reg = (uint64_t *) km_map(paddr, reg[PSYCHO_INTERNAL_REG].size,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 
 	/*
Index: kernel/arch/sparc64/src/mm/page.c
===================================================================
--- kernel/arch/sparc64/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -51,20 +51,4 @@
 }
 
-/** Map memory-mapped device into virtual memory.
- *
- * We are currently using identity mapping for mapping device registers.
- *
- * @param physaddr Physical address of the page where the device is
- *                 located.
- * @param size     Size of the device's registers.
- *
- * @return Virtual address of the page where the device is mapped.
- *
- */
-uintptr_t hw_map(uintptr_t physaddr, size_t size)
-{
-	return PA2KA(physaddr);
-}
-
 /** @}
  */
Index: kernel/arch/sparc64/src/mm/sun4u/frame.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4u/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/mm/sun4u/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,48 +41,74 @@
 #include <macros.h>
 
-uintptr_t last_frame = (uintptr_t) NULL;
-
 /** Create memory zones according to information stored in memmap.
  *
  * Walk the memory map and create frame zones according to it.
  */
-void frame_arch_init(void)
+static void frame_common_arch_init(bool low)
 {
-	if (config.cpu_active == 1) {
-		unsigned int i;
+	unsigned int i;
+	
+	for (i = 0; i < memmap.cnt; i++) {
+		uintptr_t base;
+		size_t size;
+
+		/*
+		 * The memmap is created by HelenOS boot loader.
+		 * It already contains no holes.
+		 */
+
+		/* To be safe, make the available zone possibly smaller */
+		base = ALIGN_UP((uintptr_t) memmap.zones[i].start, FRAME_SIZE);
+		size = ALIGN_DOWN(memmap.zones[i].size -
+		    (base - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
 		
-		for (i = 0; i < memmap.cnt; i++) {
-			/* To be safe, make the available zone possibly smaller */
-			uintptr_t new_start = ALIGN_UP((uintptr_t) memmap.zones[i].start,
-			    FRAME_SIZE);
-			size_t new_size = ALIGN_DOWN(memmap.zones[i].size -
-			    (new_start - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
-			
-			/*
-			 * The memmap is created by HelenOS boot loader.
-			 * It already contains no holes.
-			 */
-			
-			pfn_t confdata = ADDR2PFN(new_start);
-			
+		if (!frame_adjust_zone_bounds(low, &base, &size))
+			continue;
+ 
+		pfn_t confdata;
+		pfn_t pfn = ADDR2PFN(base);
+		size_t count = SIZE2FRAMES(size);
+
+		if (low) {
+			confdata = pfn;
 			if (confdata == ADDR2PFN(KA2PA(PFN2ADDR(0))))
 				confdata = ADDR2PFN(KA2PA(PFN2ADDR(2)));
 			
-			zone_create(ADDR2PFN(new_start), SIZE2FRAMES(new_size),
-			    confdata, 0);
-			
-			last_frame = max(last_frame, new_start + new_size);
+			zone_create(pfn, count, confdata,
+			    ZONE_AVAILABLE | ZONE_LOWMEM);
+		} else {
+			confdata = zone_external_conf_alloc(count);
+			if (confdata != 0)
+				zone_create(pfn, count, confdata,
+				    ZONE_AVAILABLE | ZONE_HIGHMEM);
 		}
-		
-		/*
-		 * On sparc64, physical memory can start on a non-zero address.
-		 * The generic frame_init() only marks PFN 0 as not free, so we
-		 * must mark the physically first frame not free explicitly
-		 * here, no matter what is its address.
-		 */
-		frame_mark_unavailable(ADDR2PFN(KA2PA(PFN2ADDR(0))), 1);
 	}
+}
+
+void frame_low_arch_init(void)
+{
+	if (config.cpu_active > 1)
+		return;
 	
-	end_of_identity = PA2KA(last_frame);
+	frame_common_arch_init(true);
+	
+	/*
+	 * On sparc64, physical memory can start on a non-zero address.
+	 * The generic frame_init() only marks PFN 0 as not free, so we
+	 * must mark the physically first frame not free explicitly
+	 * here, no matter what is its address.
+	 */
+	frame_mark_unavailable(ADDR2PFN(KA2PA(PFN2ADDR(0))), 1);
+
+	/* PA2KA will work only on low-memory. */
+	end_of_identity = PA2KA(config.physmem_end - FRAME_SIZE) + PAGE_SIZE;
+}
+
+void frame_high_arch_init(void)
+{
+	if (config.cpu_active > 1)
+		return;
+
+	frame_common_arch_init(false);
 }
 
Index: kernel/arch/sparc64/src/mm/sun4u/km.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4u/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/sparc64/src/mm/sun4u/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_SPARC64_US_IDENTITY_START;
+	config.identity_size = KM_SPARC64_US_IDENTITY_SIZE;
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_SPARC64_US_NON_IDENTITY_START,
+	    KM_SPARC64_US_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_SPARC64_US_NON_IDENTITY_START,
+	    KM_SPARC64_US_NON_IDENTITY_SIZE, addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/sparc64/src/mm/sun4u/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4u/tlb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/mm/sun4u/tlb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -206,5 +206,4 @@
 	pte_t *t;
 
-	page_table_lock(AS, true);
 	t = page_mapping_find(AS, page_16k, true);
 	if (t && PTE_EXECUTABLE(t)) {
@@ -218,5 +217,4 @@
 		itsb_pte_copy(t, index);
 #endif
-		page_table_unlock(AS, true);
 	} else {
 		/*
@@ -224,5 +222,4 @@
 		 * handler.
 		 */
-		page_table_unlock(AS, true);
 		if (as_page_fault(page_16k, PF_ACCESS_EXEC, istate) ==
 		    AS_PF_FAULT) {
@@ -250,4 +247,5 @@
 	size_t index;
 	pte_t *t;
+	as_t *as = AS;
 
 	page_8k = (uint64_t) tag.vpn << MMU_PAGE_WIDTH;
@@ -261,19 +259,13 @@
 			    "Dereferencing NULL pointer.");
 		} else if (page_8k >= end_of_identity) {
-			/*
-			 * The kernel is accessing the I/O space.
-			 * We still do identity mapping for I/O,
-			 * but without caching.
-			 */
-			dtlb_insert_mapping(page_8k, KA2PA(page_8k),
-			    PAGESIZE_8K, false, false);
-			return;
+			/* Kernel non-identity. */
+			as = AS_KERNEL;
+		} else {
+			do_fast_data_access_mmu_miss_fault(istate, tag,
+		    "Unexpected kernel page fault.");
 		}
-		do_fast_data_access_mmu_miss_fault(istate, tag, "Unexpected "
-		    "kernel page fault.");
-	}
-
-	page_table_lock(AS, true);
-	t = page_mapping_find(AS, page_16k, true);
+	}
+
+	t = page_mapping_find(as, page_16k, true);
 	if (t) {
 		/*
@@ -286,11 +278,9 @@
 		dtsb_pte_copy(t, index, true);
 #endif
-		page_table_unlock(AS, true);
 	} else {
 		/*
 		 * Forward the page fault to the address space page fault
 		 * handler.
-		 */		
-		page_table_unlock(AS, true);
+		 */
 		if (as_page_fault(page_16k, PF_ACCESS_READ, istate) ==
 		    AS_PF_FAULT) {
@@ -314,10 +304,13 @@
 	size_t index;
 	pte_t *t;
+	as_t *as = AS;
 
 	page_16k = ALIGN_DOWN((uint64_t) tag.vpn << MMU_PAGE_WIDTH, PAGE_SIZE);
 	index = tag.vpn % MMU_PAGES_PER_PAGE;	/* 16K-page emulation */
 
-	page_table_lock(AS, true);
-	t = page_mapping_find(AS, page_16k, true);
+	if (tag.context == ASID_KERNEL)
+		as = AS_KERNEL;
+
+	t = page_mapping_find(as, page_16k, true);
 	if (t && PTE_WRITABLE(t)) {
 		/*
@@ -334,5 +327,4 @@
 		dtsb_pte_copy(t, index, false);
 #endif
-		page_table_unlock(AS, true);
 	} else {
 		/*
@@ -340,5 +332,4 @@
 		 * handler.
 		 */		
-		page_table_unlock(AS, true);
 		if (as_page_fault(page_16k, PF_ACCESS_WRITE, istate) ==
 		    AS_PF_FAULT) {
Index: kernel/arch/sparc64/src/mm/sun4v/frame.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/mm/sun4v/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -45,38 +45,68 @@
  * Walk the memory map and create frame zones according to it.
  */
-void frame_arch_init(void)
+static void frame_common_arch_init(bool low)
 {
-	if (config.cpu_active == 1) {
-		unsigned int i;
+	unsigned int i;
 		
-		for (i = 0; i < memmap.cnt; i++) {
-			/* To be safe, make the available zone possibly smaller */
-			uintptr_t new_start = ALIGN_UP((uintptr_t) memmap.zones[i].start,
-			    FRAME_SIZE);
-			size_t new_size = ALIGN_DOWN(memmap.zones[i].size -
-			    (new_start - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
-			
-			/*
-			 * The memmap is created by HelenOS boot loader.
-			 * It already contains no holes.
-			 */
-			
-			pfn_t confdata = ADDR2PFN(new_start);
-			
+	for (i = 0; i < memmap.cnt; i++) {
+		uintptr_t base;
+		size_t size;
+
+		/*
+		 * The memmap is created by HelenOS boot loader.
+		 * It already contains no holes.
+		 */
+
+		/* To be safe, make the available zone possibly smaller */
+		base = ALIGN_UP((uintptr_t) memmap.zones[i].start, FRAME_SIZE);
+		size = ALIGN_DOWN(memmap.zones[i].size -
+		    (base - ((uintptr_t) memmap.zones[i].start)), FRAME_SIZE);
+		
+		if (!frame_adjust_zone_bounds(low, &base, &size))
+			continue;
+
+		pfn_t confdata;
+		pfn_t pfn = ADDR2PFN(base);
+		size_t count = SIZE2FRAMES(size);
+
+		if (low) {
+			confdata = pfn;
 			if (confdata == ADDR2PFN(KA2PA(PFN2ADDR(0))))
 				confdata = ADDR2PFN(KA2PA(PFN2ADDR(2)));
 			
-			zone_create(ADDR2PFN(new_start), SIZE2FRAMES(new_size),
-			    confdata, 0);
+			zone_create(pfn, count, confdata,
+			    ZONE_AVAILABLE | ZONE_LOWMEM);
+		} else {
+			confdata = zone_external_conf_alloc(count);
+			if (confdata != 0)
+				zone_create(pfn, count, confdata,
+				    ZONE_AVAILABLE | ZONE_HIGHMEM);
 		}
-		
-		/*
-		 * On sparc64, physical memory can start on a non-zero address.
-		 * The generic frame_init() only marks PFN 0 as not free, so we
-		 * must mark the physically first frame not free explicitly
-		 * here, no matter what is its address.
-		 */
-		frame_mark_unavailable(ADDR2PFN(KA2PA(PFN2ADDR(0))), 1);
 	}
+}
+
+
+void frame_low_arch_init(void)
+{
+	if (config.cpu_active > 1)
+		return;
+
+	frame_common_arch_init(true);
+
+	/*
+	 * On sparc64, physical memory can start on a non-zero address.
+	 * The generic frame_init() only marks PFN 0 as not free, so we
+	 * must mark the physically first frame not free explicitly
+	 * here, no matter what is its address.
+	 */
+	frame_mark_unavailable(ADDR2PFN(KA2PA(PFN2ADDR(0))), 1);
+}
+
+void frame_high_arch_init(void)
+{
+	if (config.cpu_active > 1)
+		return;
+
+	frame_common_arch_init(false);
 }
 
Index: kernel/arch/sparc64/src/mm/sun4v/km.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/arch/sparc64/src/mm/sun4v/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup sparc64mm
+ * @{
+ */
+
+#include <arch/mm/km.h>
+#include <mm/km.h>
+#include <config.h>
+#include <typedefs.h>
+#include <macros.h>
+
+void km_identity_arch_init(void)
+{
+	config.identity_base = KM_SPARC64_T1_IDENTITY_START;
+	config.identity_size = KM_SPARC64_T1_IDENTITY_SIZE;
+}
+
+void km_non_identity_arch_init(void)
+{
+	km_non_identity_span_add(KM_SPARC64_T1_NON_IDENTITY_START,
+	    KM_SPARC64_T1_NON_IDENTITY_SIZE);
+}
+
+bool km_is_non_identity_arch(uintptr_t addr)
+{
+	return iswithin(KM_SPARC64_T1_NON_IDENTITY_START,
+	    KM_SPARC64_T1_NON_IDENTITY_SIZE, addr, 1);
+}
+
+/** @}
+ */
Index: kernel/arch/sparc64/src/mm/sun4v/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -218,5 +218,4 @@
 	pte_t *t;
 
-	page_table_lock(AS, true);
 	t = page_mapping_find(AS, va, true);
 
@@ -231,5 +230,4 @@
 		itsb_pte_copy(t);
 #endif
-		page_table_unlock(AS, true);
 	} else {
 		/*
@@ -237,5 +235,4 @@
 		 * handler.
 		 */
-		page_table_unlock(AS, true);
 		if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
 			do_fast_instruction_access_mmu_miss_fault(istate,
@@ -274,5 +271,4 @@
 	}
 
-	page_table_lock(AS, true);
 	t = page_mapping_find(AS, va, true);
 	if (t) {
@@ -286,5 +282,4 @@
 		dtsb_pte_copy(t, true);
 #endif
-		page_table_unlock(AS, true);
 	} else {
 		/*
@@ -292,5 +287,4 @@
 		 * handler.
 		 */		
-		page_table_unlock(AS, true);
 		if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
 			do_fast_data_access_mmu_miss_fault(istate, page_and_ctx,
@@ -316,5 +310,4 @@
 	uint16_t ctx = DMISS_CONTEXT(page_and_ctx);
 
-	page_table_lock(AS, true);
 	t = page_mapping_find(AS, va, true);
 	if (t && PTE_WRITABLE(t)) {
@@ -331,5 +324,4 @@
 		dtsb_pte_copy(t, false);
 #endif
-		page_table_unlock(AS, true);
 	} else {
 		/*
@@ -337,5 +329,4 @@
 		 * handler.
 		 */		
-		page_table_unlock(AS, true);
 		if (as_page_fault(va, PF_ACCESS_WRITE, istate) == AS_PF_FAULT) {
 			do_fast_data_access_protection_fault(istate, page_and_ctx,
Index: kernel/arch/sparc64/src/sun4u/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4u/sparc64.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/sun4u/sparc64.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -62,5 +62,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr = (uintptr_t) bootinfo->taskmap.tasks[i].addr;
+		init.tasks[i].paddr = KA2PA(bootinfo->taskmap.tasks[i].addr);
 		init.tasks[i].size = bootinfo->taskmap.tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
Index: kernel/arch/sparc64/src/sun4v/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4v/sparc64.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/arch/sparc64/src/sun4v/sparc64.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -64,5 +64,5 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		init.tasks[i].addr = (uintptr_t) bootinfo->taskmap.tasks[i].addr;
+		init.tasks[i].paddr = KA2PA(bootinfo->taskmap.tasks[i].addr);
 		init.tasks[i].size = bootinfo->taskmap.tasks[i].size;
 		str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN,
Index: kernel/genarch/include/mm/page_ht.h
===================================================================
--- kernel/genarch/include/mm/page_ht.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/include/mm/page_ht.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,4 +43,5 @@
 #include <mm/as.h>
 #include <mm/page.h>
+#include <mm/slab.h>
 #include <synch/mutex.h>
 #include <adt/hash_table.h>
@@ -64,4 +65,5 @@
 extern page_mapping_operations_t ht_mapping_operations;
 
+extern slab_cache_t *pte_cache;
 extern mutex_t page_ht_lock;
 extern hash_table_t page_ht;
Index: kernel/genarch/src/acpi/acpi.c
===================================================================
--- kernel/genarch/src/acpi/acpi.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/acpi/acpi.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,6 +39,6 @@
 #include <genarch/acpi/madt.h>
 #include <arch/bios/bios.h>
-#include <mm/as.h>
 #include <mm/page.h>
+#include <mm/km.h>
 #include <print.h>
 
@@ -96,11 +96,20 @@
 }
 
-static void map_sdt(struct acpi_sdt_header *sdt)
-{
-	page_table_lock(AS_KERNEL, true);
-	page_mapping_insert(AS_KERNEL, (uintptr_t) sdt, (uintptr_t) sdt,
-	    PAGE_NOT_CACHEABLE | PAGE_WRITE);
-	map_structure((uintptr_t) sdt, sdt->length);
-	page_table_unlock(AS_KERNEL, true);
+static struct acpi_sdt_header *map_sdt(struct acpi_sdt_header *psdt)
+{
+	struct acpi_sdt_header *vhdr;
+	struct acpi_sdt_header *vsdt;
+
+	/* Start with mapping the header only. */
+	vhdr = (struct acpi_sdt_header *) km_map((uintptr_t) psdt,
+	    sizeof(struct acpi_sdt_header), PAGE_READ | PAGE_NOT_CACHEABLE); 
+
+	/* Now we can map the entire structure. */
+	vsdt = (struct acpi_sdt_header *) km_map((uintptr_t) psdt,
+	    vhdr->length, PAGE_WRITE | PAGE_NOT_CACHEABLE);
+	
+	// TODO: do not leak vtmp
+
+	return vsdt; 
 }
 
@@ -118,10 +127,10 @@
 			    (struct acpi_sdt_header *) (sysarg_t) acpi_rsdt->entry[i];
 			
-			map_sdt(hdr);
-			if (CMP_SIGNATURE(hdr->signature, signature_map[j].signature)) {
-				if (!acpi_sdt_check((uint8_t *) hdr))
+			struct acpi_sdt_header *vhdr = map_sdt(hdr);
+			if (CMP_SIGNATURE(vhdr->signature, signature_map[j].signature)) {
+				if (!acpi_sdt_check((uint8_t *) vhdr))
 					break;
 				
-				*signature_map[j].sdt_ptr = hdr;
+				*signature_map[j].sdt_ptr = vhdr;
 				LOG("%p: ACPI %s", *signature_map[j].sdt_ptr,
 				    signature_map[j].description);
@@ -144,10 +153,10 @@
 			    (struct acpi_sdt_header *) ((uintptr_t) acpi_xsdt->entry[i]);
 			
-			map_sdt(hdr);
-			if (CMP_SIGNATURE(hdr->signature, signature_map[j].signature)) {
-				if (!acpi_sdt_check((uint8_t *) hdr))
+			struct acpi_sdt_header *vhdr = map_sdt(hdr);
+			if (CMP_SIGNATURE(vhdr->signature, signature_map[j].signature)) {
+				if (!acpi_sdt_check((uint8_t *) vhdr))
 					break;
 				
-				*signature_map[j].sdt_ptr = hdr;
+				*signature_map[j].sdt_ptr = vhdr;
 				LOG("%p: ACPI %s", *signature_map[j].sdt_ptr,
 				    signature_map[j].description);
@@ -187,13 +196,17 @@
 	LOG("%p: ACPI Root System Description Pointer", acpi_rsdp);
 	
-	acpi_rsdt = (struct acpi_rsdt *) ((uintptr_t) acpi_rsdp->rsdt_address);
+	uintptr_t acpi_rsdt_p = (uintptr_t) acpi_rsdp->rsdt_address;
+	uintptr_t acpi_xsdt_p = 0;
+
 	if (acpi_rsdp->revision)
-		acpi_xsdt = (struct acpi_xsdt *) ((uintptr_t) acpi_rsdp->xsdt_address);
-	
-	if (acpi_rsdt)
-		map_sdt((struct acpi_sdt_header *) acpi_rsdt);
-	
-	if (acpi_xsdt)
-		map_sdt((struct acpi_sdt_header *) acpi_xsdt);
+		acpi_xsdt_p = (uintptr_t) acpi_rsdp->xsdt_address;
+	
+	if (acpi_rsdt_p)
+		acpi_rsdt = (struct acpi_rsdt *) map_sdt(
+		    (struct acpi_sdt_header *) acpi_rsdt_p);
+	
+	if (acpi_xsdt_p)
+		acpi_xsdt = (struct acpi_xsdt *) map_sdt(
+		    (struct acpi_sdt_header *) acpi_xsdt_p);
 	
 	if ((acpi_rsdt) && (!acpi_sdt_check((uint8_t *) acpi_rsdt))) {
Index: kernel/genarch/src/drivers/ega/ega.c
===================================================================
--- kernel/genarch/src/drivers/ega/ega.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/drivers/ega/ega.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -37,8 +37,7 @@
 #include <genarch/drivers/ega/ega.h>
 #include <putchar.h>
-#include <mm/page.h>
+#include <mm/km.h>
 #include <mm/as.h>
 #include <mm/slab.h>
-#include <arch/mm/page.h>
 #include <typedefs.h>
 #include <arch/asm.h>
@@ -598,5 +597,6 @@
 	
 	instance->base = base;
-	instance->addr = (uint8_t *) hw_map(addr, EGA_VRAM_SIZE);
+	instance->addr = (uint8_t *) km_map(addr, EGA_VRAM_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	if (!instance->addr) {
 		LOG("Unable to EGA video memory.");
Index: kernel/genarch/src/drivers/i8042/i8042.c
===================================================================
--- kernel/genarch/src/drivers/i8042/i8042.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/drivers/i8042/i8042.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -44,4 +44,5 @@
 #include <mm/slab.h>
 #include <ddi/device.h>
+#include <time/delay.h>
 
 #define i8042_SET_COMMAND  0x60
@@ -51,4 +52,6 @@
 #define i8042_BUFFER_FULL_MASK  0x01
 #define i8042_WAIT_MASK         0x02
+
+#define i8042_TIMEOUT  65536
 
 static irq_ownership_t i8042_claim(irq_t *irq)
@@ -77,6 +80,24 @@
 static void i8042_clear_buffer(i8042_t *dev)
 {
-	while (pio_read_8(&dev->status) & i8042_BUFFER_FULL_MASK)
+	for (uint32_t i = 0; i < i8042_TIMEOUT; i++) {
+		if ((pio_read_8(&dev->status) & i8042_BUFFER_FULL_MASK) == 0)
+			break;
+		
 		(void) pio_read_8(&dev->data);
+		delay(50);  /* 50 us think time */
+	}
+}
+
+static void i8042_send_command(i8042_t *dev, uint8_t cmd)
+{
+	for (uint32_t i = 0; i < i8042_TIMEOUT; i++) {
+		if ((pio_read_8(&dev->status) & i8042_WAIT_MASK) == 0)
+			break;
+		
+		delay(50);  /* 50 us think time */
+	}
+	
+	pio_write_8(&dev->status, cmd);
+	delay(10000);  /* 10 ms think time */
 }
 
@@ -84,6 +105,6 @@
 i8042_instance_t *i8042_init(i8042_t *dev, inr_t inr)
 {
-	i8042_instance_t *instance
-	    = malloc(sizeof(i8042_instance_t), FRAME_ATOMIC);
+	i8042_instance_t *instance =
+	    malloc(sizeof(i8042_instance_t), FRAME_ATOMIC);
 	if (instance) {
 		instance->i8042 = dev;
@@ -96,5 +117,4 @@
 		instance->irq.handler = i8042_irq_handler;
 		instance->irq.instance = instance;
-		
 	}
 	
@@ -107,7 +127,8 @@
 	ASSERT(kbrdin);
 	
+	i8042_clear_buffer(instance->i8042);
+	
 	instance->kbrdin = kbrdin;
 	irq_register(&instance->irq);
-	i8042_clear_buffer(instance->i8042);
 }
 
@@ -116,9 +137,6 @@
 {
 	interrupts_disable();
-	
 	i8042_clear_buffer(dev);
-	
-	/* Reset CPU */
-	pio_write_8(&dev->status, i8042_CPU_RESET);
+	i8042_send_command(dev, i8042_CPU_RESET);
 }
 
Index: kernel/genarch/src/drivers/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- kernel/genarch/src/drivers/s3c24xx_uart/s3c24xx_uart.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/drivers/s3c24xx_uart/s3c24xx_uart.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -45,4 +45,5 @@
 #include <mm/slab.h>
 #include <mm/page.h>
+#include <mm/km.h>
 #include <sysinfo/sysinfo.h>
 #include <str.h>
@@ -113,5 +114,6 @@
 	uart_dev->data = uart;
 
-	uart->io = (s3c24xx_uart_io_t *) hw_map(paddr, PAGE_SIZE);
+	uart->io = (s3c24xx_uart_io_t *) km_map(paddr, PAGE_SIZE,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	uart->indev = NULL;
 
Index: kernel/genarch/src/fb/bfb.c
===================================================================
--- kernel/genarch/src/fb/bfb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/fb/bfb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,5 +40,5 @@
 #include <console/console.h>
 
-uintptr_t bfb_addr = (uintptr_t) -1;
+uintptr_t bfb_addr = 0;
 uint32_t bfb_width = 0;
 uint32_t bfb_height = 0;
@@ -57,5 +57,6 @@
 bool bfb_init(void)
 {
-	if ((bfb_width == 0) || (bfb_height == 0))
+	if ((bfb_addr == 0) || (bfb_width == 0) || (bfb_height == 0) ||
+	    (bfb_bpp == 0) || (bfb_scanline == 0))
 		return false;
 	
Index: kernel/genarch/src/fb/fb.c
===================================================================
--- kernel/genarch/src/fb/fb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/fb/fb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,5 +40,5 @@
 #include <console/console.h>
 #include <sysinfo/sysinfo.h>
-#include <mm/page.h>
+#include <mm/km.h>
 #include <mm/slab.h>
 #include <align.h>
@@ -587,5 +587,6 @@
 	size_t glyphsize = FONT_GLYPHS * instance->glyphbytes;
 	
-	instance->addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
+	instance->addr = (uint8_t *) km_map((uintptr_t) props->addr, fbsize,
+	    PAGE_WRITE | PAGE_NOT_CACHEABLE);
 	if (!instance->addr) {
 		LOG("Unable to map framebuffer.");
Index: kernel/genarch/src/mm/as_ht.c
===================================================================
--- kernel/genarch/src/mm/as_ht.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/mm/as_ht.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,4 +41,5 @@
 #include <mm/as.h>
 #include <mm/frame.h>
+#include <mm/slab.h>
 #include <typedefs.h>
 #include <memstr.h>
@@ -77,4 +78,6 @@
 		hash_table_create(&page_ht, PAGE_HT_ENTRIES, 2, &ht_operations);
 		mutex_initialize(&page_ht_lock, MUTEX_PASSIVE);
+		pte_cache = slab_cache_create("pte_cache", sizeof(pte_t), 0, NULL, NULL,
+		    SLAB_CACHE_MAGDEFERRED);
 	}
 	
Index: kernel/genarch/src/mm/as_pt.c
===================================================================
--- kernel/genarch/src/mm/as_pt.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/mm/as_pt.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -73,5 +73,6 @@
 pte_t *ptl0_create(unsigned int flags)
 {
-	pte_t *dst_ptl0 = (pte_t *) frame_alloc(PTL0_SIZE, FRAME_KA);
+	pte_t *dst_ptl0 = (pte_t *) frame_alloc(PTL0_SIZE,
+	    FRAME_LOWMEM | FRAME_KA);
 	size_t table_size = FRAME_SIZE << PTL0_SIZE;
 	
@@ -89,8 +90,8 @@
 		    (pte_t *) PA2KA((uintptr_t) AS_KERNEL->genarch.page_table);
 		
-		uintptr_t src =
-		    (uintptr_t) &src_ptl0[PTL0_INDEX(KERNEL_ADDRESS_SPACE_START)];
-		uintptr_t dst =
-		    (uintptr_t) &dst_ptl0[PTL0_INDEX(KERNEL_ADDRESS_SPACE_START)];
+		uintptr_t src = (uintptr_t)
+		    &src_ptl0[PTL0_INDEX(KERNEL_ADDRESS_SPACE_START)];
+		uintptr_t dst = (uintptr_t)
+		    &dst_ptl0[PTL0_INDEX(KERNEL_ADDRESS_SPACE_START)];
 		
 		memsetb(dst_ptl0, table_size, 0);
Index: kernel/genarch/src/mm/page_ht.c
===================================================================
--- kernel/genarch/src/mm/page_ht.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/mm/page_ht.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -59,4 +59,7 @@
 static void ht_mapping_remove(as_t *, uintptr_t);
 static pte_t *ht_mapping_find(as_t *, uintptr_t, bool);
+static void ht_mapping_make_global(uintptr_t, size_t);
+
+slab_cache_t *pte_cache = NULL;
 
 /**
@@ -86,5 +89,6 @@
 	.mapping_insert = ht_mapping_insert,
 	.mapping_remove = ht_mapping_remove,
-	.mapping_find = ht_mapping_find
+	.mapping_find = ht_mapping_find,
+	.mapping_make_global = ht_mapping_make_global
 };
 
@@ -163,5 +167,5 @@
 	pte_t *pte = hash_table_get_instance(item, pte_t, link);
 	
-	free(pte);
+	slab_free(pte_cache, pte);
 }
 
@@ -188,5 +192,5 @@
 	
 	if (!hash_table_find(&page_ht, key)) {
-		pte_t *pte = (pte_t *) malloc(sizeof(pte_t), FRAME_ATOMIC);
+		pte_t *pte = slab_alloc(pte_cache, FRAME_LOWMEM | FRAME_ATOMIC);
 		ASSERT(pte != NULL);
 		
@@ -260,4 +264,9 @@
 }
 
+void ht_mapping_make_global(uintptr_t base, size_t size)
+{
+	/* nothing to do */
+}
+
 /** @}
  */
Index: kernel/genarch/src/mm/page_pt.c
===================================================================
--- kernel/genarch/src/mm/page_pt.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/mm/page_pt.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,4 +39,5 @@
 #include <mm/page.h>
 #include <mm/frame.h>
+#include <mm/km.h>
 #include <mm/as.h>
 #include <arch/mm/page.h>
@@ -45,13 +46,17 @@
 #include <arch/asm.h>
 #include <memstr.h>
+#include <align.h>
+#include <macros.h>
 
 static void pt_mapping_insert(as_t *, uintptr_t, uintptr_t, unsigned int);
 static void pt_mapping_remove(as_t *, uintptr_t);
 static pte_t *pt_mapping_find(as_t *, uintptr_t, bool);
+static void pt_mapping_make_global(uintptr_t, size_t);
 
 page_mapping_operations_t pt_mapping_operations = {
 	.mapping_insert = pt_mapping_insert,
 	.mapping_remove = pt_mapping_remove,
-	.mapping_find = pt_mapping_find
+	.mapping_find = pt_mapping_find,
+	.mapping_make_global = pt_mapping_make_global
 };
 
@@ -75,8 +80,11 @@
 	
 	if (GET_PTL1_FLAGS(ptl0, PTL0_INDEX(page)) & PAGE_NOT_PRESENT) {
-		pte_t *newpt = (pte_t *) frame_alloc(PTL1_SIZE, FRAME_KA);
+		pte_t *newpt = (pte_t *) frame_alloc(PTL1_SIZE,
+		    FRAME_LOWMEM | FRAME_KA);
 		memsetb(newpt, FRAME_SIZE << PTL1_SIZE, 0);
 		SET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page), KA2PA(newpt));
-		SET_PTL1_FLAGS(ptl0, PTL0_INDEX(page), PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE | PAGE_WRITE);
+		SET_PTL1_FLAGS(ptl0, PTL0_INDEX(page),
+		    PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE |
+		    PAGE_WRITE);
 	}
 	
@@ -84,8 +92,11 @@
 	
 	if (GET_PTL2_FLAGS(ptl1, PTL1_INDEX(page)) & PAGE_NOT_PRESENT) {
-		pte_t *newpt = (pte_t *) frame_alloc(PTL2_SIZE, FRAME_KA);
+		pte_t *newpt = (pte_t *) frame_alloc(PTL2_SIZE,
+		    FRAME_LOWMEM | FRAME_KA);
 		memsetb(newpt, FRAME_SIZE << PTL2_SIZE, 0);
 		SET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page), KA2PA(newpt));
-		SET_PTL2_FLAGS(ptl1, PTL1_INDEX(page), PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE | PAGE_WRITE);
+		SET_PTL2_FLAGS(ptl1, PTL1_INDEX(page),
+		    PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE |
+		    PAGE_WRITE);
 	}
 	
@@ -93,8 +104,11 @@
 	
 	if (GET_PTL3_FLAGS(ptl2, PTL2_INDEX(page)) & PAGE_NOT_PRESENT) {
-		pte_t *newpt = (pte_t *) frame_alloc(PTL3_SIZE, FRAME_KA);
+		pte_t *newpt = (pte_t *) frame_alloc(PTL3_SIZE,
+		    FRAME_LOWMEM | FRAME_KA);
 		memsetb(newpt, FRAME_SIZE << PTL3_SIZE, 0);
 		SET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page), KA2PA(newpt));
-		SET_PTL3_FLAGS(ptl2, PTL2_INDEX(page), PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE | PAGE_WRITE);
+		SET_PTL3_FLAGS(ptl2, PTL2_INDEX(page),
+		    PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE |
+		    PAGE_WRITE);
 	}
 	
@@ -123,5 +137,4 @@
 	/*
 	 * First, remove the mapping, if it exists.
-	 *
 	 */
 	
@@ -140,10 +153,13 @@
 	pte_t *ptl3 = (pte_t *) PA2KA(GET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page)));
 	
-	/* Destroy the mapping. Setting to PAGE_NOT_PRESENT is not sufficient. */
+	/*
+	 * Destroy the mapping.
+	 * Setting to PAGE_NOT_PRESENT is not sufficient.
+	 */
 	memsetb(&ptl3[PTL3_INDEX(page)], sizeof(pte_t), 0);
 	
 	/*
-	 * Second, free all empty tables along the way from PTL3 down to PTL0.
-	 *
+	 * Second, free all empty tables along the way from PTL3 down to PTL0
+	 * except those needed for sharing the kernel non-identity mappings.
 	 */
 	
@@ -162,8 +178,7 @@
 		/*
 		 * PTL3 is empty.
-		 * Release the frame and remove PTL3 pointer from preceding table.
-		 *
-		 */
-		frame_free(KA2PA((uintptr_t) ptl3));
+		 * Release the frame and remove PTL3 pointer from the parent
+		 * table.
+		 */
 #if (PTL2_ENTRIES != 0)
 		memsetb(&ptl2[PTL2_INDEX(page)], sizeof(pte_t), 0);
@@ -171,6 +186,10 @@
 		memsetb(&ptl1[PTL1_INDEX(page)], sizeof(pte_t), 0);
 #else
+		if (km_is_non_identity(page))
+			return;
+
 		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
 #endif
+		frame_free(KA2PA((uintptr_t) ptl3));
 	} else {
 		/*
@@ -195,13 +214,16 @@
 		/*
 		 * PTL2 is empty.
-		 * Release the frame and remove PTL2 pointer from preceding table.
-		 *
-		 */
-		frame_free(KA2PA((uintptr_t) ptl2));
+		 * Release the frame and remove PTL2 pointer from the parent
+		 * table.
+		 */
 #if (PTL1_ENTRIES != 0)
 		memsetb(&ptl1[PTL1_INDEX(page)], sizeof(pte_t), 0);
 #else
+		if (km_is_non_identity(page))
+			return;
+
 		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
 #endif
+		frame_free(KA2PA((uintptr_t) ptl2));
 	} else {
 		/*
@@ -227,9 +249,12 @@
 		/*
 		 * PTL1 is empty.
-		 * Release the frame and remove PTL1 pointer from preceding table.
-		 *
-		 */
+		 * Release the frame and remove PTL1 pointer from the parent
+		 * table.
+		 */
+		if (km_is_non_identity(page))
+			return;
+
+		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
 		frame_free(KA2PA((uintptr_t) ptl1));
-		memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
 	}
 #endif /* PTL1_ENTRIES != 0 */
@@ -267,4 +292,49 @@
 }
 
+/** Make the mappings in the given range global accross all address spaces.
+ *
+ * All PTL0 entries in the given range will be mapped to a next level page
+ * table. The next level page table will be allocated and cleared.
+ *
+ * pt_mapping_remove() will never deallocate these page tables even when there
+ * are no PTEs in them.
+ *
+ * @param as   Address space.
+ * @param base Base address corresponding to the first PTL0 entry that will be
+ *             altered by this function.
+ * @param size Size in bytes defining the range of PTL0 entries that will be
+ *             altered by this function.
+ */
+void pt_mapping_make_global(uintptr_t base, size_t size)
+{
+	uintptr_t ptl0 = PA2KA((uintptr_t) AS_KERNEL->genarch.page_table);
+	uintptr_t ptl0step = (((uintptr_t) -1) / PTL0_ENTRIES) + 1;
+	size_t order;
+	uintptr_t addr;
+
+#if (PTL1_ENTRIES != 0)
+	order = PTL1_SIZE;
+#elif (PTL2_ENTRIES != 0)
+	order = PTL2_SIZE;
+#else
+	order = PTL3_SIZE;
+#endif
+
+	ASSERT(ispwr2(ptl0step));
+	ASSERT(size > 0);
+
+	for (addr = ALIGN_DOWN(base, ptl0step); addr - 1 < base + size - 1;
+	    addr += ptl0step) {
+		uintptr_t l1;
+
+		l1 = (uintptr_t) frame_alloc(order, FRAME_KA | FRAME_LOWMEM);
+		memsetb((void *) l1, FRAME_SIZE << order, 0);
+		SET_PTL1_ADDRESS(ptl0, PTL0_INDEX(addr), KA2PA(l1));
+		SET_PTL1_FLAGS(ptl0, PTL0_INDEX(addr),
+		    PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE |
+		    PAGE_WRITE);
+	}
+}
+
 /** @}
  */
Index: kernel/genarch/src/multiboot/multiboot.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/multiboot/multiboot.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -77,5 +77,5 @@
 			break;
 		
-		init.tasks[init.cnt].addr = PA2KA(mods[i].start);
+		init.tasks[init.cnt].paddr = mods[i].start;
 		init.tasks[init.cnt].size = mods[i].end - mods[i].start;
 		
Index: kernel/genarch/src/multiboot/multiboot2.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot2.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/genarch/src/multiboot/multiboot2.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -45,5 +45,5 @@
 {
 	if (init.cnt < CONFIG_INIT_TASKS) {
-		init.tasks[init.cnt].addr = PA2KA(module->start);
+		init.tasks[init.cnt].paddr = module->start;
 		init.tasks[init.cnt].size = module->end - module->start;
 		multiboot_extract_command(init.tasks[init.cnt].name,
@@ -76,4 +76,5 @@
 static void multiboot2_fbinfo(const multiboot2_fbinfo_t *fbinfo)
 {
+#ifdef CONFIG_FB
 	if (fbinfo->visual == MULTIBOOT2_VISUAL_RGB) {
 		bfb_addr = fbinfo->addr;
@@ -92,4 +93,5 @@
 		bfb_blue_size = fbinfo->rgb.blue_size;
 	}
+#endif
 }
 
Index: kernel/generic/include/align.h
===================================================================
--- kernel/generic/include/align.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/align.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -42,5 +42,5 @@
  *
  * @param s Address or size to be aligned.
- * @param a Size of alignment, must be power of 2.
+ * @param a Size of alignment, must be a power of 2.
  */
 #define ALIGN_DOWN(s, a)  ((s) & ~((a) - 1))
@@ -50,7 +50,14 @@
  *
  * @param s Address or size to be aligned.
- * @param a Size of alignment, must be power of 2.
+ * @param a Size of alignment, must be a power of 2.
  */
 #define ALIGN_UP(s, a)  (((s) + ((a) - 1)) & ~((a) - 1))
+
+/** Check alignment.
+ *
+ * @param s Address or size to be checked for alignment.
+ * @param a Size of alignment, must be a power of 2.
+ */ 
+#define IS_ALIGNED(s, a)	(ALIGN_UP((s), (a)) == (s))
 
 #endif
Index: kernel/generic/include/config.h
===================================================================
--- kernel/generic/include/config.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/config.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -53,5 +53,5 @@
 
 typedef struct {
-	uintptr_t addr;
+	uintptr_t paddr;
 	size_t size;
 	char name[CONFIG_TASK_NAME_BUFLEN];
@@ -74,12 +74,28 @@
 
 typedef struct {
-	unsigned int cpu_count;      /**< Number of processors detected. */
-	volatile size_t cpu_active;  /**< Number of processors that are up and running. */
+	/** Number of processors detected. */
+	unsigned int cpu_count;
+	/** Number of processors that are up and running. */
+	volatile size_t cpu_active;
 	
 	uintptr_t base;
-	size_t kernel_size;          /**< Size of memory in bytes taken by kernel and stack */
+	/** Size of memory in bytes taken by kernel and stack. */
+	size_t kernel_size;
 	
-	uintptr_t stack_base;        /**< Base adddress of initial stack */
-	size_t stack_size;           /**< Size of initial stack */
+	/** Base adddress of initial stack. */
+	uintptr_t stack_base;
+	/** Size of initial stack. */
+	size_t stack_size;
+
+	bool identity_configured;
+	/** Base address of the kernel identity mapped memory. */
+	uintptr_t identity_base;
+	/** Size of the kernel identity mapped memory. */
+	size_t identity_size;
+
+	bool non_identity_configured;   
+
+	/** End of physical memory. */
+	uint64_t physmem_end;
 } config_t;
 
Index: kernel/generic/include/ddi/ddi.h
===================================================================
--- kernel/generic/include/ddi/ddi.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/ddi/ddi.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/ipc/sysipc.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/lib/ra.h
===================================================================
--- kernel/generic/include/lib/ra.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/generic/include/lib/ra.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_RA_H_
+#define KERN_RA_H_
+
+#include <typedefs.h>
+#include <adt/list.h>
+#include <adt/hash_table.h>
+#include <synch/spinlock.h>
+
+typedef struct {
+	SPINLOCK_DECLARE(lock);
+	list_t spans;		/**< List of arena's spans. */
+} ra_arena_t;
+
+typedef struct {
+	link_t span_link;	/**< Arena's list of spans link. */
+
+	list_t segments;	/**< List of span's segments. */
+
+	size_t max_order;	/**< Base 2 logarithm of span's size. */
+	list_t *free;		/**< max_order segment free lists. */
+
+	hash_table_t used;
+
+	uintptr_t base;		/**< Span base. */
+	size_t size;		/**< Span size. */
+} ra_span_t;
+
+#define RA_SEGMENT_FREE		1
+
+/*
+ * We would like to achieve a good ratio of the size of one unit of the
+ * represented resource (e.g. a page) and sizeof(ra_segment_t).  We therefore
+ * attempt to have as few redundant information in the segment as possible. For
+ * example, the size of the segment needs to be calculated from the segment
+ * base and the base of the following segment.
+ */
+typedef struct {
+	link_t segment_link;	/**< Span's segment list link. */
+	link_t fu_link;		/**< Span's free list or used hash link. */
+
+	uintptr_t base;		/**< Segment base. */
+	uint8_t flags;		/**< Segment flags. */
+} ra_segment_t;
+
+extern void ra_init(void);
+extern ra_arena_t *ra_arena_create(void);
+extern bool ra_span_add(ra_arena_t *, uintptr_t, size_t);
+extern uintptr_t ra_alloc(ra_arena_t *, size_t, size_t);
+extern void ra_free(ra_arena_t *, uintptr_t, size_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/macros.h
===================================================================
--- kernel/generic/include/macros.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/macros.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -77,4 +77,6 @@
 #endif /* __ASM__ */
 
+#define ispwr2(x)	(((x) & ((x) - 1)) == 0)
+
 #define isdigit(d)     (((d) >= '0') && ((d) <= '9'))
 #define islower(c)     (((c) >= 'a') && ((c) <= 'z'))
Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/mm/as.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/frame.h
===================================================================
--- kernel/generic/include/mm/frame.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/mm/frame.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -50,4 +50,5 @@
 typedef uint8_t frame_flags_t;
 
+#define FRAME_NONE        0x0
 /** Convert the frame address to kernel VA. */
 #define FRAME_KA          0x1
@@ -58,24 +59,42 @@
 /** Do not reserve / unreserve memory. */
 #define FRAME_NO_RESERVE  0x8
+/** Allocate a frame which can be identity-mapped. */
+#define FRAME_LOWMEM	  0x10
+/** Allocate a frame which cannot be identity-mapped. */
+#define FRAME_HIGHMEM	  0x20
 
 typedef uint8_t zone_flags_t;
 
+#define ZONE_NONE	0x0
 /** Available zone (free for allocation) */
-#define ZONE_AVAILABLE  0x0
+#define ZONE_AVAILABLE  0x1
 /** Zone is reserved (not available for allocation) */
-#define ZONE_RESERVED   0x8
+#define ZONE_RESERVED   0x2
 /** Zone is used by firmware (not available for allocation) */
-#define ZONE_FIRMWARE   0x10
+#define ZONE_FIRMWARE   0x4
+/** Zone contains memory that can be identity-mapped */
+#define ZONE_LOWMEM	0x8
+/** Zone contains memory that cannot be identity-mapped */
+#define ZONE_HIGHMEM	0x10
 
-/** Currently there is no equivalent zone flags
-    for frame flags */
-#define FRAME_TO_ZONE_FLAGS(frame_flags)  0
+/** Mask of zone bits that must be matched exactly. */
+#define ZONE_EF_MASK	0x7
+
+#define FRAME_TO_ZONE_FLAGS(ff)	\
+	((((ff) & FRAME_LOWMEM) ? ZONE_LOWMEM : \
+	    (((ff) & FRAME_HIGHMEM) ? ZONE_HIGHMEM : \
+	    ZONE_LOWMEM /* | ZONE_HIGHMEM */)) | \
+	    ZONE_AVAILABLE) 
+
+#define ZONE_FLAGS_MATCH(zf, f) \
+	(((((zf) & ZONE_EF_MASK)) == ((f) & ZONE_EF_MASK)) && \
+	    (((zf) & ~ZONE_EF_MASK) & (f)))
 
 typedef struct {
 	size_t refcount;      /**< Tracking of shared frames */
-	uint8_t buddy_order;  /**< Buddy system block order */
 	link_t buddy_link;    /**< Link to the next free block inside
                                    one order */
 	void *parent;         /**< If allocated by slab, this points there */
+	uint8_t buddy_order;  /**< Buddy system block order */
 } frame_t;
 
@@ -129,9 +148,4 @@
 }
 
-NO_TRACE static inline bool zone_flags_available(zone_flags_t flags)
-{
-	return ((flags & (ZONE_RESERVED | ZONE_FIRMWARE)) == 0);
-}
-
 #define IS_BUDDY_ORDER_OK(index, order) \
     ((~(((sysarg_t) -1) << (order)) & (index)) == 0)
@@ -146,4 +160,5 @@
 
 extern void frame_init(void);
+extern bool frame_adjust_zone_bounds(bool, uintptr_t *, size_t *);
 extern void *frame_alloc_generic(uint8_t, frame_flags_t, size_t *);
 extern void *frame_alloc(uint8_t, frame_flags_t);
@@ -161,4 +176,5 @@
 extern void frame_mark_unavailable(pfn_t, size_t);
 extern size_t zone_conf_size(size_t);
+extern pfn_t zone_external_conf_alloc(size_t);
 extern bool zone_merge(size_t, size_t);
 extern void zone_merge_all(void);
Index: kernel/generic/include/mm/km.h
===================================================================
--- kernel/generic/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/generic/include/mm/km.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericmm
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_KM_H_
+#define KERN_KM_H_
+
+#include <typedefs.h>
+#include <mm/frame.h>
+
+extern void km_identity_init(void);
+extern void km_non_identity_init(void);
+
+extern void km_non_identity_span_add(uintptr_t, size_t);
+
+extern uintptr_t km_page_alloc(size_t, size_t);
+extern void km_page_free(uintptr_t, size_t);
+
+extern bool km_is_non_identity(uintptr_t);
+
+extern uintptr_t km_map(uintptr_t, size_t, unsigned int);
+extern void km_unmap(uintptr_t, size_t);
+
+extern uintptr_t km_temporary_page_get(uintptr_t *, frame_flags_t);
+extern void km_temporary_page_put(uintptr_t);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/mm/page.h
===================================================================
--- kernel/generic/include/mm/page.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/mm/page.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -49,4 +49,5 @@
 	void (* mapping_remove)(as_t *, uintptr_t);
 	pte_t *(* mapping_find)(as_t *, uintptr_t, bool);
+	void (* mapping_make_global)(uintptr_t, size_t);
 } page_mapping_operations_t;
 
@@ -60,11 +61,10 @@
 extern void page_mapping_remove(as_t *, uintptr_t);
 extern pte_t *page_mapping_find(as_t *, uintptr_t, bool);
+extern void page_mapping_make_global(uintptr_t, size_t);
 extern pte_t *page_table_create(unsigned int);
 extern void page_table_destroy(pte_t *);
-extern void map_structure(uintptr_t, size_t);
 
-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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/synch/smc.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/include/syscall/syscall.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/cpu/cpu.c
===================================================================
--- kernel/generic/src/cpu/cpu.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/cpu/cpu.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -74,5 +74,5 @@
 		for (i = 0; i < config.cpu_count; i++) {
 			cpus[i].stack = (uint8_t *) frame_alloc(STACK_FRAMES,
-			    FRAME_KA | FRAME_ATOMIC);
+			    FRAME_LOWMEM | FRAME_KA | FRAME_ATOMIC);
 			cpus[i].id = i;
 			
Index: kernel/generic/src/ddi/ddi.c
===================================================================
--- kernel/generic/src/ddi/ddi.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/ddi/ddi.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/ipc/irq.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/ipc/sysipc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/lib/elf.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/lib/ra.c
===================================================================
--- kernel/generic/src/lib/ra.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/generic/src/lib/ra.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+
+/**
+ * @file
+ * @brief Resource allocator.
+ *
+ * This is a generic resource allocator, loosely based on the ideas presented
+ * in chapter 4 of the following paper and further simplified:
+ *
+ *   Bonwick J., Adams J.: Magazines and Vmem: Extending the Slab Allocator to
+ *   Many CPUs and Arbitrary Resources, USENIX 2001
+ *
+ */
+
+#include <lib/ra.h>
+#include <typedefs.h>
+#include <mm/slab.h>
+#include <bitops.h>
+#include <debug.h>
+#include <panic.h>
+#include <adt/list.h>
+#include <adt/hash_table.h>
+#include <align.h>
+#include <macros.h>
+#include <synch/spinlock.h>
+
+static slab_cache_t *ra_segment_cache;
+
+#define USED_BUCKETS	1024
+
+static size_t used_hash(sysarg_t *key)
+{
+	return ((*key >> 2) & (USED_BUCKETS - 1));
+}
+
+static bool used_compare(sysarg_t *key, size_t keys, link_t *item)
+{
+	ra_segment_t *seg;
+
+	seg = hash_table_get_instance(item, ra_segment_t, fu_link);
+	return seg->base == *key;
+}
+
+static hash_table_operations_t used_ops = {
+	.hash = used_hash,
+	.compare = used_compare,
+	.remove_callback = NULL,
+};
+
+/** Calculate the segment size. */
+static size_t ra_segment_size_get(ra_segment_t *seg)
+{
+	ra_segment_t *nextseg;
+
+	nextseg = list_get_instance(seg->segment_link.next, ra_segment_t,
+	    segment_link);
+	return nextseg->base - seg->base;
+}
+
+static ra_segment_t *ra_segment_create(uintptr_t base)
+{
+	ra_segment_t *seg;
+
+	seg = slab_alloc(ra_segment_cache, FRAME_ATOMIC);
+	if (!seg)
+		return NULL;
+
+	link_initialize(&seg->segment_link);
+	link_initialize(&seg->fu_link);
+
+	seg->base = base;
+	seg->flags = 0;
+
+	return seg;
+}
+
+static void ra_segment_destroy(ra_segment_t *seg)
+{
+	slab_free(ra_segment_cache, seg);
+}
+
+static ra_span_t *ra_span_create(uintptr_t base, size_t size)
+{
+	ra_span_t *span;
+	ra_segment_t *seg, *lastseg;
+	unsigned int i;
+
+	span = (ra_span_t *) malloc(sizeof(ra_span_t), FRAME_ATOMIC);
+	if (!span)
+		return NULL;
+
+	span->max_order = fnzb(size);
+	span->base = base;
+	span->size = size;
+
+	span->free = (list_t *) malloc((span->max_order + 1) * sizeof(list_t),
+	    FRAME_ATOMIC);
+	if (!span->free) {
+		free(span);
+		return NULL;
+	}
+
+	/*
+	 * Create a segment to represent the entire size of the span.
+	 */
+	seg = ra_segment_create(base);
+	if (!seg) {
+		free(span->free);
+		free(span);
+		return NULL;
+	}
+	seg->flags = RA_SEGMENT_FREE;
+
+	/*
+	 * The last segment will be used as a sentinel at the end of the
+	 * segment list so that it is possible to calculate the size for
+	 * all other segments. It will not be placed in any free list or
+	 * in the used segment hash and adjacent segments will not be
+	 * coalesced with it.
+	 */
+	lastseg = ra_segment_create(base + size);
+	if (!lastseg) {
+		ra_segment_destroy(seg);
+		free(span->free);
+		free(span);
+		return NULL;
+	}
+
+	link_initialize(&span->span_link);
+	list_initialize(&span->segments);
+
+	hash_table_create(&span->used, USED_BUCKETS, 1, &used_ops);
+
+	for (i = 0; i <= span->max_order; i++)
+		list_initialize(&span->free[i]);
+
+	/* Insert the first segment into the list of segments. */
+	list_append(&seg->segment_link, &span->segments);
+	/* Insert the last segment into the list of segments. */
+	list_append(&lastseg->segment_link, &span->segments);
+
+	/* Insert the first segment into the respective free list. */
+	list_append(&seg->fu_link, &span->free[span->max_order]);
+
+	return span;
+}
+
+/** Create an empty arena. */
+ra_arena_t *ra_arena_create(void)
+{
+	ra_arena_t *arena;
+
+	arena = (ra_arena_t *) malloc(sizeof(ra_arena_t), FRAME_ATOMIC);
+	if (!arena)
+		return NULL;
+
+	spinlock_initialize(&arena->lock, "arena_lock");
+	list_initialize(&arena->spans);
+
+	return arena;
+}
+
+/** Add a span to arena. */
+bool ra_span_add(ra_arena_t *arena, uintptr_t base, size_t size)
+{
+	ra_span_t *span;
+
+	/*
+	 * At the moment, we can only create resources that don't include 0.
+	 * If 0 needs to be considered as a valid resource, we would need to
+	 * slightly change the API of the resource allocator.
+	 */
+	if (base == 0)
+		return false;
+
+	span = ra_span_create(base, size);
+	if (!span)
+		return false;
+
+	/* TODO: check for overlaps */
+	spinlock_lock(&arena->lock);
+	list_append(&span->span_link, &arena->spans);
+	spinlock_unlock(&arena->lock);
+	return true;
+}
+
+static uintptr_t ra_span_alloc(ra_span_t *span, size_t size, size_t align)
+{
+	/*
+	 * We need to add the maximum of align - 1 to be able to compensate for
+	 * the worst case unaligned segment.
+	 */
+	size_t needed = size + align - 1;
+	size_t order = ispwr2(needed) ? fnzb(needed) : fnzb(needed) + 1;
+	ra_segment_t *pred = NULL;
+	ra_segment_t *succ = NULL;
+
+	/*
+	 * Find the free list of the smallest order which can satisfy this
+	 * request.
+	 */
+	for (; order <= span->max_order; order++) {
+		ra_segment_t *seg;
+		uintptr_t newbase;
+
+		if (list_empty(&span->free[order]))
+			continue;
+
+		/* Take the first segment from the free list. */
+		seg = list_get_instance(list_first(&span->free[order]),
+		    ra_segment_t, fu_link);
+
+		ASSERT(seg->flags & RA_SEGMENT_FREE);
+
+		/*
+		 * See if we need to allocate new segments for the chopped-off
+		 * parts of this segment.
+		 */
+		if (!IS_ALIGNED(seg->base, align)) {
+			pred = ra_segment_create(seg->base);
+			if (!pred) {
+				/*
+				 * Fail as we are unable to split the segment.
+				 */
+				break;
+			}
+			pred->flags |= RA_SEGMENT_FREE;
+		}
+		newbase = ALIGN_UP(seg->base, align);
+		if (newbase + size != seg->base + ra_segment_size_get(seg)) {
+			ASSERT(newbase + (size - 1) < seg->base +
+			    (ra_segment_size_get(seg) - 1));
+			succ = ra_segment_create(newbase + size);
+			if (!succ) {
+				if (pred)
+					ra_segment_destroy(pred);
+				/*
+				 * Fail as we are unable to split the segment.
+				 */
+				break;
+			}
+			succ->flags |= RA_SEGMENT_FREE;
+		}
+		
+	
+		/* Put unneeded parts back. */
+		if (pred) {
+			size_t pred_order;
+
+			list_insert_before(&pred->segment_link,
+			    &seg->segment_link);
+			pred_order = fnzb(ra_segment_size_get(pred));
+			list_append(&pred->fu_link, &span->free[pred_order]);
+		}
+		if (succ) {
+			size_t succ_order;
+
+			list_insert_after(&succ->segment_link,
+			    &seg->segment_link);
+			succ_order = fnzb(ra_segment_size_get(succ));
+			list_append(&succ->fu_link, &span->free[succ_order]);
+		}
+
+		/* Now remove the found segment from the free list. */
+		list_remove(&seg->fu_link);
+		seg->base = newbase;
+		seg->flags &= ~RA_SEGMENT_FREE;
+
+		/* Hash-in the segment into the used hash. */
+		sysarg_t key = seg->base;
+		hash_table_insert(&span->used, &key, &seg->fu_link);
+
+		return newbase;
+	}
+
+	return 0;
+}
+
+static void ra_span_free(ra_span_t *span, size_t base, size_t size)
+{
+	sysarg_t key = base;
+	link_t *link;
+	ra_segment_t *seg;
+	ra_segment_t *pred;
+	ra_segment_t *succ;
+	size_t order;
+
+	/*
+	 * Locate the segment in the used hash table.
+	 */
+	link = hash_table_find(&span->used, &key);
+	if (!link) {
+		panic("Freeing segment which is not known to be used (base=%"
+		    PRIxn ", size=%" PRIdn ").", base, size);
+	}
+	seg = hash_table_get_instance(link, ra_segment_t, fu_link);
+
+	/*
+	 * Hash out the segment.
+	 */
+	hash_table_remove(&span->used, &key, 1);
+
+	ASSERT(!(seg->flags & RA_SEGMENT_FREE));
+	ASSERT(seg->base == base);
+	ASSERT(ra_segment_size_get(seg) == size);
+
+	/*
+	 * Check whether the segment can be coalesced with its left neighbor.
+	 */
+	if (list_first(&span->segments) != &seg->segment_link) {
+		pred = hash_table_get_instance(seg->segment_link.prev,
+		    ra_segment_t, segment_link);
+
+		ASSERT(pred->base < seg->base);
+
+		if (pred->flags & RA_SEGMENT_FREE) {
+			/*
+			 * The segment can be coalesced with its predecessor.
+			 * Remove the predecessor from the free and segment
+			 * lists, rebase the segment and throw the predecessor
+			 * away.
+			 */
+			list_remove(&pred->fu_link);
+			list_remove(&pred->segment_link);
+			seg->base = pred->base;
+			ra_segment_destroy(pred);
+		}
+	}
+
+	/*
+	 * Check whether the segment can be coalesced with its right neighbor.
+	 */
+	succ = hash_table_get_instance(seg->segment_link.next, ra_segment_t,
+	    segment_link);
+	ASSERT(succ->base > seg->base);
+	if (succ->flags & RA_SEGMENT_FREE) {
+		/*
+		 * The segment can be coalesced with its successor.
+		 * Remove the successor from the free and segment lists
+		 * and throw it away.
+		 */
+		list_remove(&succ->fu_link);
+		list_remove(&succ->segment_link);
+		ra_segment_destroy(succ);
+	}
+
+	/* Put the segment on the appropriate free list. */
+	seg->flags |= RA_SEGMENT_FREE;
+	order = fnzb(ra_segment_size_get(seg));
+	list_append(&seg->fu_link, &span->free[order]);
+}
+
+/** Allocate resources from arena. */
+uintptr_t ra_alloc(ra_arena_t *arena, size_t size, size_t alignment)
+{
+	uintptr_t base = 0;
+
+	ASSERT(size >= 1);
+	ASSERT(alignment >= 1);
+	ASSERT(ispwr2(alignment));
+
+	spinlock_lock(&arena->lock);
+	list_foreach(arena->spans, cur) {
+		ra_span_t *span = list_get_instance(cur, ra_span_t, span_link);
+
+		base = ra_span_alloc(span, size, alignment);
+		if (base)
+			break;
+	}
+	spinlock_unlock(&arena->lock);
+
+	return base;
+}
+
+/* Return resources to arena. */
+void ra_free(ra_arena_t *arena, uintptr_t base, size_t size)
+{
+	spinlock_lock(&arena->lock);
+	list_foreach(arena->spans, cur) {
+		ra_span_t *span = list_get_instance(cur, ra_span_t, span_link);
+
+		if (iswithin(span->base, span->size, base, size)) {
+			ra_span_free(span, base, size);
+			spinlock_unlock(&arena->lock);
+			return;
+		}
+	}
+	spinlock_unlock(&arena->lock);
+
+	panic("Freeing to wrong arena (base=%" PRIxn ", size=%" PRIdn ").",
+	    base, size);
+}
+
+void ra_init(void)
+{
+	ra_segment_cache = slab_cache_create("segment_cache",
+	    sizeof(ra_segment_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED);
+}
+
+/** @}
+ */
Index: kernel/generic/src/lib/rd.c
===================================================================
--- kernel/generic/src/lib/rd.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/lib/rd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -54,5 +54,5 @@
 void init_rd(void *data, size_t size)
 {
-	uintptr_t base = KA2PA((uintptr_t) data);
+	uintptr_t base = (uintptr_t) data;
 	ASSERT((base % FRAME_SIZE) == 0);
 	
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/main/kinit.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -57,4 +57,5 @@
 #include <mm/as.h>
 #include <mm/frame.h>
+#include <mm/km.h>
 #include <print.h>
 #include <memstr.h>
@@ -68,4 +69,5 @@
 #include <str.h>
 #include <sysinfo/stats.h>
+#include <align.h>
 
 #ifdef CONFIG_SMP
@@ -178,5 +180,5 @@
 	
 	for (i = 0; i < init.cnt; i++) {
-		if (init.tasks[i].addr % FRAME_SIZE) {
+		if (init.tasks[i].paddr % FRAME_SIZE) {
 			printf("init[%zu]: Address is not frame aligned\n", i);
 			programs[i].task = NULL;
@@ -199,7 +201,15 @@
 		str_cpy(namebuf + INIT_PREFIX_LEN,
 		    TASK_NAME_BUFLEN - INIT_PREFIX_LEN, name);
-		
-		int rc = program_create_from_image((void *) init.tasks[i].addr,
-		    namebuf, &programs[i]);
+
+		/*
+		 * Create virtual memory mappings for init task images.
+		 */
+		uintptr_t page = km_map(init.tasks[i].paddr,
+		    init.tasks[i].size,
+		    PAGE_READ | PAGE_WRITE | PAGE_CACHEABLE);
+		ASSERT(page);
+		
+		int rc = program_create_from_image((void *) page, namebuf,
+		    &programs[i]);
 		
 		if (rc == 0) {
@@ -224,5 +234,5 @@
 			 * Assume the last task is the RAM disk.
 			 */
-			init_rd((void *) init.tasks[i].addr, init.tasks[i].size);
+			init_rd((void *) init.tasks[i].paddr, init.tasks[i].size);
 		} else
 			printf("init[%zu]: Init binary load failed (error %d)\n", i, rc);
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/main/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -68,4 +68,5 @@
 #include <mm/page.h>
 #include <genarch/mm/page_pt.h>
+#include <mm/km.h>
 #include <mm/tlb.h>
 #include <mm/as.h>
@@ -86,7 +87,12 @@
 #include <sysinfo/sysinfo.h>
 #include <sysinfo/stats.h>
+#include <lib/ra.h>
 
 /** Global configuration structure. */
-config_t config;
+config_t config = {
+	.identity_configured = false,
+	.non_identity_configured = false,
+	.physmem_end = 0
+};
 
 /** Initial user-space tasks */
@@ -145,8 +151,15 @@
 	size_t i;
 	for (i = 0; i < init.cnt; i++) {
-		if (PA_OVERLAPS(config.stack_base, config.stack_size,
-		    init.tasks[i].addr, init.tasks[i].size))
-			config.stack_base = ALIGN_UP(init.tasks[i].addr +
-			    init.tasks[i].size, config.stack_size);
+		if (overlaps(KA2PA(config.stack_base), config.stack_size,
+		    init.tasks[i].paddr, init.tasks[i].size)) {
+			/*
+			 * The init task overlaps with the memory behind the
+			 * kernel image so it must be in low memory and we can
+			 * use PA2KA on the init task's physical address.
+			 */
+			config.stack_base = ALIGN_UP(
+			    PA2KA(init.tasks[i].paddr) + init.tasks[i].size,
+			    config.stack_size);
+		}
 	}
 	
@@ -205,8 +218,8 @@
 	 */
 	arch_pre_mm_init();
+	km_identity_init();
 	frame_init();
-	
-	/* Initialize at least 1 memory segment big enough for slab to work. */
 	slab_cache_init();
+	ra_init();	
 	sysinfo_init();
 	btree_init();
@@ -214,4 +227,5 @@
 	page_init();
 	tlb_init();
+	km_non_identity_init();
 	ddi_init();
 	arch_post_mm_init();
@@ -262,6 +276,6 @@
 	 * Create the first thread.
 	 */
-	thread_t *kinit_thread
-		= thread_create(kinit, NULL, kernel, 0, "kinit", true);
+	thread_t *kinit_thread =
+	    thread_create(kinit, NULL, kernel, 0, "kinit", true);
 	if (!kinit_thread)
 		panic("Cannot create kinit thread.");
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/mm/as.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/backend_anon.c
===================================================================
--- kernel/generic/src/mm/backend_anon.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/mm/backend_anon.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -44,4 +44,5 @@
 #include <mm/frame.h>
 #include <mm/slab.h>
+#include <mm/km.h>
 #include <synch/mutex.h>
 #include <adt/list.h>
@@ -155,4 +156,6 @@
 int anon_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
 {
+	uintptr_t upage = ALIGN_DOWN(addr, PAGE_SIZE);
+	uintptr_t kpage;
 	uintptr_t frame;
 
@@ -175,5 +178,5 @@
 		mutex_lock(&area->sh_info->lock);
 		frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
-		    ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
+		    upage - area->base, &leaf);
 		if (!frame) {
 			bool allocate = true;
@@ -185,6 +188,5 @@
 			 */
 			for (i = 0; i < leaf->keys; i++) {
-				if (leaf->key[i] ==
-				    ALIGN_DOWN(addr, PAGE_SIZE) - area->base) {
+				if (leaf->key[i] == upage - area->base) {
 					allocate = false;
 					break;
@@ -192,7 +194,8 @@
 			}
 			if (allocate) {
-				frame = (uintptr_t) frame_alloc_noreserve(
-				    ONE_FRAME, 0);
-				memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
+				kpage = km_temporary_page_get(&frame,
+				    FRAME_NO_RESERVE);
+				memsetb((void *) kpage, PAGE_SIZE, 0);
+				km_temporary_page_put(kpage);
 				
 				/*
@@ -201,6 +204,5 @@
 				 */
 				btree_insert(&area->sh_info->pagemap,
-				    ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
-				    (void *) frame, leaf);
+				    upage - area->base, (void *) frame, leaf);
 			}
 		}
@@ -223,15 +225,16 @@
 		 *   the different causes
 		 */
-		frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
-		memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
+		kpage = km_temporary_page_get(&frame, FRAME_NO_RESERVE);
+		memsetb((void *) kpage, PAGE_SIZE, 0);
+		km_temporary_page_put(kpage);
 	}
 	
 	/*
-	 * Map 'page' to 'frame'.
+	 * Map 'upage' to 'frame'.
 	 * Note that TLB shootdown is not attempted as only new information is
 	 * being inserted into page tables.
 	 */
-	page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
-	if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
+	page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
+	if (!used_space_insert(area, upage, 1))
 		panic("Cannot insert used space.");
 		
Index: kernel/generic/src/mm/backend_elf.c
===================================================================
--- kernel/generic/src/mm/backend_elf.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/mm/backend_elf.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -44,4 +44,5 @@
 #include <mm/page.h>
 #include <mm/reserve.h>
+#include <mm/km.h>
 #include <genarch/mm/page_pt.h>
 #include <genarch/mm/page_ht.h>
@@ -229,5 +230,9 @@
 	elf_segment_header_t *entry = area->backend_data.segment;
 	btree_node_t *leaf;
-	uintptr_t base, frame, page, start_anon;
+	uintptr_t base;
+	uintptr_t frame;
+	uintptr_t kpage;
+	uintptr_t upage;
+	uintptr_t start_anon;
 	size_t i;
 	bool dirty = false;
@@ -249,6 +254,6 @@
 	    (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));
 
-	/* Virtual address of faulting page*/
-	page = ALIGN_DOWN(addr, PAGE_SIZE);
+	/* Virtual address of faulting page */
+	upage = ALIGN_DOWN(addr, PAGE_SIZE);
 
 	/* Virtual address of the end of initialized part of segment */
@@ -264,5 +269,5 @@
 		mutex_lock(&area->sh_info->lock);
 		frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
-		    page - area->base, &leaf);
+		    upage - area->base, &leaf);
 		if (!frame) {
 			unsigned int i;
@@ -273,5 +278,5 @@
 
 			for (i = 0; i < leaf->keys; i++) {
-				if (leaf->key[i] == page - area->base) {
+				if (leaf->key[i] == upage - area->base) {
 					found = true;
 					break;
@@ -281,7 +286,7 @@
 		if (frame || found) {
 			frame_reference_add(ADDR2PFN(frame));
-			page_mapping_insert(AS, addr, frame,
+			page_mapping_insert(AS, upage, frame,
 			    as_area_get_flags(area));
-			if (!used_space_insert(area, page, 1))
+			if (!used_space_insert(area, upage, 1))
 				panic("Cannot insert used space.");
 			mutex_unlock(&area->sh_info->lock);
@@ -294,5 +299,5 @@
 	 * mapping.
 	 */
-	if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
+	if (upage >= entry->p_vaddr && upage + PAGE_SIZE <= start_anon) {
 		/*
 		 * Initialized portion of the segment. The memory is backed
@@ -304,16 +309,22 @@
 		 */
 		if (entry->p_flags & PF_W) {
-			frame = (uintptr_t)frame_alloc_noreserve(ONE_FRAME, 0);
-			memcpy((void *) PA2KA(frame),
-			    (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
+			kpage = km_temporary_page_get(&frame, FRAME_NO_RESERVE);
+			memcpy((void *) kpage, (void *) (base + i * PAGE_SIZE),
+			    PAGE_SIZE);
 			if (entry->p_flags & PF_X) {
-				smc_coherence_block((void *) PA2KA(frame),
-				    FRAME_SIZE);
+				smc_coherence_block((void *) kpage, PAGE_SIZE);
 			}
+			km_temporary_page_put(kpage);
 			dirty = true;
 		} else {
-			frame = KA2PA(base + i * FRAME_SIZE);
+			pte_t *pte = page_mapping_find(AS_KERNEL,
+			    base + i * FRAME_SIZE, true);
+
+			ASSERT(pte);
+			ASSERT(PTE_PRESENT(pte));
+
+			frame = PTE_GET_FRAME(pte);
 		}	
-	} else if (page >= start_anon) {
+	} else if (upage >= start_anon) {
 		/*
 		 * This is the uninitialized portion of the segment.
@@ -322,6 +333,7 @@
 		 * and cleared.
 		 */
-		frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
-		memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
+		kpage = km_temporary_page_get(&frame, FRAME_NO_RESERVE);
+		memsetb((void *) kpage, PAGE_SIZE, 0);
+		km_temporary_page_put(kpage);
 		dirty = true;
 	} else {
@@ -334,25 +346,25 @@
 		 * (The segment can be and often is shorter than 1 page).
 		 */
-		if (page < entry->p_vaddr)
-			pad_lo = entry->p_vaddr - page;
+		if (upage < entry->p_vaddr)
+			pad_lo = entry->p_vaddr - upage;
 		else
 			pad_lo = 0;
 
-		if (start_anon < page + PAGE_SIZE)
-			pad_hi = page + PAGE_SIZE - start_anon;
+		if (start_anon < upage + PAGE_SIZE)
+			pad_hi = upage + PAGE_SIZE - start_anon;
 		else
 			pad_hi = 0;
 
-		frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
-		memcpy((void *) (PA2KA(frame) + pad_lo),
-		    (void *) (base + i * FRAME_SIZE + pad_lo),
-		    FRAME_SIZE - pad_lo - pad_hi);
+		kpage = km_temporary_page_get(&frame, FRAME_NO_RESERVE);
+		memcpy((void *) (kpage + pad_lo),
+		    (void *) (base + i * PAGE_SIZE + pad_lo),
+		    PAGE_SIZE - pad_lo - pad_hi);
 		if (entry->p_flags & PF_X) {
-			smc_coherence_block((void *) (PA2KA(frame) + pad_lo), 
-			    FRAME_SIZE - pad_lo - pad_hi);
+			smc_coherence_block((void *) (kpage + pad_lo), 
+			    PAGE_SIZE - pad_lo - pad_hi);
 		}
-		memsetb((void *) PA2KA(frame), pad_lo, 0);
-		memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
-		    0);
+		memsetb((void *) kpage, pad_lo, 0);
+		memsetb((void *) (kpage + PAGE_SIZE - pad_hi), pad_hi, 0);
+		km_temporary_page_put(kpage);
 		dirty = true;
 	}
@@ -360,5 +372,5 @@
 	if (dirty && area->sh_info) {
 		frame_reference_add(ADDR2PFN(frame));
-		btree_insert(&area->sh_info->pagemap, page - area->base,
+		btree_insert(&area->sh_info->pagemap, upage - area->base,
 		    (void *) frame, leaf);
 	}
@@ -367,6 +379,6 @@
 		mutex_unlock(&area->sh_info->lock);
 
-	page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
-	if (!used_space_insert(area, page, 1))
+	page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
+	if (!used_space_insert(area, upage, 1))
 		panic("Cannot insert used space.");
 
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/mm/frame.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -240,6 +240,6 @@
 NO_TRACE static bool zone_can_alloc(zone_t *zone, uint8_t order)
 {
-	return (zone_flags_available(zone->flags)
-	    && buddy_system_can_alloc(zone->buddy_system, order));
+	return ((zone->flags & ZONE_AVAILABLE) &&
+	    buddy_system_can_alloc(zone->buddy_system, order));
 }
 
@@ -265,5 +265,5 @@
 		 * Check whether the zone meets the search criteria.
 		 */
-		if ((zones.info[i].flags & flags) == flags) {
+		if (ZONE_FLAGS_MATCH(zones.info[i].flags, flags)) {
 			/*
 			 * Check if the zone has 2^order frames area available.
@@ -460,5 +460,5 @@
 NO_TRACE static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
 {
-	ASSERT(zone_flags_available(zone->flags));
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	/* Allocate frames from zone buddy system */
@@ -490,5 +490,5 @@
 NO_TRACE static size_t zone_frame_free(zone_t *zone, size_t frame_idx)
 {
-	ASSERT(zone_flags_available(zone->flags));
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	frame_t *frame = &zone->frames[frame_idx];
@@ -518,5 +518,5 @@
 NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t frame_idx)
 {
-	ASSERT(zone_flags_available(zone->flags));
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	frame_t *frame = zone_get_frame(zone, frame_idx);
@@ -549,6 +549,6 @@
     buddy_system_t *buddy)
 {
-	ASSERT(zone_flags_available(zones.info[z1].flags));
-	ASSERT(zone_flags_available(zones.info[z2].flags));
+	ASSERT(zones.info[z1].flags & ZONE_AVAILABLE);
+	ASSERT(zones.info[z2].flags & ZONE_AVAILABLE);
 	ASSERT(zones.info[z1].flags == zones.info[z2].flags);
 	ASSERT(zones.info[z1].base < zones.info[z2].base);
@@ -645,5 +645,5 @@
 NO_TRACE static void return_config_frames(size_t znum, pfn_t pfn, size_t count)
 {
-	ASSERT(zone_flags_available(zones.info[znum].flags));
+	ASSERT(zones.info[znum].flags & ZONE_AVAILABLE);
 	
 	size_t cframes = SIZE2FRAMES(zone_conf_size(count));
@@ -681,5 +681,5 @@
     size_t count)
 {
-	ASSERT(zone_flags_available(zones.info[znum].flags));
+	ASSERT(zones.info[znum].flags & ZONE_AVAILABLE);
 	ASSERT(frame_idx + count < zones.info[znum].count);
 	
@@ -723,9 +723,6 @@
 	 * set of flags
 	 */
-	if ((z1 >= zones.count) || (z2 >= zones.count)
-	    || (z2 - z1 != 1)
-	    || (!zone_flags_available(zones.info[z1].flags))
-	    || (!zone_flags_available(zones.info[z2].flags))
-	    || (zones.info[z1].flags != zones.info[z2].flags)) {
+	if ((z1 >= zones.count) || (z2 >= zones.count) || (z2 - z1 != 1) ||
+	    (zones.info[z1].flags != zones.info[z2].flags)) {
 		ret = false;
 		goto errout;
@@ -828,5 +825,5 @@
 	zone->buddy_system = buddy;
 	
-	if (zone_flags_available(flags)) {
+	if (flags & ZONE_AVAILABLE) {
 		/*
 		 * Compute order for buddy system and initialize
@@ -865,4 +862,14 @@
 {
 	return (count * sizeof(frame_t) + buddy_conf_size(fnzb(count)));
+}
+
+/** Allocate external configuration frames from low memory. */
+pfn_t zone_external_conf_alloc(size_t count)
+{
+	size_t size = zone_conf_size(count);
+	size_t order = ispwr2(size) ? fnzb(size) : (fnzb(size) + 1);
+
+	return ADDR2PFN((uintptr_t) frame_alloc(order - FRAME_WIDTH,
+	    FRAME_LOWMEM | FRAME_ATOMIC));
 }
 
@@ -888,5 +895,5 @@
 	irq_spinlock_lock(&zones.lock, true);
 	
-	if (zone_flags_available(flags)) {  /* Create available zone */
+	if (flags & ZONE_AVAILABLE) {  /* Create available zone */
 		/* Theoretically we could have NULL here, practically make sure
 		 * nobody tries to do that. If some platform requires, remove
@@ -894,4 +901,7 @@
 		 */
 		ASSERT(confframe != ADDR2PFN((uintptr_t ) NULL));
+
+		/* Update the known end of physical memory. */
+		config.physmem_end = max(config.physmem_end, PFN2ADDR(start + count));
 		
 		/* If confframe is supposed to be inside our zone, then make sure
@@ -914,5 +924,5 @@
 				for (i = 0; i < init.cnt; i++)
 					if (overlaps(addr, PFN2ADDR(confcount),
-					    KA2PA(init.tasks[i].addr),
+					    init.tasks[i].paddr,
 					    init.tasks[i].size)) {
 						overlap = true;
@@ -1232,5 +1242,5 @@
 	
 	/* Tell the architecture to create some memory */
-	frame_arch_init();
+	frame_low_arch_init();
 	if (config.cpu_active == 1) {
 		frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
@@ -1241,5 +1251,5 @@
 		size_t i;
 		for (i = 0; i < init.cnt; i++) {
-			pfn_t pfn = ADDR2PFN(KA2PA(init.tasks[i].addr));
+			pfn_t pfn = ADDR2PFN(init.tasks[i].paddr);
 			frame_mark_unavailable(pfn,
 			    SIZE2FRAMES(init.tasks[i].size));
@@ -1255,4 +1265,37 @@
 		frame_mark_unavailable(0, 1);
 	}
+	frame_high_arch_init();
+}
+
+/** Adjust bounds of physical memory region according to low/high memory split.
+ *
+ * @param low[in]	If true, the adujstment is performed to make the region
+ *			fit in the low memory. Otherwise the adjustment is
+ *			performed to make the region fit in the high memory.
+ * @param basep[inout]	Pointer to a variable which contains the region's base
+ *			address and which may receive the adjusted base address.
+ * @param sizep[inout]	Pointer to a variable which contains the region's size
+ *			and which may receive the adjusted size.
+ * @retun		True if the region still exists even after the
+ *			adjustment, false otherwise.
+ */
+bool frame_adjust_zone_bounds(bool low, uintptr_t *basep, size_t *sizep)
+{
+	uintptr_t limit = config.identity_size;
+
+	if (low) {
+		if (*basep > limit)
+			return false;
+		if (*basep + *sizep > limit)
+			*sizep = limit - *basep;
+	} else {
+		if (*basep + *sizep <= limit)
+			return false;
+		if (*basep <= limit) {
+			*sizep -= limit - *basep;
+			*basep = limit;
+		}
+	}
+	return true;
 }
 
@@ -1293,5 +1336,5 @@
 		*total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
 		
-		if (zone_flags_available(zones.info[i].flags)) {
+		if (zones.info[i].flags & ZONE_AVAILABLE) {
 			*busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
 			*free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
@@ -1344,5 +1387,5 @@
 		irq_spinlock_unlock(&zones.lock, true);
 		
-		bool available = zone_flags_available(flags);
+		bool available = ((flags & ZONE_AVAILABLE) != 0);
 		
 		printf("%-4zu", i);
@@ -1356,8 +1399,10 @@
 #endif
 		
-		printf(" %12zu %c%c%c      ", count,
-		    available ? 'A' : ' ',
-		    (flags & ZONE_RESERVED) ? 'R' : ' ',
-		    (flags & ZONE_FIRMWARE) ? 'F' : ' ');
+		printf(" %12zu %c%c%c%c%c    ", count,
+		    available ? 'A' : '-',
+		    (flags & ZONE_RESERVED) ? 'R' : '-',
+		    (flags & ZONE_FIRMWARE) ? 'F' : '-',
+		    (flags & ZONE_LOWMEM) ? 'L' : '-',
+		    (flags & ZONE_HIGHMEM) ? 'H' : '-');
 		
 		if (available)
@@ -1401,5 +1446,5 @@
 	irq_spinlock_unlock(&zones.lock, true);
 	
-	bool available = zone_flags_available(flags);
+	bool available = ((flags & ZONE_AVAILABLE) != 0);
 	
 	uint64_t size;
@@ -1411,8 +1456,10 @@
 	printf("Zone size:         %zu frames (%" PRIu64 " %s)\n", count,
 	    size, size_suffix);
-	printf("Zone flags:        %c%c%c\n",
-	    available ? 'A' : ' ',
-	    (flags & ZONE_RESERVED) ? 'R' : ' ',
-	    (flags & ZONE_FIRMWARE) ? 'F' : ' ');
+	printf("Zone flags:        %c%c%c%c%c\n",
+	    available ? 'A' : '-',
+	    (flags & ZONE_RESERVED) ? 'R' : '-',
+	    (flags & ZONE_FIRMWARE) ? 'F' : '-',
+	    (flags & ZONE_LOWMEM) ? 'L' : '-',
+	    (flags & ZONE_HIGHMEM) ? 'H' : '-');
 	
 	if (available) {
Index: kernel/generic/src/mm/km.c
===================================================================
--- kernel/generic/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ kernel/generic/src/mm/km.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genericmm
+ * @{
+ */
+
+/**
+ * @file
+ * @brief Kernel virtual memory setup.
+ */
+
+#include <mm/km.h>
+#include <arch/mm/km.h>
+#include <mm/page.h>
+#include <mm/frame.h>
+#include <mm/asid.h>
+#include <config.h>
+#include <typedefs.h>
+#include <lib/ra.h>
+#include <debug.h>
+#include <arch.h>
+#include <align.h>
+#include <macros.h>
+#include <bitops.h>
+
+static ra_arena_t *km_ni_arena;
+
+#define DEFERRED_PAGES_MAX	(PAGE_SIZE / sizeof(uintptr_t)) 
+
+/** Number of freed pages in the deferred buffer. */
+static volatile unsigned deferred_pages;
+/** Buffer of deferred freed pages. */
+static uintptr_t deferred_page[DEFERRED_PAGES_MAX];
+
+/** Flush the buffer of deferred freed pages.
+ *
+ * @return		Number of freed pages.
+ */
+static unsigned km_flush_deferred(void)
+{
+	unsigned i = 0;
+	ipl_t ipl;
+
+	ipl = tlb_shootdown_start(TLB_INVL_ASID, ASID_KERNEL, 0, 0);
+
+	for (i = 0; i < deferred_pages; i++) {
+		page_mapping_remove(AS_KERNEL, deferred_page[i]);
+		km_page_free(deferred_page[i], PAGE_SIZE);
+	}
+
+	tlb_invalidate_asid(ASID_KERNEL);
+
+	as_invalidate_translation_cache(AS_KERNEL, 0, -1);
+	tlb_shootdown_finalize(ipl);
+
+	return i;
+}
+
+/** Architecture dependent setup of identity-mapped kernel memory. */
+void km_identity_init(void)
+{
+	km_identity_arch_init();
+	config.identity_configured = true;
+}
+
+/** Architecture dependent setup of non-identity-mapped kernel memory. */
+void km_non_identity_init(void)
+{
+	km_ni_arena = ra_arena_create();
+	ASSERT(km_ni_arena != NULL);
+	km_non_identity_arch_init();
+	config.non_identity_configured = true;
+}
+
+bool km_is_non_identity(uintptr_t addr)
+{
+	return km_is_non_identity_arch(addr);
+}
+
+void km_non_identity_span_add(uintptr_t base, size_t size)
+{
+	bool span_added;
+
+	page_mapping_make_global(base, size);
+
+	span_added = ra_span_add(km_ni_arena, base, size);
+	ASSERT(span_added);
+}
+
+uintptr_t km_page_alloc(size_t size, size_t align)
+{
+	return ra_alloc(km_ni_arena, size, align);
+}
+
+void km_page_free(uintptr_t page, size_t size)
+{
+	ra_free(km_ni_arena, page, size);
+}
+
+static uintptr_t
+km_map_aligned(uintptr_t paddr, size_t size, unsigned int flags)
+{
+	uintptr_t vaddr;
+	size_t align;
+	uintptr_t offs;
+
+	ASSERT(ALIGN_DOWN(paddr, FRAME_SIZE) == paddr);
+	ASSERT(ALIGN_UP(size, FRAME_SIZE) == size);
+
+	align = ispwr2(size) ? size : (1U << (fnzb(size) + 1));
+	vaddr = km_page_alloc(size, max(PAGE_SIZE, align));
+
+	page_table_lock(AS_KERNEL, true);
+	for (offs = 0; offs < size; offs += PAGE_SIZE) {
+		page_mapping_insert(AS_KERNEL, vaddr + offs, paddr + offs,
+		    flags);
+	}
+	page_table_unlock(AS_KERNEL, true);
+	
+	return vaddr;
+}
+
+static void km_unmap_aligned(uintptr_t vaddr, size_t size)
+{
+	uintptr_t offs;
+	ipl_t ipl;
+
+	ASSERT(ALIGN_DOWN(vaddr, PAGE_SIZE) == vaddr);
+	ASSERT(ALIGN_UP(size, PAGE_SIZE) == size);
+
+	page_table_lock(AS_KERNEL, true);
+
+	ipl = tlb_shootdown_start(TLB_INVL_ASID, ASID_KERNEL, 0, 0);
+
+	for (offs = 0; offs < size; offs += PAGE_SIZE)
+		page_mapping_remove(AS_KERNEL, vaddr + offs);
+
+	tlb_invalidate_asid(ASID_KERNEL);
+
+	as_invalidate_translation_cache(AS_KERNEL, 0, -1);
+	tlb_shootdown_finalize(ipl);
+	page_table_unlock(AS_KERNEL, true);
+
+	km_page_free(vaddr, size);
+}
+
+/** Map a piece of physical address space into the virtual address space.
+ *
+ * @param paddr		Physical address to be mapped. May be unaligned.
+ * @param size		Size of area starting at paddr to be mapped.
+ * @param flags		Protection flags to be used for the mapping.
+ *
+ * @return New virtual address mapped to paddr.
+ */
+uintptr_t km_map(uintptr_t paddr, size_t size, unsigned int flags)
+{
+	uintptr_t page;
+	size_t offs; 
+
+	offs = paddr - ALIGN_DOWN(paddr, FRAME_SIZE); 
+	page = km_map_aligned(ALIGN_DOWN(paddr, FRAME_SIZE),
+	    ALIGN_UP(size + offs, FRAME_SIZE), flags);
+
+	return page + offs;
+}
+
+/** Unmap a piece of virtual address space.
+ *
+ * @param vaddr		Virtual address to be unmapped. May be unaligned, but
+ *			it must a value previously returned by km_map().
+ * @param size		Size of area starting at vaddr to be unmapped.
+ */
+void km_unmap(uintptr_t vaddr, size_t size)
+{
+	size_t offs; 
+
+	offs = vaddr - ALIGN_DOWN(vaddr, PAGE_SIZE); 
+	km_unmap_aligned(ALIGN_DOWN(vaddr, PAGE_SIZE),
+	    ALIGN_UP(size + offs, PAGE_SIZE));
+}
+
+/** Unmap kernel non-identity page.
+ *
+ * @param[in] page	Non-identity page to be unmapped.
+ */
+static void km_unmap_deferred(uintptr_t page)
+{
+	page_table_lock(AS_KERNEL, true);
+
+	if (deferred_pages == DEFERRED_PAGES_MAX) {
+		(void) km_flush_deferred();
+		deferred_pages = 0;
+	}
+
+	deferred_page[deferred_pages++] = page;
+
+	page_table_unlock(AS_KERNEL, true);
+}
+
+/** Create a temporary page.
+ *
+ * The page is mapped read/write to a newly allocated frame of physical memory.
+ * The page must be returned back to the system by a call to
+ * km_temporary_page_put().
+ *
+ * @param[inout] framep	Pointer to a variable which will receive the physical
+ *			address of the allocated frame.
+ * @param[in] flags	Frame allocation flags. FRAME_NONE or FRAME_NO_RESERVE.
+ * @return		Virtual address of the allocated frame.
+ */
+uintptr_t km_temporary_page_get(uintptr_t *framep, frame_flags_t flags)
+{
+	uintptr_t frame;
+	uintptr_t page;
+
+	ASSERT(THREAD);
+	ASSERT(framep);
+	ASSERT(!(flags & ~FRAME_NO_RESERVE));
+
+	/*
+	 * Allocate a frame, preferably from high memory.
+	 */
+	frame = (uintptr_t) frame_alloc(ONE_FRAME,
+	    FRAME_HIGHMEM | FRAME_ATOMIC | flags); 
+	if (frame) {
+		page = km_map(frame, PAGE_SIZE,
+		    PAGE_READ | PAGE_WRITE | PAGE_CACHEABLE);
+		ASSERT(page);	// FIXME
+	} else {
+		frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME,
+		    FRAME_LOWMEM);
+		page = PA2KA(frame);
+	}
+
+	*framep = frame;
+	return page;	
+}
+
+/** Destroy a temporary page.
+ *
+ * This function destroys a temporary page previously created by
+ * km_temporary_page_get(). The page destruction may be immediate or deferred.
+ * The frame mapped by the destroyed page is not freed.
+ *
+ * @param[in] page	Temporary page to be destroyed.
+ */
+void km_temporary_page_put(uintptr_t page)
+{
+	ASSERT(THREAD);
+
+	if (km_is_non_identity(page))
+		km_unmap_deferred(page);
+}
+
+/** @}
+ */
+
Index: kernel/generic/src/mm/page.c
===================================================================
--- kernel/generic/src/mm/page.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/mm/page.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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. */
@@ -81,28 +82,4 @@
 {
 	page_arch_init();
-}
-
-/** Map memory structure
- *
- * Identity-map memory structure
- * considering possible crossings
- * of page boundaries.
- *
- * @param addr Address of the structure.
- * @param size Size of the structure.
- *
- */
-void map_structure(uintptr_t addr, size_t size)
-{
-	size_t length = size + (addr - (addr & ~(PAGE_SIZE - 1)));
-	size_t cnt = length / PAGE_SIZE + (length % PAGE_SIZE > 0);
-	
-	size_t i;
-	for (i = 0; i < cnt; i++)
-		page_mapping_insert(AS_KERNEL, addr + i * PAGE_SIZE,
-		    addr + i * PAGE_SIZE, PAGE_NOT_CACHEABLE | PAGE_WRITE);
-	
-	/* Repel prefetched accesses to the old mapping. */
-	memory_barrier();
 }
 
@@ -176,33 +153,50 @@
 }
 
+/** Make the mapping shared by all page tables (not address spaces).
+ * 
+ * @param base Starting virtual address of the range that is made global.
+ * @param size Size of the address range that is made global.
+ */
+void page_mapping_make_global(uintptr_t base, size_t size)
+{
+	ASSERT(page_mapping_operations);
+	ASSERT(page_mapping_operations->mapping_make_global);
+	
+	return page_mapping_operations->mapping_make_global(base, size);
+}
+
+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/mm/reserve.c
===================================================================
--- kernel/generic/src/mm/reserve.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/mm/reserve.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -42,4 +42,7 @@
 #include <typedefs.h>
 #include <arch/types.h>
+#include <debug.h>
+
+static bool reserve_initialized = false;
 
 IRQ_SPINLOCK_STATIC_INITIALIZE_NAME(reserve_lock, "reserve_lock");
@@ -54,4 +57,5 @@
 {
 	reserve = frame_total_free_get();
+	reserve_initialized = true;
 }
 
@@ -67,4 +71,6 @@
 {
 	bool reserved = false;
+
+	ASSERT(reserve_initialized);
 
 	irq_spinlock_lock(&reserve_lock, true);
@@ -111,4 +117,7 @@
 void reserve_force_alloc(size_t size)
 {
+	if (!reserve_initialized)
+		return;
+
 	irq_spinlock_lock(&reserve_lock, true);
 	reserve -= size;
@@ -122,4 +131,7 @@
 void reserve_free(size_t size)
 {
+	if (!reserve_initialized)
+		return;
+
 	irq_spinlock_lock(&reserve_lock, true);
 	reserve += size;
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/proc/program.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/proc/thread.c
===================================================================
--- kernel/generic/src/proc/thread.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/proc/thread.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -173,4 +173,23 @@
 #endif /* CONFIG_FPU */
 	
+	/*
+	 * Allocate the kernel stack from the low-memory to prevent an infinite
+	 * nesting of TLB-misses when accessing the stack from the part of the
+	 * TLB-miss handler written in C.
+	 *
+	 * Note that low-memory is safe to be used for the stack as it will be
+	 * covered by the kernel identity mapping, which guarantees not to
+	 * nest TLB-misses infinitely (either via some hardware mechanism or
+	 * by the construciton of the assembly-language part of the TLB-miss
+	 * handler).
+	 *
+	 * This restriction can be lifted once each architecture provides
+	 * a similar guarantee, for example by locking the kernel stack
+	 * in the TLB whenever it is allocated from the high-memory and the
+	 * thread is being scheduled to run.
+	 */
+	kmflags |= FRAME_LOWMEM;
+	kmflags &= ~FRAME_HIGHMEM;
+
 	thread->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags);
 	if (!thread->kstack) {
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/generic/src/syscall/syscall.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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: kernel/test/mm/mapping1.c
===================================================================
--- kernel/test/mm/mapping1.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/test/mm/mapping1.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -31,76 +31,65 @@
 #include <mm/page.h>
 #include <mm/frame.h>
-#include <mm/as.h>
 #include <arch/mm/page.h>
+#include <mm/km.h>
 #include <typedefs.h>
 #include <debug.h>
 #include <arch.h>
 
-#define PAGE0  0x10000000
-#define PAGE1  (PAGE0 + PAGE_SIZE)
-
-#define VALUE0  UINT32_C(0x01234567)
-#define VALUE1  UINT32_C(0x89abcdef)
+#define TEST_MAGIC  UINT32_C(0x01234567)
 
 const char *test_mapping1(void)
 {
-	uintptr_t frame0, frame1;
-	uint32_t v0, v1;
+	uintptr_t page0, page1;
+	uintptr_t frame;
+	uint32_t v;
+	int i;
 	
-	frame0 = (uintptr_t) frame_alloc(ONE_FRAME, FRAME_KA);
-	frame1 = (uintptr_t) frame_alloc(ONE_FRAME, FRAME_KA);
+	frame = (uintptr_t) frame_alloc(ONE_FRAME, FRAME_NONE);
+
+	page0 = km_map(frame, FRAME_SIZE,
+	    PAGE_READ | PAGE_WRITE | PAGE_CACHEABLE);
+	TPRINTF("Virtual address %p mapped to physical address %p.\n",
+	    (void *) page0, (void *) frame);
+	page1 = km_map(frame, FRAME_SIZE,
+	    PAGE_READ | PAGE_WRITE | PAGE_CACHEABLE);
+	TPRINTF("Virtual address %p mapped to physical address %p.\n",
+	    (void *) page1, (void *) frame);
 	
-	TPRINTF("Writing %#" PRIx32 " to physical address %p.\n",
-	    (uint32_t) VALUE0, (void *) KA2PA(frame0));
-	*((uint32_t *) frame0) = VALUE0;
+	for (i = 0; i < 2; i++) {
+		TPRINTF("Writing magic using the first virtual address.\n");
+
+		*((uint32_t *) page0) = TEST_MAGIC;
+
+		TPRINTF("Reading magic using the second virtual address.\n");
+
+		v = *((uint32_t *) page1);
 	
-	TPRINTF("Writing %#" PRIx32 " to physical address %p.\n",
-	    (uint32_t) VALUE1, (void *) KA2PA(frame1));
-	*((uint32_t *) frame1) = VALUE1;
+		if (v != TEST_MAGIC) {
+			km_unmap(page0, PAGE_SIZE);
+			km_unmap(page1, PAGE_SIZE);
+			frame_free(frame);
+			return "Criss-cross read does not match the value written.";
+		}
+
+		TPRINTF("Writing zero using the second virtual address.\n");
 	
-	page_table_lock(AS, true);
+		*((uint32_t *) page1) = 0;
 
-	TPRINTF("Mapping virtual address %p to physical address %p.\n",
-	    (void *) PAGE0, (void *) KA2PA(frame0));
-	page_mapping_insert(AS_KERNEL, PAGE0, KA2PA(frame0), PAGE_PRESENT | PAGE_WRITE);
+		TPRINTF("Reading zero using the first virtual address.\n");
 	
-	TPRINTF("Mapping virtual address %p to physical address %p.\n",
-	    (void *) PAGE1, (void *) KA2PA(frame1));
-	page_mapping_insert(AS_KERNEL, PAGE1, KA2PA(frame1), PAGE_PRESENT | PAGE_WRITE);
+		v = *((uint32_t *) page0);
+	
+		if (v != 0) {
+			km_unmap(page0, PAGE_SIZE);
+			km_unmap(page1, PAGE_SIZE);
+			frame_free(frame);
+			return "Criss-cross read does not match the value written.";
+		}
+	}
 
-	page_table_unlock(AS, true);
-	
-	v0 = *((uint32_t *) PAGE0);
-	v1 = *((uint32_t *) PAGE1);
-	TPRINTF("Value at virtual address %p is %#" PRIx32 ".\n",
-	    (void *) PAGE0, v0);
-	TPRINTF("Value at virtual address %p is %#" PRIx32 ".\n",
-	    (void *) PAGE1, v1);
-	
-	if (v0 != VALUE0)
-		return "Value at v0 not equal to VALUE0";
-	if (v1 != VALUE1)
-		return "Value at v1 not equal to VALUE1";
-	
-	TPRINTF("Writing %#" PRIx32 " to virtual address %p.\n",
-	    (uint32_t) 0, (void *) PAGE0);
-	*((uint32_t *) PAGE0) = 0;
-	
-	TPRINTF("Writing %#" PRIx32 " to virtual address %p.\n",
-	    (uint32_t) 0, (void *) PAGE1);
-	*((uint32_t *) PAGE1) = 0;
-	
-	v0 = *((uint32_t *) PAGE0);
-	v1 = *((uint32_t *) PAGE1);
-	
-	TPRINTF("Value at virtual address %p is %#" PRIx32 ".\n",
-	    (void *) PAGE0, *((uint32_t *) PAGE0));
-	TPRINTF("Value at virtual address %p is %#" PRIx32 ".\n",
-	    (void *) PAGE1, *((uint32_t *) PAGE1));
-	
-	if (v0 != 0)
-		return "Value at v0 not equal to 0";
-	if (v1 != 0)
-		return "Value at v1 not equal to 0";
+	km_unmap(page0, PAGE_SIZE);
+	km_unmap(page1, PAGE_SIZE);
+	frame_free(frame);
 	
 	return NULL;
Index: kernel/test/mm/mapping1.def
===================================================================
--- kernel/test/mm/mapping1.def	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ kernel/test/mm/mapping1.def	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -3,4 +3,4 @@
 	"Mapping test",
 	&test_mapping1,
-	false
+	true	
 },
Index: tools/autotool.py
===================================================================
--- tools/autotool.py	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ tools/autotool.py	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -184,4 +184,37 @@
 	sys.stderr.write("ok\n")
 
+def check_app_alternatives(alts, args, name, details):
+	"Check whether an application can be executed (use several alternatives)"
+	
+	tried = []
+	found = None
+	
+	for alt in alts:
+		working = True
+		cmdline = [alt] + args
+		tried.append(" ".join(cmdline))
+		
+		try:
+			sys.stderr.write("Checking for %s ... " % alt)
+			subprocess.Popen(cmdline, stdout = subprocess.PIPE, stderr = subprocess.PIPE).wait()
+		except:
+			sys.stderr.write("failed\n")
+			working = False
+		
+		if (working):
+			sys.stderr.write("ok\n")
+			found = alt
+			break
+	
+	if (found is None):
+		print_error(["%s is missing." % name,
+		             "",
+		             "Please make sure that it is installed in your",
+		             "system (%s)." % details,
+		             "",
+		             "The following alternatives were tried:"] + tried)
+	
+	return found
+
 def check_gcc(path, prefix, common, details):
 	"Check for GCC"
@@ -459,5 +492,8 @@
 	
 	for key, value in common.items():
-		outmk.write('%s = %s\n' % (key, value))
+		if (type(value) is list):
+			outmk.write('%s = %s\n' % (key, " ".join(value)))
+		else:
+			outmk.write('%s = %s\n' % (key, value))
 	
 	outmk.close()
@@ -624,5 +660,5 @@
 		# Platform-specific utilities
 		if ((config['BARCH'] == "amd64") or (config['BARCH'] == "ia32") or (config['BARCH'] == "ppc32") or (config['BARCH'] == "sparc64")):
-			check_app(["mkisofs", "--version"], "ISO 9660 creation utility", "usually part of genisoimage")
+			common['GENISOIMAGE'] = check_app_alternatives(["mkisofs", "genisoimage"], ["--version"], "ISO 9660 creation utility", "usually part of genisoimage")
 		
 		probe = probe_compiler(common,
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -64,4 +64,5 @@
 	app/nettest1 \
 	app/nettest2 \
+	app/nettest3 \
 	app/ping \
 	app/websrv \
@@ -92,5 +93,5 @@
 	srv/hid/fb \
 	srv/hid/input \
-	srv/hw/char/i8042 \
+	srv/hid/remcons \
 	srv/hw/char/s3c24xx_uart \
 	srv/net/il/arp \
@@ -104,4 +105,7 @@
 	drv/infrastructure/root \
 	drv/infrastructure/rootvirt \
+	drv/char/i8042 \
+	drv/char/ps2mouse \
+	drv/char/xtkbd \
 	drv/test/test1 \
 	drv/test/test2 \
@@ -118,5 +122,7 @@
 	drv/bus/usb/vhc \
 	drv/nic/lo \
-	drv/nic/ne2k
+	drv/nic/ne2k \
+	drv/nic/e1k \
+	drv/nic/rtl8139
 
 ifeq ($(CONFIG_PCC),y)
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/init/init.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -302,5 +302,4 @@
 	spawn("/srv/obio");
 	srv_start("/srv/cuda_adb");
-	srv_start("/srv/i8042");
 	srv_start("/srv/s3c24ser");
 	srv_start("/srv/s3c24ts");
@@ -313,4 +312,5 @@
 	
 	spawn("/srv/clip");
+	spawn("/srv/remcons");
 	
 	/*
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/klog/klog.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/mkbd/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/netecho/netecho.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/app/nettest3/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/app/nettest3/nettest3.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/tester/mm/common.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/tester/mm/mapping1.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/trace/syscalls.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/trace/trace.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -623,5 +623,4 @@
 error:
 	loader_abort(ldr);
-	free(ldr);
 	return NULL;
 }
Index: uspace/app/usbinfo/dev.c
===================================================================
--- uspace/app/usbinfo/dev.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/usbinfo/dev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/usbinfo/info.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/usbinfo/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/usbinfo/usbinfo.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/app/websrv/websrv.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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>
@@ -40,101 +46,374 @@
 #include <net/socket.h>
 
+#include <arg_parse.h>
+#include <macros.h>
 #include <str.h>
-
-#define PORT_NUMBER 8080
+#include <str_error.h>
+
+#define NAME  "websrv"
+
+#define DEFAULT_PORT  8080
+#define BACKLOG_SIZE  3
+
+#define WEB_ROOT  "/data/web"
 
 /** Buffer for receiving the request. */
-#define BUFFER_SIZE 1024
-static char buf[BUFFER_SIZE];
-
-/** Response to send to client. */
-static const char *response_msg =
+#define BUFFER_SIZE  1024
+
+static uint16_t port = DEFAULT_PORT;
+
+static char rbuf[BUFFER_SIZE];
+static size_t rbuf_out;
+static size_t rbuf_in;
+
+static char lbuf[BUFFER_SIZE + 1];
+static size_t lbuf_used;
+
+static char fbuf[BUFFER_SIZE];
+
+/** Responses to send to client. */
+
+static const char *msg_ok =
     "HTTP/1.0 200 OK\r\n"
+    "\r\n";
+
+static const char *msg_bad_request =
+    "HTTP/1.0 400 Bad Request\r\n"
     "\r\n"
-    "<h1>Hello from HelenOS!</h1>\r\n";
+    "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
+    "<html><head>\r\n"
+    "<title>400 Bad Request</title>\r\n"
+    "</head>\r\n"
+    "<body>\r\n"
+    "<h1>Bad Request</h1>\r\n"
+    "<p>The requested URL has bad syntax.</p>\r\n"
+    "</body>\r\n"
+    "</html>\r\n";
+
+static const char *msg_not_found =
+    "HTTP/1.0 404 Not Found\r\n"
+    "\r\n"
+    "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
+    "<html><head>\r\n"
+    "<title>404 Not Found</title>\r\n"
+    "</head>\r\n"
+    "<body>\r\n"
+    "<h1>Not Found</h1>\r\n"
+    "<p>The requested URL was not found on this server.</p>\r\n"
+    "</body>\r\n"
+    "</html>\r\n";
+
+static const char *msg_not_implemented =
+    "HTTP/1.0 501 Not Implemented\r\n"
+    "\r\n"
+    "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
+    "<html><head>\r\n"
+    "<title>501 Not Implemented</title>\r\n"
+    "</head>\r\n"
+    "<body>\r\n"
+    "<h1>Not Implemented</h1>\r\n"
+    "<p>The requested method is not implemented on this server.</p>\r\n"
+    "</body>\r\n"
+    "</html>\r\n";
+
+/** Receive one character (with buffering) */
+static int recv_char(int fd, char *c)
+{
+	if (rbuf_out == rbuf_in) {
+		rbuf_out = 0;
+		rbuf_in = 0;
+		
+		ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0);
+		if (rc <= 0) {
+			fprintf(stderr, "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 *bp = lbuf;
+	char c = '\0';
+	
+	while (bp < lbuf + BUFFER_SIZE) {
+		char prev = c;
+		int 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)
+{
+	if (uri[0] != '/')
+		return false;
+	
+	if (uri[1] == '.')
+		return false;
+	
+	char *cp = uri + 1;
+	
+	while (*cp != '\0') {
+		char c = *cp++;
+		if (c == '/')
+			return false;
+	}
+	
+	return true;
+}
+
+static int send_response(int conn_sd, const char *msg)
+{
+	size_t response_size = str_size(msg);
+	
+	fprintf(stderr, "Sending response\n");
+	ssize_t rc = send(conn_sd, (void *) msg, response_size, 0);
+	if (rc < 0) {
+		fprintf(stderr, "send() failed\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int uri_get(const char *uri, int conn_sd)
+{
+	if (str_cmp(uri, "/") == 0)
+		uri = "/index.htm";
+	
+	char *fname;
+	int rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
+	if (rc < 0)
+		return ENOMEM;
+	
+	int fd = open(fname, O_RDONLY);
+	if (fd < 0) {
+		rc = send_response(conn_sd, msg_not_found);
+		free(fname);
+		return rc;
+	}
+	
+	free(fname);
+	
+	rc = send_response(conn_sd, msg_ok);
+	if (rc != EOK)
+		return rc;
+	
+	while (true) {
+		ssize_t 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) {
+			fprintf(stderr, "send() failed\n");
+			close(fd);
+			return rc;
+		}
+	}
+	
+	close(fd);
+	
+	return EOK;
+}
+
+static int req_process(int conn_sd)
+{
+	int rc = recv_line(conn_sd);
+	if (rc != EOK) {
+		fprintf(stderr, "recv_line() failed\n");
+		return rc;
+	}
+	
+	fprintf(stderr, "Request: %s", lbuf);
+	
+	if (str_lcmp(lbuf, "GET ", 4) != 0) {
+		rc = send_response(conn_sd, msg_not_implemented);
+		return rc;
+	}
+	
+	char *uri = lbuf + 4;
+	char *end_uri = str_chr(uri, ' ');
+	if (end_uri == NULL) {
+		end_uri = lbuf + lbuf_used - 2;
+		assert(*end_uri == '\r');
+	}
+	
+	*end_uri = '\0';
+	fprintf(stderr, "Requested URI: %s\n", uri);
+	
+	if (!uri_is_valid(uri)) {
+		rc = send_response(conn_sd, msg_bad_request);
+		return rc;
+	}
+	
+	return uri_get(uri, conn_sd);
+}
+
+static void usage(void)
+{
+	printf("Skeletal server\n"
+	    "\n"
+	    "Usage: " NAME " [options]\n"
+	    "\n"
+	    "Where options are:\n"
+	    "-p port_number | --port=port_number\n"
+	    "\tListening port (default " STRING(DEFAULT_PORT) ").\n"
+	    "\n"
+	    "-h | --help\n"
+	    "\tShow this application help.\n");
+}
+
+static int parse_option(int argc, char *argv[], int *index)
+{
+	int value;
+	int rc;
+	
+	switch (argv[*index][1]) {
+	case 'h':
+		usage();
+		exit(0);
+		break;
+	case 'p':
+		rc = arg_parse_int(argc, argv, index, &value, 0);
+		if (rc != EOK)
+			return rc;
+		
+		port = (uint16_t) value;
+		break;
+	/* Long options with double dash */
+	case '-':
+		if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
+			usage();
+			exit(0);
+		} else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
+			rc = arg_parse_int(argc, argv, index, &value, 7);
+			if (rc != EOK)
+				return rc;
+			
+			port = (uint16_t) value;
+		} else {
+			usage();
+			return EINVAL;
+		}
+		break;
+	default:
+		usage();
+		return EINVAL;
+	}
+	
+	return EOK;
+}
 
 int main(int argc, char *argv[])
 {
+	/* Parse command line arguments */
+	for (int i = 1; i < argc; i++) {
+		if (argv[i][0] == '-') {
+			int rc = parse_option(argc, argv, &i);
+			if (rc != EOK)
+				return rc;
+		} else {
+			usage();
+			return EINVAL;
+		}
+	}
+	
 	struct sockaddr_in addr;
-	struct sockaddr_in raddr;
-
-	socklen_t raddr_len;
-
-	int listen_sd, conn_sd;
-	int rc;
-
-	size_t response_size;
-
+	
 	addr.sin_family = AF_INET;
-	addr.sin_port = htons(PORT_NUMBER);
-
-	rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr);
+	addr.sin_port = htons(port);
+	
+	int rc = inet_pton(AF_INET, "127.0.0.1", (void *)
+	    &addr.sin_addr.s_addr);
 	if (rc != EOK) {
-		printf("Error parsing network address.\n");
+		fprintf(stderr, "Error parsing network address (%s)\n",
+		    str_error(rc));
 		return 1;
 	}
-
-	printf("Creating socket.\n");
-
-	listen_sd = socket(PF_INET, SOCK_STREAM, 0);
+	
+	fprintf(stderr, "Creating socket\n");
+	
+	int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
 	if (listen_sd < 0) {
-		printf("Error creating listening socket.\n");
-		return 1;
-	}
-
+		fprintf(stderr, "Error creating listening socket (%s)\n",
+		    str_error(listen_sd));
+		return 2;
+	}
+	
 	rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
 	if (rc != EOK) {
-		printf("Error binding socket.\n");
-		return 1;
-	}
-
-	rc = listen(listen_sd, 1);
+		fprintf(stderr, "Error binding socket (%s)\n",
+		    str_error(rc));
+		return 3;
+	}
+	
+	rc = listen(listen_sd, BACKLOG_SIZE);
 	if (rc != EOK) {
-		printf("Error calling listen() (%d).\n", rc);
-		return 1;
-	}
-
-	response_size = str_size(response_msg);
-
-	printf("Listening for connections at port number %u.\n", PORT_NUMBER);
+		fprintf(stderr, "listen() failed (%s)\n", str_error(rc));
+		return 4;
+	}
+	
+	fprintf(stderr, "Listening for connections at port %" PRIu16 "\n",
+	    port);
 	while (true) {
-		raddr_len = sizeof(raddr);
-		conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
+		struct sockaddr_in raddr;
+		socklen_t raddr_len = sizeof(raddr);
+		int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
 		    &raddr_len);
-
+		
 		if (conn_sd < 0) {
-			printf("accept() failed.\n");
-			return 1;
-		}
-
-		printf("Accepted connection, sd=%d.\n", conn_sd);
-
-		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;
-		}
-
+			fprintf(stderr, "accept() failed (%s)\n", str_error(rc));
+			continue;
+		}
+		
+		fprintf(stderr, "Connection accepted (sd=%d), "
+		    "waiting for request\n", conn_sd);
+		
+		rbuf_out = 0;
+		rbuf_in = 0;
+		
+		rc = req_process(conn_sd);
+		if (rc != EOK)
+			fprintf(stderr, "Error processing request (%s)\n",
+			    str_error(rc));
+		
 		rc = closesocket(conn_sd);
 		if (rc != EOK) {
-			printf("Error closing connection socket: %d\n", rc);
-			return 1;
-		}
-
-		printf("Closed connection.\n");
-	}
-
-	/* Not reached. */
+			fprintf(stderr, "Error closing connection socket (%s)\n",
+			    str_error(rc));
+			closesocket(listen_sd);
+			return 5;
+		}
+		
+		fprintf(stderr, "Connection closed\n");
+	}
+	
+	/* Not reached */
 	return 0;
 }
Index: uspace/dist/data/web/bar.htm
===================================================================
--- uspace/dist/data/web/bar.htm	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/dist/data/web/bar.htm	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/dist/data/web/foo.htm	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/dist/data/web/index.htm	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,19 @@
+<html>
+    <head>
+        <title>
+    	    Hello from HelenOS!
+        </title>
+    </head>
+    <body>
+        <h1>Hello from HelenOS!</h1>
+        <img src="helenos.png" alt="" style="float: left; margin: 6px;">
+        <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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/isa/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/bus/isa/i8237.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/bus/isa/i8237.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/isa/isa.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -2,4 +2,5 @@
  * Copyright (c) 2010 Lenka Trochtova
  * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -51,5 +52,13 @@
 #include <dirent.h>
 #include <fcntl.h>
+#include <ipc/irc.h>
+#include <ipc/services.h>
+#include <sysinfo.h>
+#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>
@@ -61,4 +70,6 @@
 #include <device/hw_res.h>
 
+#include "i8237.h"
+
 #define NAME "isa"
 #define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
@@ -70,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 {
@@ -96,12 +107,70 @@
 static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
 {
-	/* TODO */
-
-	return false;
+	/* This is an old ugly way, copied from pci driver */
+	assert(fnode);
+	isa_fun_t *isa_fun = fnode->driver_data;
+
+	sysarg_t apic;
+	sysarg_t i8259;
+
+	async_sess_t *irc_sess = NULL;
+
+	if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
+	    || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
+		irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_IRC, 0, 0);
+	}
+
+	if (!irc_sess)
+		return false;
+
+	assert(isa_fun);
+	const hw_resource_list_t *res = &isa_fun->hw_resources;
+	assert(res);
+	for (size_t i = 0; i < res->count; ++i) {
+		if (res->resources[i].type == INTERRUPT) {
+			const int irq = res->resources[i].res.interrupt.irq;
+
+			async_exch_t *exch = async_exchange_begin(irc_sess);
+			const int rc =
+			    async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
+			async_exchange_end(exch);
+
+			if (rc != EOK) {
+				async_hangup(irc_sess);
+				return false;
+			}
+		}
+	}
+
+	async_hangup(irc_sess);
+	return true;
+}
+
+static int 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,
 };
 
@@ -274,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)
 {
@@ -299,8 +401,20 @@
 
 	val = skip_spaces(val);
-	irq = (int)strtol(val, &end, 0x10);
+	irq = (int) strtol(val, &end, 10);
 
 	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);
 }
 
@@ -396,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)) {
 
@@ -406,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);
 }
 
@@ -590,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/isa/isa.dev	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -9,7 +9,20 @@
 	io_range 2f8 8
 
-keyboard:
-	match 100 isa/keyboard
+i8042:
+	match 100 isa/i8042
 	irq 1
-	io_range 060 10
-	
+	irq 12
+	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/isa/isa.ma
===================================================================
--- uspace/drv/bus/isa/isa.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/isa/isa.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,1 +1,1 @@
-9 	pci/ven=8086&dev=7000
+9 pci/class=06&subclass=01
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -92,5 +92,5 @@
 static bool pciintel_enable_interrupt(ddf_fun_t *fnode)
 {
-	/* This is an old ugly way, copied from ne2000 driver */
+	/* This is an old ugly way */
 	assert(fnode);
 	pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data;
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/pci/pciintel/pci.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
Index: uspace/drv/bus/usb/ehci/ehci.ma
===================================================================
--- uspace/drv/bus/usb/ehci/ehci.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ehci/ehci.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,39 +1,1 @@
-10 pci/ven=1002&dev=4345
-10 pci/ven=1002&dev=4386
-10 pci/ven=1002&dev=4396
-10 pci/ven=1002&dev=4373
-10 pci/ven=1022&dev=7463
-10 pci/ven=1022&dev=7808
-10 pci/ven=102f&dev=01b5
-10 pci/ven=10cf&dev=1415
-10 pci/ven=10de&dev=00e8
-10 pci/ven=10de&dev=055f
-10 pci/ven=10de&dev=056a
-10 pci/ven=10de&dev=077c
-10 pci/ven=10de&dev=077e
-10 pci/ven=10de&dev=0aa6
-10 pci/ven=10de&dev=0aa9
-10 pci/ven=10de&dev=0aaa
-10 pci/ven=10de&dev=0d9d
-10 pci/ven=1166&dev=0414
-10 pci/ven=1166&dev=0416
-10 pci/ven=1414&dev=5805
-10 pci/ven=1414&dev=5807
-10 pci/ven=15ad&dev=0770
-10 pci/ven=17a0&dev=8084
-10 pci/ven=8086&dev=24cd
-10 pci/ven=8086&dev=24dd
-10 pci/ven=8086&dev=265c
-10 pci/ven=8086&dev=268c
-10 pci/ven=8086&dev=27cc
-10 pci/ven=8086&dev=2836
-10 pci/ven=8086&dev=283a
-10 pci/ven=8086&dev=293a
-10 pci/ven=8086&dev=293c
-10 pci/ven=8086&dev=3a3a
-10 pci/ven=8086&dev=3a3c
-10 pci/ven=8086&dev=3a6a
-10 pci/ven=8086&dev=3a6c
-10 pci/ven=8086&dev=8117
-10 pci/ven=8086&dev=8807
-10 pci/ven=8086&dev=880f
+10 pci/class=0c&subclass=03&progif=20
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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.ma
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/ohci.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,15 +1,1 @@
-10 pci/ven=106b&dev=0026
-10 pci/ven=106b&dev=003f
-10 pci/ven=10de&dev=0aa5
-
-10 pci/ven=1002&dev=4374
-10 pci/ven=1002&dev=4375
-
-10 pci/ven=1002&dev=4387
-10 pci/ven=1002&dev=4388
-10 pci/ven=1002&dev=4389
-10 pci/ven=1002&dev=438a
-10 pci/ven=1002&dev=438b
-10 pci/ven=1002&dev=4397
-10 pci/ven=1002&dev=4398
-10 pci/ven=1002&dev=4399
+10 pci/class=0c&subclass=03&progif=10
Index: uspace/drv/bus/usb/ohci/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/ohci_batch.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/pci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/root_hub.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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,20 +219,20 @@
 	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");
 		fibril_mutex_lock(&instance->guard);
 		assert(instance->unfinished_interrupt_transfer == NULL);
-		const uint16_t mask = create_interrupt_mask(instance);
+		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);
+	}
 }
 /*----------------------------------------------------------------------------*/
@@ -251,9 +257,7 @@
 	if (instance->unfinished_interrupt_transfer) {
 		usb_log_debug("Finalizing interrupt transfer\n");
-		const uint16_t mask = create_interrupt_mask(instance);
+		uint16_t mask = create_interrupt_mask(instance);
 		interrupt_request(instance->unfinished_interrupt_transfer,
 		    mask, instance->interrupt_mask_size);
-		usb_transfer_batch_destroy(
-		    instance->unfinished_interrupt_transfer);
 		instance->unfinished_interrupt_transfer = NULL;
 	}
@@ -274,10 +278,10 @@
 
 	/* 7 bytes + 2 port bit fields (port count + global bit) */
-	const size_t size = 7 + (instance->interrupt_mask_size * 2);
+	size_t size = 7 + (instance->interrupt_mask_size * 2);
 	assert(size <= HUB_DESCRIPTOR_MAX_SIZE);
 	instance->hub_descriptor_size = size;
 
-	const uint32_t hub_desc = instance->registers->rh_desc_a;
-	const uint32_t port_desc = instance->registers->rh_desc_b;
+	uint32_t hub_desc = instance->registers->rh_desc_a;
+	uint32_t port_desc = instance->registers->rh_desc_b;
 
 	/* bDescLength */
@@ -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_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 {
+			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 {
+			unsigned port = request_packet->index;
+			if (port < 1 || port > instance->port_count)
+				TRANSFER_END(request, EINVAL);
+
+			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 {
+			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) */
+			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,54 +475,52 @@
  * @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);
 	assert(request);
 
-	const usb_device_request_setup_packet_t *setup_request =
+	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);
+	uint16_t setup_request_value = setup_request->value_high;
 	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,10 +643,10 @@
  * @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);
 	assert(request);
 
-	const usb_device_request_setup_packet_t *setup_request =
+	usb_device_request_setup_packet_t *setup_request =
 	    (usb_device_request_setup_packet_t *) request->setup_buffer;
 	switch (setup_request->request_type)
@@ -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,
+		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,13 +681,11 @@
  * @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);
 	assert(request);
 
-	const usb_device_request_setup_packet_t *setup_request =
+	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,
+		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,15 +743,15 @@
 	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);
 	}
 
 	usb_log_debug2("CTRL packet: %s.\n",
 	    usb_debug_str_buffer((uint8_t *) request->setup_buffer, 8, 8));
-	const usb_device_request_setup_packet_t *setup_request =
+	usb_device_request_setup_packet_t *setup_request =
 	    (usb_device_request_setup_packet_t *) request->setup_buffer;
 	switch (setup_request->request)
@@ -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);
+		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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/pci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/transfer_list.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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.ma
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/uhci.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,29 +1,1 @@
-10 pci/ven=8086&dev=7020
-10 pci/ven=8086&dev=7112
-
-10 pci/ven=8086&dev=27c8
-10 pci/ven=8086&dev=27c9
-10 pci/ven=8086&dev=27ca
-10 pci/ven=8086&dev=27cb
-
-10 pci/ven=8086&dev=2830
-10 pci/ven=8086&dev=2831
-10 pci/ven=8086&dev=2832
-10 pci/ven=8086&dev=2834
-10 pci/ven=8086&dev=2835
-
-10 pci/ven=8086&dev=2934
-10 pci/ven=8086&dev=2935
-10 pci/ven=8086&dev=2936
-10 pci/ven=8086&dev=2937
-10 pci/ven=8086&dev=2938
-10 pci/ven=8086&dev=2939
-
-10 pci/ven=8086&dev=24c2
-10 pci/ven=8086&dev=24c4
-10 pci/ven=8086&dev=24c7
-
-10 pci/ven=8086&dev=2688
-10 pci/ven=8086&dev=2689
-10 pci/ven=8086&dev=268a
-10 pci/ven=8086&dev=268b
+10 pci/class=0c&subclass=03&progif=00
Index: uspace/drv/bus/usb/uhci/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/uhci_batch.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/uhcirh/port.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -52,7 +52,4 @@
 #include "../usbhid.h"
 
-/** Number of simulated arrow-key presses for singel wheel step. */
-#define ARROWS_PER_SINGLE_WHEEL 3
-
 #define NAME "mouse"
 
@@ -69,7 +66,5 @@
 
 const char *HID_MOUSE_FUN_NAME = "mouse";
-const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
 const char *HID_MOUSE_CATEGORY = "mouse";
-const char *HID_MOUSE_WHEEL_CATEGORY = "keyboard";
 
 /** Default idle rate for mouses. */
@@ -126,15 +121,12 @@
 
 	usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, fun->name);
-	usb_log_debug("%s: mouse_sess: %p, wheel_sess: %p\n",
-	    __FUNCTION__, mouse_dev->mouse_sess, mouse_dev->wheel_sess);
-
-	async_sess_t **sess_ptr = (fun == mouse_dev->mouse_fun) ?
-	    &mouse_dev->mouse_sess : &mouse_dev->wheel_sess;
+	usb_log_debug("%s: mouse_sess: %p\n",
+	    __FUNCTION__, mouse_dev->mouse_sess);
 
 	async_sess_t *sess =
 	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
 	if (sess != NULL) {
-		if (*sess_ptr == NULL) {
-			*sess_ptr = sess;
+		if (mouse_dev->mouse_sess == NULL) {
+			mouse_dev->mouse_sess = sess;
 			usb_log_debug("Console session to %s set ok (%p).\n",
 			    fun->name, sess);
@@ -144,4 +136,5 @@
 			    fun->name);
 			async_answer_0(icallid, ELIMIT);
+			async_hangup(sess);
 		}
 	} else {
@@ -150,34 +143,5 @@
 	}
 }
-
-/*----------------------------------------------------------------------------*/
-
-static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel)
-{
-	unsigned int key = (wheel > 0) ? KC_UP : KC_DOWN;
-
-	if (mouse_dev->wheel_sess == NULL) {
-		usb_log_warning(
-		    "Connection to console not ready, wheel roll discarded.\n");
-		return;
-	}
-
-	const unsigned count =
-	    ((wheel < 0) ? -wheel : wheel) * ARROWS_PER_SINGLE_WHEEL;
-	for (unsigned i = 0; i < count; i++) {
-		/* Send arrow press and release. */
-		usb_log_debug2("Sending key %d to the console\n", key);
-		
-		async_exch_t *exch = async_exchange_begin(mouse_dev->wheel_sess);
-		
-		async_msg_4(exch, KBDEV_EVENT, KEY_PRESS, key, 0, 0);
-		async_msg_4(exch, KBDEV_EVENT, KEY_RELEASE, key, 0, 0);
-		
-		async_exchange_end(exch);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int get_mouse_axis_move_value(uint8_t rid, usb_hid_report_t *report,
     int32_t usage)
@@ -221,15 +185,13 @@
 	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
 
-	if ((shift_x != 0) || (shift_y != 0)) {
+	if (shift_x || shift_y || wheel) {
 		async_exch_t *exch =
 		    async_exchange_begin(mouse_dev->mouse_sess);
 		if (exch != NULL) {
-			async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
+			async_msg_3(exch, MOUSEEV_MOVE_EVENT,
+			    shift_x, shift_y, wheel);
 			async_exchange_end(exch);
 		}
 	}
-
-	if (wheel != 0)
-		usb_mouse_send_wheel(mouse_dev, wheel);
 
 	/* Buttons */
@@ -341,57 +303,6 @@
 	mouse->mouse_fun = fun;
 
-	/*
-	 * Special function for acting as keyboard (wheel)
-	 */
-	usb_log_debug("Creating DDF function %s...\n",
-	              HID_MOUSE_WHEEL_FUN_NAME);
-	fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
-	    HID_MOUSE_WHEEL_FUN_NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node `%s'.\n",
-		    HID_MOUSE_WHEEL_FUN_NAME);
-		FUN_UNBIND_DESTROY(mouse->mouse_fun);
-		mouse->mouse_fun = NULL;
-		return ENOMEM;
-	}
-
-	/*
-	 * Store the initialized HID device and HID ops
-	 * to the DDF function.
-	 */
-	fun->ops = &mouse->ops;
-	fun->driver_data = mouse;
-
-	rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function `%s': %s.\n",
-		    fun->name, str_error(rc));
-		FUN_UNBIND_DESTROY(mouse->mouse_fun);
-		mouse->mouse_fun = NULL;
-
-		fun->driver_data = NULL;
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-
-	usb_log_debug("Adding DDF function to category %s...\n", 
-	    HID_MOUSE_WHEEL_CATEGORY);
-	rc = ddf_fun_add_to_category(fun, HID_MOUSE_WHEEL_CATEGORY);
-	if (rc != EOK) {
-		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
-		    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
-
-		FUN_UNBIND_DESTROY(mouse->mouse_fun);
-		mouse->mouse_fun = NULL;
-		FUN_UNBIND_DESTROY(fun);
-		return rc;
-	}
-	mouse->wheel_fun = fun;
-
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
 
 /** Get highest index of a button mentioned in given report.
@@ -516,13 +427,5 @@
 	}
 
-	if (mouse_dev->wheel_sess != NULL) {
-		const int ret = async_hangup(mouse_dev->wheel_sess);
-		if (ret != EOK)
-			usb_log_warning("Failed to hang up wheel session: "
-			    "%p, %s.\n", mouse_dev->wheel_sess, str_error(ret));
-	}
-
 	FUN_UNBIND_DESTROY(mouse_dev->mouse_fun);
-	FUN_UNBIND_DESTROY(mouse_dev->wheel_fun);
 
 	free(mouse_dev->buttons);
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -48,5 +48,4 @@
 	/** IPC session to console (consumer). */
 	async_sess_t *mouse_sess;
-	async_sess_t *wheel_sess;
 
 	/* Mouse buttons statuses. */
@@ -57,6 +56,4 @@
 	/* DDF mouse function */
 	ddf_fun_t *mouse_fun;
-	/* DDF mouse function */
-	ddf_fun_t *wheel_fun;
 } usb_mouse_t;
 
Index: uspace/drv/bus/usb/usbhub/port.c
===================================================================
--- uspace/drv/bus/usb/usbhub/port.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbhub/port.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbhub/usbhub.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/usbmid/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/vhc/hub.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/bus/usb/vhc/vhc.ma
===================================================================
--- uspace/drv/bus/usb/vhc/vhc.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/bus/usb/vhc/vhc.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,2 +1,1 @@
 10 usb&hc=vhc
-
Index: uspace/drv/char/i8042/Makefile
===================================================================
--- uspace/drv/char/i8042/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/i8042/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = i8042
+
+SOURCES = \
+	i8042.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/i8042/buffer.h
===================================================================
--- uspace/drv/char/i8042/buffer.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/i8042/buffer.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,153 @@
+/*
+ * 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 kbd
+ * @{
+ */
+
+/** @file
+ * @brief Cyclic buffer structure.
+ */
+
+#ifndef BUFFER_H_
+#define BUFFER_H_
+
+#include <assert.h>
+#include <fibril_synch.h>
+
+/** Cyclic buffer that blocks on full/empty.
+ *
+ * read_head == write_head means that the buffer is empty.
+ * write_head + 1 == read_head means that the buffer is full.
+ * Attempt to insert byte into the full buffer will block until it can succeed.
+ * Attempt to read from empty buffer will block until it can succeed.
+ *
+ */
+typedef struct {
+	uint8_t *buffer;          /**< Storage space. */
+	uint8_t *buffer_end;      /**< End of storage place. */
+	fibril_mutex_t guard;     /**< Protects buffer structures. */
+	fibril_condvar_t change;  /**< Indicates change (empty/full). */
+	uint8_t *read_head;       /**< Place of the next readable element. */
+	uint8_t *write_head;      /**< Pointer to the next writable place. */
+} buffer_t;
+
+/** Initialize cyclic buffer using provided memory space.
+ *
+ * @param buffer Cyclic buffer structure to initialize.
+ * @param data   Memory space to use.
+ * @param size   Size of the memory place.
+ *
+ */
+static inline void buffer_init(buffer_t *buffer, uint8_t *data, size_t size)
+{
+	assert(buffer);
+	
+	fibril_mutex_initialize(&buffer->guard);
+	fibril_condvar_initialize(&buffer->change);
+	buffer->buffer = data;
+	buffer->buffer_end = data + size;
+	buffer->read_head = buffer->buffer;
+	buffer->write_head = buffer->buffer;
+	bzero(buffer->buffer, size);
+}
+
+/** Write byte to cyclic buffer.
+ *
+ * @param buffer Cyclic buffer to write to.
+ * @param data   Data to write.
+ *
+ */
+static inline void buffer_write(buffer_t *buffer, uint8_t data)
+{
+	fibril_mutex_lock(&buffer->guard);
+	
+	/* Next position. */
+	uint8_t *new_head = buffer->write_head + 1;
+	if (new_head == buffer->buffer_end)
+		new_head = buffer->buffer;
+	
+	/* Buffer full. */
+	while (new_head == buffer->read_head)
+		fibril_condvar_wait(&buffer->change, &buffer->guard);
+	
+	/* Write data. */
+	*buffer->write_head = data;
+	
+	/* Buffer was empty. */
+	if (buffer->write_head == buffer->read_head)
+		fibril_condvar_broadcast(&buffer->change);
+	
+	/* Move head */
+	buffer->write_head = new_head;
+	fibril_mutex_unlock(&buffer->guard);
+}
+
+/** Read byte from cyclic buffer.
+ *
+ * @param buffer Cyclic buffer to read from.
+ *
+ * @return Byte read.
+ *
+ */
+static inline uint8_t buffer_read(buffer_t *buffer)
+{
+	fibril_mutex_lock(&buffer->guard);
+	
+	/* Buffer is empty. */
+	while (buffer->write_head == buffer->read_head)
+		fibril_condvar_wait(&buffer->change, &buffer->guard);
+	
+	/* Next position. */
+	uint8_t *new_head = buffer->read_head + 1;
+	if (new_head == buffer->buffer_end)
+		new_head = buffer->buffer;
+	
+	/* Read data. */
+	const uint8_t data = *buffer->read_head;
+	
+	/* Buffer was full. */
+	uint8_t *new_write_head = buffer->write_head + 1;
+	if (new_write_head == buffer->buffer_end)
+		new_write_head = buffer->buffer;
+	if (new_write_head == buffer->read_head)
+		fibril_condvar_broadcast(&buffer->change);
+	
+	/* Move head */
+	buffer->read_head = new_head;
+	
+	fibril_mutex_unlock(&buffer->guard);
+	return data;
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/char/i8042/i8042.c
===================================================================
--- uspace/drv/char/i8042/i8042.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/i8042/i8042.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2001-2004 Jakub Jermar
+ * Copyright (c) 2006 Josef Cejka
+ * Copyright (c) 2009 Jiri Svoboda
+ * 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 kbd_port
+ * @ingroup kbd
+ * @{
+ */
+
+/** @file
+ * @brief i8042 PS/2 port driver.
+ */
+
+#include <devman.h>
+#include <device/hw_res.h>
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <errno.h>
+#include <str_error.h>
+#include <inttypes.h>
+#include <ddf/log.h>
+#include <ddf/interrupt.h>
+#include "i8042.h"
+
+/* Interesting bits for status register */
+#define i8042_OUTPUT_FULL  0x01
+#define i8042_INPUT_FULL   0x02
+#define i8042_AUX_DATA     0x20
+
+/* Command constants */
+#define i8042_CMD_WRITE_CMDB  0x60  /**< Write command byte */
+#define i8042_CMD_WRITE_AUX   0xd4  /**< Write aux device */
+
+/* Command byte fields */
+#define i8042_KBD_IE         0x01
+#define i8042_AUX_IE         0x02
+#define i8042_KBD_DISABLE    0x10
+#define i8042_AUX_DISABLE    0x20
+#define i8042_KBD_TRANSLATE  0x40  /* Use this to switch to XT scancodes */
+
+#define CHECK_RET_DESTROY(ret, msg...) \
+	do { \
+		if (ret != EOK) { \
+			ddf_msg(LVL_ERROR, msg); \
+			if (dev->kbd_fun) { \
+				dev->kbd_fun->driver_data = NULL; \
+				ddf_fun_destroy(dev->kbd_fun); \
+			} \
+			if (dev->aux_fun) { \
+				dev->aux_fun->driver_data = NULL; \
+				ddf_fun_destroy(dev->aux_fun); \
+			} \
+		} \
+	} while (0)
+
+#define CHECK_RET_UNBIND_DESTROY(ret, msg...) \
+	do { \
+		if (ret != EOK) { \
+			ddf_msg(LVL_ERROR, msg); \
+			if (dev->kbd_fun) { \
+				ddf_fun_unbind(dev->kbd_fun); \
+				dev->kbd_fun->driver_data = NULL; \
+				ddf_fun_destroy(dev->kbd_fun); \
+			} \
+			if (dev->aux_fun) { \
+				ddf_fun_unbind(dev->aux_fun); \
+				dev->aux_fun->driver_data = NULL; \
+				ddf_fun_destroy(dev->aux_fun); \
+			} \
+		} \
+	} while (0)
+
+void default_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** Port function operations. */
+static ddf_dev_ops_t ops = {
+	.default_handler = default_handler,
+};
+
+/** i8042 Interrupt pseudo-code. */
+static const irq_cmd_t i8042_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,  /* will be patched in run-time */
+		.dstarg = 1
+	},
+	{
+		.cmd = CMD_BTEST,
+		.value = i8042_OUTPUT_FULL,
+		.srcarg = 1,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 3
+	},
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,  /* will be patched in run-time */
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+/** Wait until it is safe to write to the device. */
+static void wait_ready(i8042_t *dev)
+{
+	assert(dev);
+	while (pio_read_8(&dev->regs->status) & i8042_INPUT_FULL);
+}
+
+/** Interrupt handler routine.
+ *
+ * Write new data to the corresponding buffer.
+ *
+ * @param dev  Device that caued the interrupt.
+ * @param iid  Call id.
+ * @param call pointerr to call data.
+ *
+ */
+static void i8042_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *call)
+{
+	if ((!dev) || (!dev->driver_data))
+		return;
+	
+	i8042_t *controller = dev->driver_data;
+	
+	const uint8_t status = IPC_GET_ARG1(*call);
+	const uint8_t data = IPC_GET_ARG2(*call);
+	
+	buffer_t *buffer = (status & i8042_AUX_DATA) ?
+	    &controller->aux_buffer : &controller->kbd_buffer;
+	
+	buffer_write(buffer, data);
+}
+
+/** Initialize i8042 driver structure.
+ *
+ * @param dev       Driver structure to initialize.
+ * @param regs      I/O address of registers.
+ * @param reg_size  size of the reserved I/O address space.
+ * @param irq_kbd   IRQ for primary port.
+ * @param irq_mouse IRQ for aux port.
+ * @param ddf_dev   DDF device structure of the device.
+ *
+ * @return Error code.
+ *
+ */
+int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
+    int irq_mouse, ddf_dev_t *ddf_dev)
+{
+	assert(ddf_dev);
+	assert(dev);
+	
+	if (reg_size < sizeof(i8042_regs_t))
+		return EINVAL;
+	
+	if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0)
+		return -1;
+	
+	dev->kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a");
+	if (!dev->kbd_fun)
+		return ENOMEM;
+	
+	int ret = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
+	if (ret != EOK) {
+		ddf_fun_destroy(dev->kbd_fun);
+		return ret;
+	}
+	
+	dev->aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b");
+	if (!dev->aux_fun) {
+		ddf_fun_destroy(dev->kbd_fun);
+		return ENOMEM;
+	}
+	
+	ret = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
+	if (ret != EOK) {
+		ddf_fun_destroy(dev->kbd_fun);
+		ddf_fun_destroy(dev->aux_fun);
+		return ret;
+	}
+	
+	dev->kbd_fun->ops = &ops;
+	dev->aux_fun->ops = &ops;
+	dev->kbd_fun->driver_data = dev;
+	dev->aux_fun->driver_data = dev;
+	
+	buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
+	buffer_init(&dev->aux_buffer, dev->aux_data, BUFFER_SIZE);
+	fibril_mutex_initialize(&dev->write_guard);
+	
+	ret = ddf_fun_bind(dev->kbd_fun);
+	CHECK_RET_DESTROY(ret, "Failed to bind keyboard function: %s.",
+	    str_error(ret));
+	
+	ret = ddf_fun_bind(dev->aux_fun);
+	CHECK_RET_DESTROY(ret, "Failed to bind mouse function: %s.",
+	    str_error(ret));
+	
+	/* Disable kbd and aux */
+	wait_ready(dev);
+	pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB);
+	wait_ready(dev);
+	pio_write_8(&dev->regs->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);
+	
+	/* Flush all current IO */
+	while (pio_read_8(&dev->regs->status) & i8042_OUTPUT_FULL)
+		(void) pio_read_8(&dev->regs->data);
+	
+	const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
+	irq_cmd_t cmds[cmd_count];
+	memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
+	cmds[0].addr = (void *) &dev->regs->status;
+	cmds[3].addr = (void *) &dev->regs->data;
+	
+	irq_code_t irq_code = {
+		.cmdcount = cmd_count,
+		.cmds = cmds
+	};
+	
+	ret = register_interrupt_handler(ddf_dev, irq_kbd, i8042_irq_handler,
+	    &irq_code);
+	CHECK_RET_UNBIND_DESTROY(ret, "Failed set handler for kbd: %s.",
+	    str_error(ret));
+	
+	ret = register_interrupt_handler(ddf_dev, irq_mouse, i8042_irq_handler,
+	    &irq_code);
+	CHECK_RET_UNBIND_DESTROY(ret, "Failed set handler for mouse: %s.",
+	    str_error(ret));
+	
+	/* Enable interrupts */
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, ddf_dev->handle,
+	    IPC_FLAG_BLOCKING);
+	ret = parent_sess ? EOK : ENOMEM;
+	CHECK_RET_UNBIND_DESTROY(ret, "Failed to create parent connection.");
+	
+	const bool enabled = hw_res_enable_interrupt(parent_sess);
+	async_hangup(parent_sess);
+	ret = enabled ? EOK : EIO;
+	CHECK_RET_UNBIND_DESTROY(ret, "Failed to enable interrupts: %s.");
+	
+	/* Enable port interrupts. */
+	wait_ready(dev);
+	pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB);
+	wait_ready(dev);
+	pio_write_8(&dev->regs->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
+	    i8042_AUX_IE);
+	
+	return EOK;
+}
+
+// FIXME TODO use shared instead this
+enum {
+	IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
+	IPC_CHAR_WRITE,
+};
+
+/** Write data to i8042 port.
+ *
+ * @param fun    DDF function.
+ * @param buffer Data source.
+ * @param size   Data size.
+ *
+ * @return Bytes written.
+ *
+ */
+static int i8042_write(ddf_fun_t *fun, char *buffer, size_t size)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	
+	i8042_t *controller = fun->driver_data;
+	fibril_mutex_lock(&controller->write_guard);
+	
+	for (size_t i = 0; i < size; ++i) {
+		if (controller->aux_fun == fun) {
+			wait_ready(controller);
+			pio_write_8(&controller->regs->status,
+			    i8042_CMD_WRITE_AUX);
+		}
+		
+		wait_ready(controller);
+		pio_write_8(&controller->regs->data, buffer[i]);
+	}
+	
+	fibril_mutex_unlock(&controller->write_guard);
+	return size;
+}
+
+/** Read data from i8042 port.
+ *
+ * @param fun    DDF function.
+ * @param buffer Data place.
+ * @param size   Data place size.
+ *
+ * @return Bytes read.
+ *
+ */
+static int i8042_read(ddf_fun_t *fun, char *data, size_t size)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	
+	i8042_t *controller = fun->driver_data;
+	buffer_t *buffer = (fun == controller->aux_fun) ?
+	    &controller->aux_buffer : &controller->kbd_buffer;
+	
+	for (size_t i = 0; i < size; ++i)
+		*data++ = buffer_read(buffer);
+	
+	return size;
+}
+
+/** Handle data requests.
+ *
+ * @param fun  ddf_fun_t function.
+ * @param id   callid
+ * @param call IPC request.
+ *
+ */
+void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
+{
+	const sysarg_t method = IPC_GET_IMETHOD(*call);
+	const size_t size = IPC_GET_ARG1(*call);
+	
+	switch (method) {
+	case IPC_CHAR_READ:
+		if (size <= 4 * sizeof(sysarg_t)) {
+			sysarg_t message[4] = {};
+			
+			i8042_read(fun, (char *) message, size);
+			async_answer_4(id, size, message[0], message[1],
+			    message[2], message[3]);
+		} else
+			async_answer_0(id, ELIMIT);
+		break;
+	
+	case IPC_CHAR_WRITE:
+		if (size <= 3 * sizeof(sysarg_t)) {
+			const sysarg_t message[3] = {
+				IPC_GET_ARG2(*call),
+				IPC_GET_ARG3(*call),
+				IPC_GET_ARG4(*call)
+			};
+			
+			i8042_write(fun, (char *) message, size);
+			async_answer_0(id, size);
+		} else
+			async_answer_0(id, ELIMIT);
+	
+	default:
+		async_answer_0(id, EINVAL);
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/char/i8042/i8042.h
===================================================================
--- uspace/drv/char/i8042/i8042.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/i8042/i8042.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * 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 kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+
+/** @file
+ * @brief i8042 port driver.
+ */
+
+#ifndef i8042_H_
+#define i8042_H_
+
+#include <sys/types.h>
+#include <fibril_synch.h>
+#include <ddf/driver.h>
+#include "buffer.h"
+
+#define NAME  "i8042"
+
+#define BUFFER_SIZE  12
+
+/** i8042 HW I/O interface */
+typedef struct {
+	ioport8_t data;
+	uint8_t pad[3];
+	ioport8_t status;
+} __attribute__ ((packed)) i8042_regs_t;
+
+/** i8042 driver structure. */
+typedef struct i8042 {
+	i8042_regs_t *regs;             /**< I/O registers. */
+	ddf_fun_t *kbd_fun;             /**< Pirmary port device function. */
+	ddf_fun_t *aux_fun;             /**< Auxiliary port device function. */
+	buffer_t kbd_buffer;            /**< Primary port buffer. */
+	buffer_t aux_buffer;            /**< Aux. port buffer. */
+	uint8_t aux_data[BUFFER_SIZE];  /**< Primary port buffer space. */
+	uint8_t kbd_data[BUFFER_SIZE];  /**< Aux. port buffer space. */
+	fibril_mutex_t write_guard;     /**< Prevents simultanous port writes.*/
+} i8042_t;
+
+int i8042_init(i8042_t *, void *, size_t, int, int, ddf_dev_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/char/i8042/i8042.ma
===================================================================
--- uspace/drv/char/i8042/i8042.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/i8042/i8042.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,1 @@
+100 isa/i8042
Index: uspace/drv/char/i8042/main.c
===================================================================
--- uspace/drv/char/i8042/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/i8042/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,162 @@
+/*
+ * 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 drvi8042
+ * @{
+ */
+
+/** @file
+ * @brief i8042 driver DDF bits.
+ */
+
+#include <libarch/inttypes.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/log.h>
+#include <stdio.h>
+#include "i8042.h"
+
+#define CHECK_RET_RETURN(ret, message...) \
+	do { \
+		if (ret != EOK) { \
+			ddf_msg(LVL_ERROR, message); \
+			return ret; \
+		} \
+	} while (0)
+
+/** Get address of I/O registers.
+ *
+ * @param[in]  dev            Device asking for the addresses.
+ * @param[out] io_reg_address Base address of the memory range.
+ * @param[out] io_reg_size    Size of the memory range.
+ * @param[out] kbd_irq        Primary port IRQ.
+ * @param[out] mouse_irq      Auxiliary port IRQ.
+ *
+ * @return Error code.
+ *
+ */
+static int get_my_registers(const ddf_dev_t *dev, uintptr_t *io_reg_address,
+    size_t *io_reg_size, int *kbd_irq, int *mouse_irq)
+{
+	assert(dev);
+	
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+	
+	hw_res_list_parsed_t hw_resources;
+	hw_res_list_parsed_init(&hw_resources);
+	const int ret = hw_res_get_list_parsed(parent_sess, &hw_resources, 0);
+	async_hangup(parent_sess);
+	if (ret != EOK)
+		return ret;
+	
+	if ((hw_resources.irqs.count != 2) ||
+	    (hw_resources.io_ranges.count != 1)) {
+		hw_res_list_parsed_clean(&hw_resources);
+		return EINVAL;
+	}
+	
+	if (io_reg_address)
+		*io_reg_address = hw_resources.io_ranges.ranges[0].address;
+	
+	if (io_reg_size)
+		*io_reg_size = hw_resources.io_ranges.ranges[0].size;
+	
+	if (kbd_irq)
+		*kbd_irq = hw_resources.irqs.irqs[0];
+	
+	if (mouse_irq)
+		*mouse_irq = hw_resources.irqs.irqs[1];
+	
+	hw_res_list_parsed_clean(&hw_resources);
+	return EOK;
+}
+
+/** Initialize a new ddf driver instance of i8042 driver
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ *
+ * @return Error code.
+ *
+ */
+static int i8042_dev_add(ddf_dev_t *device)
+{
+	if (!device)
+		return EINVAL;
+	
+	uintptr_t io_regs = 0;
+	size_t io_size = 0;
+	int kbd = 0;
+	int mouse = 0;
+	
+	int ret = get_my_registers(device, &io_regs, &io_size, &kbd, &mouse);
+	CHECK_RET_RETURN(ret, "Failed to get registers: %s.",
+	    str_error(ret));
+	ddf_msg(LVL_DEBUG, "I/O regs at %p (size %zuB), IRQ kbd %d, IRQ mouse %d.",
+	    (void *) io_regs, io_size, kbd, mouse);
+	
+	i8042_t *i8042 = ddf_dev_data_alloc(device, sizeof(i8042_t));
+	ret = (i8042 == NULL) ? ENOMEM : EOK;
+	CHECK_RET_RETURN(ret, "Failed to allocate i8042 driver instance.");
+	
+	ret = i8042_init(i8042, (void *) io_regs, io_size, kbd, mouse, device);
+	CHECK_RET_RETURN(ret, "Failed to initialize i8042 driver: %s.",
+	    str_error(ret));
+	
+	ddf_msg(LVL_NOTE, "Controlling '%s' (%" PRIun ").",
+	    device->name, device->handle);
+	return EOK;
+}
+
+/** DDF driver operations. */
+static driver_ops_t i8042_driver_ops = {
+	.dev_add = i8042_dev_add,
+};
+
+/** DDF driver. */
+static driver_t i8042_driver = {
+	.name = NAME,
+	.driver_ops = &i8042_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS PS/2 driver.\n", NAME);
+	ddf_log_init(NAME, LVL_NOTE);
+	return ddf_driver_main(&i8042_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/Makefile
===================================================================
--- uspace/drv/char/ps2mouse/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011 Jan Vesely
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = ps2mouse
+
+SOURCES = \
+	chardev.c \
+	main.c \
+	ps2mouse.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/ps2mouse/chardev.c
===================================================================
--- uspace/drv/char/ps2mouse/chardev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/chardev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <mem.h>
+#include <ipc/dev_iface.h>
+#include <ddf/log.h>
+
+#include "chardev.h"
+
+// TODO make this shared
+enum {
+	IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
+	IPC_CHAR_WRITE,
+};
+
+ssize_t chardev_read(async_exch_t *exch, void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 4 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[4] = { 0 };
+	const ssize_t ret = async_req_1_4(exch, IPC_CHAR_READ, size,
+	    &message[0], &message[1], &message[2], &message[3]);
+	if (ret > 0 && (size_t)ret <= size)
+		memcpy(data, message, size);
+	return ret;
+}
+
+ssize_t chardev_write(async_exch_t *exch, const void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 3 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[3] = { 0 };
+	memcpy(message, data, size);
+	return async_req_4_0(exch, IPC_CHAR_WRITE, size,
+	    message[0], message[1], message[2]);
+}
Index: uspace/drv/char/ps2mouse/chardev.h
===================================================================
--- uspace/drv/char/ps2mouse/chardev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/chardev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver.
+ */
+
+#ifndef _CHARDEV_H_
+#define _CHARDEV_H_
+
+#include <libarch/types.h>
+#include <async.h>
+
+ssize_t chardev_read(async_exch_t *, void *, size_t);
+ssize_t chardev_write(async_exch_t *, const void *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/main.c
===================================================================
--- uspace/drv/char/ps2mouse/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver
+ */
+
+#include <libarch/inttypes.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/log.h>
+#include <stdio.h>
+
+#include "ps2mouse.h"
+
+#define NAME "ps2mouse"
+
+static int mouse_add(ddf_dev_t *device);
+
+/** DDF driver ops. */
+static driver_ops_t mouse_driver_ops = {
+	.dev_add = mouse_add,
+};
+
+/** DDF driver structure. */
+static driver_t mouse_driver = {
+	.name = NAME,
+	.driver_ops = &mouse_driver_ops
+};
+
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS ps/2 mouse driver.\n");
+	ddf_log_init(NAME, LVL_NOTE);
+	return ddf_driver_main(&mouse_driver);
+}
+
+/** Initialize a new ddf driver instance
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int mouse_add(ddf_dev_t *device)
+{
+	if (!device)
+		return EINVAL;
+
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	ddf_msg(LVL_ERROR, message); \
+	return ret; \
+} else (void)0
+
+	ps2_mouse_t *mouse = ddf_dev_data_alloc(device, sizeof(ps2_mouse_t));
+	int ret = (mouse == NULL) ? ENOMEM : EOK;
+	CHECK_RET_RETURN(ret, "Failed to allocate mouse driver instance.");
+
+	ret = ps2_mouse_init(mouse, device);
+	CHECK_RET_RETURN(ret,
+	    "Failed to initialize mouse driver: %s.", str_error(ret));
+
+	ddf_msg(LVL_NOTE, "Controlling '%s' (%" PRIun ").",
+	    device->name, device->handle);
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/ps2mouse.c
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/ps2mouse.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,407 @@
+/*
+ * 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 drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps2 mouse driver.
+ */
+
+#include <bool.h>
+#include <errno.h>
+#include <devman.h>
+#include <ddf/log.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <ipc/mouseev.h>
+#include <abi/ipc/methods.h>
+
+#include "ps2mouse.h"
+#include "chardev.h"
+
+#define PS2_MOUSE_GET_DEVICE_ID   0xf2
+#define PS2_MOUSE_SET_SAMPLE_RATE   0xf3
+#define PS2_MOUSE_ENABLE_DATA_REPORT   0xf4
+#define PS2_MOUSE_ACK   0xfa
+
+#define PS2_BUFSIZE 3
+#define INTELLIMOUSE_BUFSIZE 4
+
+#define Z_SIGN (1 << 3) /* 4th byte */
+#define X_SIGN (1 << 4) /* 1st byte */
+#define Y_SIGN (1 << 5) /* 1st byte */
+#define X_OVERFLOW (1 << 6) /* 1st byte */
+#define Y_OVERFLOW (1 << 7) /* 1st byte */
+
+#define BUTTON_LEFT   0
+#define BUTTON_RIGHT   1
+#define BUTTON_MIDDLE   2
+#define PS2_BUTTON_COUNT   3
+
+#define INTELLIMOUSE_ALWAYS_ZERO (0xc0)
+#define INTELLIMOUSE_BUTTON_4 (1 << 4) /* 4th byte */
+#define INTELLIMOUSE_BUTTON_5 (1 << 5) /* 4th byte */
+#define INTELLIMOUSE_BUTTON_COUNT 5
+
+#define PS2_BUTTON_MASK(button) (1 << button)
+
+#define MOUSE_READ_BYTE_TEST(sess, value) \
+do { \
+	uint8_t data = 0; \
+	const ssize_t size = chardev_read(sess, &data, 1); \
+	if (size != 1) { \
+		ddf_msg(LVL_ERROR, "Failed reading byte: %d)", size);\
+		return size < 0 ? size : EIO; \
+	} \
+	if (data != (value)) { \
+		ddf_msg(LVL_ERROR, "Failed testing byte: got %hhx vs. %hhx)", \
+		    data, (value)); \
+		return EIO; \
+	} \
+} while (0)
+
+#define MOUSE_WRITE_BYTE(sess, value) \
+do { \
+	uint8_t data = (value); \
+	const ssize_t size = chardev_write(sess, &data, 1); \
+	if (size < 0 ) { \
+		ddf_msg(LVL_ERROR, "Failed writing byte: %hhx", value); \
+		return size; \
+	} \
+} while (0)
+
+static int polling_ps2(void *);
+static int polling_intellimouse(void *);
+static int probe_intellimouse(async_exch_t *, bool);
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** ps/2 mouse driver ops. */
+static ddf_dev_ops_t mouse_ops = {
+	.default_handler = default_connection_handler
+};
+
+/** Initialize mouse driver structure.
+ * @param kbd Mouse driver structure to initialize.
+ * @param dev DDF device structure.
+ *
+ * Connects to parent, creates keyboard function, starts polling fibril.
+ */
+int ps2_mouse_init(ps2_mouse_t *mouse, ddf_dev_t *dev)
+{
+	assert(mouse);
+	assert(dev);
+	mouse->client_sess = NULL;
+	mouse->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    dev->handle, IPC_FLAG_BLOCKING);
+	if (!mouse->parent_sess)
+		return ENOMEM;
+
+	mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse");
+	if (!mouse->mouse_fun) {
+		async_hangup(mouse->parent_sess);
+		return ENOMEM;
+	}
+	mouse->mouse_fun->ops = &mouse_ops;
+	mouse->mouse_fun->driver_data = mouse;
+
+	int ret = ddf_fun_bind(mouse->mouse_fun);
+	if (ret != EOK) {
+		async_hangup(mouse->parent_sess);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return ENOMEM;
+	}
+
+	ret = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
+	if (ret != EOK) {
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return ENOMEM;
+	}
+	/* Probe IntelliMouse extensions. */
+	int (*polling_f)(void*) = polling_ps2;
+	async_exch_t *exch = async_exchange_begin(mouse->parent_sess);
+	if (probe_intellimouse(exch, false) == EOK) {
+		ddf_msg(LVL_NOTE, "Enabled IntelliMouse extensions");
+		polling_f = polling_intellimouse;
+		if (probe_intellimouse(exch, true) == EOK)
+			ddf_msg(LVL_NOTE, "Enabled 4th and 5th button.");
+	}
+	/* Enable mouse data reporting. */
+	uint8_t report = PS2_MOUSE_ENABLE_DATA_REPORT;
+	ssize_t size = chardev_write(exch, &report, 1);
+	if (size != 1) {
+		ddf_msg(LVL_ERROR, "Failed to enable data reporting.");
+		async_exchange_end(exch);
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return EIO;
+	}
+
+	size = chardev_read(exch, &report, 1);
+	async_exchange_end(exch);
+	if (size != 1 || report != PS2_MOUSE_ACK) {
+		ddf_msg(LVL_ERROR, "Failed to confirm data reporting: %hhx.",
+		    report);
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return EIO;
+	}
+
+	mouse->polling_fibril = fibril_create(polling_f, mouse);
+	if (!mouse->polling_fibril) {
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return ENOMEM;
+	}
+	fibril_add_ready(mouse->polling_fibril);
+	return EOK;
+}
+
+/** Get data and parse ps2 protocol packets.
+ * @param arg Pointer to ps2_mouse_t structure.
+ * @return Never.
+ */
+int polling_ps2(void *arg)
+{
+	assert(arg);
+	const ps2_mouse_t *mouse = arg;
+
+	assert(mouse->parent_sess);
+	bool buttons[PS2_BUTTON_COUNT] = {};
+	async_exch_t *parent_exch = async_exchange_begin(mouse->parent_sess);
+	while (1) {
+
+		uint8_t packet[PS2_BUFSIZE] = {};
+		const ssize_t size =
+		    chardev_read(parent_exch, packet, PS2_BUFSIZE);
+
+		if (size != PS2_BUFSIZE) {
+			ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
+			continue;
+		}
+		ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx.",
+		    packet[0], packet[1], packet[2]);
+
+		async_exch_t *exch =
+		    async_exchange_begin(mouse->client_sess);
+		if (!exch) {
+			ddf_msg(LVL_ERROR,
+			    "Failed creating exchange.");
+			continue;
+		}
+
+		/* Buttons */
+		for (unsigned i = 0; i < PS2_BUTTON_COUNT; ++i) {
+			const bool status = (packet[0] & PS2_BUTTON_MASK(i));
+			if (buttons[i] != status) {
+				buttons[i] = status;
+				async_msg_2(exch, MOUSEEV_BUTTON_EVENT, i + 1,
+				    buttons[i]);
+			}
+		}
+
+		/* Movement */
+		const int16_t move_x =
+		    ((packet[0] & X_SIGN) ? 0xff00 : 0) | packet[1];
+		const int16_t move_y =
+		    (((packet[0] & Y_SIGN) ? 0xff00 : 0) | packet[2]);
+		//TODO: Consider overflow bit
+		if (move_x != 0 || move_y != 0) {
+			async_msg_2(exch, MOUSEEV_MOVE_EVENT, move_x, -move_y);
+		}
+		async_exchange_end(exch);
+	}
+	async_exchange_end(parent_exch);
+}
+
+/** Get data and parse ps2 protocol with IntelliMouse extension packets.
+ * @param arg Pointer to ps2_mouse_t structure.
+ * @return Never.
+ */
+static int polling_intellimouse(void *arg)
+{
+	assert(arg);
+	const ps2_mouse_t *mouse = arg;
+
+	assert(mouse->parent_sess);
+	bool buttons[INTELLIMOUSE_BUTTON_COUNT] = {};
+	async_exch_t *parent_exch = NULL;
+	while (1) {
+		if (!parent_exch)
+			parent_exch = async_exchange_begin(mouse->parent_sess);
+
+		uint8_t packet[INTELLIMOUSE_BUFSIZE] = {};
+		const ssize_t size = chardev_read(
+		    parent_exch, packet, INTELLIMOUSE_BUFSIZE);
+
+		if (size != INTELLIMOUSE_BUFSIZE) {
+			ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
+			continue;
+		}
+		ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx:%hhx.",
+		    packet[0], packet[1], packet[2], packet[3]);
+
+		async_exch_t *exch =
+		    async_exchange_begin(mouse->client_sess);
+		if (!exch) {
+			ddf_msg(LVL_ERROR,
+			    "Failed creating exchange.");
+			continue;
+		}
+
+		/* Buttons */
+		/* NOTE: Parsing 4th and 5th button works even if this extension
+		 * is not supported and whole 4th byte should be interpreted
+		 * as Z-axis movement. the upper 4 bits are just a sign
+		 * extension then. + sign is interpreted as "button up"
+		 * (i.e no change since that is the default) and - sign fails
+		 * the "imb" condition. Thus 4th and 5th buttons are never
+		 * down on wheel only extension. */
+		const bool imb = (packet[3] & INTELLIMOUSE_ALWAYS_ZERO) == 0;
+		const bool status[] = {
+			[0] = packet[0] & PS2_BUTTON_MASK(0),
+			[1] = packet[0] & PS2_BUTTON_MASK(1),
+			[2] = packet[0] & PS2_BUTTON_MASK(2),
+			[3] = (packet[3] & INTELLIMOUSE_BUTTON_4) && imb,
+			[4] = (packet[3] & INTELLIMOUSE_BUTTON_5) && imb,
+		};
+		for (unsigned i = 0; i < INTELLIMOUSE_BUTTON_COUNT; ++i) {
+			if (buttons[i] != status[i]) {
+				buttons[i] = status[i];
+				async_msg_2(exch, MOUSEEV_BUTTON_EVENT, i + 1,
+				    buttons[i]);
+			}
+		}
+
+		/* Movement */
+		const int16_t move_x =
+		    ((packet[0] & X_SIGN) ? 0xff00 : 0) | packet[1];
+		const int16_t move_y =
+		    (((packet[0] & Y_SIGN) ? 0xff00 : 0) | packet[2]);
+		const int8_t move_z =
+		    (((packet[3] & Z_SIGN) ? 0xf0 : 0) | (packet[3] & 0xf));
+		ddf_msg(LVL_DEBUG2, "Parsed moves: %d:%d:%hhd", move_x, move_y,
+		    move_z);
+		//TODO: Consider overflow bit
+		if (move_x != 0 || move_y != 0 || move_z != 0) {
+			async_msg_3(exch, MOUSEEV_MOVE_EVENT,
+			    move_x, -move_y, -move_z);
+		}
+		async_exchange_end(exch);
+	}
+	async_exchange_end(parent_exch);
+}
+
+/** Send magic sequence to initialize IntelliMouse extensions.
+ * @param exch IPC exchange to the parent device.
+ * @param buttons True selects magic sequence for 4th and 5th button,
+ * false selects wheel support magic sequence.
+ * See http://www.computer-engineering.org/ps2mouse/ for details.
+ */
+static int probe_intellimouse(async_exch_t *exch, bool buttons)
+{
+	assert(exch);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(exch, 200);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(exch, buttons ? 200 : 100);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(exch, 80);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_GET_DEVICE_ID);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_READ_BYTE_TEST(exch, buttons ? 4 : 3);
+
+	return EOK;
+}
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	if (fun == NULL || fun->driver_data == NULL) {
+		ddf_msg(LVL_ERROR, "%s: Missing parameter.", __FUNCTION__);
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	const sysarg_t method = IPC_GET_IMETHOD(*icall);
+	ps2_mouse_t *mouse = fun->driver_data;
+
+	switch (method) {
+	/* This might be ugly but async_callback_receive_start makes no
+	 * difference for incorrect call and malloc failure. */
+	case IPC_M_CONNECT_TO_ME: {
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+		/* Probably ENOMEM error, try again. */
+		if (sess == NULL) {
+			ddf_msg(LVL_WARN,
+			    "Failed creating client callback session");
+			async_answer_0(icallid, EAGAIN);
+			break;
+		}
+		if (mouse->client_sess == NULL) {
+			mouse->client_sess = sess;
+			ddf_msg(LVL_DEBUG, "Set client session");
+			async_answer_0(icallid, EOK);
+		} else {
+			ddf_msg(LVL_ERROR, "Client session already set");
+			async_answer_0(icallid, ELIMIT);
+		}
+		break;
+	}
+	default:
+		ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
+		async_answer_0(icallid, EINVAL);
+		break;
+	}
+}
Index: uspace/drv/char/ps2mouse/ps2mouse.h
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/ps2mouse.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver.
+ */
+
+#ifndef _PS2MOUSE_H_
+#define _PS2MOUSE_H_
+
+#include <ddf/driver.h>
+#include <fibril.h>
+
+/** PS/2 mouse driver structure. */
+typedef struct {
+	ddf_fun_t *mouse_fun;      /**< Mouse function. */
+	async_sess_t *parent_sess; /**< Connection to device providing data. */
+	async_sess_t *client_sess;  /**< Callback connection to client. */
+	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+} ps2_mouse_t;
+
+int ps2_mouse_init(ps2_mouse_t *, ddf_dev_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/ps2mouse.ma
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/ps2mouse/ps2mouse.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,1 @@
+100 char/ps2mouse
Index: uspace/drv/char/xtkbd/Makefile
===================================================================
--- uspace/drv/char/xtkbd/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011 Jan Vesely
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = xtkbd
+
+SOURCES = \
+	chardev.c \
+	main.c \
+	xtkbd.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/xtkbd/chardev.c
===================================================================
--- uspace/drv/char/xtkbd/chardev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/chardev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <mem.h>
+#include <ipc/dev_iface.h>
+#include <ddf/log.h>
+
+#include "chardev.h"
+
+// TODO make this shared
+enum {
+	IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
+	IPC_CHAR_WRITE,
+};
+
+ssize_t chardev_read(async_exch_t *exch, void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 4 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[4] = { 0 };
+	const ssize_t ret = async_req_1_4(exch, IPC_CHAR_READ, size,
+	    &message[0], &message[1], &message[2], &message[3]);
+	if (ret > 0 && (size_t)ret <= size)
+		memcpy(data, message, size);
+	return ret;
+}
+
+ssize_t chardev_write(async_exch_t *exch, const void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 3 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[3] = { 0 };
+	memcpy(message, data, size);
+	return async_req_4_0(exch, IPC_CHAR_WRITE, size,
+	    message[0], message[1], message[2]);
+}
Index: uspace/drv/char/xtkbd/chardev.h
===================================================================
--- uspace/drv/char/xtkbd/chardev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/chardev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver.
+ */
+
+#ifndef _CHARDEV_H_
+#define _CHARDEV_H_
+
+#include <libarch/types.h>
+#include <async.h>
+
+ssize_t chardev_read(async_exch_t *, void *, size_t);
+ssize_t chardev_write(async_exch_t *, const void *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/xtkbd/main.c
===================================================================
--- uspace/drv/char/xtkbd/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief XT keyboard driver
+ */
+
+#include <libarch/inttypes.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/log.h>
+#include <stdio.h>
+
+#include "xtkbd.h"
+
+#define NAME "xtkbd"
+
+static int xt_kbd_add(ddf_dev_t *device);
+
+/** DDF driver ops. */
+static driver_ops_t kbd_driver_ops = {
+	.dev_add = xt_kbd_add,
+};
+
+/** DDF driver structure. */
+static driver_t kbd_driver = {
+	.name = NAME,
+	.driver_ops = &kbd_driver_ops
+};
+
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS XT keyboard driver.\n");
+	ddf_log_init(NAME, LVL_NOTE);
+	return ddf_driver_main(&kbd_driver);
+}
+
+/** Initialize a new ddf driver instance of the driver
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int xt_kbd_add(ddf_dev_t *device)
+{
+	if (!device)
+		return EINVAL;
+
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	ddf_msg(LVL_ERROR, message); \
+	return ret; \
+} else (void)0
+
+	xt_kbd_t *kbd = ddf_dev_data_alloc(device, sizeof(xt_kbd_t));
+	int ret = (kbd == NULL) ? ENOMEM : EOK;
+	CHECK_RET_RETURN(ret, "Failed to allocate XT/KBD driver instance.");
+
+	ret = xt_kbd_init(kbd, device);
+	CHECK_RET_RETURN(ret,
+	    "Failed to initialize XT_KBD driver: %s.", str_error(ret));
+
+	ddf_msg(LVL_NOTE, "Controlling '%s' (%" PRIun ").",
+	    device->name, device->handle);
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/char/xtkbd/xtkbd.c
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/xtkbd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,373 @@
+/*
+ * 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 drvkbd
+ * @{
+ */
+/** @file
+ * @brief XT keyboard driver;
+ */
+
+#include <errno.h>
+#include <devman.h>
+#include <ddf/log.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <ipc/kbdev.h>
+#include <abi/ipc/methods.h>
+
+#include "chardev.h"
+#include "xtkbd.h"
+
+/** Scancode set 1 table. */
+static const int scanmap_simple[] = {
+
+	[0x29] = KC_BACKTICK,
+
+	[0x02] = KC_1,
+	[0x03] = KC_2,
+	[0x04] = KC_3,
+	[0x05] = KC_4,
+	[0x06] = KC_5,
+	[0x07] = KC_6,
+	[0x08] = KC_7,
+	[0x09] = KC_8,
+	[0x0a] = KC_9,
+	[0x0b] = KC_0,
+
+	[0x0c] = KC_MINUS,
+	[0x0d] = KC_EQUALS,
+	[0x0e] = KC_BACKSPACE,
+
+	[0x0f] = KC_TAB,
+
+	[0x10] = KC_Q,
+	[0x11] = KC_W,
+	[0x12] = KC_E,
+	[0x13] = KC_R,
+	[0x14] = KC_T,
+	[0x15] = KC_Y,
+	[0x16] = KC_U,
+	[0x17] = KC_I,
+	[0x18] = KC_O,
+	[0x19] = KC_P,
+
+	[0x1a] = KC_LBRACKET,
+	[0x1b] = KC_RBRACKET,
+
+	[0x3a] = KC_CAPS_LOCK,
+
+	[0x1e] = KC_A,
+	[0x1f] = KC_S,
+	[0x20] = KC_D,
+	[0x21] = KC_F,
+	[0x22] = KC_G,
+	[0x23] = KC_H,
+	[0x24] = KC_J,
+	[0x25] = KC_K,
+	[0x26] = KC_L,
+
+	[0x27] = KC_SEMICOLON,
+	[0x28] = KC_QUOTE,
+	[0x2b] = KC_BACKSLASH,
+
+	[0x2a] = KC_LSHIFT,
+
+	[0x2c] = KC_Z,
+	[0x2d] = KC_X,
+	[0x2e] = KC_C,
+	[0x2f] = KC_V,
+	[0x30] = KC_B,
+	[0x31] = KC_N,
+	[0x32] = KC_M,
+
+	[0x33] = KC_COMMA,
+	[0x34] = KC_PERIOD,
+	[0x35] = KC_SLASH,
+
+	[0x36] = KC_RSHIFT,
+
+	[0x1d] = KC_LCTRL,
+	[0x38] = KC_LALT,
+	[0x39] = KC_SPACE,
+
+	[0x01] = KC_ESCAPE,
+
+	[0x3b] = KC_F1,
+	[0x3c] = KC_F2,
+	[0x3d] = KC_F3,
+	[0x3e] = KC_F4,
+	[0x3f] = KC_F5,
+	[0x40] = KC_F6,
+	[0x41] = KC_F7,
+
+	[0x42] = KC_F8,
+	[0x43] = KC_F9,
+	[0x44] = KC_F10,
+
+	[0x57] = KC_F11,
+	[0x58] = KC_F12,
+
+	[0x46] = KC_SCROLL_LOCK,
+
+	[0x1c] = KC_ENTER,
+
+	[0x45] = KC_NUM_LOCK,
+	[0x37] = KC_NTIMES,
+	[0x4a] = KC_NMINUS,
+	[0x4e] = KC_NPLUS,
+	[0x47] = KC_N7,
+	[0x48] = KC_N8,
+	[0x49] = KC_N9,
+	[0x4b] = KC_N4,
+	[0x4c] = KC_N5,
+	[0x4d] = KC_N6,
+	[0x4f] = KC_N1,
+	[0x50] = KC_N2,
+	[0x51] = KC_N3,
+	[0x52] = KC_N0,
+	[0x53] = KC_NPERIOD
+};
+
+#define KBD_ACK   0xfa
+#define KBD_RESEND   0xfe
+#define KBD_SCANCODE_SET_EXTENDED   0xe0
+/** Scancode set 1 extended codes table */
+static const int scanmap_e0[] = {
+	[0x38] = KC_RALT,
+	[0x1d] = KC_RSHIFT,
+
+	[0x37] = KC_PRTSCR,
+
+	[0x52] = KC_INSERT,
+	[0x47] = KC_HOME,
+	[0x49] = KC_PAGE_UP,
+
+	[0x53] = KC_DELETE,
+	[0x4f] = KC_END,
+	[0x51] = KC_PAGE_DOWN,
+
+	[0x48] = KC_UP,
+	[0x4b] = KC_LEFT,
+	[0x50] = KC_DOWN,
+	[0x4d] = KC_RIGHT,
+
+	[0x35] = KC_NSLASH,
+	[0x1c] = KC_NENTER
+};
+
+#define KBD_CMD_SET_LEDS 0xed
+enum led_indicators {
+	LI_SCROLL       = 0x01,
+	LI_NUM          = 0x02,
+	LI_CAPS         = 0x04,
+};
+
+static int polling(void *);
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** Keyboard function ops. */
+static ddf_dev_ops_t kbd_ops = {
+	.default_handler = default_connection_handler
+};
+
+/** Initialize keyboard driver structure.
+ * @param kbd Keyboard driver structure to initialize.
+ * @param dev DDF device structure.
+ *
+ * Connects to parent, creates mouse function, starts polling fibril.
+ */
+int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
+{
+	assert(kbd);
+	assert(dev);
+	kbd->client_sess = NULL;
+	kbd->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    dev->handle, IPC_FLAG_BLOCKING);
+	if (!kbd->parent_sess)
+		return ENOMEM;
+
+	kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd");
+	if (!kbd->kbd_fun) {
+		async_hangup(kbd->parent_sess);
+		return ENOMEM;
+	}
+	kbd->kbd_fun->ops = &kbd_ops;
+	kbd->kbd_fun->driver_data = kbd;
+
+	int ret = ddf_fun_bind(kbd->kbd_fun);
+	if (ret != EOK) {
+		async_hangup(kbd->parent_sess);
+		kbd->kbd_fun->driver_data = NULL;
+		ddf_fun_destroy(kbd->kbd_fun);
+		return ENOMEM;
+	}
+
+	ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
+	if (ret != EOK) {
+		async_hangup(kbd->parent_sess);
+		ddf_fun_unbind(kbd->kbd_fun);
+		kbd->kbd_fun->driver_data = NULL;
+		ddf_fun_destroy(kbd->kbd_fun);
+		return ENOMEM;
+	}
+
+	kbd->polling_fibril = fibril_create(polling, kbd);
+	if (!kbd->polling_fibril) {
+		async_hangup(kbd->parent_sess);
+		ddf_fun_unbind(kbd->kbd_fun);
+		kbd->kbd_fun->driver_data = NULL;
+		ddf_fun_destroy(kbd->kbd_fun);
+		return ENOMEM;
+	}
+	fibril_add_ready(kbd->polling_fibril);
+	return EOK;
+}
+
+/** Get data and parse scancodes.
+ * @param arg Pointer to xt_kbd_t structure.
+ * @return Never.
+ */
+int polling(void *arg)
+{
+	assert(arg);
+	const xt_kbd_t *kbd = arg;
+
+	assert(kbd->parent_sess);
+	async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
+	while (1) {
+		if (!parent_exch)
+			parent_exch = async_exchange_begin(kbd->parent_sess);
+
+		const int *map = scanmap_simple;
+		size_t map_size = sizeof(scanmap_simple) / sizeof(int);
+
+		uint8_t code = 0;
+		ssize_t size = chardev_read(parent_exch, &code, 1);
+
+		/** Ignore AT command reply */
+		if (code == KBD_ACK || code == KBD_RESEND) {
+			continue;
+		}
+
+		if (code == KBD_SCANCODE_SET_EXTENDED) {
+			map = scanmap_e0;
+			map_size = sizeof(scanmap_e0) / sizeof(int);
+			size = chardev_read(parent_exch, &code, 1);
+			// TODO handle print screen
+		}
+
+		/* Invalid read. */
+		if (size != 1) {
+			continue;
+		}
+
+
+		/* Bit 7 indicates press/release */
+		const kbd_event_type_t type =
+		    (code & 0x80) ? KEY_RELEASE : KEY_PRESS;
+		code &= ~0x80;
+
+		const unsigned key = (code < map_size) ? map[code] : 0;
+		if (key != 0) {
+			async_exch_t *exch =
+			    async_exchange_begin(kbd->client_sess);
+			if (!exch) {
+				ddf_msg(LVL_ERROR,
+				    "Failed creating exchange.");
+				continue;
+			}
+			async_msg_4(exch, KBDEV_EVENT, type, key, 0, 0);
+			async_exchange_end(exch);
+		} else {
+			ddf_msg(LVL_WARN, "Unknown scancode: %hhx", code);
+		}
+	}
+}
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	if (fun == NULL || fun->driver_data == NULL) {
+		ddf_msg(LVL_ERROR, "%s: Missing parameter.", __FUNCTION__);
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	const sysarg_t method = IPC_GET_IMETHOD(*icall);
+	xt_kbd_t *kbd = fun->driver_data;
+
+	switch (method) {
+	case KBDEV_SET_IND: {
+		/* XT keyboards do not support setting mods,
+		 * assume AT keyboard with Scan Code Set 1 */
+		const unsigned mods = IPC_GET_ARG1(*icall);
+		const uint8_t status = 0 |
+		    ((mods & KM_CAPS_LOCK) ? LI_CAPS : 0) |
+		    ((mods & KM_NUM_LOCK) ? LI_NUM : 0) |
+		    ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0);
+		uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
+		async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
+		const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
+		async_exchange_end(exch);
+		async_answer_0(icallid, size < 0 ? size : EOK);
+		break;
+	}
+	/* This might be ugly but async_callback_receive_start makes no
+	 * difference for incorrect call and malloc failure. */
+	case IPC_M_CONNECT_TO_ME: {
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+		/* Probably ENOMEM error, try again. */
+		if (sess == NULL) {
+			ddf_msg(LVL_WARN,
+			    "Failed creating callback session");
+			async_answer_0(icallid, EAGAIN);
+			break;
+		}
+		if (kbd->client_sess == NULL) {
+			kbd->client_sess = sess;
+			ddf_msg(LVL_DEBUG, "Set client session");
+			async_answer_0(icallid, EOK);
+		} else {
+			ddf_msg(LVL_ERROR, "Client session already set");
+			async_answer_0(icallid, ELIMIT);
+		}
+		break;
+	}
+	default:
+			ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method);
+			async_answer_0(icallid, EINVAL);
+			break;
+	}
+}
Index: uspace/drv/char/xtkbd/xtkbd.h
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/xtkbd.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief XT keyboard driver
+ */
+
+#ifndef _XT_KBD_H_
+#define _XT_KBD_H_
+
+#include <ddf/driver.h>
+#include <fibril.h>
+
+/** PC/XT keyboard driver structure. */
+typedef struct {
+	ddf_fun_t *kbd_fun;        /**< Keyboard function. */
+	async_sess_t *parent_sess; /**< Connection to device providing data. */
+	async_sess_t *client_sess; /**< Callback connection to client. */
+	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+} xt_kbd_t;
+
+int xt_kbd_init(xt_kbd_t *, ddf_dev_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/xtkbd/xtkbd.ma
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/char/xtkbd/xtkbd.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,1 @@
+100 char/xtkbd
Index: uspace/drv/infrastructure/rootmac/rootmac.c
===================================================================
--- uspace/drv/infrastructure/rootmac/rootmac.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/infrastructure/rootmac/rootmac.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -161,6 +161,6 @@
 
 static hw_res_ops_t fun_hw_res_ops = {
-	&rootmac_get_resources,
-	&rootmac_enable_interrupt
+   	.get_resource_list = &rootmac_get_resources,
+	.enable_interrupt = &rootmac_enable_interrupt
 };
 
Index: uspace/drv/infrastructure/rootpc/rootpc.c
===================================================================
--- uspace/drv/infrastructure/rootpc/rootpc.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/e1k/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/e1k/e1k.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,2381 @@
+/*
+ * 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/log.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 "e1k.h"
+
+#define NAME  "e1k"
+
+#define E1000_DEFAULT_INTERRUPT_INTERVAL_USEC  250
+
+/* Must be power of 8 */
+#define E1000_RX_FRAME_COUNT  128
+#define E1000_TX_FRAME_COUNT  128
+
+#define E1000_RECEIVE_ADDRESS  16
+
+/** Maximum sending frame size */
+#define E1000_MAX_SEND_FRAME_SIZE  2048
+/** Maximum receiving frame size */
+#define E1000_MAX_RECEIVE_FRAME_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 {
+	/** Device configuration */
+	e1000_info_t info;
+	
+	/** 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;
+	
+	/** Ring of TX frames, physical address */
+	void **tx_frame_phys;
+	/** Ring of TX frames, virtual address */
+	void **tx_frame_virt;
+	
+	/** Physical rx ring address */
+	void *rx_ring_phys;
+	/** Virtual rx ring address */
+	void *rx_ring_virt;
+	
+	/** Ring of RX frames, physical address */
+	void **rx_frame_phys;
+	/** Ring of RX frames, virtual address */
+	void **rx_frame_virt;
+	
+	/** VLAN tag */
+	uint16_t vlan_tag;
+	
+	/** Add VLAN tag to frame */
+	bool vlan_tag_add;
+	
+	/** Used unicast Receive Address count */
+	unsigned int unicast_ra_count;
+	
+	/** Used milticast Receive addrress count */
+	unsigned int multicast_ra_count;
+	
+	/** 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_send_frame(nic_t *, void *, size_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 frames
+ *
+ * @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 frames
+ *
+ * @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 frames 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 frames 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 frames
+ *
+ * @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 frames
+ *
+ * @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 frames 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 frames 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 frames 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 frame 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 buffer
+ *
+ * Store frame in e1000->rx_frame_phys
+ *
+ * @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);
+	
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + offset * sizeof(e1000_rx_descriptor_t));
+	
+	rx_descriptor->phys_addr = PTR_TO_U64(e1000->rx_frame_phys[offset]);
+	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));
+	
+	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 frames
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_receive_frames(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_FRAME_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 frame_size = rx_descriptor->length - E1000_CRC_SIZE;
+		
+		nic_frame_t *frame = nic_alloc_frame(nic, frame_size);
+		if (frame != NULL) {
+			memcpy(frame->data, e1000->rx_frame_virt[next_tail], frame_size);
+			nic_received_frame(nic, frame);
+		} else {
+			ddf_msg(LVL_ERROR, "Memory allocation failed. Frame dropped.");
+		}
+		
+		e1000_fill_new_rx_descriptor(nic, next_tail);
+		
+		*tail_addr = e1000_inc_tail(*tail_addr, E1000_RX_FRAME_COUNT);
+		next_tail = e1000_inc_tail(*tail_addr, E1000_RX_FRAME_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_frames(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 frames 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_FRAME_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_FRAME_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_FRAME_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_frame_phys =
+	    calloc(E1000_RX_FRAME_COUNT, sizeof(void *));
+	e1000->rx_frame_virt =
+	    calloc(E1000_RX_FRAME_COUNT, sizeof(void *));
+	if (e1000->rx_frame_phys == NULL || e1000->rx_frame_virt == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+	
+	size_t i;
+	void *frame_virt;
+	void *frame_phys;
+	
+	for (i = 0; i < E1000_RX_FRAME_COUNT; i++) {
+		rc = dmamem_map_anonymous(
+		    E1000_MAX_SEND_FRAME_SIZE, AS_AREA_READ | AS_AREA_WRITE,
+		    0, &frame_phys, &frame_virt);
+		if (rc != EOK)
+			goto error;
+		
+		e1000->rx_frame_virt[i] = frame_virt;
+		e1000->rx_frame_phys[i] = frame_phys;
+	}
+	
+	/* Write descriptor */
+	for (i = 0; i < E1000_RX_FRAME_COUNT; i++)
+		e1000_fill_new_rx_descriptor(nic, i);
+	
+	e1000_initialize_rx_registers(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return EOK;
+	
+error:
+	for (i = 0; i < E1000_RX_FRAME_COUNT; i++) {
+		if (e1000->rx_frame_virt[i] != NULL) {
+			dmamem_unmap_anonymous(e1000->rx_frame_virt[i]);
+			e1000->rx_frame_virt[i] = NULL;
+			e1000->rx_frame_phys[i] = NULL;
+		}
+	}
+	
+	if (e1000->rx_frame_phys != NULL) {
+		free(e1000->rx_frame_phys);
+		e1000->rx_frame_phys = NULL;
+	}
+	
+	if (e1000->rx_frame_virt != NULL) {
+		free(e1000->rx_frame_virt);
+		e1000->rx_frame_phys = NULL;
+	}
+	
+	return rc;
+}
+
+/** 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_FRAME_COUNT; offset++) {
+		dmamem_unmap_anonymous(e1000->rx_frame_virt[offset]);
+		e1000->rx_frame_virt[offset] = NULL;
+		e1000->rx_frame_phys[offset] = NULL;
+	}
+	
+	free(e1000->rx_frame_virt);
+	free(e1000->rx_frame_phys);
+	e1000->rx_frame_virt = NULL;
+	e1000->rx_frame_phys = NULL;
+	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_FRAME_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_FRAME_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)
+{
+	size_t i;
+	
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	e1000->tx_ring_phys = NULL;
+	e1000->tx_ring_virt = NULL;
+	e1000->tx_frame_phys = NULL;
+	e1000->tx_frame_virt = NULL;
+	
+	int rc = dmamem_map_anonymous(
+	    E1000_TX_FRAME_COUNT * sizeof(e1000_tx_descriptor_t),
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &e1000->tx_ring_phys,
+	    &e1000->tx_ring_virt);
+	if (rc != EOK)
+		goto error;
+	
+	bzero(e1000->tx_ring_virt,
+	    E1000_TX_FRAME_COUNT * sizeof(e1000_tx_descriptor_t));
+	
+	e1000->tx_frame_phys = calloc(E1000_TX_FRAME_COUNT, sizeof(void *));
+	e1000->tx_frame_virt = calloc(E1000_TX_FRAME_COUNT, sizeof(void *));
+
+	if (e1000->tx_frame_phys == NULL || e1000->tx_frame_virt == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+	
+	for (i = 0; i < E1000_TX_FRAME_COUNT; i++) {
+		rc = dmamem_map_anonymous(
+		    E1000_MAX_SEND_FRAME_SIZE, AS_AREA_READ | AS_AREA_WRITE,
+		    0, &e1000->tx_frame_phys[i], &e1000->tx_frame_virt[i]);
+		if (rc != EOK)
+			goto error;
+	}
+	
+	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_initialize_tx_registers(e1000);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+	return EOK;
+	
+error:
+	if (e1000->tx_ring_virt != NULL) {
+		dmamem_unmap_anonymous(e1000->tx_ring_virt);
+		e1000->tx_ring_virt = NULL;
+	}
+	
+	if (e1000->tx_frame_phys != NULL && e1000->tx_frame_virt != NULL) {
+		for (i = 0; i < E1000_TX_FRAME_COUNT; i++) {
+			if (e1000->tx_frame_virt[i] != NULL) {
+				dmamem_unmap_anonymous(e1000->tx_frame_virt[i]);
+				e1000->tx_frame_virt[i] = NULL;
+				e1000->tx_frame_phys[i] = NULL;
+			}
+		}
+	}
+	
+	if (e1000->tx_frame_phys != NULL) {
+		free(e1000->tx_frame_phys);
+		e1000->tx_frame_phys = NULL;
+	}
+	
+	if (e1000->tx_frame_virt != NULL) {
+		free(e1000->tx_frame_virt);
+		e1000->tx_frame_phys = NULL;
+	}
+	
+	return rc;
+}
+
+/** Uninitialize transmit structure
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_uninitialize_tx_structure(e1000_t *e1000)
+{
+	size_t i;
+	
+	for (i = 0; i < E1000_TX_FRAME_COUNT; i++) {
+		dmamem_unmap_anonymous(e1000->tx_frame_virt[i]);
+		e1000->tx_frame_virt[i] = NULL;
+		e1000->tx_frame_phys[i] = NULL;
+	}
+	
+	if (e1000->tx_frame_phys != NULL) {
+		free(e1000->tx_frame_phys);
+		e1000->tx_frame_phys = NULL;
+	}
+	
+	if (e1000->tx_frame_virt != NULL) {
+		free(e1000->tx_frame_virt);
+		e1000->tx_frame_phys = NULL;
+	}
+	
+	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_FRAME_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 frames
+ *
+ * @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_send_frame_handler(nic, e1000_send_frame);
+	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) {
+		ddf_msg(LVL_ERROR, "Unable to allocate device softstate");
+		return ENOMEM;
+	}
+	
+	/* Obtain and fill hardware resources info */
+	int rc = e1000_get_resource_info(dev);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Cannot obtain hardware resources");
+		e1000_dev_cleanup(dev);
+		return rc;
+	}
+	
+	uint16_t device_id;
+	rc = pci_config_space_read_16(dev->parent_sess, PCI_DEVICE_ID,
+	    &device_id);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Cannot access PCI configuration space");
+		e1000_dev_cleanup(dev);
+		return rc;
+	}
+	
+	e1000_board_t board;
+	switch (device_id) {
+	case 0x100e:
+	case 0x1015:
+	case 0x1016:
+	case 0x1017:
+		board = E1000_82540;
+		break;
+	case 0x1013:
+	case 0x1018:
+	case 0x1078:
+		board = E1000_82541;
+		break;
+	case 0x1076:
+	case 0x1077:
+	case 0x107c:
+		board = E1000_82541REV2;
+		break;
+	case 0x100f:
+	case 0x1011:
+	case 0x1026:
+	case 0x1027:
+	case 0x1028:
+		board = E1000_82545;
+		break;
+	case 0x1010:
+	case 0x1012:
+	case 0x101d:
+	case 0x1079:
+	case 0x107a:
+	case 0x107b:
+		board = E1000_82546;
+		break;
+	case 0x1019:
+	case 0x101a:
+		board = E1000_82547;
+		break;
+	case 0x10b9:
+		board = E1000_82572;
+		break;
+	case 0x1096:
+		board = E1000_80003ES2;
+		break;
+	default:
+		ddf_msg(LVL_ERROR, "Device not supported (%#" PRIx16 ")",
+		    device_id);
+		e1000_dev_cleanup(dev);
+		return ENOTSUP;
+	}
+	
+	switch (board) {
+	case E1000_82540:
+	case E1000_82541:
+	case E1000_82541REV2:
+	case E1000_82545:
+	case E1000_82546:
+		e1000->info.eerd_start = 0x01;
+		e1000->info.eerd_done = 0x10;
+		e1000->info.eerd_address_offset = 8;
+		e1000->info.eerd_data_offset = 16;
+		break;
+	case E1000_82547:
+	case E1000_82572:
+	case E1000_80003ES2:
+		e1000->info.eerd_start = 0x01;
+		e1000->info.eerd_done = 0x02;
+		e1000->info.eerd_address_offset = 2;
+		e1000->info.eerd_data_offset = 16;
+		break;
+	}
+	
+	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)
+{
+	ddf_fun_t *fun;
+	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);
+	
+	fun = ddf_fun_create(nic_get_ddf_dev(nic), fun_exposed, "port0");
+	if (fun == NULL)
+		goto err_tx_structure;
+	nic_set_ddf_fun(nic, fun);
+	fun->ops = &e1000_dev_ops;
+	fun->driver_data = nic;
+	
+	rc = e1000_register_int_handler(nic);
+	if (rc != EOK)
+		goto err_fun_create;
+	
+	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;
+	
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK)
+		goto err_fun_bind;
+	
+	rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK)
+		goto err_add_to_cat;
+	
+	return EOK;
+	
+err_add_to_cat:
+	ddf_fun_unbind(fun);
+err_fun_bind:
+err_rx_structure:
+	e1000_uninitialize_rx_structure(nic);
+err_irq:
+	unregister_interrupt_handler(dev, DRIVER_DATA_DEV(dev)->irq);
+err_fun_create:
+	ddf_fun_destroy(fun);
+	nic_set_ddf_fun(nic, NULL);
+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);
+	
+	/* Write address and START bit to EERD register */
+	uint32_t write_data = e1000->info.eerd_start |
+	    (((uint32_t) eeprom_address) <<
+	    e1000->info.eerd_address_offset);
+	E1000_REG_WRITE(e1000, E1000_EERD, write_data);
+	
+	uint32_t eerd = E1000_REG_READ(e1000, E1000_EERD);
+	while ((eerd & e1000->info.eerd_done) == 0) {
+		usleep(1);
+		eerd = E1000_REG_READ(e1000, E1000_EERD);
+	}
+	
+	fibril_mutex_unlock(&e1000->eeprom_lock);
+	
+	return (uint16_t) (eerd >> e1000->info.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 frame
+ *
+ * @param nic    NIC driver data structure
+ * @param data   Frame data
+ * @param size   Frame size in bytes
+ *
+ * @return EOK if succeed
+ * @return Error code in the case of error
+ *
+ */
+static void e1000_send_frame(nic_t *nic, void *data, size_t size)
+{
+	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;
+	
+	if (!descriptor_available) {
+		/* Frame lost */
+		fibril_mutex_unlock(&e1000->tx_lock);
+		return;
+	}
+	
+	memcpy(e1000->tx_frame_virt[tdt], data, size);
+	
+	tx_descriptor_addr->phys_addr = PTR_TO_U64(e1000->tx_frame_phys[tdt]);
+	tx_descriptor_addr->length = 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_FRAME_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);
+	
+	ddf_log_init(NAME, LVL_ERROR);
+	ddf_msg(LVL_NOTE, "HelenOS E1000 driver started");
+	return ddf_driver_main(&e1000_driver);
+}
Index: uspace/drv/nic/e1k/e1k.h
===================================================================
--- uspace/drv/nic/e1k/e1k.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/e1k/e1k.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,245 @@
+/*
+ * 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 frame 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;
+
+/** E1000 boards */
+typedef enum {
+	E1000_82540,
+	E1000_82541,
+	E1000_82541REV2,
+	E1000_82545,
+	E1000_82546,
+	E1000_82547,
+	E1000_82572,
+	E1000_80003ES2
+} e1000_board_t;
+
+typedef struct {
+	uint32_t eerd_start;
+	uint32_t eerd_done;
+	
+	uint32_t eerd_address_offset;
+	uint32_t eerd_data_offset;
+} e1000_info_t;
+
+/** VLAN tag bits */
+typedef enum {
+	VLANTAG_CFI = (1 << 12),  /**< Canonical Form Indicator */
+} e1000_vlantag_t;
+
+/** Transmit descriptor COMMAND field bits */
+typedef enum {
+	TXDESCRIPTOR_COMMAND_VLE = (1 << 6),   /**< VLAN frame Enable */
+	TXDESCRIPTOR_COMMAND_RS = (1 << 3),    /**< Report Status */
+	TXDESCRIPTOR_COMMAND_IFCS = (1 << 1),  /**< Insert FCS */
+	TXDESCRIPTOR_COMMAND_EOP = (1 << 0)    /**< End Of Packet */
+} e1000_txdescriptor_command_t;
+
+/** Transmit descriptor STATUS field bits */
+typedef enum {
+	TXDESCRIPTOR_STATUS_DD = (1 << 0)  /**< Descriptor Done */
+} e1000_txdescriptor_status_t;
+
+/** E1000 Registers */
+typedef enum {
+	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 */
+} e1000_registers_t;
+
+/** Device Control Register fields */
+typedef enum {
+	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 */
+} e1000_ctrl_t;
+
+/** Device Status Register fields */
+typedef enum {
+	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,
+} e1000_status_t;
+
+/** Transmit IPG Register fields
+ *
+ * IPG = Inter Packet Gap
+ *
+ */
+typedef enum {
+	TIPG_IPGT_SHIFT = 0,    /**< IPG Transmit Time shift */
+	TIPG_IPGR1_SHIFT = 10,  /**< IPG Receive Time 1 */
+	TIPG_IPGR2_SHIFT = 20   /**< IPG Receive Time 2 */
+} e1000_tipg_t;
+
+/** Transmit Control Register fields */
+typedef enum {
+	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 */
+} e1000_tctl_t;
+
+/** ICR register fields */
+typedef enum {
+	ICR_TXDW = (1 << 0),  /**< Transmit Descriptor Written Back */
+	ICR_RXT0 = (1 << 7)   /**< Receiver Timer Interrupt */
+} e1000_icr_t;
+
+/** RAH register fields */
+typedef enum {
+	RAH_AV = (1 << 31)   /**< Address Valid */
+} e1000_rah_t;
+
+/** RCTL register fields */
+typedef enum {
+	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 */
+} e1000_rctl_t;
+
+#endif
Index: uspace/drv/nic/e1k/e1k.ma
===================================================================
--- uspace/drv/nic/e1k/e1k.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/e1k/e1k.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,25 @@
+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=1096
+10 pci/ven=8086&dev=10b9
Index: uspace/drv/nic/lo/lo.c
===================================================================
--- uspace/drv/nic/lo/lo.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/nic/lo/lo.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -42,5 +42,4 @@
 #include <async.h>
 #include <nic.h>
-#include <packet_client.h>
 
 #define NAME  "lo"
@@ -59,8 +58,8 @@
 };
 
-static void lo_write_packet(nic_t *nic_data, packet_t *packet)
+static void lo_send_frame(nic_t *nic_data, void *data, size_t size)
 {
-	nic_report_send_ok(nic_data, 1, packet_get_data_length(packet));
-	nic_received_noneth_packet(nic_data, packet);
+	nic_report_send_ok(nic_data, 1, size);
+	nic_received_noneth_frame(nic_data, data, size);
 }
 
@@ -81,36 +80,61 @@
 static int lo_dev_add(ddf_dev_t *dev)
 {
-	nic_t *nic_data = nic_create_and_bind(dev);
-	if (nic_data == NULL) {
+	ddf_fun_t *fun = NULL;
+	bool bound = false;
+	
+	nic_t *nic = nic_create_and_bind(dev);
+	if (nic == NULL) {
 		printf("%s: Failed to initialize\n", NAME);
 		return ENOMEM;
 	}
 	
-	dev->driver_data = nic_data;
-	nic_set_write_packet_handler(nic_data, lo_write_packet);
+	dev->driver_data = nic;
+	nic_set_send_frame_handler(nic, lo_send_frame);
 	
-	int rc = nic_connect_to_services(nic_data);
+	int rc = nic_connect_to_services(nic);
 	if (rc != EOK) {
 		printf("%s: Failed to connect to services\n", NAME);
-		nic_unbind_and_destroy(dev);
-		return rc;
+		goto error;
 	}
 	
-	rc = nic_register_as_ddf_fun(nic_data, &lo_dev_ops);
+	fun = ddf_fun_create(nic_get_ddf_dev(nic), fun_exposed, "port0");
+	if (fun == NULL) {
+		printf("%s: Failed creating function\n", NAME);
+		rc = ENOMEM;
+		goto error;
+	}
+	nic_set_ddf_fun(nic, fun);
+	fun->ops = &lo_dev_ops;
+	fun->driver_data = nic;
+	
+	rc = nic_report_address(nic, &lo_addr);
 	if (rc != EOK) {
-		printf("%s: Failed to register as DDF function\n", NAME);
-		nic_unbind_and_destroy(dev);
-		return rc;
+		printf("%s: Failed to setup loopback address\n", NAME);
+		goto error;
 	}
 	
-	rc = nic_report_address(nic_data, &lo_addr);
+	rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
-		printf("%s: Failed to setup loopback address\n", NAME);
-		nic_unbind_and_destroy(dev);
-		return rc;
+		printf("%s: Failed binding function\n", NAME);
+		goto error;
 	}
+	bound = true;
+	
+	rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK)
+		goto error;
 	
 	printf("%s: Adding loopback device '%s'\n", NAME, dev->name);
 	return EOK;
+	
+error:
+	if (bound)
+		ddf_fun_unbind(fun);
+	
+	if (fun != NULL)
+		ddf_fun_destroy(fun);
+	
+	nic_unbind_and_destroy(dev);
+	return rc;
 }
 
Index: uspace/drv/nic/lo/lo.ma
===================================================================
--- uspace/drv/nic/lo/lo.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/nic/lo/lo.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
Index: uspace/drv/nic/ne2k/dp8390.c
===================================================================
--- uspace/drv/nic/ne2k/dp8390.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/nic/ne2k/dp8390.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -59,6 +59,4 @@
 #include <stdio.h>
 #include <libarch/ddi.h>
-#include <net/packet.h>
-#include <packet_client.h>
 #include "dp8390.h"
 
@@ -76,5 +74,5 @@
 	uint8_t status;
 	
-	/** Pointer to next packet */
+	/** Pointer to next frame */
 	uint8_t next;
 	
@@ -142,8 +140,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);
@@ -392,6 +391,6 @@
 	/*
 	 * Reset the transmit ring. If we were transmitting a frame,
-	 * we pretend that the packet is processed. Higher layers will
-	 * retransmit if the packet wasn't actually sent.
+	 * we pretend that the frame is processed. Higher layers will
+	 * retransmit if the frame wasn't actually sent.
 	 */
 	ne2k->sq.dirty = false;
@@ -403,8 +402,9 @@
  *
  * @param[in,out] ne2k   Network interface structure.
- * @param[in]     packet Frame to be sent.
- *
- */
-void ne2k_send(nic_t *nic_data, packet_t *packet)
+ * @param[in]     data   Pointer to frame data
+ * @param[in]     size   Frame size in bytes
+ *
+ */
+void ne2k_send(nic_t *nic_data, void *data, size_t size)
 {
 	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
@@ -418,6 +418,4 @@
 		fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
 	}
-	void *buf = packet_get_data(packet);
-	size_t size = packet_get_data_length(packet);
 	
 	if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
@@ -427,5 +425,5 @@
 
 	/* Upload the frame to the ethernet card */
-	ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
+	ne2k_upload(ne2k, data, ne2k->sq.page * DP_PAGE, size);
 	ne2k->sq.dirty = true;
 	ne2k->sq.size = size;
@@ -437,7 +435,4 @@
 	pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
 	fibril_mutex_unlock(&ne2k->sq_mutex);
-
-	/* Relase packet */
-	nic_release_packet(nic_data, packet);
 }
 
@@ -451,6 +446,5 @@
 		return NULL;
 	
-	void *buf = packet_suffix(frame->packet, length);
-	bzero(buf, length);
+	bzero(frame->data, length);
 	uint8_t last = page + length / DP_PAGE;
 	
@@ -458,10 +452,10 @@
 		size_t left = (ne2k->stop_page - page) * DP_PAGE
 		    - sizeof(recv_header_t);
-		ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
+		ne2k_download(ne2k, frame->data, page * DP_PAGE + sizeof(recv_header_t),
 		    left);
-		ne2k_download(ne2k, buf + left, ne2k->start_page * DP_PAGE,
+		ne2k_download(ne2k, frame->data + left, ne2k->start_page * DP_PAGE,
 		    length - left);
 	} else {
-		ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
+		ne2k_download(ne2k, frame->data, page * DP_PAGE + sizeof(recv_header_t),
 		    length);
 	}
@@ -544,5 +538,5 @@
 		 * Update the boundary pointer
 		 * to the value of the page
-		 * prior to the next packet to
+		 * prior to the next frame to
 		 * be processed.
 		 */
@@ -587,5 +581,5 @@
 		fibril_mutex_lock(&ne2k->sq_mutex);
 		if (ne2k->sq.dirty) {
-			/* Prepare the buffer for next packet */
+			/* Prepare the buffer for next frame */
 			ne2k->sq.dirty = false;
 			ne2k->sq.size = 0;
Index: uspace/drv/nic/ne2k/dp8390.h
===================================================================
--- uspace/drv/nic/ne2k/dp8390.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/nic/ne2k/dp8390.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -262,7 +262,6 @@
 extern int ne2k_up(ne2k_t *);
 extern void ne2k_down(ne2k_t *);
-extern void ne2k_send(nic_t *, packet_t *);
+extern void ne2k_send(nic_t *, void *, size_t);
 extern void ne2k_interrupt(nic_t *, uint8_t, uint8_t);
-extern packet_t *ne2k_alloc_packet(nic_t *, size_t);
 
 extern void ne2k_set_accept_mcast(ne2k_t *, int);
Index: uspace/drv/nic/ne2k/ne2k.c
===================================================================
--- uspace/drv/nic/ne2k/ne2k.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/nic/ne2k/ne2k.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -261,5 +261,5 @@
 	/* Note: some frame with previous physical address may slip to NIL here
 	 * (for a moment the filtering is not exact), but ethernet should be OK with
-	 * that. Some packet may also be lost, but this is not a problem.
+	 * that. Some frames may also be lost, but this is not a problem.
 	 */
 	ne2k_set_physical_address((ne2k_t *) nic_get_specific(nic_data), address);
@@ -338,4 +338,6 @@
 static int ne2k_dev_add(ddf_dev_t *dev)
 {
+	ddf_fun_t *fun;
+	
 	/* Allocate driver data for the device. */
 	nic_t *nic_data = nic_create_and_bind(dev);
@@ -343,5 +345,5 @@
 		return ENOMEM;
 	
-	nic_set_write_packet_handler(nic_data, ne2k_send);
+	nic_set_send_frame_handler(nic_data, ne2k_send);
 	nic_set_state_change_handlers(nic_data,
 		ne2k_on_activating, NULL, ne2k_on_stopping);
@@ -371,5 +373,5 @@
 	}
 	
-	rc = nic_register_as_ddf_fun(nic_data, &ne2k_dev_ops);
+	rc = nic_connect_to_services(nic_data);
 	if (rc != EOK) {
 		ne2k_dev_cleanup(dev);
@@ -377,7 +379,24 @@
 	}
 	
-	rc = nic_connect_to_services(nic_data);
-	if (rc != EOK) {
+	fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
+	if (fun == NULL) {
 		ne2k_dev_cleanup(dev);
+		return ENOMEM;
+	}
+	nic_set_ddf_fun(nic_data, fun);
+	fun->ops = &ne2k_dev_ops;
+	fun->driver_data = nic_data;
+	
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_fun_destroy(fun);
+		ne2k_dev_cleanup(dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK) {
+		ddf_fun_unbind(fun);
+		ddf_fun_destroy(fun);
 		return rc;
 	}
Index: uspace/drv/nic/ne2k/ne2k.ma
===================================================================
--- uspace/drv/nic/ne2k/ne2k.ma	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/drv/nic/ne2k/ne2k.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
Index: uspace/drv/nic/rtl8139/Makefile
===================================================================
--- uspace/drv/nic/rtl8139/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/defs.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 "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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/defs.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,514 @@
+/*
+ * 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_
+#define RTL8139_DEFS_H_
+
+#include <sys/types.h>
+#include <libarch/ddi.h>
+
+/** Size of RTL8139 registers address space */
+#define RTL8139_IO_SIZE  256
+
+/** Maximal transmitted frame length
+ *
+ * Maximal transmitted frame length in bytes
+ * allowed according to the RTL8139 documentation
+ * (see SIZE part of TSD documentation).
+ *
+ */
+#define RTL8139_FRAME_MAX_LENGTH  1792
+
+/** HW version
+ *
+ * As can be detected from HWVERID part of TCR
+ * (Transmit Configuration Register).
+ *
+ */
+typedef enum {
+	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 */
+} rtl8139_version_id_t;
+
+/** 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 */
+
+	// 0x06 - 0x07 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 frame 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 frame 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 frame */
+	RCR_ACCEPT_RUNT       = 1 << 4,  /**< Accept Runt (8-64 bytes) frames */
+	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 frames 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 frame 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 frame 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 frame size + 1 */
+#define RTL8139_RUNT_MAX_SIZE  64
+
+/** Bits in frame header */
+enum rtl8139_frame_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 frame (< RTL8139_RUNT_MAX_SIZE bytes) */
+
+	RSR_LONG = (1 << 3),   /**< Long frame (size > 4k bytes) */
+	RSR_CRC  = (1 << 2),   /**< CRC error */
+	RSR_FAE  = (1 << 1),   /**< Frame alignment error */
+	RSR_ROK  = (1 << 0)    /**< Good frame 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 frame */
+
+	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 frame 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 */
+	rtl8139_version_id_t ver_id;  /**< appropriate version id */
+};
+
+/** Mapping of HW version -> version ID */
+extern const struct rtl8139_hwver_map rtl8139_versions[RTL8139_VER_COUNT + 1];
+extern const char* model_names[RTL8139_VER_COUNT];
+
+/** Size in the frame header while copying from RxFIFO to Rx buffer */
+#define RTL8139_EARLY_SIZE  UINT16_C(0xfff0)
+
+/** The only supported pause frame time value */
+#define RTL8139_PAUSE_VAL  UINT16_C(0xFFFF)
+
+/** Size of the frame header in front of the received frame */
+#define RTL_FRAME_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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/driver.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,2186 @@
+/*
+ * 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 <as.h>
+#include <ddf/log.h>
+#include <ddf/interrupt.h>
+#include <io/log.h>
+#include <nic.h>
+#include <device/pci.h>
+
+#include <ipc/irc.h>
+#include <sysinfo.h>
+#include <ipc/ns.h>
+
+#include <net_checksum.h>
+
+#include <str.h>
+
+#include "defs.h"
+#include "driver.h"
+#include "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 frames 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);
+	
+	ddf_msg(LVL_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 frames 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_dev_add(ddf_dev_t *dev);
+
+/** Basic driver operations for RTL8139 driver */
+static driver_ops_t rtl8139_driver_ops = {
+	.dev_add = &rtl8139_dev_add,
+};
+
+/** 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_send_frame(nic_t *nic_data, void *data, size_t size);
+
+/** Check if the transmit buffer is busy */
+#define rtl8139_tbuf_busy(tsd) ((pio_read_32(tsd) & TSD_OWN) == 0)
+
+/** Send frame with the hardware
+ *
+ * note: the main_lock is locked when framework calls this function
+ *
+ * @param nic_data  The nic driver data structure
+ * @param data      Frame data
+ * @param size      Frame size in bytes
+ *
+ * @return EOK if succeed, error code in the case of error
+ */
+static void rtl8139_send_frame(nic_t *nic_data, void *data, size_t size)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+	ddf_msg(LVL_DEBUG, "Sending frame");
+
+	if (size > RTL8139_FRAME_MAX_LENGTH) {
+		ddf_msg(LVL_ERROR, "Send frame: frame too long, %zu bytes",
+		    size);
+		nic_report_send_error(rtl8139->nic_data, NIC_SEC_OTHER, 1);
+		goto err_size;
+	}
+
+	assert((size & TSD_SIZE_MASK) == size);
+
+	/* 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 frame 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 frame data to the buffer, set the size to TSD and clear OWN bit */
+	memcpy(buf_addr, data, size);
+
+	/* Set size of the data to send */
+	uint32_t tsd_value = pio_read_32(tsd);
+	tsd_value = rtl8139_tsd_set_size(tsd_value, size);
+	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);
+	return;
+	
+err_busy_no_inc:
+err_size:
+	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 frame structure from the buffer data
+ *
+ * @param nic_data      NIC driver data
+ * @param rx_buffer     The receiver buffer
+ * @param rx_size       The buffer size
+ * @param frame_start   The offset where packet data start
+ * @param frame_size    The size of the frame data
+ *
+ * @return The frame list node (not connected)
+ *
+ */
+static nic_frame_t *rtl8139_read_frame(nic_t *nic_data,
+    void *rx_buffer, size_t rx_size, size_t frame_start, size_t frame_size)
+{
+	nic_frame_t *frame = nic_alloc_frame(nic_data, frame_size);
+	if (! frame) {
+		ddf_msg(LVL_ERROR, "Can not allocate frame for received frame.");
+		return NULL;
+	}
+
+	void *ret = rtl8139_memcpy_wrapped(frame->data, rx_buffer, frame_start,
+	    RxBUF_SIZE, frame_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_phys));
+
+	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 frames in queue
+ *
+ *  @param nic_data  The controller data
+ *  @return The linked list of nic_frame_list_t nodes, each containing one frame
+ */
+static nic_frame_list_t *rtl8139_frame_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)
+		ddf_msg(LVL_ERROR, "Can not allocate frame list for received frames.");
+
+	void *rx_buffer = rtl8139->rx_buff_virt;
+
+	/* 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 frame_header = uint32_t_le2host( *((uint32_t*)rx_ptr) );
+		uint16_t size = frame_header >> 16;
+		uint16_t frame_size = size - RTL8139_CRC_SIZE;
+		/* received frame flags in frame header */
+		uint16_t rcs = (uint16_t) frame_header;
+
+		if (size == RTL8139_EARLY_SIZE) {
+			/* The frame copying is still in progress, break receiving */
+			ddf_msg(LVL_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_FRAME_MAX_LENGTH) {
+			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (size: %4"PRIu16", "
+			    "header 0x%4"PRIx16". Offset: %zu)", size, frame_header, 
+			    rx_offset);
+			goto rx_err;
+		}
+		if (size < RTL8139_RUNT_MAX_SIZE && !(rcs & RSR_RUNT)) {
+			ddf_msg(LVL_ERROR, "Receiver error -> receiver reset (%"PRIx16")", size);
+			goto rx_err;
+		}
+
+		cur_read += size + RTL_FRAME_HEADER_SIZE;
+		if (cur_read > max_read)
+			break;
+
+		if (frames) {
+			nic_frame_t *frame = rtl8139_read_frame(nic_data, rx_buffer,
+			    RxBUF_SIZE, rx_offset + RTL_FRAME_HEADER_SIZE, frame_size);
+
+			if (frame)
+				nic_frame_list_append(frames, frame);
+		}
+
+		/* Update offset */
+		rx_offset = ALIGN_UP(rx_offset + size + RTL_FRAME_HEADER_SIZE, 4);
+
+		/* Write lesser value to prevent overflow into unread frame
+		 * (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 frame 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 frames from the buffer
+ *
+ *  @param rtl8139  driver private data
+ */
+static void rtl8139_receive_frames(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_frame_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);
+	ddf_msg(LVL_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 frames
+	 * sooner
+	 */
+	if (isr & (INT_TOK | INT_TER)) {
+		rtl8139_tx_interrupt(nic_data);
+	}
+	if (isr & INT_ROK) {
+		rtl8139_receive_frames(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_phys + 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_phys));
+
+	/* 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 frames
+ *
+ *  @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);
+	ddf_msg(LVL_NOTE, "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);
+
+	ddf_msg(LVL_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_send_frame_handler(nic_data, rtl8139_send_frame);
+	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) {
+		ddf_msg(LVL_ERROR, "%s device: unexpected irq count", dev->name);
+		return EINVAL;
+	};
+	if (hw_resources->io_ranges.count != 1) {
+		ddf_msg(LVL_ERROR, "%s device: unexpected io ranges count", dev->name);
+		return EINVAL;
+	}
+
+	rtl8139->irq = hw_resources->irqs.irqs[0];
+	ddf_msg(LVL_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) {
+		ddf_msg(LVL_ERROR, "i/o range assigned to the device "
+		    "%s is too small.", dev->name);
+		return EINVAL;
+	}
+	ddf_msg(LVL_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)
+{
+	size_t i = 0;
+	int rc;
+
+	ddf_msg(LVL_DEBUG, "Creating buffers");
+
+	rc = dmamem_map_anonymous(TX_PAGES * PAGE_SIZE, AS_AREA_WRITE, 0,
+	    &rtl8139->tx_buff_phys, &rtl8139->tx_buff_virt);
+	if (rc != EOK) {
+		ddf_msg(LVL_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_virt + i * TX_BUFF_SIZE;
+
+	ddf_msg(LVL_DEBUG, "The transmittion buffers allocated");
+
+	/* Use the first buffer for next transmittion */
+	rtl8139->tx_next = 0;
+	rtl8139->tx_used = 0;
+
+	/* Allocate buffer for receiver */
+	ddf_msg(LVL_DEBUG, "Allocating receiver buffer of the size %zu bytes",
+	    RxBUF_TOT_LENGTH);
+
+	rc = dmamem_map_anonymous(RxBUF_TOT_LENGTH, AS_AREA_READ, 0,
+	    &rtl8139->rx_buff_phys, &rtl8139->rx_buff_virt);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Can not allocate receive buffer.");
+		goto err_rx_alloc;
+	}
+	ddf_msg(LVL_DEBUG, "The buffers created");
+
+	return EOK;
+
+err_rx_alloc:
+	dmamem_unmap_anonymous(&rtl8139->tx_buff_virt);
+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)
+{
+	ddf_msg(LVL_DEBUG, "rtl8139_dev_initialize %s", dev->name);
+
+	int ret = EOK;
+
+	ddf_msg(LVL_DEBUG, "rtl8139: creating device data");
+
+	/* Allocate driver data for the device. */
+	rtl8139_t *rtl8139 = rtl8139_create_dev_data(dev);
+	if (rtl8139 == NULL) {
+		ddf_msg(LVL_ERROR, "Not enough memory for initializing %s.", dev->name);
+		return ENOMEM;
+	}
+
+	ddf_msg(LVL_DEBUG, "rtl8139: dev_data created");
+
+	/* Obtain and fill hardware resources info and connect to parent */
+	ret = rtl8139_get_resource_info(dev);
+	if (ret != EOK) {
+		ddf_msg(LVL_ERROR, "Can not obatin hw resources information");
+		goto failed;
+	}
+
+	ddf_msg(LVL_DEBUG, "rtl8139: resource_info obtained");
+
+	/* Allocate DMA buffers */
+	ret = rtl8139_buffers_create(rtl8139);
+	if (ret != EOK)
+		goto failed;
+
+	/* Set default frame 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 frame length */
+	rtl8139->rcr_data.rcr_base = (0x8 << RCR_ERTH_SHIFT);
+
+	ddf_msg(LVL_DEBUG, "The device is initialized");
+	return ret;
+	
+failed:
+	ddf_msg(LVL_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)
+{
+	ddf_msg(LVL_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)) {
+		ddf_msg(LVL_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;
+			ddf_msg(LVL_NOTE, "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_dev_add(ddf_dev_t *dev)
+{
+	ddf_fun_t *fun;
+
+	assert(dev);
+	ddf_msg(LVL_NOTE, "RTL8139_dev_add %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) {
+		ddf_msg(LVL_ERROR, "Failed to connect to services", rc);
+		goto err_irq;
+	}
+
+	fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
+	if (fun == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating device function");
+		goto err_srv;
+	}
+	nic_set_ddf_fun(nic_data, fun);
+	fun->ops = &rtl8139_dev_ops;
+	fun->driver_data = nic_data;
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding device function");
+		goto err_fun_create;
+	}
+	rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding function to category");
+		goto err_fun_bind;
+	}
+
+	ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
+	    dev->name);
+
+	return EOK;
+	
+err_fun_bind:
+	ddf_fun_unbind(fun);
+err_fun_create:
+	ddf_fun_destroy(fun);
+err_srv:
+	/* XXX Disconnect from services */
+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 frame 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 frame 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 frame
+ *  @param[out] we_receive  Sign if local constroller receives pause frame
+ *  @param[out] time        Time filled in pause frames. 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 frame configuration
+ *
+ *  @param fun            The DDF structure of the RTL8139
+ *  @param allow_send     Sign if local constroller sends pause frame
+ *  @param allow_receive  Sign if local constroller receives pause frames
+ *  @param time           Time to use, ignored (not supported by device)
+ *
+ *  @return EOK if succeed, INVAL if the pause frame 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) {
+		ddf_msg(LVL_WARN, "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 frames 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 frames 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 frames 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 frames
+ *
+ *  @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 frames
+ *
+ *  @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);
+
+		ddf_msg(LVL_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 frames 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);
+
+	ddf_log_init(NAME, LVL_ERROR);
+	ddf_msg(LVL_NOTE, "HelenOS RTL8139 driver started");
+	return ddf_driver_main(&rtl8139_driver);
+}
Index: uspace/drv/nic/rtl8139/driver.h
===================================================================
--- uspace/drv/nic/rtl8139/driver.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/driver.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,240 @@
+/*
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include "defs.h"
+#include "general.h"
+
+/** The driver name */
+#define NAME  "rtl8139"
+
+/** Transmittion buffers count */
+#define TX_BUFF_COUNT  4
+
+/** Size of buffer for one frame (2kB) */
+#define TX_BUFF_SIZE  (2 * 1024)
+
+/** Number 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 frames */
+#define RTL8139_RCR_UCAST_DEFAULT  RCR_ACCEPT_PHYS_MATCH
+
+/** The default mode of accepting multicast frames */
+#define RTL8139_RCR_MCAST_DEFAULT  0
+
+/** The default mode of accepting broadcast frames */
+#define RTL8139_RCR_BCAST_DEFAULT  RCR_ACCEPT_BROADCAST
+
+/** The default mode of accepting defect frames */
+#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
+	 */
+	void *tx_buff_phys;
+	void *tx_buff_virt;
+
+	/** 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 frames */
+	void *rx_buff_phys;
+	void *rx_buff_virt;
+
+	/** 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 */
+	rtl8139_version_id_t 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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/general.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 "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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/general.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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>
+
+/** Number of microseconds in second */
+#define RTL8139_USEC_IN_SEC  1000000
+
+/** Structure for HW timer control */
+typedef struct {
+	/** 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;
+
+extern void *rtl8139_memcpy_wrapped(void *, const void *, size_t, size_t,
+    size_t);
+extern int rtl8139_timer_act_init(rtl8139_timer_act_t *, uint32_t,
+    const struct timeval *);
+extern int rtl8139_timer_act_step(rtl8139_timer_act_t *, uint32_t *);
+
+#endif
Index: uspace/drv/nic/rtl8139/rtl8139.ma
===================================================================
--- uspace/drv/nic/rtl8139/rtl8139.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/drv/nic/rtl8139/rtl8139.ma	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,1 @@
+10 pci/ven=10ec&dev=8139
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/as.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/async.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -257,4 +257,5 @@
 void async_set_client_data_constructor(async_client_data_ctor_t ctor)
 {
+	assert(async_client_data_create == default_client_data_constructor);
 	async_client_data_create = ctor;
 }
@@ -262,4 +263,5 @@
 void async_set_client_data_destructor(async_client_data_dtor_t dtor)
 {
+	assert(async_client_data_destroy == default_client_data_destructor);
 	async_client_data_destroy = dtor;
 }
@@ -303,4 +305,5 @@
 void async_set_client_connection(async_client_conn_t conn)
 {
+	assert(client_connection == default_client_connection);
 	client_connection = conn;
 }
@@ -1846,5 +1849,5 @@
 	
 	fibril_mutex_lock(&async_sess_mutex);
-
+	
 	int rc = async_hangup_internal(sess->phone);
 	
@@ -1998,25 +2001,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 +2052,5 @@
 		return false;
 	
-	*size = (size_t) IPC_GET_ARG2(data);
+	*size = (size_t) IPC_GET_ARG1(data);
 	return true;
 }
@@ -2053,5 +2058,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 +2136,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/ddi.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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.
@@ -53,22 +57,51 @@
 }
 
-/** Map piece of physical memory to task.
+/** Map a piece of physical memory to task.
  *
  * 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 pages		Number of pages to map.
- * @param flags		Flags for the new address space area.
+ * @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 		0 on success, EPERM if the caller lacks the
- *			CAP_MEM_MANAGER capability, ENOENT if there is no task
- *			with specified ID and ENOMEM if there was some problem
- *			in creating address space area.
+ * @return EOK on success
+ * @return EPERM if the caller lacks the CAP_MEM_MANAGER capability
+ * @return ENOENT if there is no task with specified ID
+ * @return ENOMEM if there was some problem in creating
+ *         the address space area.
+ *
  */
-int physmem_map(void *pf, void *vp, unsigned long pages, 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);
 }
 
@@ -77,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);
 }
@@ -99,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;
 }
 
@@ -138,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);
 }
@@ -152,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/device/nic.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -44,26 +44,36 @@
 #include <ipc/services.h>
 
-/** Send a packet through the device
- *
- * @param[in] dev_sess
- * @param[in] packet_id Id of the sent packet
- *
- * @return EOK If the operation was successfully completed
- *
- */
-int nic_send_message(async_sess_t *dev_sess, packet_id_t packet_id)
-{
-	async_exch_t *exch = async_exchange_begin(dev_sess);
-	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
-	    NIC_SEND_MESSAGE, packet_id);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Connect the driver to the NET and NIL services
- *
- * @param[in] dev_sess
- * @param[in] nil_service Service identifier for the NIL service
+/** Send frame from NIC
+ *
+ * @param[in] dev_sess
+ * @param[in] data     Frame data
+ * @param[in] size     Frame size in bytes
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_send_frame(async_sess_t *dev_sess, void *data, size_t size)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SEND_MESSAGE, &answer);
+	sysarg_t retval = async_data_write_start(exch, data, size);
+	
+	async_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+
+	async_wait_for(req, &retval);
+	return retval;
+}
+
+/** Create callback connection from NIC service
+ *
+ * @param[in] dev_sess
  * @param[in] device_id
  *
@@ -71,13 +81,24 @@
  *
  */
-int nic_connect_to_nil(async_sess_t *dev_sess, services_t nil_service,
-    nic_device_id_t device_id)
-{
-	async_exch_t *exch = async_exchange_begin(dev_sess);
-	int rc = async_req_3_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
-	    NIC_CONNECT_TO_NIL, nil_service, device_id);
-	async_exchange_end(exch);
-	
-	return rc;
+int nic_callback_create(async_sess_t *dev_sess, async_client_conn_t cfun,
+    void *carg)
+{
+	ipc_call_t answer;
+	int rc;
+	sysarg_t retval;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	aid_t req = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_CALLBACK_CREATE, &answer);
+	
+	rc = async_connect_to_me(exch, 0, 0, 0, cfun, carg);
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return rc;
+	}
+	async_exchange_end(exch);
+	
+	async_wait_for(req, &retval);
+	return (int) retval;
 }
 
@@ -324,5 +345,5 @@
  * it can never force the NIC to advertise unsupported modes.
  *
- * The allowed modes are defined in "net/eth_phys.h" in the C library.
+ * The allowed modes are defined in "nic/eth_phys.h" in the C library.
  *
  * @param[in] dev_sess
@@ -361,5 +382,5 @@
 /** Probe current state of auto-negotiation.
  *
- * Modes are defined in the "net/eth_phys.h" in the C library.
+ * Modes are defined in the "nic/eth_phys.h" in the C library.
  *
  * @param[in]  dev_sess
@@ -895,5 +916,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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/c/generic/device/pci.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/devman.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -177,5 +177,5 @@
 
 /** Register running driver with device manager. */
-int devman_driver_register(const char *name, async_client_conn_t conn)
+int devman_driver_register(const char *name)
 {
 	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
@@ -192,8 +192,6 @@
 	}
 	
-	async_set_client_connection(conn);
-	
 	exch = devman_exchange_begin(DEVMAN_DRIVER);
-	async_connect_to_me(exch, 0, 0, 0, conn, NULL);
+	async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
 	devman_exchange_end(exch);
 	
Index: uspace/lib/c/generic/elf/elf_load.c
===================================================================
--- uspace/lib/c/generic/elf/elf_load.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/elf/elf_load.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/fibril_synch.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/ipc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/loc.c
===================================================================
--- uspace/lib/c/generic/loc.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/loc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -47,4 +47,5 @@
 static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
 static bool loc_callback_created = false;
+static loc_cat_change_cb_t cat_change_cb = NULL;
 
 static async_sess_t *loc_supp_block_sess = NULL;
@@ -54,10 +55,6 @@
 static async_sess_t *loc_consumer_sess = NULL;
 
-static loc_cat_change_cb_t cat_change_cb = NULL;
-
 static void loc_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
-	loc_cat_change_cb_t cb_fun;
-	
 	while (true) {
 		ipc_call_t call;
@@ -69,21 +66,19 @@
 		}
 		
-		int retval;
-		
 		switch (IPC_GET_IMETHOD(call)) {
 		case LOC_EVENT_CAT_CHANGE:
 			fibril_mutex_lock(&loc_callback_mutex);
-			cb_fun = cat_change_cb;
-			if (cb_fun != NULL) {
+			loc_cat_change_cb_t cb_fun = cat_change_cb;
+			fibril_mutex_unlock(&loc_callback_mutex);
+			
+			async_answer_0(callid, EOK);
+			
+			if (cb_fun != NULL)
 				(*cb_fun)();
-			}
-			fibril_mutex_unlock(&loc_callback_mutex);
-			retval = 0;
+			
 			break;
 		default:
-			retval = ENOTSUP;
+			async_answer_0(callid, ENOTSUP);
 		}
-		
-		async_answer_0(callid, retval);
 	}
 }
@@ -101,36 +96,34 @@
 }
 
+/** Create callback
+ *
+ * Must be called with loc_callback_mutex locked.
+ *
+ * @return EOK on success.
+ *
+ */
 static int loc_callback_create(void)
 {
-	async_exch_t *exch;
-	sysarg_t retval;
-	int rc = EOK;
-
-	fibril_mutex_lock(&loc_callback_mutex);
-	
 	if (!loc_callback_created) {
-		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		async_exch_t *exch =
+		    loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
 		
 		ipc_call_t answer;
 		aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
-		async_connect_to_me(exch, 0, 0, 0, loc_cb_conn, NULL);
+		int rc = async_connect_to_me(exch, 0, 0, 0, loc_cb_conn, NULL);
 		loc_exchange_end(exch);
 		
+		if (rc != EOK)
+			return rc;
+		
+		sysarg_t retval;
 		async_wait_for(req, &retval);
-		if (rc != EOK)
-			goto done;
-		
-		if (retval != EOK) {
-			rc = retval;
-			goto done;
-		}
+		if (retval != EOK)
+			return retval;
 		
 		loc_callback_created = true;
 	}
 	
-	rc = EOK;
-done:
-	fibril_mutex_unlock(&loc_callback_mutex);
-	return rc;
+	return EOK;
 }
 
@@ -242,5 +235,5 @@
 
 /** Register new driver with loc. */
-int loc_server_register(const char *name, async_client_conn_t conn)
+int loc_server_register(const char *name)
 {
 	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
@@ -256,6 +249,4 @@
 		return retval;
 	}
-	
-	async_set_client_connection(conn);
 	
 	exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
@@ -797,22 +788,18 @@
     sysarg_t **data, size_t *count)
 {
-	service_id_t *ids;
-	size_t act_size;
-	size_t alloc_size;
-	int rc;
-
 	*data = NULL;
-	act_size = 0;	/* silence warning */
-
-	rc = loc_category_get_ids_once(method, arg1, NULL, 0,
+	*count = 0;
+	
+	size_t act_size = 0;
+	int rc = loc_category_get_ids_once(method, arg1, NULL, 0,
 	    &act_size);
 	if (rc != EOK)
 		return rc;
-
-	alloc_size = act_size;
-	ids = malloc(alloc_size);
+	
+	size_t alloc_size = act_size;
+	service_id_t *ids = malloc(alloc_size);
 	if (ids == NULL)
 		return ENOMEM;
-
+	
 	while (true) {
 		rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
@@ -820,16 +807,14 @@
 		if (rc != EOK)
 			return rc;
-
+		
 		if (act_size <= alloc_size)
 			break;
-
-		alloc_size *= 2;
-		free(ids);
-
-		ids = malloc(alloc_size);
+		
+		alloc_size = act_size;
+		ids = realloc(ids, alloc_size);
 		if (ids == NULL)
 			return ENOMEM;
 	}
-
+	
 	*count = act_size / sizeof(category_id_t);
 	*data = ids;
@@ -869,8 +854,13 @@
 int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
 {
-	if (loc_callback_create() != EOK)
+	fibril_mutex_lock(&loc_callback_mutex);
+	if (loc_callback_create() != EOK) {
+		fibril_mutex_unlock(&loc_callback_mutex);
 		return EIO;
-
+	}
+	
 	cat_change_cb = cb_fun;
+	fibril_mutex_unlock(&loc_callback_mutex);
+	
 	return EOK;
 }
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/malloc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/mman.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/generic/time.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/as.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/async.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/bitops.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/ddi.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,9 +41,18 @@
 
 extern int device_assign_devno(void);
-extern int physmem_map(void *, void *, unsigned long, 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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/device/hw_res.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/device/hw_res_parsed.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/device/nic.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -37,11 +37,10 @@
 
 #include <async.h>
-#include <net/device.h>
-#include <net/packet.h>
-#include <ipc/services.h>
+#include <nic/nic.h>
+#include <ipc/common.h>
 
 typedef enum {
 	NIC_SEND_MESSAGE = 0,
-	NIC_CONNECT_TO_NIL,
+	NIC_CALLBACK_CREATE,
 	NIC_GET_STATE,
 	NIC_SET_STATE,
@@ -85,6 +84,12 @@
 } nic_funcs_t;
 
-extern int nic_send_message(async_sess_t *, packet_id_t);
-extern int nic_connect_to_nil(async_sess_t *, services_t, nic_device_id_t);
+typedef enum {
+	NIC_EV_ADDR_CHANGED = IPC_FIRST_USER_METHOD,
+	NIC_EV_RECEIVED,
+	NIC_EV_DEVICE_STATE
+} nic_event_t;
+
+extern int nic_send_frame(async_sess_t *, void *, size_t);
+extern int nic_callback_create(async_sess_t *, async_client_conn_t, void *);
 extern int nic_get_state(async_sess_t *, nic_device_state_t *);
 extern int nic_set_state(async_sess_t *, nic_device_state_t);
@@ -127,5 +132,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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/c/include/device/pci.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/devman.h
===================================================================
--- uspace/lib/c/include/devman.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/devman.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,5 +46,5 @@
 extern void devman_exchange_end(async_exch_t *);
 
-extern int devman_driver_register(const char *, async_client_conn_t);
+extern int devman_driver_register(const char *);
 extern int devman_add_function(const char *, fun_type_t, match_id_list_t *,
     devman_handle_t, devman_handle_t *);
Index: uspace/lib/c/include/errno.h
===================================================================
--- uspace/lib/c/include/errno.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/errno.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/fibril_synch.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/ipc/devman.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -146,5 +146,4 @@
 typedef enum {
 	DRIVER_DEV_ADD = IPC_FIRST_USER_METHOD,
-	DRIVER_DEV_ADDED,
 	DRIVER_DEV_REMOVE,
 	DRIVER_DEV_GONE,
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/ipc/ipc.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/ipc/net.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -305,5 +305,5 @@
  *
  */
-#define IPC_GET_DEVICE_HANDLE(call) ((devman_handle_t) IPC_GET_ARG2(call))
+#define IPC_GET_DEVICE_HANDLE(call)  ((service_id_t) IPC_GET_ARG2(call))
 
 /** Return the device driver service message argument.
Index: uspace/lib/c/include/ipc/net_net.h
===================================================================
--- uspace/lib/c/include/ipc/net_net.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/ipc/net_net.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -54,7 +54,5 @@
 	NET_NET_GET_DEVICES_COUNT,
 	/** Return names and device IDs of all devices */
-	NET_NET_GET_DEVICES,
-	/** Notify the networking service about a ready device */
-	NET_NET_DRIVER_READY
+	NET_NET_GET_DEVICES
 } net_messages;
 
Index: uspace/lib/c/include/ipc/nil.h
===================================================================
--- uspace/lib/c/include/ipc/nil.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/ipc/nil.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,12 +46,4 @@
 	 */
 	NET_NIL_DEVICE = NET_NIL_FIRST,
-	/** New device state message.
-	 * @see nil_device_state_msg()
-	 */
-	NET_NIL_DEVICE_STATE,
-	/** Received packet queue message.
-	 * @see nil_received_msg()
-	 */
-	NET_NIL_RECEIVED,
 	/** Send packet queue message.
 	 * @see nil_send_msg()
@@ -69,9 +61,5 @@
 	 * @see nil_get_broadcast_addr()
 	 */
-	NET_NIL_BROADCAST_ADDR,
-	/** Device has changed address
-	 * @see nil_addr_changed_msg()
-	 */
-	NET_NIL_ADDR_CHANGED
+	NET_NIL_BROADCAST_ADDR
 } nil_messages;
 
Index: uspace/lib/c/include/loc.h
===================================================================
--- uspace/lib/c/include/loc.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/loc.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,5 +46,5 @@
 extern void loc_exchange_end(async_exch_t *);
 
-extern int loc_server_register(const char *, async_client_conn_t);
+extern int loc_server_register(const char *);
 extern int loc_service_register(const char *, service_id_t *);
 extern int loc_service_register_with_iface(const char *, service_id_t *,
Index: uspace/lib/c/include/net/device.h
===================================================================
--- uspace/lib/c/include/net/device.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/c/include/net/device.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,5 +1,4 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
- * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -33,31 +32,12 @@
 
 /** @file
- * Device identifier, state and usage statistics.
+ * Network device.
  */
 
-#ifndef LIBC_DEVICE_ID_TYPE_H_
-#define LIBC_DEVICE_ID_TYPE_H_
+#ifndef LIBC_NET_DEVICE_H_
+#define LIBC_NET_DEVICE_H_
 
 #include <adt/int_map.h>
-#include <net/eth_phys.h>
-#include <bool.h>
-
-/** Ethernet address length. */
-#define ETH_ADDR  6
-
-/** MAC printing format */
-#define PRIMAC  "%02x:%02x:%02x:%02x:%02x:%02x"
-
-/** MAC arguments */
-#define ARGSMAC(__a) \
-	(__a)[0], (__a)[1], (__a)[2], (__a)[3], (__a)[4], (__a)[5]
-
-/* Compare MAC address with specific value */
-#define MAC_EQUALS_VALUE(__a, __a0, __a1, __a2, __a3, __a4, __a5) \
-	((__a)[0] == (__a0) && (__a)[1] == (__a1) && (__a)[2] == (__a2) \
-	&& (__a)[3] == (__a3) && (__a)[4] == (__a4) && (__a)[5] == (__a5))
-
-#define MAC_IS_ZERO(__x) \
-	MAC_EQUALS_VALUE(__x, 0, 0, 0, 0, 0, 0)
+#include <nic/nic.h>
 
 /** Device identifier to generic type map declaration. */
@@ -67,411 +47,9 @@
 #define DEVICE_MAP_IMPLEMENT  INT_MAP_IMPLEMENT
 
-/** Max length of any hw nic address (currently only eth) */
-#define NIC_MAX_ADDRESS_LENGTH  16
+/** Device identifier type. */
+typedef int nic_device_id_t;
 
 /** Invalid device identifier. */
 #define NIC_DEVICE_INVALID_ID  (-1)
-
-#define NIC_VENDOR_MAX_LENGTH         64
-#define NIC_MODEL_MAX_LENGTH          64
-#define NIC_PART_NUMBER_MAX_LENGTH    64
-#define NIC_SERIAL_NUMBER_MAX_LENGTH  64
-
-/**
- * The bitmap uses single bit for each of the 2^12 = 4096 possible VLAN tags.
- * This means its size is 4096/8 = 512 bytes.
- */
-#define NIC_VLAN_BITMAP_SIZE  512
-
-#define NIC_DEVICE_PRINT_FMT  "%x"
-
-/** Device identifier type. */
-typedef int nic_device_id_t;
-
-/**
- * Structure covering the MAC address.
- */
-typedef struct nic_address {
-	uint8_t address[ETH_ADDR];
-} nic_address_t;
-
-/** Device state. */
-typedef enum nic_device_state {
-	/**
-	 * Device present and stopped. Moving device to this state means to discard
-	 * all settings and WOL virtues, rebooting the NIC to state as if the
-	 * computer just booted (or the NIC was just inserted in case of removable
-	 * NIC).
-	 */
-	NIC_STATE_STOPPED,
-	/**
-	 * If the NIC is in this state no packets (frames) are transmitted nor
-	 * received. However, the settings are not restarted. You can use this state
-	 * to temporarily disable transmition/reception or atomically (with respect
-	 * to incoming/outcoming packets) change frames acceptance etc.
-	 */
-	NIC_STATE_DOWN,
-	/** Device is normally operating. */
-	NIC_STATE_ACTIVE,
-	/** Just a constant to limit the state numbers */
-	NIC_STATE_MAX,
-} nic_device_state_t;
-
-/**
- * Channel operating mode used on the medium.
- */
-typedef enum {
-	NIC_CM_UNKNOWN,
-	NIC_CM_FULL_DUPLEX,
-	NIC_CM_HALF_DUPLEX,
-	NIC_CM_SIMPLEX
-} nic_channel_mode_t;
-
-/**
- * Role for the device (used e.g. for 1000Gb ethernet)
- */
-typedef enum {
-	NIC_ROLE_UNKNOWN,
-	NIC_ROLE_AUTO,
-	NIC_ROLE_MASTER,
-	NIC_ROLE_SLAVE
-} nic_role_t;
-
-/**
- * Current state of the cable in the device
- */
-typedef enum {
-	NIC_CS_UNKNOWN,
-	NIC_CS_PLUGGED,
-	NIC_CS_UNPLUGGED
-} nic_cable_state_t;
-
-/**
- * Result of the requested operation
- */
-typedef enum {
-	/** Successfully disabled */
-	NIC_RESULT_DISABLED,
-	/** Successfully enabled */
-	NIC_RESULT_ENABLED,
-	/** Not supported at all */
-	NIC_RESULT_NOT_SUPPORTED,
-	/** Temporarily not available */
-	NIC_RESULT_NOT_AVAILABLE,
-	/** Result extensions */
-	NIC_RESULT_FIRST_EXTENSION
-} nic_result_t;
-
-/** Device usage statistics. */
-typedef struct nic_device_stats {
-	/** Total packets received (accepted). */
-	unsigned long receive_packets;
-	/** Total packets transmitted. */
-	unsigned long send_packets;
-	/** Total bytes received (accepted). */
-	unsigned long receive_bytes;
-	/** Total bytes transmitted. */
-	unsigned long send_bytes;
-	/** Bad packets received counter. */
-	unsigned long receive_errors;
-	/** Packet transmition problems counter. */
-	unsigned long send_errors;
-	/** Number of frames dropped due to insufficient space in RX buffers */
-	unsigned long receive_dropped;
-	/** Number of frames dropped due to insufficient space in TX buffers */
-	unsigned long send_dropped;
-	/** Total multicast packets received (accepted). */
-	unsigned long receive_multicast;
-	/** Total broadcast packets received (accepted). */
-	unsigned long receive_broadcast;
-	/** The number of collisions due to congestion on the medium. */
-	unsigned long collisions;
-	/** Unicast packets received but not accepted (filtered) */
-	unsigned long receive_filtered_unicast;
-	/** Multicast packets received but not accepted (filtered) */
-	unsigned long receive_filtered_multicast;
-	/** Broadcast packets received but not accepted (filtered) */
-	unsigned long receive_filtered_broadcast;
-
-	/* detailed receive_errors */
-
-	/** Received packet length error counter. */
-	unsigned long receive_length_errors;
-	/** Receiver buffer overflow counter. */
-	unsigned long receive_over_errors;
-	/** Received packet with crc error counter. */
-	unsigned long receive_crc_errors;
-	/** Received frame alignment error counter. */
-	unsigned long receive_frame_errors;
-	/** Receiver fifo overrun counter. */
-	unsigned long receive_fifo_errors;
-	/** Receiver missed packet counter. */
-	unsigned long receive_missed_errors;
-
-	/* detailed send_errors */
-
-	/** Transmitter aborted counter. */
-	unsigned long send_aborted_errors;
-	/** Transmitter carrier errors counter. */
-	unsigned long send_carrier_errors;
-	/** Transmitter fifo overrun counter. */
-	unsigned long send_fifo_errors;
-	/** Transmitter carrier errors counter. */
-	unsigned long send_heartbeat_errors;
-	/** Transmitter window errors counter. */
-	unsigned long send_window_errors;
-
-	/* for cslip etc */
-	
-	/** Total compressed packets received. */
-	unsigned long receive_compressed;
-	/** Total compressed packet transmitted. */
-	unsigned long send_compressed;
-} nic_device_stats_t;
-
-/** Errors corresponding to those in the nic_device_stats_t */
-typedef enum {
-	NIC_SEC_BUFFER_FULL,
-	NIC_SEC_ABORTED,
-	NIC_SEC_CARRIER_LOST,
-	NIC_SEC_FIFO_OVERRUN,
-	NIC_SEC_HEARTBEAT,
-	NIC_SEC_WINDOW_ERROR,
-	/* Error encountered during TX but with other type of error */
-	NIC_SEC_OTHER
-} nic_send_error_cause_t;
-
-/** Errors corresponding to those in the nic_device_stats_t */
-typedef enum {
-	NIC_REC_BUFFER_FULL,
-	NIC_REC_LENGTH,
-	NIC_REC_BUFFER_OVERFLOW,
-	NIC_REC_CRC,
-	NIC_REC_FRAME_ALIGNMENT,
-	NIC_REC_FIFO_OVERRUN,
-	NIC_REC_MISSED,
-	/* Error encountered during RX but with other type of error */
-	NIC_REC_OTHER
-} nic_receive_error_cause_t;
-
-/**
- * Information about the NIC that never changes - name, vendor, model,
- * capabilites and so on.
- */
-typedef struct nic_device_info {
-	/* Device identification */
-	char vendor_name[NIC_VENDOR_MAX_LENGTH];
-	char model_name[NIC_MODEL_MAX_LENGTH];
-	char part_number[NIC_PART_NUMBER_MAX_LENGTH];
-	char serial_number[NIC_SERIAL_NUMBER_MAX_LENGTH];
-	uint16_t vendor_id;
-	uint16_t device_id;
-	uint16_t subsystem_vendor_id;
-	uint16_t subsystem_id;
-	/* Device capabilities */
-	uint16_t ethernet_support[ETH_PHYS_LAYERS];
-
-	/** The mask of all modes which the device can advertise
-	 *
-	 *  see ETH_AUTONEG_ macros in net/eth_phys.h of libc
-	 */
-	uint32_t autoneg_support;
-} nic_device_info_t;
-
-/**
- * Type of the ethernet frame
- */
-typedef enum nic_frame_type {
-	NIC_FRAME_UNICAST,
-	NIC_FRAME_MULTICAST,
-	NIC_FRAME_BROADCAST
-} nic_frame_type_t;
-
-/**
- * Specifies which unicast frames is the NIC receiving.
- */
-typedef enum nic_unicast_mode {
-	NIC_UNICAST_UNKNOWN,
-	/** No unicast frames are received */
-	NIC_UNICAST_BLOCKED,
-	/** Only the frames with this NIC's MAC as destination are received */
-	NIC_UNICAST_DEFAULT,
-	/**
-	 * Both frames with this NIC's MAC and those specified in the list are
-	 * received
-	 */
-	NIC_UNICAST_LIST,
-	/** All unicast frames are received */
-	NIC_UNICAST_PROMISC
-} nic_unicast_mode_t;
-
-typedef enum nic_multicast_mode {
-	NIC_MULTICAST_UNKNOWN,
-	/** No multicast frames are received */
-	NIC_MULTICAST_BLOCKED,
-	/** Frames with multicast addresses specified in this list are received */
-	NIC_MULTICAST_LIST,
-	/** All multicast frames are received */
-	NIC_MULTICAST_PROMISC
-} nic_multicast_mode_t;
-
-typedef enum nic_broadcast_mode {
-	NIC_BROADCAST_UNKNOWN,
-	/** Broadcast frames are dropped */
-	NIC_BROADCAST_BLOCKED,
-	/** Broadcast frames are received */
-	NIC_BROADCAST_ACCEPTED
-} nic_broadcast_mode_t;
-
-/**
- * Structure covering the bitmap with VLAN tags.
- */
-typedef struct nic_vlan_mask {
-	uint8_t bitmap[NIC_VLAN_BITMAP_SIZE];
-} nic_vlan_mask_t;
-
-/* WOL virtue identifier */
-typedef unsigned int nic_wv_id_t;
-
-/**
- * Structure passed as argument for virtue NIC_WV_MAGIC_PACKET.
- */
-typedef struct nic_wv_magic_packet_data {
-	uint8_t password[6];
-} nic_wv_magic_packet_data_t;
-
-/**
- * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV4
- */
-typedef struct nic_wv_ipv4_data {
-	uint8_t address[4];
-} nic_wv_ipv4_data_t;
-
-/**
- * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV6
- */
-typedef struct nic_wv_ipv6_data {
-	uint8_t address[16];
-} nic_wv_ipv6_data_t;
-
-/**
- * WOL virtue types defining the interpretation of data passed to the virtue.
- * Those tagged with S can have only single virtue active at one moment, those
- * tagged with M can have multiple ones.
- */
-typedef enum nic_wv_type {
-	/**
-	 * Used for deletion of the virtue - in this case the mask, data and length
-	 * arguments are ignored.
-	 */
-	NIC_WV_NONE,
-	/** S
-	 * Enabled <=> wakeup upon link change
-	 */
-	NIC_WV_LINK_CHANGE,
-	/** S
-	 * If this virtue is set up, wakeup can be issued by a magic packet frame.
-	 * If the data argument is not NULL, it must contain
-	 * nic_wv_magic_packet_data structure with the SecureOn password.
-	 */
-	NIC_WV_MAGIC_PACKET,
-	/** M
-	 * If the virtue is set up, wakeup can be issued by a frame targeted to
-	 * device with MAC address specified in data. The data must contain
-	 * nic_address_t structure.
-	 */
-	NIC_WV_DESTINATION,
-	/** S
-	 * Enabled <=> wakeup upon receiving broadcast frame
-	 */
-	NIC_WV_BROADCAST,
-	/** S
-	 * Enabled <=> wakeup upon receiving ARP Request
-	 */
-	NIC_WV_ARP_REQUEST,
-	/** M
-	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
-	 * with IPv4 address specified in data. The data must contain
-	 * nic_wv_ipv4_data structure.
-	 */
-	NIC_WV_DIRECTED_IPV4,
-	/** M
-	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
-	 * with IPv6 address specified in data. The data must contain
-	 * nic_wv_ipv6_data structure.
-	 */
-	NIC_WV_DIRECTED_IPV6,
-	/** M
-	 * First length/2 bytes in the argument are interpreted as mask, second
-	 * length/2 bytes are interpreted as content.
-	 * If enabled, the wakeup is issued upon receiving frame where the bytes
-	 * with non-zero value in the mask equal to those in the content.
-	 */
-	NIC_WV_FULL_MATCH,
-	/**
-	 * Dummy value, do not use.
-	 */
-	NIC_WV_MAX
-} nic_wv_type_t;
-
-/**
- * Specifies the interrupt/polling mode used by the driver and NIC
- */
-typedef enum nic_poll_mode {
-	/**
-	 * NIC issues interrupts upon events.
-	 */
-	NIC_POLL_IMMEDIATE,
-	/**
-	 * Some uspace app calls nic_poll_now(...) in order to check the NIC state
-	 * - no interrupts are received from the NIC.
-	 */
-	NIC_POLL_ON_DEMAND,
-	/**
-	 * The driver itself issues a poll request in a periodic manner. It is
-	 * allowed to use hardware timer if the NIC supports it.
-	 */
-	NIC_POLL_PERIODIC,
-	/**
-	 * The driver itself issued a poll request in a periodic manner. The driver
-	 * must create software timer, internal hardware timer of NIC must not be
-	 * used even if the NIC supports it.
-	 */
-	NIC_POLL_SOFTWARE_PERIODIC
-} nic_poll_mode_t;
-
-/**
- * Says if this virtue type is a multi-virtue (there can be multiple virtues of
- * this type at once).
- *
- * @param type
- *
- * @return true or false
- */
-static inline int nic_wv_is_multi(nic_wv_type_t type) {
-	switch (type) {
-	case NIC_WV_FULL_MATCH:
-	case NIC_WV_DESTINATION:
-	case NIC_WV_DIRECTED_IPV4:
-	case NIC_WV_DIRECTED_IPV6:
-		return true;
-	default:
-		return false;
-	}
-}
-
-static inline const char *nic_device_state_to_string(nic_device_state_t state)
-{
-	switch (state) {
-	case NIC_STATE_STOPPED:
-		return "stopped";
-	case NIC_STATE_DOWN:
-		return "down";
-	case NIC_STATE_ACTIVE:
-		return "active";
-	default:
-		return "undefined";
-	}
-}
 
 #endif
Index: pace/lib/c/include/net/eth_phys.h
===================================================================
--- uspace/lib/c/include/net/eth_phys.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(revision )
@@ -1,142 +1,0 @@
-/*
- * Copyright (c) 2011 Radim Vansa
- * 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 LIBC_NET_ETH_PHYS_H_
-#define LIBC_NET_ETH_PHYS_H_
-
-#include <sys/types.h>
-
-/*****************************************************/
-/* Definitions of possible supported physical layers */
-/*****************************************************/
-
-/* Ethernet physical layers */
-#define ETH_OLD          0
-#define ETH_10M          1
-#define ETH_100M         2
-#define ETH_1000M        3
-#define ETH_10G          4
-#define ETH_40G_100G     5
-/* 6, 7 reserved for future use */
-#define ETH_PHYS_LAYERS  8
-
-/* < 10Mbs ethernets */
-#define ETH_EXPERIMENTAL     0x0001
-#define ETH_1BASE5           0x0002
-/* 10Mbs ethernets */
-#define ETH_10BASE5          0x0001
-#define ETH_10BASE2          0x0002
-#define ETH_10BROAD36        0x0004
-#define ETH_STARLAN_10       0x0008
-#define ETH_LATTISNET        0x0010
-#define ETH_10BASE_T         0x0020
-#define ETH_FOIRL            0x0040
-#define ETH_10BASE_FL        0x0080
-#define ETH_10BASE_FB        0x0100
-#define ETH_10BASE_FP        0x0200
-/* 100Mbs (fast) ethernets */
-#define ETH_100BASE_TX       0x0001
-#define ETH_100BASE_T4       0x0002
-#define ETH_100BASE_T2       0x0004
-#define ETH_100BASE_FX       0x0008
-#define ETH_100BASE_SX       0x0010
-#define ETH_100BASE_BX10     0x0020
-#define ETH_100BASE_LX10     0x0040
-#define ETH_100BASE_VG       0x0080
-/* 1000Mbs (gigabit) ethernets */
-#define ETH_1000BASE_T       0x0001
-#define ETH_1000BASE_TX      0x0002
-#define ETH_1000BASE_SX      0x0004
-#define ETH_1000BASE_LX      0x0008
-#define ETH_1000BASE_LH      0x0010
-#define ETH_1000BASE_CX      0x0020
-#define ETH_1000BASE_BX10    0x0040
-#define ETH_1000BASE_LX10    0x0080
-#define ETH_1000BASE_PX10_D  0x0100
-#define ETH_1000BASE_PX10_U  0x0200
-#define ETH_1000BASE_PX20_D  0x0400
-#define ETH_1000BASE_PX20_U  0x0800
-#define ETH_1000BASE_ZX      0x1000
-#define ETH_1000BASE_KX      0x2000
-/* 10Gbs ethernets */
-#define ETH_10GBASE_SR       0x0001
-#define ETH_10GBASE_LX4      0x0002
-#define ETH_10GBASE_LR       0x0004
-#define ETH_10GBASE_ER       0x0008
-#define ETH_10GBASE_SW       0x0010
-#define ETH_10GBASE_LW       0x0020
-#define ETH_10GBASE_EW       0x0040
-#define ETH_10GBASE_CX4      0x0080
-#define ETH_10GBASE_T        0x0100
-#define ETH_10GBASE_LRM      0x0200
-#define ETH_10GBASE_KX4      0x0400
-#define ETH_10GBASE_KR       0x0800
-/* 40Gbs and 100Gbs ethernets */
-#define ETH_40GBASE_SR4      0x0001
-#define ETH_40GBASE_LR4      0x0002
-#define ETH_40GBASE_CR4      0x0004
-#define ETH_40GBASE_KR4      0x0008
-#define ETH_100GBASE_SR10    0x0010
-#define ETH_100GBASE_LR4     0x0020
-#define ETH_100GBASE_ER4     0x0040
-#define ETH_100GBASE_CR10    0x0080
-
-/******************************************/
-/* Auto-negotiation advertisement options */
-/******************************************/
-
-#define ETH_AUTONEG_10BASE_T_HALF    UINT32_C(0x00000001)
-#define ETH_AUTONEG_10BASE_T_FULL    UINT32_C(0x00000002)
-#define ETH_AUTONEG_100BASE_TX_HALF  UINT32_C(0x00000004)
-#define ETH_AUTONEG_100BASE_T4_HALF  UINT32_C(0x00000008)
-#define ETH_AUTONEG_100BASE_T2_HALF  UINT32_C(0x00000010)
-#define ETH_AUTONEG_100BASE_TX_FULL  UINT32_C(0x00000020)
-#define ETH_AUTONEG_100BASE_T2_FULL  UINT32_C(0x00000040)
-#define ETH_AUTONEG_1000BASE_T_HALF  UINT32_C(0x00000080)
-#define ETH_AUTONEG_1000BASE_T_FULL  UINT32_C(0x00000100)
-
-/** Symetric pause packet (802.3x standard) */
-#define ETH_AUTONEG_PAUSE_SYMETRIC   UINT32_C(0x10000000)
-/** Asymetric pause packet (802.3z standard, gigabit ethernet) */
-#define ETH_AUTONEG_PAUSE_ASYMETRIC  UINT32_C(0x20000000)
-
-#define ETH_AUTONEG_MODE_MASK      UINT32_C(0x0FFFFFFF)
-#define ETH_AUTONEG_FEATURES_MASK  UINT32_C(~(ETH_AUTONEG_MODE_MASK))
-
-#define ETH_AUTONEG_MODES  9
-
-struct eth_autoneg_map {
-	uint32_t value;
-	const char *name;
-};
-
-extern const char *ethernet_names[8][17];
-extern const struct eth_autoneg_map ethernet_autoneg_mapping[ETH_AUTONEG_MODES];
-
-#endif
Index: uspace/lib/c/include/nic/eth_phys.h
===================================================================
--- uspace/lib/c/include/nic/eth_phys.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/c/include/nic/eth_phys.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 LIBC_NIC_ETH_PHYS_H_
+#define LIBC_NIC_ETH_PHYS_H_
+
+#include <sys/types.h>
+
+/*****************************************************/
+/* Definitions of possible supported physical layers */
+/*****************************************************/
+
+/* Ethernet physical layers */
+#define ETH_OLD          0
+#define ETH_10M          1
+#define ETH_100M         2
+#define ETH_1000M        3
+#define ETH_10G          4
+#define ETH_40G_100G     5
+/* 6, 7 reserved for future use */
+#define ETH_PHYS_LAYERS  8
+
+/* < 10Mbs ethernets */
+#define ETH_EXPERIMENTAL     0x0001
+#define ETH_1BASE5           0x0002
+/* 10Mbs ethernets */
+#define ETH_10BASE5          0x0001
+#define ETH_10BASE2          0x0002
+#define ETH_10BROAD36        0x0004
+#define ETH_STARLAN_10       0x0008
+#define ETH_LATTISNET        0x0010
+#define ETH_10BASE_T         0x0020
+#define ETH_FOIRL            0x0040
+#define ETH_10BASE_FL        0x0080
+#define ETH_10BASE_FB        0x0100
+#define ETH_10BASE_FP        0x0200
+/* 100Mbs (fast) ethernets */
+#define ETH_100BASE_TX       0x0001
+#define ETH_100BASE_T4       0x0002
+#define ETH_100BASE_T2       0x0004
+#define ETH_100BASE_FX       0x0008
+#define ETH_100BASE_SX       0x0010
+#define ETH_100BASE_BX10     0x0020
+#define ETH_100BASE_LX10     0x0040
+#define ETH_100BASE_VG       0x0080
+/* 1000Mbs (gigabit) ethernets */
+#define ETH_1000BASE_T       0x0001
+#define ETH_1000BASE_TX      0x0002
+#define ETH_1000BASE_SX      0x0004
+#define ETH_1000BASE_LX      0x0008
+#define ETH_1000BASE_LH      0x0010
+#define ETH_1000BASE_CX      0x0020
+#define ETH_1000BASE_BX10    0x0040
+#define ETH_1000BASE_LX10    0x0080
+#define ETH_1000BASE_PX10_D  0x0100
+#define ETH_1000BASE_PX10_U  0x0200
+#define ETH_1000BASE_PX20_D  0x0400
+#define ETH_1000BASE_PX20_U  0x0800
+#define ETH_1000BASE_ZX      0x1000
+#define ETH_1000BASE_KX      0x2000
+/* 10Gbs ethernets */
+#define ETH_10GBASE_SR       0x0001
+#define ETH_10GBASE_LX4      0x0002
+#define ETH_10GBASE_LR       0x0004
+#define ETH_10GBASE_ER       0x0008
+#define ETH_10GBASE_SW       0x0010
+#define ETH_10GBASE_LW       0x0020
+#define ETH_10GBASE_EW       0x0040
+#define ETH_10GBASE_CX4      0x0080
+#define ETH_10GBASE_T        0x0100
+#define ETH_10GBASE_LRM      0x0200
+#define ETH_10GBASE_KX4      0x0400
+#define ETH_10GBASE_KR       0x0800
+/* 40Gbs and 100Gbs ethernets */
+#define ETH_40GBASE_SR4      0x0001
+#define ETH_40GBASE_LR4      0x0002
+#define ETH_40GBASE_CR4      0x0004
+#define ETH_40GBASE_KR4      0x0008
+#define ETH_100GBASE_SR10    0x0010
+#define ETH_100GBASE_LR4     0x0020
+#define ETH_100GBASE_ER4     0x0040
+#define ETH_100GBASE_CR10    0x0080
+
+/******************************************/
+/* Auto-negotiation advertisement options */
+/******************************************/
+
+#define ETH_AUTONEG_10BASE_T_HALF    UINT32_C(0x00000001)
+#define ETH_AUTONEG_10BASE_T_FULL    UINT32_C(0x00000002)
+#define ETH_AUTONEG_100BASE_TX_HALF  UINT32_C(0x00000004)
+#define ETH_AUTONEG_100BASE_T4_HALF  UINT32_C(0x00000008)
+#define ETH_AUTONEG_100BASE_T2_HALF  UINT32_C(0x00000010)
+#define ETH_AUTONEG_100BASE_TX_FULL  UINT32_C(0x00000020)
+#define ETH_AUTONEG_100BASE_T2_FULL  UINT32_C(0x00000040)
+#define ETH_AUTONEG_1000BASE_T_HALF  UINT32_C(0x00000080)
+#define ETH_AUTONEG_1000BASE_T_FULL  UINT32_C(0x00000100)
+
+/** Symetric pause packet (802.3x standard) */
+#define ETH_AUTONEG_PAUSE_SYMETRIC   UINT32_C(0x10000000)
+/** Asymetric pause packet (802.3z standard, gigabit ethernet) */
+#define ETH_AUTONEG_PAUSE_ASYMETRIC  UINT32_C(0x20000000)
+
+#define ETH_AUTONEG_MODE_MASK      UINT32_C(0x0FFFFFFF)
+#define ETH_AUTONEG_FEATURES_MASK  UINT32_C(~(ETH_AUTONEG_MODE_MASK))
+
+#define ETH_AUTONEG_MODES  9
+
+struct eth_autoneg_map {
+	uint32_t value;
+	const char *name;
+};
+
+extern const char *ethernet_names[8][17];
+extern const struct eth_autoneg_map ethernet_autoneg_mapping[ETH_AUTONEG_MODES];
+
+#endif
Index: uspace/lib/c/include/nic/nic.h
===================================================================
--- uspace/lib/c/include/nic/nic.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/c/include/nic/nic.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+
+/** @file
+ * NIC interface definitions.
+ */
+
+#ifndef LIBC_NIC_H_
+#define LIBC_NIC_H_
+
+#include <nic/eth_phys.h>
+#include <bool.h>
+
+/** Ethernet address length. */
+#define ETH_ADDR  6
+
+/** MAC printing format */
+#define PRIMAC  "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/** MAC arguments */
+#define ARGSMAC(__a) \
+	(__a)[0], (__a)[1], (__a)[2], (__a)[3], (__a)[4], (__a)[5]
+
+/* Compare MAC address with specific value */
+#define MAC_EQUALS_VALUE(__a, __a0, __a1, __a2, __a3, __a4, __a5) \
+	((__a)[0] == (__a0) && (__a)[1] == (__a1) && (__a)[2] == (__a2) \
+	&& (__a)[3] == (__a3) && (__a)[4] == (__a4) && (__a)[5] == (__a5))
+
+#define MAC_IS_ZERO(__x) \
+	MAC_EQUALS_VALUE(__x, 0, 0, 0, 0, 0, 0)
+
+/** Max length of any hw nic address (currently only eth) */
+#define NIC_MAX_ADDRESS_LENGTH  16
+
+#define NIC_VENDOR_MAX_LENGTH         64
+#define NIC_MODEL_MAX_LENGTH          64
+#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
+
+/**
+ * The bitmap uses single bit for each of the 2^12 = 4096 possible VLAN tags.
+ * This means its size is 4096/8 = 512 bytes.
+ */
+#define NIC_VLAN_BITMAP_SIZE  512
+
+#define NIC_DEVICE_PRINT_FMT  "%x"
+
+/**
+ * Structure covering the MAC address.
+ */
+typedef struct nic_address {
+	uint8_t address[ETH_ADDR];
+} nic_address_t;
+
+/** Device state. */
+typedef enum nic_device_state {
+	/**
+	 * Device present and stopped. Moving device to this state means to discard
+	 * all settings and WOL virtues, rebooting the NIC to state as if the
+	 * computer just booted (or the NIC was just inserted in case of removable
+	 * NIC).
+	 */
+	NIC_STATE_STOPPED,
+	/**
+	 * If the NIC is in this state no packets (frames) are transmitted nor
+	 * received. However, the settings are not restarted. You can use this state
+	 * to temporarily disable transmition/reception or atomically (with respect
+	 * to incoming/outcoming packets) change frames acceptance etc.
+	 */
+	NIC_STATE_DOWN,
+	/** Device is normally operating. */
+	NIC_STATE_ACTIVE,
+	/** Just a constant to limit the state numbers */
+	NIC_STATE_MAX,
+} nic_device_state_t;
+
+/**
+ * Channel operating mode used on the medium.
+ */
+typedef enum {
+	NIC_CM_UNKNOWN,
+	NIC_CM_FULL_DUPLEX,
+	NIC_CM_HALF_DUPLEX,
+	NIC_CM_SIMPLEX
+} nic_channel_mode_t;
+
+/**
+ * Role for the device (used e.g. for 1000Gb ethernet)
+ */
+typedef enum {
+	NIC_ROLE_UNKNOWN,
+	NIC_ROLE_AUTO,
+	NIC_ROLE_MASTER,
+	NIC_ROLE_SLAVE
+} nic_role_t;
+
+/**
+ * Current state of the cable in the device
+ */
+typedef enum {
+	NIC_CS_UNKNOWN,
+	NIC_CS_PLUGGED,
+	NIC_CS_UNPLUGGED
+} nic_cable_state_t;
+
+/**
+ * Result of the requested operation
+ */
+typedef enum {
+	/** Successfully disabled */
+	NIC_RESULT_DISABLED,
+	/** Successfully enabled */
+	NIC_RESULT_ENABLED,
+	/** Not supported at all */
+	NIC_RESULT_NOT_SUPPORTED,
+	/** Temporarily not available */
+	NIC_RESULT_NOT_AVAILABLE,
+	/** Result extensions */
+	NIC_RESULT_FIRST_EXTENSION
+} nic_result_t;
+
+/** Device usage statistics. */
+typedef struct nic_device_stats {
+	/** Total packets received (accepted). */
+	unsigned long receive_packets;
+	/** Total packets transmitted. */
+	unsigned long send_packets;
+	/** Total bytes received (accepted). */
+	unsigned long receive_bytes;
+	/** Total bytes transmitted. */
+	unsigned long send_bytes;
+	/** Bad packets received counter. */
+	unsigned long receive_errors;
+	/** Packet transmition problems counter. */
+	unsigned long send_errors;
+	/** Number of frames dropped due to insufficient space in RX buffers */
+	unsigned long receive_dropped;
+	/** Number of frames dropped due to insufficient space in TX buffers */
+	unsigned long send_dropped;
+	/** Total multicast packets received (accepted). */
+	unsigned long receive_multicast;
+	/** Total broadcast packets received (accepted). */
+	unsigned long receive_broadcast;
+	/** The number of collisions due to congestion on the medium. */
+	unsigned long collisions;
+	/** Unicast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_unicast;
+	/** Multicast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_multicast;
+	/** Broadcast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_broadcast;
+
+	/* detailed receive_errors */
+
+	/** Received packet length error counter. */
+	unsigned long receive_length_errors;
+	/** Receiver buffer overflow counter. */
+	unsigned long receive_over_errors;
+	/** Received packet with crc error counter. */
+	unsigned long receive_crc_errors;
+	/** Received frame alignment error counter. */
+	unsigned long receive_frame_errors;
+	/** Receiver fifo overrun counter. */
+	unsigned long receive_fifo_errors;
+	/** Receiver missed packet counter. */
+	unsigned long receive_missed_errors;
+
+	/* detailed send_errors */
+
+	/** Transmitter aborted counter. */
+	unsigned long send_aborted_errors;
+	/** Transmitter carrier errors counter. */
+	unsigned long send_carrier_errors;
+	/** Transmitter fifo overrun counter. */
+	unsigned long send_fifo_errors;
+	/** Transmitter carrier errors counter. */
+	unsigned long send_heartbeat_errors;
+	/** Transmitter window errors counter. */
+	unsigned long send_window_errors;
+
+	/* for cslip etc */
+	
+	/** Total compressed packets received. */
+	unsigned long receive_compressed;
+	/** Total compressed packet transmitted. */
+	unsigned long send_compressed;
+} nic_device_stats_t;
+
+/** Errors corresponding to those in the nic_device_stats_t */
+typedef enum {
+	NIC_SEC_BUFFER_FULL,
+	NIC_SEC_ABORTED,
+	NIC_SEC_CARRIER_LOST,
+	NIC_SEC_FIFO_OVERRUN,
+	NIC_SEC_HEARTBEAT,
+	NIC_SEC_WINDOW_ERROR,
+	/* Error encountered during TX but with other type of error */
+	NIC_SEC_OTHER
+} nic_send_error_cause_t;
+
+/** Errors corresponding to those in the nic_device_stats_t */
+typedef enum {
+	NIC_REC_BUFFER_FULL,
+	NIC_REC_LENGTH,
+	NIC_REC_BUFFER_OVERFLOW,
+	NIC_REC_CRC,
+	NIC_REC_FRAME_ALIGNMENT,
+	NIC_REC_FIFO_OVERRUN,
+	NIC_REC_MISSED,
+	/* Error encountered during RX but with other type of error */
+	NIC_REC_OTHER
+} nic_receive_error_cause_t;
+
+/**
+ * Information about the NIC that never changes - name, vendor, model,
+ * capabilites and so on.
+ */
+typedef struct nic_device_info {
+	/* Device identification */
+	char vendor_name[NIC_VENDOR_MAX_LENGTH];
+	char model_name[NIC_MODEL_MAX_LENGTH];
+	char part_number[NIC_PART_NUMBER_MAX_LENGTH];
+	char serial_number[NIC_SERIAL_NUMBER_MAX_LENGTH];
+	uint16_t vendor_id;
+	uint16_t device_id;
+	uint16_t subsystem_vendor_id;
+	uint16_t subsystem_id;
+	/* Device capabilities */
+	uint16_t ethernet_support[ETH_PHYS_LAYERS];
+
+	/** The mask of all modes which the device can advertise
+	 *
+	 *  see ETH_AUTONEG_ macros in nic/eth_phys.h of libc
+	 */
+	uint32_t autoneg_support;
+} nic_device_info_t;
+
+/**
+ * Type of the ethernet frame
+ */
+typedef enum nic_frame_type {
+	NIC_FRAME_UNICAST,
+	NIC_FRAME_MULTICAST,
+	NIC_FRAME_BROADCAST
+} nic_frame_type_t;
+
+/**
+ * Specifies which unicast frames is the NIC receiving.
+ */
+typedef enum nic_unicast_mode {
+	NIC_UNICAST_UNKNOWN,
+	/** No unicast frames are received */
+	NIC_UNICAST_BLOCKED,
+	/** Only the frames with this NIC's MAC as destination are received */
+	NIC_UNICAST_DEFAULT,
+	/**
+	 * Both frames with this NIC's MAC and those specified in the list are
+	 * received
+	 */
+	NIC_UNICAST_LIST,
+	/** All unicast frames are received */
+	NIC_UNICAST_PROMISC
+} nic_unicast_mode_t;
+
+typedef enum nic_multicast_mode {
+	NIC_MULTICAST_UNKNOWN,
+	/** No multicast frames are received */
+	NIC_MULTICAST_BLOCKED,
+	/** Frames with multicast addresses specified in this list are received */
+	NIC_MULTICAST_LIST,
+	/** All multicast frames are received */
+	NIC_MULTICAST_PROMISC
+} nic_multicast_mode_t;
+
+typedef enum nic_broadcast_mode {
+	NIC_BROADCAST_UNKNOWN,
+	/** Broadcast frames are dropped */
+	NIC_BROADCAST_BLOCKED,
+	/** Broadcast frames are received */
+	NIC_BROADCAST_ACCEPTED
+} nic_broadcast_mode_t;
+
+/**
+ * Structure covering the bitmap with VLAN tags.
+ */
+typedef struct nic_vlan_mask {
+	uint8_t bitmap[NIC_VLAN_BITMAP_SIZE];
+} nic_vlan_mask_t;
+
+/* WOL virtue identifier */
+typedef unsigned int nic_wv_id_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_MAGIC_PACKET.
+ */
+typedef struct nic_wv_magic_packet_data {
+	uint8_t password[6];
+} nic_wv_magic_packet_data_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV4
+ */
+typedef struct nic_wv_ipv4_data {
+	uint8_t address[4];
+} nic_wv_ipv4_data_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV6
+ */
+typedef struct nic_wv_ipv6_data {
+	uint8_t address[16];
+} nic_wv_ipv6_data_t;
+
+/**
+ * WOL virtue types defining the interpretation of data passed to the virtue.
+ * Those tagged with S can have only single virtue active at one moment, those
+ * tagged with M can have multiple ones.
+ */
+typedef enum nic_wv_type {
+	/**
+	 * Used for deletion of the virtue - in this case the mask, data and length
+	 * arguments are ignored.
+	 */
+	NIC_WV_NONE,
+	/** S
+	 * Enabled <=> wakeup upon link change
+	 */
+	NIC_WV_LINK_CHANGE,
+	/** S
+	 * If this virtue is set up, wakeup can be issued by a magic packet frame.
+	 * If the data argument is not NULL, it must contain
+	 * nic_wv_magic_packet_data structure with the SecureOn password.
+	 */
+	NIC_WV_MAGIC_PACKET,
+	/** M
+	 * If the virtue is set up, wakeup can be issued by a frame targeted to
+	 * device with MAC address specified in data. The data must contain
+	 * nic_address_t structure.
+	 */
+	NIC_WV_DESTINATION,
+	/** S
+	 * Enabled <=> wakeup upon receiving broadcast frame
+	 */
+	NIC_WV_BROADCAST,
+	/** S
+	 * Enabled <=> wakeup upon receiving ARP Request
+	 */
+	NIC_WV_ARP_REQUEST,
+	/** M
+	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
+	 * with IPv4 address specified in data. The data must contain
+	 * nic_wv_ipv4_data structure.
+	 */
+	NIC_WV_DIRECTED_IPV4,
+	/** M
+	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
+	 * with IPv6 address specified in data. The data must contain
+	 * nic_wv_ipv6_data structure.
+	 */
+	NIC_WV_DIRECTED_IPV6,
+	/** M
+	 * First length/2 bytes in the argument are interpreted as mask, second
+	 * length/2 bytes are interpreted as content.
+	 * If enabled, the wakeup is issued upon receiving frame where the bytes
+	 * with non-zero value in the mask equal to those in the content.
+	 */
+	NIC_WV_FULL_MATCH,
+	/**
+	 * Dummy value, do not use.
+	 */
+	NIC_WV_MAX
+} nic_wv_type_t;
+
+/**
+ * Specifies the interrupt/polling mode used by the driver and NIC
+ */
+typedef enum nic_poll_mode {
+	/**
+	 * NIC issues interrupts upon events.
+	 */
+	NIC_POLL_IMMEDIATE,
+	/**
+	 * Some uspace app calls nic_poll_now(...) in order to check the NIC state
+	 * - no interrupts are received from the NIC.
+	 */
+	NIC_POLL_ON_DEMAND,
+	/**
+	 * The driver itself issues a poll request in a periodic manner. It is
+	 * allowed to use hardware timer if the NIC supports it.
+	 */
+	NIC_POLL_PERIODIC,
+	/**
+	 * The driver itself issued a poll request in a periodic manner. The driver
+	 * must create software timer, internal hardware timer of NIC must not be
+	 * used even if the NIC supports it.
+	 */
+	NIC_POLL_SOFTWARE_PERIODIC
+} nic_poll_mode_t;
+
+/**
+ * Says if this virtue type is a multi-virtue (there can be multiple virtues of
+ * this type at once).
+ *
+ * @param type
+ *
+ * @return true or false
+ */
+static inline int nic_wv_is_multi(nic_wv_type_t type) {
+	switch (type) {
+	case NIC_WV_FULL_MATCH:
+	case NIC_WV_DESTINATION:
+	case NIC_WV_DIRECTED_IPV4:
+	case NIC_WV_DIRECTED_IPV6:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline const char *nic_device_state_to_string(nic_device_state_t state)
+{
+	switch (state) {
+	case NIC_STATE_STOPPED:
+		return "stopped";
+	case NIC_STATE_DOWN:
+		return "down";
+	case NIC_STATE_ACTIVE:
+		return "active";
+	default:
+		return "undefined";
+	}
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -35,4 +35,5 @@
 	generic/driver.c \
 	generic/dev_iface.c \
+	generic/interrupt.c \
 	generic/log.c \
 	generic/logbuf.c \
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/generic/driver.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -70,18 +70,4 @@
 FIBRIL_MUTEX_INITIALIZE(functions_mutex);
 
-/** Interrupts */
-static interrupt_context_list_t interrupt_contexts;
-
-static irq_cmd_t default_cmds[] = {
-	{
-		.cmd = CMD_ACCEPT
-	}
-};
-
-static irq_code_t default_pseudocode = {
-	sizeof(default_cmds) / sizeof(irq_cmd_t),
-	default_cmds
-};
-
 static ddf_dev_t *create_device(void);
 static void delete_device(ddf_dev_t *);
@@ -93,132 +79,4 @@
 static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
 
-static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
-{
-	int id = (int)IPC_GET_IMETHOD(*icall);
-	interrupt_context_t *ctx;
-	
-	ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
-	if (ctx != NULL && ctx->handler != NULL)
-		(*ctx->handler)(ctx->dev, iid, icall);
-}
-
-interrupt_context_t *create_interrupt_context(void)
-{
-	interrupt_context_t *ctx;
-	
-	ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
-	if (ctx != NULL)
-		memset(ctx, 0, sizeof(interrupt_context_t));
-	
-	return ctx;
-}
-
-void delete_interrupt_context(interrupt_context_t *ctx)
-{
-	if (ctx != NULL)
-		free(ctx);
-}
-
-void init_interrupt_context_list(interrupt_context_list_t *list)
-{
-	memset(list, 0, sizeof(interrupt_context_list_t));
-	fibril_mutex_initialize(&list->mutex);
-	list_initialize(&list->contexts);
-}
-
-void
-add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
-{
-	fibril_mutex_lock(&list->mutex);
-	ctx->id = list->curr_id++;
-	list_append(&ctx->link, &list->contexts);
-	fibril_mutex_unlock(&list->mutex);
-}
-
-void remove_interrupt_context(interrupt_context_list_t *list,
-    interrupt_context_t *ctx)
-{
-	fibril_mutex_lock(&list->mutex);
-	list_remove(&ctx->link);
-	fibril_mutex_unlock(&list->mutex);
-}
-
-interrupt_context_t *
-find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
-{
-	interrupt_context_t *ctx;
-	
-	fibril_mutex_lock(&list->mutex);
-	
-	list_foreach(list->contexts, link) {
-		ctx = list_get_instance(link, interrupt_context_t, link);
-		if (ctx->id == id) {
-			fibril_mutex_unlock(&list->mutex);
-			return ctx;
-		}
-	}
-	
-	fibril_mutex_unlock(&list->mutex);
-	return NULL;
-}
-
-interrupt_context_t *
-find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
-{
-	interrupt_context_t *ctx;
-	
-	fibril_mutex_lock(&list->mutex);
-	
-	list_foreach(list->contexts, link) {
-		ctx = list_get_instance(link, interrupt_context_t, link);
-		if (ctx->irq == irq && ctx->dev == dev) {
-			fibril_mutex_unlock(&list->mutex);
-			return ctx;
-		}
-	}
-	
-	fibril_mutex_unlock(&list->mutex);
-	return NULL;
-}
-
-
-int
-register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
-    irq_code_t *pseudocode)
-{
-	interrupt_context_t *ctx = create_interrupt_context();
-	
-	ctx->dev = dev;
-	ctx->irq = irq;
-	ctx->handler = handler;
-	
-	add_interrupt_context(&interrupt_contexts, ctx);
-	
-	if (pseudocode == NULL)
-		pseudocode = &default_pseudocode;
-	
-	int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
-	if (res != EOK) {
-		remove_interrupt_context(&interrupt_contexts, ctx);
-		delete_interrupt_context(ctx);
-	}
-
-	return res;
-}
-
-int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
-{
-	interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
-	    dev, irq);
-	int res = unregister_irq(irq, dev->handle);
-	
-	if (ctx != NULL) {
-		remove_interrupt_context(&interrupt_contexts, ctx);
-		delete_interrupt_context(ctx);
-	}
-	
-	return res;
-}
-
 static void add_to_functions_list(ddf_fun_t *fun)
 {
@@ -301,14 +159,4 @@
 	
 	async_answer_0(iid, res);
-}
-
-static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
-{
-	fibril_mutex_lock(&devices_mutex);
-	ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));
-	fibril_mutex_unlock(&devices_mutex);
-	
-	if (dev != NULL && driver->driver_ops->device_added != NULL)
-		driver->driver_ops->device_added(dev);
 }
 
@@ -460,8 +308,4 @@
 		case DRIVER_DEV_ADD:
 			driver_dev_add(callid, &call);
-			break;
-		case DRIVER_DEV_ADDED:
-			async_answer_0(callid, EOK);
-			driver_dev_added(callid, &call);
 			break;
 		case DRIVER_DEV_REMOVE:
@@ -751,5 +595,5 @@
 
 /** Allocate driver-specific device data. */
-extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
+void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
 {
 	void *data;
@@ -813,5 +657,5 @@
 
 /** Allocate driver-specific function data. */
-extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
+void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
 {
 	void *data;
@@ -1006,9 +850,6 @@
 	driver = drv;
 	
-	/* Initialize the list of interrupt contexts. */
-	init_interrupt_context_list(&interrupt_contexts);
-	
-	/* Set generic interrupt handler. */
-	async_set_interrupt_received(driver_irq_handler);
+	/* Initialize interrupt module */
+	interrupt_init();
 	
 	/*
@@ -1016,5 +857,6 @@
 	 * incoming connections.
 	 */
-	rc = devman_driver_register(driver->name, driver_connection);
+	async_set_client_connection(driver_connection);
+	rc = devman_driver_register(driver->name);
 	if (rc != EOK) {
 		printf("Error: Failed to register driver with device manager "
Index: uspace/lib/drv/generic/interrupt.c
===================================================================
--- uspace/lib/drv/generic/interrupt.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/drv/generic/interrupt.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup libdrv generic device driver support.
+ * @brief HelenOS generic device driver support.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "ddf/interrupt.h"
+
+static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall);
+static interrupt_context_t *create_interrupt_context(void);
+static void delete_interrupt_context(interrupt_context_t *ctx);
+static void init_interrupt_context_list(interrupt_context_list_t *list);
+static void add_interrupt_context(interrupt_context_list_t *list,
+    interrupt_context_t *ctx);
+static void remove_interrupt_context(interrupt_context_list_t *list,
+    interrupt_context_t *ctx);
+static interrupt_context_t *find_interrupt_context_by_id(
+    interrupt_context_list_t *list, int id);
+static interrupt_context_t *find_interrupt_context(
+    interrupt_context_list_t *list, ddf_dev_t *dev, int irq);
+int register_interrupt_handler(ddf_dev_t *dev, int irq,
+    interrupt_handler_t *handler, irq_code_t *pseudocode);
+int unregister_interrupt_handler(ddf_dev_t *dev, int irq);
+
+/** Interrupts */
+static interrupt_context_list_t interrupt_contexts;
+
+static irq_cmd_t default_cmds[] = {
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+static irq_code_t default_pseudocode = {
+	sizeof(default_cmds) / sizeof(irq_cmd_t),
+	default_cmds
+};
+
+void interrupt_init(void)
+{
+	/* Initialize the list of interrupt contexts. */
+	init_interrupt_context_list(&interrupt_contexts);
+	
+	/* Set generic interrupt handler. */
+	async_set_interrupt_received(driver_irq_handler);
+}
+
+static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
+{
+	int id = (int)IPC_GET_IMETHOD(*icall);
+	interrupt_context_t *ctx;
+	
+	ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
+	if (ctx != NULL && ctx->handler != NULL)
+		(*ctx->handler)(ctx->dev, iid, icall);
+}
+
+static interrupt_context_t *create_interrupt_context(void)
+{
+	interrupt_context_t *ctx;
+	
+	ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
+	if (ctx != NULL)
+		memset(ctx, 0, sizeof(interrupt_context_t));
+	
+	return ctx;
+}
+
+static void delete_interrupt_context(interrupt_context_t *ctx)
+{
+	if (ctx != NULL)
+		free(ctx);
+}
+
+static void init_interrupt_context_list(interrupt_context_list_t *list)
+{
+	memset(list, 0, sizeof(interrupt_context_list_t));
+	fibril_mutex_initialize(&list->mutex);
+	list_initialize(&list->contexts);
+}
+
+static void
+add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
+{
+	fibril_mutex_lock(&list->mutex);
+	ctx->id = list->curr_id++;
+	list_append(&ctx->link, &list->contexts);
+	fibril_mutex_unlock(&list->mutex);
+}
+
+static void remove_interrupt_context(interrupt_context_list_t *list,
+    interrupt_context_t *ctx)
+{
+	fibril_mutex_lock(&list->mutex);
+	list_remove(&ctx->link);
+	fibril_mutex_unlock(&list->mutex);
+}
+
+static interrupt_context_t *
+find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
+{
+	interrupt_context_t *ctx;
+	
+	fibril_mutex_lock(&list->mutex);
+	
+	list_foreach(list->contexts, link) {
+		ctx = list_get_instance(link, interrupt_context_t, link);
+		if (ctx->id == id) {
+			fibril_mutex_unlock(&list->mutex);
+			return ctx;
+		}
+	}
+	
+	fibril_mutex_unlock(&list->mutex);
+	return NULL;
+}
+
+static interrupt_context_t *
+find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
+{
+	interrupt_context_t *ctx;
+	
+	fibril_mutex_lock(&list->mutex);
+	
+	list_foreach(list->contexts, link) {
+		ctx = list_get_instance(link, interrupt_context_t, link);
+		if (ctx->irq == irq && ctx->dev == dev) {
+			fibril_mutex_unlock(&list->mutex);
+			return ctx;
+		}
+	}
+	
+	fibril_mutex_unlock(&list->mutex);
+	return NULL;
+}
+
+
+int
+register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
+    irq_code_t *pseudocode)
+{
+	interrupt_context_t *ctx = create_interrupt_context();
+	
+	ctx->dev = dev;
+	ctx->irq = irq;
+	ctx->handler = handler;
+	
+	add_interrupt_context(&interrupt_contexts, ctx);
+	
+	if (pseudocode == NULL)
+		pseudocode = &default_pseudocode;
+	
+	int res = irq_register(irq, dev->handle, ctx->id, pseudocode);
+	if (res != EOK) {
+		remove_interrupt_context(&interrupt_contexts, ctx);
+		delete_interrupt_context(ctx);
+	}
+
+	return res;
+}
+
+int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
+{
+	interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
+	    dev, irq);
+	int res = irq_unregister(irq, dev->handle);
+	
+	if (ctx != NULL) {
+		remove_interrupt_context(&interrupt_contexts, ctx);
+		delete_interrupt_context(ctx);
+	}
+	
+	return res;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/generic/remote_nic.c
===================================================================
--- uspace/lib/drv/generic/remote_nic.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/generic/remote_nic.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,30 +39,35 @@
 #include <errno.h>
 #include <ipc/services.h>
-#include <adt/measured_strings.h>
 #include <sys/time.h>
 #include "ops/nic.h"
 
-static void remote_nic_send_message(ddf_fun_t *dev, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	nic_iface_t *nic_iface = (nic_iface_t *) iface;
-	assert(nic_iface->send_message);
-	
-	packet_id_t packet_id = (packet_id_t) IPC_GET_ARG2(*call);
-	
-	int rc = nic_iface->send_message(dev, packet_id);
-	async_answer_0(callid, rc);
-}
-
-static void remote_nic_connect_to_nil(ddf_fun_t *dev, void *iface,
-    ipc_callid_t callid, ipc_call_t *call)
-{
-	nic_iface_t *nic_iface = (nic_iface_t *) iface;
-	assert(nic_iface->connect_to_nil);
-	
-	services_t nil_service = (services_t) IPC_GET_ARG2(*call);
-	nic_device_id_t device_id = (nic_device_id_t) IPC_GET_ARG3(*call);
-	
-	int rc = nic_iface->connect_to_nil(dev, nil_service, device_id);
+static void remote_nic_send_frame(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->send_frame);
+	
+	void *data;
+	size_t size;
+	int rc;
+	
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+	
+	rc = nic_iface->send_frame(dev, data, size);
+	async_answer_0(callid, rc);
+	free(data);
+}
+
+static void remote_nic_callback_create(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->callback_create);
+	
+	int rc = nic_iface->callback_create(dev);
 	async_answer_0(callid, rc);
 }
@@ -829,6 +834,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);
@@ -1194,6 +1199,6 @@
  */
 static remote_iface_func_ptr_t remote_nic_iface_ops[] = {
-	&remote_nic_send_message,
-	&remote_nic_connect_to_nil,
+	&remote_nic_send_frame,
+	&remote_nic_callback_create,
 	&remote_nic_get_state,
 	&remote_nic_set_state,
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/include/ddf/driver.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -145,13 +145,4 @@
 	/** Ask driver to offline a specific function */
 	int (*fun_offline)(ddf_fun_t *);
-
-	/**
-	 * Notification that the device was succesfully added.
-	 * The driver can do any blocking operation without
-	 * blocking the device manager.
-	 *
-	 * XXX REMOVE THIS
-	 */
-	void (*device_added)(ddf_dev_t *dev);
 } driver_ops_t;
 
Index: uspace/lib/drv/include/ddf/interrupt.h
===================================================================
--- uspace/lib/drv/include/ddf/interrupt.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/include/ddf/interrupt.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -64,16 +64,5 @@
 } interrupt_context_list_t;
 
-extern interrupt_context_t *create_interrupt_context(void);
-extern void delete_interrupt_context(interrupt_context_t *);
-extern void init_interrupt_context_list(interrupt_context_list_t *);
-extern void add_interrupt_context(interrupt_context_list_t *,
-    interrupt_context_t *);
-extern void remove_interrupt_context(interrupt_context_list_t *,
-    interrupt_context_t *);
-extern interrupt_context_t *find_interrupt_context_by_id(
-    interrupt_context_list_t *, int);
-extern interrupt_context_t *find_interrupt_context(
-    interrupt_context_list_t *, ddf_dev_t *, int);
-
+extern void interrupt_init(void);
 extern int register_interrupt_handler(ddf_dev_t *, int, interrupt_handler_t *,
     irq_code_t *);
Index: uspace/lib/drv/include/ops/hw_res.h
===================================================================
--- uspace/lib/drv/include/ops/hw_res.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/include/ops/hw_res.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/include/ops/nic.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -37,7 +37,6 @@
 #define LIBDRV_OPS_NIC_H_
 
-#include <net/packet.h>
 #include <ipc/services.h>
-#include <net/device.h>
+#include <nic/nic.h>
 #include <sys/time.h>
 
@@ -46,6 +45,6 @@
 typedef struct nic_iface {
 	/** Mandatory methods */
-	int (*send_message)(ddf_fun_t *, packet_id_t);
-	int (*connect_to_nil)(ddf_fun_t *, services_t, nic_device_id_t);
+	int (*send_frame)(ddf_fun_t *, void *, size_t);
+	int (*callback_create)(ddf_fun_t *);
 	int (*get_state)(ddf_fun_t *, nic_device_state_t *);
 	int (*set_state)(ddf_fun_t *, nic_device_state_t);
@@ -89,5 +88,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -31,4 +32,5 @@
  * @{
  */
+
 /** @file
  * @brief USB host controller interface definition.
@@ -46,5 +48,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/fb/imgmap.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/fb/screenbuffer.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/fs/libfs.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/minix/minix.h
===================================================================
--- uspace/lib/minix/minix.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/minix/minix.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,9 +39,9 @@
 #define S_ISDIR(m)		(((m) & S_IFMT) == S_IFDIR)
 #define S_ISREG(m)		(((m) & S_IFMT) == S_IFREG)
-#define S_IFDIR			0040000		/*Directory*/
-#define S_IFREG			0100000		/*Regular file*/
+#define S_IFDIR			0040000		/* Directory */
+#define S_IFREG			0100000		/* Regular file */
 #define S_IFMT			00170000
 
-/*The following block sizes are valid only on V3 filesystem*/
+/* The following block sizes are valid only on V3 filesystem */
 #define MFS_MIN_BLOCKSIZE	1024
 #define MFS_MAX_BLOCKSIZE	4096
@@ -88,19 +88,19 @@
 #define MFS_ERROR_FS		0x0002
 
-/*MFS V1/V2 superblock data on disk*/
+/* MFS V1/V2 superblock data on disk */
 struct mfs_superblock {
-	/*Total number of inodes on the device*/
+	/* Total number of inodes on the device */
 	uint16_t	s_ninodes;
-	/*Total number of zones on the device*/
+	/* Total number of zones on the device */
 	uint16_t	s_nzones;
-	/*Number of inode bitmap blocks*/
+	/* Number of inode bitmap blocks */
 	uint16_t	s_ibmap_blocks;
-	/*Number of zone bitmap blocks*/
+	/* Number of zone bitmap blocks */
 	uint16_t	s_zbmap_blocks;
-	/*First data zone on device*/
+	/* First data zone on device */
 	uint16_t	s_first_data_zone;
-	/*Base 2 logarithm of the zone to block ratio*/
+	/* Base 2 logarithm of the zone to block ratio */
 	uint16_t	s_log2_zone_size;
-	/*Maximum file size expressed in bytes*/
+	/* Maximum file size expressed in bytes */
 	uint32_t	s_max_file_size;
 	/*
@@ -109,28 +109,28 @@
 	 */
 	uint16_t	s_magic;
-	/*Flag used to detect FS errors*/
+	/* Flag used to detect FS errors*/
 	uint16_t	s_state;
-	/*Total number of zones on the device (V2 only)*/
+	/* Total number of zones on the device (V2 only) */
 	uint32_t	s_nzones2;
 } __attribute__ ((packed));
 
 
-/*MFS V3 superblock data on disk*/
+/* MFS V3 superblock data on disk */
 struct mfs3_superblock {
-	/*Total number of inodes on the device*/
+	/* Total number of inodes on the device */
 	uint32_t	s_ninodes;
 	uint16_t	s_pad0;
-	/*Number of inode bitmap blocks*/
+	/* Number of inode bitmap blocks */
 	int16_t		s_ibmap_blocks;
-	/*Number of zone bitmap blocks*/
+	/* Number of zone bitmap blocks */
 	int16_t		s_zbmap_blocks;
-	/*First data zone on device*/
+	/* First data zone on device */
 	uint16_t	s_first_data_zone;
-	/*Base 2 logarithm of the zone to block ratio*/
+	/* Base 2 logarithm of the zone to block ratio */
 	int16_t		s_log2_zone_size;
 	int16_t		s_pad1;
-	/*Maximum file size expressed in bytes*/
+	/* Maximum file size expressed in bytes */
 	uint32_t	s_max_file_size;
-	/*Total number of zones on the device*/
+	/* Total number of zones on the device */
 	uint32_t	s_nzones;
 	/*
@@ -140,11 +140,11 @@
 	int16_t		s_magic;
 	int16_t		s_pad2;
-	/*Filesystem block size expressed in bytes*/
+	/* Filesystem block size expressed in bytes */
 	uint16_t	s_block_size;
-	/*Filesystem disk format version*/
+	/* Filesystem disk format version */
 	int8_t		s_disk_version;
 } __attribute__ ((packed));
 
-/*MinixFS V1 inode structure as it is on disk*/
+/* MinixFS V1 inode structure as it is on disk */
 struct mfs_inode {
 	uint16_t	i_mode;
@@ -154,11 +154,11 @@
 	uint8_t		i_gid;
 	uint8_t		i_nlinks;
-	/*Block numbers for direct zones*/
+	/* Block numbers for direct zones */
 	uint16_t	i_dzone[V1_NR_DIRECT_ZONES];
-	/*Block numbers for indirect zones*/
+	/* Block numbers for indirect zones */
 	uint16_t	i_izone[V1_NR_INDIRECT_ZONES];
 } __attribute__ ((packed));
 
-/*MinixFS V2 inode structure as it is on disk (also valid for V3).*/
+/* MinixFS V2 inode structure as it is on disk (also valid for V3). */
 struct mfs2_inode {
 	uint16_t 	i_mode;
@@ -170,11 +170,11 @@
 	int32_t		i_mtime;
 	int32_t		i_ctime;
-	/*Block numbers for direct zones*/
+	/* Block numbers for direct zones */
 	uint32_t	i_dzone[V2_NR_DIRECT_ZONES];
-	/*Block numbers for indirect zones*/
+	/* Block numbers for indirect zones */
 	uint32_t	i_izone[V2_NR_INDIRECT_ZONES];
 } __attribute__ ((packed));
 
-/*MinixFS V1/V2 directory entry on-disk structure*/
+/* MinixFS V1/V2 directory entry on-disk structure */
 struct mfs_dentry {
 	uint16_t d_inum;
@@ -182,5 +182,5 @@
 };
 
-/*MinixFS V3 directory entry on-disk structure*/
+/* MinixFS V3 directory entry on-disk structure */
 struct mfs3_dentry {
 	uint32_t d_inum;
Index: uspace/lib/net/generic/net_checksum.c
===================================================================
--- uspace/lib/net/generic/net_checksum.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/generic/net_checksum.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -45,7 +45,4 @@
 #define CRC_DIVIDER_LE  0xedb88320
 
-/** Polynomial used in multicast address hashing */
-#define CRC_MCAST_POLYNOMIAL  0x04c11db6
-
 /** Compacts the computed checksum to the 16 bit number adding the carries.
  *
@@ -224,39 +221,4 @@
 }
 
-/** Compute the standard hash from MAC
- *
- * Hashing MAC into 64 possible values and using the value as index to
- * 64bit number.
- *
- * The code is copied from qemu-0.13's implementation of ne2000 and rt8139
- * drivers, but according to documentation there it originates in FreeBSD.
- *
- * @param[in] addr The 6-byte MAC address to be hashed
- *
- * @return 64-bit number with only single bit set to 1
- *
- */
-uint64_t multicast_hash(const uint8_t addr[6])
-{
-	uint32_t crc;
-    int carry, i, j;
-    uint8_t b;
-
-    crc = 0xffffffff;
-    for (i = 0; i < 6; i++) {
-        b = addr[i];
-        for (j = 0; j < 8; j++) {
-            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
-            crc <<= 1;
-            b >>= 1;
-            if (carry)
-                crc = ((crc ^ CRC_MCAST_POLYNOMIAL) | carry);
-        }
-    }
-	
-    uint64_t one64 = 1;
-    return one64 << (crc >> 26);
-}
-
 /** @}
  */
Index: uspace/lib/net/generic/net_remote.c
===================================================================
--- uspace/lib/net/generic/net_remote.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/generic/net_remote.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -167,13 +167,4 @@
 }
 
-int net_driver_ready(async_sess_t *sess, devman_handle_t handle)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_1_0(exch, NET_NET_DRIVER_READY, handle);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
 /** @}
  */
Index: uspace/lib/net/generic/packet_client.c
===================================================================
--- uspace/lib/net/generic/packet_client.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/generic/packet_client.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/generic/packet_remote.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/net/include/net_checksum.h
===================================================================
--- uspace/lib/net/include/net_checksum.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/include/net_checksum.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -67,5 +67,4 @@
 extern uint16_t flip_checksum(uint16_t);
 extern uint16_t ip_checksum(uint8_t *, size_t);
-extern uint64_t multicast_hash(const uint8_t addr[6]);
 
 #endif
Index: uspace/lib/net/include/net_interface.h
===================================================================
--- uspace/lib/net/include/net_interface.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/include/net_interface.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -52,5 +52,4 @@
 extern int net_get_devices_req(async_sess_t *, measured_string_t **, size_t *,
     uint8_t **);
-extern int net_driver_ready(async_sess_t *, devman_handle_t);
 extern async_sess_t *net_connect_module(void);
 
Index: uspace/lib/net/include/nil_remote.h
===================================================================
--- uspace/lib/net/include/nil_remote.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/include/nil_remote.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -34,4 +34,5 @@
 #define __NET_NIL_REMOTE_H__
 
+#include <ipc/loc.h>
 #include <net/device.h>
 #include <net/packet.h>
@@ -39,4 +40,5 @@
 #include <generic.h>
 #include <async.h>
+#include <sys/types.h>
 
 #define nil_bind_service(service, device_id, me, receiver) \
@@ -60,8 +62,4 @@
 extern int nil_device_req(async_sess_t *, nic_device_id_t, devman_handle_t,
     size_t);
-extern int nil_device_state_msg(async_sess_t *, nic_device_id_t, sysarg_t);
-extern int nil_received_msg(async_sess_t *, nic_device_id_t, packet_id_t);
-extern int nil_addr_changed_msg(async_sess_t *, nic_device_id_t,
-    const nic_address_t *);
 
 #endif
Index: uspace/lib/net/nil/nil_remote.c
===================================================================
--- uspace/lib/net/nil/nil_remote.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/net/nil/nil_remote.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -36,4 +36,5 @@
  */
 
+#include <ipc/loc.h>
 #include <nil_remote.h>
 #include <generic.h>
@@ -43,75 +44,10 @@
 #include <ipc/nil.h>
 
-/** Notify the network interface layer about the device state change.
- *
- * @param[in] sess      Network interface layer session.
- * @param[in] device_id Device identifier.
- * @param[in] state     New device state.
- *
- * @return EOK on success.
- * @return Other error codes as defined for each specific module
- *         device state function.
- *
- */
-int nil_device_state_msg(async_sess_t *sess, nic_device_id_t device_id,
-    sysarg_t state)
-{
-	return generic_device_state_msg_remote(sess, NET_NIL_DEVICE_STATE,
-	    device_id, state, 0);
-}
-
-/** Pass the packet queue to the network interface layer.
- *
- * Process and redistribute the received packet queue to the registered
- * upper layers.
- *
- * @param[in] sess      Network interface layer session.
- * @param[in] device_id Source device identifier.
- * @param[in] packet    Received packet or the received packet queue.
- * @param[in] target    Target service. Ignored parameter.
- *
- * @return EOK on success.
- * @return Other error codes as defined for each specific module
- *         received function.
- *
- */
-int nil_received_msg(async_sess_t *sess, nic_device_id_t device_id,
-    packet_id_t packet_id)
-{
-	return generic_received_msg_remote(sess, NET_NIL_RECEIVED,
-	    device_id, packet_id, 0, 0);
-}
-
-/** Notify upper layers that device address has changed
- *
- */
-int nil_addr_changed_msg(async_sess_t *sess, nic_device_id_t device_id,
-    const nic_address_t *address)
-{
-	assert(sess);
-	
-	async_exch_t *exch = async_exchange_begin(sess);
-	
-	aid_t message_id = async_send_1(exch, NET_NIL_ADDR_CHANGED,
-	    (sysarg_t) device_id, NULL);
-	int rc = async_data_write_start(exch, address, sizeof (nic_address_t));
-	
-	async_exchange_end(exch);
-	
-	sysarg_t res;
-    async_wait_for(message_id, &res);
-	
-    if (rc != EOK)
-		return rc;
-	
-    return (int) res;
-}
-
 int nil_device_req(async_sess_t *sess, nic_device_id_t device_id,
-    devman_handle_t handle, size_t mtu)
+    service_id_t sid, size_t mtu)
 {
 	async_exch_t *exch = async_exchange_begin(sess);
 	int rc = async_req_3_0(exch, NET_NIL_DEVICE, (sysarg_t) device_id,
-	    (sysarg_t) handle, (sysarg_t) mtu);
+	    (sysarg_t) sid, (sysarg_t) mtu);
 	async_exchange_end(exch);
 	return rc;
Index: uspace/lib/nic/Makefile
===================================================================
--- uspace/lib/nic/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -29,9 +29,9 @@
 USPACE_PREFIX = ../..
 LIBRARY = libnic
-LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBNET_PREFIX)/libnet.a
-EXTRA_CFLAGS += -DLIBNIC_INTERNAL -Iinclude -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include
+EXTRA_CFLAGS += -DLIBNIC_INTERNAL -Iinclude -I$(LIBDRV_PREFIX)/include
 
 SOURCES = \
 	src/nic_driver.c \
+	src/nic_ev.c \
 	src/nic_addr_db.c \
 	src/nic_rx_control.c \
Index: uspace/lib/nic/include/nic.h
===================================================================
--- uspace/lib/nic/include/nic.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/include/nic.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -42,6 +42,7 @@
 #include <ddf/driver.h>
 #include <device/hw_res_parsed.h>
-#include <net/packet.h>
 #include <ops/nic.h>
+
+#define DEVICE_CATEGORY_NIC "nic"
 
 struct nic;
@@ -61,9 +62,10 @@
 
 /**
- * Simple structure for sending the allocated frames (packets) in a list.
+ * Simple structure for sending lists of frames.
  */
 typedef struct {
 	link_t link;
-	packet_t *packet;
+	void *data;
+	size_t size;
 } nic_frame_t;
 
@@ -71,13 +73,14 @@
 
 /**
- * Handler for writing packet data to the NIC device.
- * The function is responsible for releasing the packet.
+ * Handler for writing frame data to the NIC device.
+ * The function is responsible for releasing the frame.
  * It does not return anything, if some error is detected the function just
  * silently fails (logging on debug level is suggested).
  *
  * @param nic_data
- * @param packet	Pointer to the packet to be sent
- */
-typedef void (*write_packet_handler)(nic_t *, packet_t *);
+ * @param data		Pointer to frame data
+ * @param size		Size of frame data in bytes
+ */
+typedef void (*send_frame_handler)(nic_t *, void *, size_t);
 /**
  * The handler for transitions between driver states.
@@ -157,5 +160,5 @@
  * @return ENOTSUP	If this filter cannot work on this NIC (e.g. the NIC
  * 					cannot run in promiscuous node or the limit of WOL
- * 					packets' specifications was reached).
+ * 					frames' specifications was reached).
  * @return ELIMIT	If this filter must implemented in HW but currently the
  * 					limit of these HW filters was reached.
@@ -203,8 +206,7 @@
 /* Functions called in add_device */
 extern int nic_connect_to_services(nic_t *);
-extern int nic_register_as_ddf_fun(nic_t *, ddf_dev_ops_t *);
 extern int nic_get_resources(nic_t *, hw_res_list_parsed_t *);
 extern void nic_set_specific(nic_t *, void *);
-extern void nic_set_write_packet_handler(nic_t *, write_packet_handler);
+extern void nic_set_send_frame_handler(nic_t *, send_frame_handler);
 extern void nic_set_state_change_handlers(nic_t *,
 	state_change_handler, state_change_handler, state_change_handler);
@@ -218,10 +220,8 @@
 	poll_mode_change_handler, poll_request_handler);
 
-/* Functions called in device_added */
-extern int nic_ready(nic_t *);
-
 /* General driver functions */
 extern ddf_dev_t *nic_get_ddf_dev(nic_t *);
 extern ddf_fun_t *nic_get_ddf_fun(nic_t *);
+extern void nic_set_ddf_fun(nic_t *, ddf_fun_t *);
 extern nic_t *nic_get_from_ddf_dev(ddf_dev_t *);
 extern nic_t *nic_get_from_ddf_fun(ddf_fun_t *);
@@ -232,6 +232,5 @@
 extern int nic_report_poll_mode(nic_t *, nic_poll_mode_t, struct timeval *);
 extern void nic_query_address(nic_t *, nic_address_t *);
-extern void nic_received_packet(nic_t *, packet_t *);
-extern void nic_received_noneth_packet(nic_t *, packet_t *);
+extern void nic_received_noneth_frame(nic_t *, void *, size_t);
 extern void nic_received_frame(nic_t *, nic_frame_t *);
 extern void nic_received_frame_list(nic_t *, nic_frame_list_t *);
@@ -247,7 +246,5 @@
 extern void nic_report_collisions(nic_t *, unsigned);
 
-/* Packet / frame / frame list allocation and deallocation */
-extern packet_t *nic_alloc_packet(nic_t *, size_t);
-extern void nic_release_packet(nic_t *, packet_t *);
+/* Frame / frame list allocation and deallocation */
 extern nic_frame_t *nic_alloc_frame(nic_t *, size_t);
 extern nic_frame_list_t *nic_alloc_frame_list(void);
@@ -274,8 +271,4 @@
 extern void nic_sw_period_stop(nic_t *);
 
-/* Packet DMA lock */
-extern void * nic_dma_lock_packet(packet_t * packet);
-extern void nic_dma_unlock_packet(packet_t * packet);
-
 #endif // __NIC_H__
 
Index: uspace/lib/nic/include/nic_driver.h
===================================================================
--- uspace/lib/nic/include/nic_driver.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/include/nic_driver.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -44,5 +44,5 @@
 
 #include <fibril_synch.h>
-#include <net/device.h>
+#include <nic/nic.h>
 #include <async.h>
 
@@ -50,6 +50,4 @@
 #include "nic_rx_control.h"
 #include "nic_wol_virtues.h"
-
-#define DEVICE_CATEGORY_NIC "nic"
 
 struct sw_poll_info {
@@ -72,6 +70,4 @@
 	 */
 	ddf_fun_t *fun;
-	/** Identifier for higher network stack layers */
-	nic_device_id_t device_id;
 	/** Current state of the device */
 	nic_device_state_t state;
@@ -82,8 +78,6 @@
 	/** Device's default MAC address (assigned the first time, used in STOP) */
 	nic_address_t default_mac;
-	/** Session to SERVICE_NETWORKING */
-	async_sess_t *net_session;
-	/** Session to SERVICE_ETHERNET or SERVICE_NILDUMMY */
-	async_sess_t *nil_session;
+	/** Client callback session */
+	async_sess_t *client_session;
 	/** Phone to APIC or i8259 */
 	async_sess_t *irc_session;
@@ -134,5 +128,5 @@
 	 * Called with the main_lock locked for reading.
 	 */
-	write_packet_handler write_packet;
+	send_frame_handler send_frame;
 	/**
 	 * Event handler called when device goes to the ACTIVE state.
Index: uspace/lib/nic/include/nic_ev.h
===================================================================
--- uspace/lib/nic/include/nic_ev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/nic/include/nic_ev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,52 @@
+/*
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Prototypes of default DDF NIC interface methods implementations
+ */
+
+#ifndef NIC_EV_H__
+#define NIC_EV_H__
+
+#include <async.h>
+#include <nic/nic.h>
+#include <sys/types.h>
+
+extern int nic_ev_addr_changed(async_sess_t *, const nic_address_t *);
+extern int nic_ev_device_state(async_sess_t *, sysarg_t);
+extern int nic_ev_received(async_sess_t *, void *, size_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_impl.h
===================================================================
--- uspace/lib/nic/include/nic_impl.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/include/nic_impl.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,7 +40,6 @@
 
 #include <assert.h>
-#include <net/device.h>
+#include <nic/nic.h>
 #include <ddf/driver.h>
-#include <nil_remote.h>
 
 /* Inclusion of this file is not prohibited, because drivers could want to
@@ -48,7 +47,6 @@
 
 extern int nic_get_address_impl(ddf_fun_t *dev_fun, nic_address_t *address);
-extern int nic_send_message_impl(ddf_fun_t *dev_fun, packet_id_t packet_id);
-extern int nic_connect_to_nil_impl(ddf_fun_t *dev_fun, services_t nil_service,
-	int device_id);
+extern int nic_send_frame_impl(ddf_fun_t *dev_fun, void *data, size_t size);
+extern int nic_callback_create_impl(ddf_fun_t *dev_fun);
 extern int nic_get_state_impl(ddf_fun_t *dev_fun, nic_device_state_t *state);
 extern int nic_set_state_impl(ddf_fun_t *dev_fun, nic_device_state_t state);
Index: uspace/lib/nic/include/nic_rx_control.h
===================================================================
--- uspace/lib/nic/include/nic_rx_control.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/include/nic_rx_control.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -45,6 +45,5 @@
 #include <adt/hash_table.h>
 #include <fibril_synch.h>
-#include <net/device.h>
-#include <net/packet_header.h>
+#include <nic/nic.h>
 
 #include "nic_addr_db.h"
@@ -120,5 +119,5 @@
 	const nic_address_t *prev_addr, const nic_address_t *curr_addr);
 extern int nic_rxc_check(const nic_rxc_t *rxc,
-	const packet_t *packet, nic_frame_type_t *frame_type);
+	const void *data, size_t size, nic_frame_type_t *frame_type);
 extern void nic_rxc_hw_filtering(nic_rxc_t *rxc,
 	int unicast_exact, int multicast_exact, int vlan_exact);
Index: uspace/lib/nic/include/nic_wol_virtues.h
===================================================================
--- uspace/lib/nic/include/nic_wol_virtues.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/include/nic_wol_virtues.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,5 +43,5 @@
 #endif
 
-#include <net/device.h>
+#include <nic/nic.h>
 #include <adt/hash_table.h>
 #include "nic.h"
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/src/nic_driver.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -46,15 +46,12 @@
 #include <ipc/irc.h>
 #include <sysinfo.h>
-
+#include <as.h>
 #include <devman.h>
 #include <ddf/interrupt.h>
-#include <net_interface.h>
 #include <ops/nic.h>
-#include <packet_client.h>
-#include <packet_remote.h>
-#include <net/packet_header.h>
 #include <errno.h>
 
 #include "nic_driver.h"
+#include "nic_ev.h"
 #include "nic_impl.h"
 
@@ -64,5 +61,5 @@
 
 /**
- * Initializes libraries required for NIC framework - logger, packet manager
+ * Initializes libraries required for NIC framework - logger
  *
  * @param name	Name of the device/driver (used in logging)
@@ -79,6 +76,5 @@
 	snprintf(buffer, 256, "drv/" DEVICE_CATEGORY_NIC "/%s", name);
 	
-	/* Initialize packet manager */
-	return pm_init();
+	return EOK;
 }
 
@@ -93,9 +89,4 @@
     nic_iface_t *iface)
 {
-	if (driver_ops) {
-		if (!driver_ops->device_added)
-			driver_ops->device_added = nic_device_added_impl;
-	}
-
 	if (dev_ops) {
 		if (!dev_ops->open)
@@ -114,8 +105,8 @@
 		if (!iface->set_state)
 			iface->set_state = nic_set_state_impl;
-		if (!iface->send_message)
-			iface->send_message = nic_send_message_impl;
-		if (!iface->connect_to_nil)
-			iface->connect_to_nil = nic_connect_to_nil_impl;
+		if (!iface->send_frame)
+			iface->send_frame = nic_send_frame_impl;
+		if (!iface->callback_create)
+			iface->callback_create = nic_callback_create_impl;
 		if (!iface->get_address)
 			iface->get_address = nic_get_address_impl;
@@ -162,5 +153,5 @@
 
 /**
- * Setup write packet handler. This MUST be called in the add_device handler
+ * Setup send frame handler. This MUST be called in the add_device handler
  * if the nic_send_message_impl function is used for sending messages (filled
  * as send_message member of the nic_iface_t structure). The function must not
@@ -168,9 +159,9 @@
  *
  * @param nic_data
- * @param wpfunc		Function handling the write_packet request
- */
-void nic_set_write_packet_handler(nic_t *nic_data, write_packet_handler wpfunc)
-{
-	nic_data->write_packet = wpfunc;
+ * @param sffunc	Function handling the send_frame request
+ */
+void nic_set_send_frame_handler(nic_t *nic_data, send_frame_handler sffunc)
+{
+	nic_data->send_frame = sffunc;
 }
 
@@ -270,29 +261,11 @@
 }
 
-/**
- * Just a wrapper over the packet_get_1_remote function
- */
-packet_t *nic_alloc_packet(nic_t *nic_data, size_t data_size)
-{
-	return packet_get_1_remote(nic_data->net_session, data_size);
-}
-
-
-/**
- * Just a wrapper over the pq_release_remote function
- */
-void nic_release_packet(nic_t *nic_data, packet_t *packet)
-{
-	pq_release_remote(nic_data->net_session, packet_get_id(packet));
-}
-
-/** Allocate frame and packet
+/** Allocate frame
  *
  *  @param nic_data 	The NIC driver data
- *  @param packet_size	Size of packet
- *  @param offload_size	Size of packet offload
+ *  @param size	        Frame size in bytes
  *  @return pointer to allocated frame if success, NULL otherwise
  */
-nic_frame_t *nic_alloc_frame(nic_t *nic_data, size_t packet_size)
+nic_frame_t *nic_alloc_frame(nic_t *nic_data, size_t size)
 {
 	nic_frame_t *frame;
@@ -313,11 +286,11 @@
 	}
 
-	packet_t *packet = nic_alloc_packet(nic_data, packet_size);
-	if (!packet) {
+	frame->data = malloc(size);
+	if (frame->data == NULL) {
 		free(frame);
 		return NULL;
 	}
 
-	frame->packet = packet;
+	frame->size = size;
 	return frame;
 }
@@ -332,7 +305,11 @@
 	if (!frame)
 		return;
-	if (frame->packet != NULL) {
-		nic_release_packet(nic_data, frame->packet);
-	}
+
+	if (frame->data != NULL) {
+		free(frame->data);
+		frame->data = NULL;
+		frame->size = 0;
+	}
+
 	fibril_mutex_lock(&nic_globals.lock);
 	if (nic_globals.frame_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
@@ -447,5 +424,5 @@
 
 /**
- * Connect to the NET and IRQ services. This function should be called only from
+ * Connect to IRC service. This function should be called only from
  * the add_device handler, thus no locking is required.
  *
@@ -454,14 +431,8 @@
  * @return EOK		If connection was successful.
  * @return EINVAL	If the IRC service cannot be determined.
- * @return EREFUSED	If NET or IRC service cannot be connected.
+ * @return EREFUSED	If IRC service cannot be connected.
  */
 int nic_connect_to_services(nic_t *nic_data)
 {
-	/* NET service */
-	nic_data->net_session = service_connect_blocking(EXCHANGE_SERIALIZE,
-		SERVICE_NETWORKING, 0, 0);
-	if (nic_data->net_session == NULL)
-		return errno;
-	
 	/* IRC service */
 	sysarg_t apic;
@@ -480,26 +451,4 @@
 	
 	return EOK;
-}
-
-/** Notify the NET service that the device is ready
- *
- * @param nic NICF structure
- *
- * @return EOK on success
- *
- */
-int nic_ready(nic_t *nic)
-{
-	fibril_rwlock_read_lock(&nic->main_lock);
-	
-	async_sess_t *session = nic->net_session;
-	devman_handle_t handle = nic->dev->handle;
-	
-	fibril_rwlock_read_unlock(&nic->main_lock);
-	
-	if (session == NULL)
-		return EINVAL;
-	
-	return net_driver_ready(session, handle);
 }
 
@@ -546,7 +495,7 @@
 	
 	/* Notify NIL layer (and uppper) if bound - not in add_device */
-	if (nic_data->nil_session != NULL) {
-		int rc = nil_addr_changed_msg(nic_data->nil_session,
-		    nic_data->device_id, address);
+	if (nic_data->client_session != NULL) {
+		int rc = nic_ev_addr_changed(nic_data->client_session,
+		    address);
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&nic_data->main_lock);
@@ -604,5 +553,5 @@
 
 /**
- * The busy flag can be set to 1 only in the write_packet handler, to 0 it can
+ * The busy flag can be set to 1 only in the send_frame handler, to 0 it can
  * be set anywhere.
  *
@@ -613,5 +562,5 @@
 {
 	/*
-	 * When the function is called in write_packet handler the main lock is
+	 * When the function is called in send_frame handler the main lock is
 	 * locked so no race can happen.
 	 * Otherwise, when it is unexpectedly set to 0 (even with main lock held
@@ -622,42 +571,26 @@
 
 /**
- * Provided for correct naming conventions.
- * The packet is checked by filters and then sent up to the NIL layer or
- * discarded, the frame is released.
- *
- * @param nic_data
- * @param frame		The frame containing received packet
+ * This is the function that the driver should call when it receives a frame.
+ * The frame is checked by filters and then sent up to the NIL layer or
+ * discarded. The frame is released.
+ *
+ * @param nic_data
+ * @param frame		The received frame
  */
 void nic_received_frame(nic_t *nic_data, nic_frame_t *frame)
 {
-	nic_received_packet(nic_data, frame->packet);
-	frame->packet = NULL;
-	nic_release_frame(nic_data, frame);
-}
-
-/**
- * This is the function that the driver should call when it receives a packet.
- * The packet is checked by filters and then sent up to the NIL layer or
- * discarded.
- *
- * @param nic_data
- * @param packet		The received packet
- */
-void nic_received_packet(nic_t *nic_data, packet_t *packet)
-{
 	/* Note: this function must not lock main lock, because loopback driver
-	 * 		 calls it inside write_packet handler (with locked main lock) */
-	packet_id_t pid = packet_get_id(packet);
-	
+	 * 		 calls it inside send_frame handler (with locked main lock) */
 	fibril_rwlock_read_lock(&nic_data->rxc_lock);
 	nic_frame_type_t frame_type;
-	int check = nic_rxc_check(&nic_data->rx_control, packet, &frame_type);
+	int check = nic_rxc_check(&nic_data->rx_control, frame->data,
+	    frame->size, &frame_type);
 	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
 	/* Update statistics */
 	fibril_rwlock_write_lock(&nic_data->stats_lock);
-	/* Both sending message up and releasing packet are atomic IPC calls */
+
 	if (nic_data->state == NIC_STATE_ACTIVE && check) {
 		nic_data->stats.receive_packets++;
-		nic_data->stats.receive_bytes += packet_get_data_length(packet);
+		nic_data->stats.receive_bytes += frame->size;
 		switch (frame_type) {
 		case NIC_FRAME_MULTICAST:
@@ -671,5 +604,6 @@
 		}
 		fibril_rwlock_write_unlock(&nic_data->stats_lock);
-		nil_received_msg(nic_data->nil_session, nic_data->device_id, pid);
+		nic_ev_received(nic_data->client_session, frame->data,
+		    frame->size);
 	} else {
 		switch (frame_type) {
@@ -685,31 +619,31 @@
 		}
 		fibril_rwlock_write_unlock(&nic_data->stats_lock);
-		nic_release_packet(nic_data, packet);
-	}
+	}
+	nic_release_frame(nic_data, frame);
 }
 
 /**
  * This function is to be used only in the loopback driver. It's workaround
- * for the situation when the packet does not contain ethernet address.
+ * for the situation when the frame does not contain ethernet address.
  * The filtering is therefore not applied here.
  *
  * @param nic_data
- * @param packet
- */
-void nic_received_noneth_packet(nic_t *nic_data, packet_t *packet)
+ * @param data		Frame data
+ * @param size		Frame size in bytes
+ */
+void nic_received_noneth_frame(nic_t *nic_data, void *data, size_t size)
 {
 	fibril_rwlock_write_lock(&nic_data->stats_lock);
 	nic_data->stats.receive_packets++;
-	nic_data->stats.receive_bytes += packet_get_data_length(packet);
+	nic_data->stats.receive_bytes += size;
 	fibril_rwlock_write_unlock(&nic_data->stats_lock);
 	
-	nil_received_msg(nic_data->nil_session, nic_data->device_id,
-	    packet_get_id(packet));
-}
-
-/**
- * Some NICs can receive multiple packets during single interrupt. These can
+	nic_ev_received(nic_data->client_session, data, size);
+}
+
+/**
+ * Some NICs can receive multiple frames during single interrupt. These can
  * send them in whole list of frames (actually nic_frame_t structures), then
- * the list is deallocated and each packet is passed to the
+ * the list is deallocated and each frame is passed to the
  * nic_received_packet function.
  *
@@ -726,7 +660,5 @@
 
 		list_remove(&frame->link);
-		nic_received_packet(nic_data, frame->packet);
-		frame->packet = NULL;
-		nic_release_frame(nic_data, frame);
+		nic_received_frame(nic_data, frame);
 	}
 	nic_driver_release_frame_list(frames);
@@ -758,12 +690,10 @@
 	nic_data->dev = NULL;
 	nic_data->fun = NULL;
-	nic_data->device_id = NIC_DEVICE_INVALID_ID;
 	nic_data->state = NIC_STATE_STOPPED;
-	nic_data->net_session = NULL;
-	nic_data->nil_session = NULL;
+	nic_data->client_session = NULL;
 	nic_data->irc_session = NULL;
 	nic_data->poll_mode = NIC_POLL_IMMEDIATE;
 	nic_data->default_poll_mode = NIC_POLL_IMMEDIATE;
-	nic_data->write_packet = NULL;
+	nic_data->send_frame = NULL;
 	nic_data->on_activating = NULL;
 	nic_data->on_going_down = NULL;
@@ -815,10 +745,6 @@
  */
 static void nic_destroy(nic_t *nic_data) {
-	if (nic_data->net_session != NULL) {
-		async_hangup(nic_data->net_session);
-	}
-
-	if (nic_data->nil_session != NULL) {
-		async_hangup(nic_data->nil_session);
+	if (nic_data->client_session != NULL) {
+		async_hangup(nic_data->client_session);
 	}
 
@@ -846,41 +772,4 @@
 
 /**
- * Creates an exposed DDF function for the device, named "port0".
- * Device options are set as this function's options. The function is bound
- * (see ddf_fun_bind) and then registered to the DEVICE_CATEGORY_NIC class.
- * Note: this function should be called only from add_device handler, therefore
- * we don't need to use locks.
- *
- * @param nic_data	The NIC structure
- * @param ops		Device options for the DDF function.
- */
-int nic_register_as_ddf_fun(nic_t *nic_data, ddf_dev_ops_t *ops)
-{
-	int rc;
-	assert(nic_data);
-
-	nic_data->fun = ddf_fun_create(nic_data->dev, fun_exposed, "port0");
-	if (nic_data->fun == NULL)
-		return ENOMEM;
-	
-	nic_data->fun->ops = ops;
-	nic_data->fun->driver_data = nic_data;
-
-	rc = ddf_fun_bind(nic_data->fun);
-	if (rc != EOK) {
-		ddf_fun_destroy(nic_data->fun);
-		return rc;
-	}
-
-	rc = ddf_fun_add_to_category(nic_data->fun, DEVICE_CATEGORY_NIC);
-	if (rc != EOK) {
-		ddf_fun_destroy(nic_data->fun);
-		return rc;
-	}
-	
-	return EOK;
-}
-
-/**
  * Set information about current HW filtering.
  *  1 ...	Only those frames we want to receive are passed through HW
@@ -1097,4 +986,13 @@
 {
 	return nic_data->fun;
+}
+
+/**
+ * @param nic_data
+ * @param fun
+ */
+void nic_set_ddf_fun(nic_t *nic_data, ddf_fun_t *fun)
+{
+	nic_data->fun = fun;
 }
 
@@ -1329,40 +1227,4 @@
 }
 
-// FIXME: Later
-#if 0
-
-/** Lock packet for DMA usage
- *
- * @param packet
- * @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;
-}
-
-/** Unlock packet after DMA usage
- *
- * @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
-
 /** @}
  */
Index: uspace/lib/nic/src/nic_ev.c
===================================================================
--- uspace/lib/nic/src/nic_ev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/nic/src/nic_ev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,97 @@
+/*
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#include <async.h>
+#include <device/nic.h>
+#include <errno.h>
+#include "nic_ev.h"
+
+/** Device address changed. */
+int nic_ev_addr_changed(async_sess_t *sess, const nic_address_t *addr)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, NIC_EV_ADDR_CHANGED, &answer);
+	sysarg_t retval = async_data_write_start(exch, addr,
+	    sizeof(nic_address_t));
+
+	async_exchange_end(exch);
+
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+
+	async_wait_for(req, &retval);
+	return retval;
+}
+
+/** Device state changed. */
+int nic_ev_device_state(async_sess_t *sess, sysarg_t state)
+{
+	int rc;
+
+	async_exch_t *exch = async_exchange_begin(sess);
+	rc = async_req_1_0(exch, NIC_EV_DEVICE_STATE, state);
+	async_exchange_end(exch);
+
+	return rc;
+}
+
+/** Frame received. */
+int nic_ev_received(async_sess_t *sess, void *data, size_t size)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, NIC_EV_RECEIVED, &answer);
+	sysarg_t retval = async_data_write_start(exch, data, size);
+
+	async_exchange_end(exch);
+
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+
+	async_wait_for(req, &retval);
+	return retval;
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_impl.c
===================================================================
--- uspace/lib/nic/src/nic_impl.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/src/nic_impl.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -36,10 +36,10 @@
  */
 
+#include <errno.h>
 #include <str_error.h>
 #include <ipc/services.h>
 #include <ns.h>
-#include <packet_client.h>
-#include <packet_remote.h>
 #include "nic_driver.h"
+#include "nic_ev.h"
 #include "nic_impl.h"
 
@@ -87,6 +87,5 @@
 	}
 	if (state == NIC_STATE_ACTIVE) {
-		if (nic_data->nil_session == NULL || nic_data->net_session == NULL
-		    || nic_data->device_id < 0) {
+		if (nic_data->client_session == NULL) {
 			fibril_rwlock_write_unlock(&nic_data->main_lock);
 			return EINVAL;
@@ -118,6 +117,6 @@
 	if (state == NIC_STATE_STOPPED) {
 		/* Notify upper layers that we are reseting the MAC */
-		int rc = nil_addr_changed_msg(nic_data->nil_session,
-			nic_data->device_id, &nic_data->default_mac);
+		int rc = nic_ev_addr_changed(nic_data->client_session,
+			&nic_data->default_mac);
 		nic_data->poll_mode = nic_data->default_poll_mode;
 		memcpy(&nic_data->poll_period, &nic_data->default_poll_period,
@@ -151,5 +150,5 @@
 	nic_data->state = state;
 
-	nil_device_state_msg(nic_data->nil_session, nic_data->device_id, state);
+	nic_ev_device_state(nic_data->client_session, state);
 
 	fibril_rwlock_write_unlock(&nic_data->main_lock);
@@ -159,77 +158,49 @@
 
 /**
- * Default implementation of the send_message method.
+ * Default implementation of the send_frame method.
  * Send messages to the network.
  *
  * @param	fun
- * @param	packet_id	ID of the first packet in a queue of sent packets
+ * @param	data	Frame data
+ * @param 	size	Frame size in bytes
  *
  * @return EOK		If the message was sent
- * @return EBUSY	If the device is not in state when the packet can be set.
- * @return EINVAL	If the packet ID is invalid
- */
-int nic_send_message_impl(ddf_fun_t *fun, packet_id_t packet_id)
-{
-	nic_t *nic_data = (nic_t *) fun->driver_data;
-	packet_t *packet, *next;
+ * @return EBUSY	If the device is not in state when the frame can be sent.
+ */
+int nic_send_frame_impl(ddf_fun_t *fun, void *data, size_t size)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
 
 	fibril_rwlock_read_lock(&nic_data->main_lock);
 	if (nic_data->state != NIC_STATE_ACTIVE || nic_data->tx_busy) {
 		fibril_rwlock_read_unlock(&nic_data->main_lock);
-		pq_release_remote(nic_data->net_session, packet_id);
 		return EBUSY;
 	}
 
-	int rc = packet_translate_remote(nic_data->net_session, &packet, packet_id);
-
-	if (rc != EOK) {
-		fibril_rwlock_read_unlock(&nic_data->main_lock);
-		return EINVAL;
-	}
-
-	/*
-	 * Process the packet queue. Each sent packet must be detached from the
-	 * queue and destroyed. This is why the cycle differs from loopback's
-	 * cycle, where the packets are immediately used in upper layers and
-	 * therefore they must not be destroyed (released).
-	 */
-	assert(nic_data->write_packet != NULL);
-	do {
-		next = pq_detach(packet);
-		nic_data->write_packet(nic_data, packet);
-		packet = next;
-	} while (packet);
-	fibril_rwlock_read_unlock(&nic_data->main_lock);
-	return EOK;
-}
-
-/**
- * Default implementation of the connect_to_nil method.
- * Connects the driver to the NIL service.
+	nic_data->send_frame(nic_data, data, size);
+	return EOK;
+}
+
+/**
+ * Default implementation of the connect_client method.
+ * Creates callback connection to the client.
  *
  * @param	fun
- * @param	nil_service	ID of the server implementing the NIL service
- * @param	device_id	ID of the device as used in higher layers
- *
- * @return EOK		If the services were bound
- * @return 			Negative error code from service_connect_blocking
- */
-int nic_connect_to_nil_impl(ddf_fun_t *fun, services_t nil_service,
-    nic_device_id_t device_id)
-{
-	nic_t *nic_data = (nic_t *) fun->driver_data;
-	fibril_rwlock_write_lock(&nic_data->main_lock);
+ *
+ * @return EOK		On success, or negative error code.
+ */
+int nic_callback_create_impl(ddf_fun_t *fun)
+{
+	nic_t *nic = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic->main_lock);
 	
-	nic_data->device_id = device_id;
+	nic->client_session = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (nic->client_session == NULL) {
+		fibril_rwlock_write_unlock(&nic->main_lock);
+		return ENOMEM;
+	}
 	
-	nic_data->nil_session = service_connect_blocking(EXCHANGE_SERIALIZE,
-	    nil_service, 0, 0);
-	if (nic_data->nil_session != NULL) {
-		fibril_rwlock_write_unlock(&nic_data->main_lock);
-		return EOK;
-	}
-	
-	fibril_rwlock_write_unlock(&nic_data->main_lock);
-	return EHANGUP;
+	fibril_rwlock_write_unlock(&nic->main_lock);
+	return EOK;
 }
 
@@ -828,16 +799,4 @@
 }
 
-/** Default implementation of the device_added method
- *
- * Just calls nic_ready.
- *
- * @param dev
- *
- */
-void nic_device_added_impl(ddf_dev_t *dev)
-{
-	nic_ready((nic_t *) dev->driver_data);
-}
-
 /**
  * Default handler for unknown methods (outside of the NIC interface).
Index: uspace/lib/nic/src/nic_rx_control.c
===================================================================
--- uspace/lib/nic/src/nic_rx_control.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/src/nic_rx_control.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -40,7 +40,6 @@
 #include <bool.h>
 #include <errno.h>
-#include <net/device.h>
-#include <net_checksum.h>
-#include <packet_client.h>
+#include <mem.h>
+#include <nic/nic.h>
 #include "nic_rx_control.h"
 
@@ -392,14 +391,17 @@
  *
  * @param rxc
- * @param packet	The probed frame
+ * @param frame	    The probed frame
  *
  * @return True if the frame passes, false if it does not
  */
-int nic_rxc_check(const nic_rxc_t *rxc, const packet_t *packet,
+int nic_rxc_check(const nic_rxc_t *rxc, const void *data, size_t size,
 	nic_frame_type_t *frame_type)
 {
 	assert(frame_type != NULL);
-	uint8_t *dest_addr = (uint8_t *) packet + packet->data_start;
+	uint8_t *dest_addr = (uint8_t *) data;
 	uint8_t *src_addr = dest_addr + ETH_ADDR;
+
+	if (size < 2 * ETH_ADDR)
+		return false;
 
 	if (dest_addr[0] & 1) {
@@ -438,4 +440,5 @@
 		}
 	}
+	
 	/* Blocked source addresses */
 	if (rxc->block_sources) {
@@ -443,8 +446,9 @@
 			return false;
 	}
+	
 	/* VLAN filtering */
 	if (!rxc->vlan_exact && rxc->vlan_mask != NULL) {
 		vlan_header_t *vlan_header = (vlan_header_t *)
-			((uint8_t *) packet + packet->data_start + 2 * ETH_ADDR);
+			((uint8_t *) data + 2 * ETH_ADDR);
 		if (vlan_header->tpid_upper == VLAN_TPID_UPPER &&
 			vlan_header->tpid_lower == VLAN_TPID_LOWER) {
@@ -482,4 +486,43 @@
 		rxc->vlan_exact = vlan_exact;
 }
+
+/** Polynomial used in multicast address hashing */
+#define CRC_MCAST_POLYNOMIAL  0x04c11db6
+
+/** Compute the standard hash from MAC
+ *
+ * Hashing MAC into 64 possible values and using the value as index to
+ * 64bit number.
+ *
+ * The code is copied from qemu-0.13's implementation of ne2000 and rt8139
+ * drivers, but according to documentation there it originates in FreeBSD.
+ *
+ * @param[in] addr The 6-byte MAC address to be hashed
+ *
+ * @return 64-bit number with only single bit set to 1
+ *
+ */
+static uint64_t multicast_hash(const uint8_t addr[6])
+{
+	uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = addr[i];
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = ((crc ^ CRC_MCAST_POLYNOMIAL) | carry);
+        }
+    }
+	
+    uint64_t one64 = 1;
+    return one64 << (crc >> 26);
+}
+
 
 /**
Index: uspace/lib/nic/src/nic_wol_virtues.c
===================================================================
--- uspace/lib/nic/src/nic_wol_virtues.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/nic/src/nic_wol_virtues.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -38,4 +38,5 @@
 #include "nic_wol_virtues.h"
 #include <assert.h>
+#include <errno.h>
 
 #define NIC_WV_HASH_COUNT 32
Index: uspace/lib/posix/ctype.c
===================================================================
--- uspace/lib/posix/ctype.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/posix/ctype.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -112,5 +112,5 @@
  * @return Non-zero if character match the definition, zero otherwise.
  */
-extern int posix_isascii(int c)
+int posix_isascii(int c)
 {
 	return c >= 0 && c < 128;
@@ -123,5 +123,5 @@
  * @return Coverted character.
  */
-extern int posix_toascii(int c)
+int posix_toascii(int c)
 {
 	return c & 0x7F;
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/usb/include/usb/dev.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/include/usb/hc.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/include/usb/usb.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/src/ddfiface.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/usb/src/dev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/src/hc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usb/src/usb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/include/usb/dev/driver.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/include/usb/dev/hub.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/include/usb/dev/poll.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/include/usb/dev/request.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/lib/usbdev/include/usb/dev/usb_device_connection.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/altiface.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/devdrv.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/devpoll.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/hub.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/pipes.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbdev/src/recognise.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/src/iface.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/src/usb_device_manager.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -245,6 +245,7 @@
 	void *vaddr;
 	int rc;
-
-	rc = loc_server_register(NAME, ata_bd_connection);
+	
+	async_set_client_connection(ata_bd_connection);
+	rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -309,11 +310,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -141,6 +141,7 @@
 	int rc;
 	long img_size;
-
-	rc = loc_server_register(NAME, file_bd_connection);
+	
+	async_set_client_connection(file_bd_connection);
+	rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -190,11 +191,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -125,6 +125,7 @@
 	int rc, i;
 	char name[16];
-
-	rc = loc_server_register(NAME, gxe_bd_connection);
+	
+	async_set_client_connection(gxe_bd_connection);
+	rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -193,11 +194,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/bd/part/guid_part/guid_part.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -164,5 +164,6 @@
 
 	/* Register server with location service. */
-	rc = loc_server_register(NAME, gpt_connection);
+	async_set_client_connection(gpt_connection);
+	rc = loc_server_register(NAME);
 	if (rc != EOK) {
 		printf(NAME ": Unable to register server.\n");
@@ -348,11 +349,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -214,5 +214,6 @@
 
 	/* Register server with location service. */
-	rc = loc_server_register(NAME, mbr_connection);
+	async_set_client_connection(mbr_connection);
+	rc = loc_server_register(NAME);
 	if (rc != EOK) {
 		printf(NAME ": Unable to register server.\n");
@@ -425,11 +426,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/bd/rd/rd.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -55,6 +55,7 @@
 #include <ipc/bd.h>
 #include <macros.h>
-
-#define NAME "rd"
+#include <inttypes.h>
+
+#define NAME  "rd"
 
 /** Pointer to the ramdisk's image */
@@ -104,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;
@@ -208,39 +207,42 @@
 static bool rd_init(void)
 {
-	int ret = sysinfo_get_value("rd.size", &rd_size);
-	if ((ret != EOK) || (rd_size == 0)) {
+	sysarg_t size;
+	int ret = sysinfo_get_value("rd.size", &size);
+	if ((ret != EOK) || (size == 0)) {
 		printf("%s: No RAM disk found\n", NAME);
 		return false;
 	}
 	
-	sysarg_t rd_ph_addr;
-	ret = sysinfo_get_value("rd.address.physical", &rd_ph_addr);
-	if ((ret != EOK) || (rd_ph_addr == 0)) {
+	sysarg_t addr_phys;
+	ret = sysinfo_get_value("rd.address.physical", &addr_phys);
+	if ((ret != EOK) || (addr_phys == 0)) {
 		printf("%s: Invalid RAM disk physical address\n", NAME);
 		return false;
 	}
 	
-	rd_addr = as_get_mappable_page(rd_size);
-	
-	int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
-	int retval = physmem_map((void *) rd_ph_addr, rd_addr,
-	    ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
-	
-	if (retval < 0) {
+	rd_size = ALIGN_UP(size, block_size);
+	unsigned int flags =
+	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
+	
+	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;
 	}
 	
-	printf("%s: Found RAM disk at %p, %zu bytes\n", NAME,
-	    (void *) rd_ph_addr, rd_size);
-	
-	int rc = loc_server_register(NAME, rd_connection);
-	if (rc < 0) {
-		printf("%s: Unable to register driver (%d)\n", NAME, rc);
+	printf("%s: Found RAM disk at %p, %" PRIun " bytes\n", NAME,
+	    (void *) addr_phys, size);
+	
+	async_set_client_connection(rd_connection);
+	ret = loc_server_register(NAME);
+	if (ret < 0) {
+		printf("%s: Unable to register driver (%d)\n", NAME, ret);
 		return false;
 	}
 	
 	service_id_t service_id;
-	if (loc_service_register("bd/initrd", &service_id) != EOK) {
+	ret = loc_service_register("bd/initrd", &service_id);
+	if (ret != EOK) {
 		printf("%s: Unable to register device service\n", NAME);
 		return false;
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/devman/devman.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -794,7 +794,4 @@
 	case EOK:
 		dev->state = DEVICE_USABLE;
-		exch = async_exchange_begin(drv->sess);
-		async_msg_1(exch, DRIVER_DEV_ADDED, dev->handle);
-		async_exchange_end(exch);
 		break;
 	case ENOENT:
@@ -803,4 +800,5 @@
 	default:
 		dev->state = DEVICE_INVALID;
+		break;
 	}
 	
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/devman/main.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -1309,10 +1309,11 @@
 
 	/*
-	 * !!! devman_connection ... as the device manager is not a real loc
-	 * driver (it uses a completely different ipc protocol than an ordinary
-	 * loc driver) forwarding a connection from client to the devman by
-	 * location service would not work.
+	 * Caution: As the device manager is not a real loc
+	 * driver (it uses a completely different IPC protocol
+	 * than an ordinary loc driver), forwarding a connection
+	 * from client to the devman by location service will
+	 * not work.
 	 */
-	loc_server_register(NAME, devman_connection);
+	loc_server_register(NAME);
 	
 	return true;
@@ -1325,9 +1326,4 @@
 	if (log_init(NAME, LVL_WARN) != EOK) {
 		printf(NAME ": Error initializing logging subsystem.\n");
-		return -1;
-	}
-
-	if (!devman_init()) {
-		log_msg(LVL_ERROR, "Error while initializing service.");
 		return -1;
 	}
@@ -1338,4 +1334,9 @@
 	async_set_client_connection(devman_connection);
 
+	if (!devman_init()) {
+		log_msg(LVL_ERROR, "Error while initializing service.");
+		return -1;
+	}
+
 	/* Register device manager at naming service. */
 	if (service_register(SERVICE_DEVMAN) != EOK) {
Index: uspace/srv/fs/mfs/mfs.h
===================================================================
--- uspace/srv/fs/mfs/mfs.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/fs/mfs/mfs.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -48,5 +48,5 @@
 #define NAME		"mfs"
 
-//#define DEBUG_MODE
+/* #define DEBUG_MODE */
 
 #define min(a, b)	((a) < (b) ? (a) : (b))
@@ -71,5 +71,5 @@
 } mfs_version_t;
 
-/*Generic MinixFS superblock*/
+/* Generic MinixFS superblock */
 struct mfs_sb_info {
 	uint32_t ninodes;
@@ -84,5 +84,5 @@
 	uint16_t state;
 
-	/*The following fields do not exist on disk but only in memory*/
+	/* The following fields do not exist on disk but only in memory */
 	unsigned long itable_size;
 	mfs_version_t fs_version;
@@ -97,5 +97,5 @@
 };
 
-/*Generic MinixFS inode*/
+/* Generic MinixFS inode */
 struct mfs_ino_info {
 	uint16_t	i_mode;
@@ -107,24 +107,24 @@
 	int32_t		i_mtime;
 	int32_t		i_ctime;
-	/*Block numbers for direct zones*/
+	/* Block numbers for direct zones */
 	uint32_t	i_dzone[V2_NR_DIRECT_ZONES];
-	/*Block numbers for indirect zones*/
+	/* Block numbers for indirect zones */
 	uint32_t	i_izone[V2_NR_INDIRECT_ZONES];
 
-	/*The following fields do not exist on disk but only in memory*/
+	/* The following fields do not exist on disk but only in memory */
 	bool dirty;
 	fs_index_t index;
 };
 
-/*Generic MFS directory entry*/
+/* Generic MFS directory entry */
 struct mfs_dentry_info {
 	uint32_t d_inum;
 	char d_name[MFS3_MAX_NAME_LEN + 1];
 
-	/*The following fields do not exist on disk but only in memory*/
-
-	/*Index of the dentry in the list*/
+	/* The following fields do not exist on disk but only in memory */
+
+	/* Index of the dentry in the list */
 	unsigned index;
-	/*Pointer to the node at witch the dentry belongs*/
+	/* Pointer to the node at witch the dentry belongs */
 	struct mfs_node *node;
 };
@@ -136,5 +136,5 @@
 };
 
-/*MinixFS node in core*/
+/* MinixFS node in core */
 struct mfs_node {
 	struct mfs_ino_info *ino_i;
@@ -145,5 +145,5 @@
 };
 
-/*mfs_ops.c*/
+/* mfs_ops.c */
 extern vfs_out_ops_t mfs_ops;
 extern libfs_ops_t mfs_libfs_ops;
@@ -152,8 +152,8 @@
 mfs_global_init(void);
 
-/*mfs_inode.c*/
+/* mfs_inode.c */
 extern int
 mfs_get_inode(struct mfs_instance *inst, struct mfs_ino_info **ino_i,
-	  fs_index_t index);
+    fs_index_t index);
 
 extern int
@@ -163,5 +163,5 @@
 mfs_inode_shrink(struct mfs_node *mnode, size_t size_shrink);
 
-/*mfs_rw.c*/
+/* mfs_rw.c */
 extern int
 mfs_read_map(uint32_t *b, const struct mfs_node *mnode, const uint32_t pos);
@@ -169,13 +169,13 @@
 extern int
 mfs_write_map(struct mfs_node *mnode, uint32_t pos, uint32_t new_zone,
-	  uint32_t *old_zone);
+    uint32_t *old_zone);
 
 extern int
 mfs_prune_ind_zones(struct mfs_node *mnode, size_t new_size);
 
-/*mfs_dentry.c*/
+/* mfs_dentry.c */
 extern int
 mfs_read_dentry(struct mfs_node *mnode,
-		     struct mfs_dentry_info *d_info, unsigned index);
+    struct mfs_dentry_info *d_info, unsigned index);
 
 extern int
@@ -188,5 +188,5 @@
 mfs_insert_dentry(struct mfs_node *mnode, const char *d_name, fs_index_t d_inum);
 
-/*mfs_balloc.c*/
+/* mfs_balloc.c */
 extern int
 mfs_alloc_inode(struct mfs_instance *inst, uint32_t *inum);
@@ -201,5 +201,5 @@
 mfs_free_zone(struct mfs_instance *inst, uint32_t zone);
 
-/*mfs_utils.c*/
+/* mfs_utils.c */
 extern uint16_t
 conv16(bool native, uint16_t n);
Index: uspace/srv/fs/mfs/mfs_balloc.c
===================================================================
--- uspace/srv/fs/mfs/mfs_balloc.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/fs/mfs/mfs_balloc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -198,5 +198,5 @@
 		limit = sbi->nzones - sbi->firstdatazone - 1;
 	} else {
-		/*bid == BMAP_INODE*/
+		/* bid == BMAP_INODE */
 		search = &sbi->isearch;
 		start_block = 2;
@@ -212,5 +212,5 @@
 	for (i = *search / bits_per_block; i < nblocks; ++i) {
 		r = block_get(&b, inst->service_id, i + start_block,
-			      BLOCK_FLAGS_NONE);
+		    BLOCK_FLAGS_NONE);
 
 		if (r != EOK)
Index: uspace/srv/fs/mfs/mfs_dentry.c
===================================================================
--- uspace/srv/fs/mfs/mfs_dentry.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/fs/mfs/mfs_dentry.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -168,5 +168,5 @@
 		return ENAMETOOLONG;
 
-	/*Search the directory entry to be removed*/
+	/* Search the directory entry to be removed */
 	unsigned i;
 	for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize ; ++i) {
Index: uspace/srv/fs/mfs/mfs_inode.c
===================================================================
--- uspace/srv/fs/mfs/mfs_inode.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/fs/mfs/mfs_inode.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -235,6 +235,6 @@
 
 	r = block_get(&b, mnode->instance->service_id,
-		      itable_off + inum / sbi->ino_per_block,
-		      BLOCK_FLAGS_NONE);
+	    itable_off + inum / sbi->ino_per_block,
+	    BLOCK_FLAGS_NONE);
 
 	if (r != EOK)
@@ -278,6 +278,6 @@
 
 	r = block_get(&b, mnode->instance->service_id,
-		      itable_off + inum / sbi->ino_per_block,
-		      BLOCK_FLAGS_NONE);
+	    itable_off + inum / sbi->ino_per_block,
+	    BLOCK_FLAGS_NONE);
 
 	if (r != EOK)
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -664,4 +664,5 @@
 	struct mfs_node *child = cfn->data;
 	struct mfs_sb_info *sbi = parent->instance->sbi;
+	bool destroy_dentry = false;
 
 	mfsdebug("%s()\n", __FUNCTION__);
@@ -672,17 +673,24 @@
 	int r = mfs_insert_dentry(parent, name, child->ino_i->index);
 	if (r != EOK)
-		goto exit_error;
-
-	child->ino_i->i_nlinks++;
-	child->ino_i->dirty = true;
+		return r;
 
 	if (S_ISDIR(child->ino_i->i_mode)) {
+		if (child->ino_i->i_nlinks != 1) {
+			/* It's not possible to hardlink directories in MFS */
+			destroy_dentry = true;
+			r = EMLINK;
+			goto exit;
+		}
 		r = mfs_insert_dentry(child, ".", child->ino_i->index);
-		if (r != EOK)
-			goto exit_error;
+		if (r != EOK) {
+			destroy_dentry = true;
+			goto exit;
+		}
 
 		r = mfs_insert_dentry(child, "..", parent->ino_i->index);
-		if (r != EOK)
-			goto exit_error;
+		if (r != EOK) {
+			destroy_dentry = true;
+			goto exit;
+		}
 
 		parent->ino_i->i_nlinks++;
@@ -690,5 +698,13 @@
 	}
 
-exit_error:
+exit:
+	if (destroy_dentry) {
+		int r2 = mfs_remove_dentry(parent, name);
+		if (r2 != EOK)
+			r = r2;
+	} else {
+		child->ino_i->i_nlinks++;
+		child->ino_i->dirty = true;
+	}
 	return r;
 }
@@ -821,5 +837,5 @@
 found:
 		async_data_read_finalize(callid, d_info.d_name,
-					 str_size(d_info.d_name) + 1);
+		    str_size(d_info.d_name) + 1);
 		bytes = ((pos - spos) + 1);
 	} else {
Index: uspace/srv/fs/mfs/mfs_rw.c
===================================================================
--- uspace/srv/fs/mfs/mfs_rw.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/fs/mfs/mfs_rw.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -147,5 +147,5 @@
 				ino_i->dirty = true;
 			} else {
-				/*Sparse block*/
+				/* Sparse block */
 				*b = 0;
 				return EOK;
@@ -233,5 +233,5 @@
 }
 
-/**Free unused indirect zones from a MINIX inode according to it's new size.
+/**Free unused indirect zones from a MINIX inode according to its new size.
  *
  * @param mnode		Pointer to a generic MINIX inode in memory.
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/console/console.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -825,5 +825,6 @@
 	
 	/* Register server */
-	int rc = loc_server_register(NAME, client_connection);
+	async_set_client_connection(client_connection);
+	int rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf("%s: Unable to register server (%s)\n", NAME,
Index: uspace/srv/hid/fb/fb.c
===================================================================
--- uspace/srv/hid/fb/fb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/fb/fb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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);
@@ -989,5 +987,6 @@
 	
 	/* Register server */
-	int rc = loc_server_register(NAME, client_connection);
+	async_set_client_connection(client_connection);
+	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
 		printf("%s: Unable to register driver (%d)\n", NAME, rc);
Index: uspace/srv/hid/fb/port/ega.c
===================================================================
--- uspace/srv/hid/fb/port/ega.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/fb/port/ega.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/fb/port/kchar.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/fb/port/kfb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/fb/port/niagara.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/Makefile
===================================================================
--- uspace/srv/hid/input/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -43,5 +43,4 @@
 	port/adb_mouse.c \
 	port/chardev.c \
-	port/chardev_mouse.c \
 	port/gxemul.c \
 	port/msim.c \
@@ -52,5 +51,4 @@
 	proto/adb.c \
 	proto/mousedev.c \
-	proto/ps2.c \
 	ctl/apple.c \
 	ctl/gxe_fb.c \
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/generic/input.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -39,4 +39,5 @@
 #include <adt/list.h>
 #include <bool.h>
+#include <fibril_synch.h>
 #include <ipc/services.h>
 #include <ipc/input.h>
@@ -83,4 +84,6 @@
 async_sess_t *irc_sess = NULL;
 
+static FIBRIL_MUTEX_INITIALIZE(discovery_lock);
+
 void kbd_push_data(kbd_dev_t *kdev, sysarg_t data)
 {
@@ -172,8 +175,17 @@
 
 /** Mouse pointer has moved. */
-void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy)
+void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy, int dz)
 {
 	async_exch_t *exch = async_exchange_begin(client_sess);
-	async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
+	if (dx || dy)
+		async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
+	if (dz) {
+		// TODO: Implement proper wheel support
+		keycode_t code = dz > 0 ? KC_UP : KC_DOWN;
+		for (int i = 0; i < 3; ++i) {
+			async_msg_4(exch, INPUT_EVENT_KEY, KEY_PRESS, code, 0, 0);
+		}
+		async_msg_4(exch, INPUT_EVENT_KEY, KEY_RELEASE, code, 0, 0);
+	}
 	async_exchange_end(exch);
 }
@@ -397,7 +409,4 @@
 	 * them automatically.
 	 */
-#if defined(UARCH_amd64)
-	kbd_add_dev(&chardev_port, &pc_ctl);
-#endif
 #if defined(UARCH_arm32) && defined(MACHINE_gta02)
 	kbd_add_dev(&chardev_port, &stty_ctl);
@@ -411,10 +420,4 @@
 #if defined(UARCH_arm32) && defined(MACHINE_integratorcp)
 	kbd_add_dev(&pl050_port, &pc_ctl);
-#endif
-#if defined(UARCH_ia32)
-	kbd_add_dev(&chardev_port, &pc_ctl);
-#endif
-#if defined(MACHINE_i460GX)
-	kbd_add_dev(&chardev_port, &pc_ctl);
 #endif
 #if defined(MACHINE_ski)
@@ -450,13 +453,4 @@
 	 * them automatically.
 	 */
-#if defined(UARCH_amd64)
-	mouse_add_dev(&chardev_mouse_port, &ps2_proto);
-#endif
-#if defined(UARCH_ia32)
-	mouse_add_dev(&chardev_mouse_port, &ps2_proto);
-#endif
-#if defined(MACHINE_i460GX)
-	mouse_add_dev(&chardev_mouse_port, &ps2_proto);
-#endif
 #if defined(UARCH_ppc32)
 	mouse_add_dev(&adb_mouse_port, &adb_proto);
@@ -602,12 +596,20 @@
 	int rc;
 	
+	fibril_mutex_lock(&discovery_lock);
+	
 	rc = dev_check_new_kbdevs();
-	if (rc != EOK)
+	if (rc != EOK) {
+		fibril_mutex_unlock(&discovery_lock);
 		return rc;
+	}
 	
 	rc = dev_check_new_mousedevs();
-	if (rc != EOK)
+	if (rc != EOK) {
+		fibril_mutex_unlock(&discovery_lock);
 		return rc;
-
+	}
+	
+	fibril_mutex_unlock(&discovery_lock);
+	
 	return EOK;
 }
@@ -658,5 +660,6 @@
 	
 	/* Register driver */
-	int rc = loc_server_register(NAME, client_connection);
+	async_set_client_connection(client_connection);
+	int rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf("%s: Unable to register server (%d)\n", NAME, rc);
Index: uspace/srv/hid/input/include/mouse.h
===================================================================
--- uspace/srv/hid/input/include/mouse.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/include/mouse.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -62,5 +62,5 @@
 
 extern void mouse_push_data(mouse_dev_t *, sysarg_t);
-extern void mouse_push_event_move(mouse_dev_t *, int, int);
+extern void mouse_push_event_move(mouse_dev_t *, int, int, int);
 extern void mouse_push_event_button(mouse_dev_t *, int, int);
 
Index: uspace/srv/hid/input/include/mouse_proto.h
===================================================================
--- uspace/srv/hid/input/include/mouse_proto.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/include/mouse_proto.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -48,5 +48,4 @@
 
 extern mouse_proto_ops_t adb_proto;
-extern mouse_proto_ops_t ps2_proto;
 extern mouse_proto_ops_t mousedev_proto;
 
Index: uspace/srv/hid/input/port/chardev.c
===================================================================
--- uspace/srv/hid/input/port/chardev.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/port/chardev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -63,5 +63,4 @@
 /** List of devices to try connecting to. */
 static const char *in_devs[] = {
-	"char/ps2a",
 	"char/s3c24ser"
 };
Index: pace/srv/hid/input/port/chardev_mouse.c
===================================================================
--- uspace/srv/hid/input/port/chardev_mouse.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(revision )
@@ -1,157 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup mouse_port
- * @ingroup mouse
- * @{
- */
-/** @file
- * @brief Chardev mouse port driver.
- */
-
-#include <ipc/char.h>
-#include <stdio.h>
-#include <async.h>
-#include <errno.h>
-#include <loc.h>
-#include <input.h>
-#include <mouse_port.h>
-#include <mouse.h>
-
-static mouse_dev_t *mouse_dev;
-static async_sess_t *dev_sess;
-
-/** List of devices to try connecting to. */
-static const char *in_devs[] = {
-	"char/ps2b",
-};
-
-static const unsigned int num_devs = sizeof(in_devs) / sizeof(in_devs[0]);
-
-static void mouse_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	/* Ignore parameters, the connection is already opened */
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			/* TODO: Handle hangup */
-			return;
-		}
-		
-		int retval;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case CHAR_NOTIF_BYTE:
-			mouse_push_data(mouse_dev, IPC_GET_ARG1(call));
-			break;
-		default:
-			retval = ENOENT;
-		}
-		
-		async_answer_0(callid, retval);
-	}
-}
-
-static int chardev_port_init(mouse_dev_t *mdev)
-{
-	service_id_t service_id;
-	unsigned int i;
-	int rc;
-	
-	mouse_dev = mdev;
-	
-	for (i = 0; i < num_devs; i++) {
-		rc = loc_service_get_id(in_devs[i], &service_id, 0);
-		if (rc == EOK)
-			break;
-	}
-	
-	if (i >= num_devs) {
-		printf("%s: Could not find any suitable input device\n", NAME);
-		return -1;
-	}
-	
-	dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id,
-	    IPC_FLAG_BLOCKING);
-	if (dev_sess == NULL) {
-		printf("%s: Failed connecting to device\n", NAME);
-		return ENOENT;
-	}
-	
-	async_exch_t *exch = async_exchange_begin(dev_sess);
-	if (exch == NULL) {
-		printf("%s: Failed starting exchange with device\n", NAME);
-		async_hangup(dev_sess);
-		return ENOMEM;
-	}
-	
-	/* NB: The callback connection is slotted for removal */
-	rc = async_connect_to_me(exch, 0, 0, 0, mouse_port_events, NULL);
-	async_exchange_end(exch);
-	
-	if (rc != 0) {
-		printf("%s: Failed to create callback from device\n", NAME);
-		async_hangup(dev_sess);
-		return -1;
-	}
-	
-	return 0;
-}
-
-static void chardev_port_yield(void)
-{
-}
-
-static void chardev_port_reclaim(void)
-{
-}
-
-static void chardev_port_write(uint8_t data)
-{
-	async_exch_t *exch = async_exchange_begin(dev_sess);
-	if (exch == NULL) {
-		printf("%s: Failed starting exchange with device\n", NAME);
-		return;
-	}
-
-	async_msg_1(exch, CHAR_WRITE_BYTE, data);
-	async_exchange_end(exch);
-}
-
-mouse_port_ops_t chardev_mouse_port = {
-	.init = chardev_port_init,
-	.yield = chardev_port_yield,
-	.reclaim = chardev_port_reclaim,
-	.write = chardev_port_write
-};
-
-/**
- * @}
- */
Index: uspace/srv/hid/input/port/gxemul.c
===================================================================
--- uspace/srv/hid/input/port/gxemul.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/port/gxemul.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/port/msim.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/port/niagara.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/port/ns16550.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/port/pl050.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/input/proto/adb.c
===================================================================
--- uspace/srv/hid/input/proto/adb.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/proto/adb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -82,5 +82,5 @@
 	
 	if (dx != 0 || dy != 0)
-		mouse_push_event_move(mouse_dev, dx, dy);
+		mouse_push_event_move(mouse_dev, dx, dy, 0);
 }
 
Index: uspace/srv/hid/input/proto/mousedev.c
===================================================================
--- uspace/srv/hid/input/proto/mousedev.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/input/proto/mousedev.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -91,11 +91,12 @@
 		switch (IPC_GET_IMETHOD(call)) {
 		case MOUSEEV_MOVE_EVENT:
-			mouse_push_event_move(mousedev->mouse_dev, IPC_GET_ARG1(call),
-			    IPC_GET_ARG2(call));
+			mouse_push_event_move(mousedev->mouse_dev,
+			    IPC_GET_ARG1(call), IPC_GET_ARG2(call),
+			    IPC_GET_ARG3(call));
 			retval = EOK;
 			break;
 		case MOUSEEV_BUTTON_EVENT:
-			mouse_push_event_button(mousedev->mouse_dev, IPC_GET_ARG1(call),
-			    IPC_GET_ARG2(call));
+			mouse_push_event_button(mousedev->mouse_dev,
+			    IPC_GET_ARG1(call), IPC_GET_ARG2(call));
 			retval = EOK;
 			break;
Index: pace/srv/hid/input/proto/ps2.c
===================================================================
--- uspace/srv/hid/input/proto/ps2.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(revision )
@@ -1,139 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup mouse_proto
- * @ingroup input
- * @{
- */
-/**
- * @file
- * @brief PS/2 protocol driver.
- */
-
-#include <mouse.h>
-#include <mouse_port.h>
-#include <mouse_proto.h>
-
-#define PS2_MOUSE_OUT_INIT  0xf4
-#define PS2_MOUSE_ACK       0xfa
-
-#define BUFSIZE 3
-
-typedef struct {
-	union {
-		unsigned char data[BUFSIZE];
-		struct {
-			unsigned int leftbtn : 1;
-			unsigned int rightbtn : 1;
-			unsigned int middlebtn : 1;
-			unsigned int isone : 1; /* Always one */
-			unsigned int xsign : 1;
-			unsigned int ysign : 1;
-			unsigned int xovfl : 1;
-			unsigned int yovfl : 1;
-			unsigned char x;
-			unsigned char y;
-		} val;
-	} u;
-} ps2packet_t;
-
-static ps2packet_t buf;
-static unsigned int bufpos;
-static unsigned int leftbtn;
-static unsigned int rightbtn;
-static unsigned int middlebtn;
-
-static mouse_dev_t *mouse_dev;
-
-static int ps2_proto_init(mouse_dev_t *mdev)
-{
-	mouse_dev = mdev;
-	bufpos = 0;
-	leftbtn = 0;
-	rightbtn = 0;
-	
-	mouse_dev->port_ops->write(PS2_MOUSE_OUT_INIT);
-	return 0;
-}
-
-/** Convert 9-bit 2-complement signed number to integer */
-static int bit9toint(int sign, unsigned char data)
-{
-	int tmp;
-	
-	if (!sign)
-		return data;
-	
-	tmp = ((unsigned char) ~data) + 1;
-	return -tmp;
-}
-
-/** Process mouse data */
-static void ps2_proto_parse(sysarg_t data)
-{
-	int x, y;
-	
-	/* Check that we have not lost synchronization */
-	if (bufpos == 0 && !(data & 0x8))
-		return; /* Synchro lost, ignore byte */
-	
-	buf.u.data[bufpos++] = data;
-	if (bufpos == BUFSIZE) {
-		bufpos = 0;
-		
-		if (buf.u.val.leftbtn ^ leftbtn) {
-			leftbtn = buf.u.val.leftbtn;
-			mouse_push_event_button(mouse_dev, 1, leftbtn);
-		}
-		
-		if (buf.u.val.rightbtn ^ rightbtn) {
-			rightbtn = buf.u.val.rightbtn;
-			mouse_push_event_button(mouse_dev, 2, rightbtn);
-		}
-		
-		if (buf.u.val.middlebtn ^ middlebtn) {
-			middlebtn = buf.u.val.middlebtn;
-			mouse_push_event_button(mouse_dev, 3, middlebtn);
-		}
-		
-		x = bit9toint(buf.u.val.xsign, buf.u.val.x);
-		y = -bit9toint(buf.u.val.ysign, buf.u.val.y);
-		
-		if (x != 0 || y != 0)
-			mouse_push_event_move(mouse_dev, x, y);
-	}
-}
-
-mouse_proto_ops_t ps2_proto = {
-	.parse = ps2_proto_parse,
-	.init = ps2_proto_init
-};
-
-/**
- * @}
- */
Index: uspace/srv/hid/remcons/Makefile
===================================================================
--- uspace/srv/hid/remcons/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/hid/remcons/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2012 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+BINARY = remcons
+
+SOURCES = \
+	remcons.c \
+	user.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/hid/remcons/remcons.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2012 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 remcons
+ * @{
+ */
+/** @file
+ */
+
+#include <async.h>
+#include <stdio.h>
+#include <adt/prodcons.h>
+#include <ipc/input.h>
+#include <ipc/console.h>
+#include <ipc/vfs.h>
+#include <errno.h>
+#include <str_error.h>
+#include <loc.h>
+#include <event.h>
+#include <io/keycode.h>
+#include <align.h>
+#include <malloc.h>
+#include <as.h>
+#include <fibril_synch.h>
+#include <task.h>
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
+#include <io/console.h>
+#include <inttypes.h>
+#include "telnet.h"
+#include "user.h"
+
+#define APP_GETTERM  "/app/getterm"
+#define APP_SHELL "/app/bdsh"
+
+/** Telnet commands to force character mode
+ * (redundant to be on the safe side).
+ * See
+ * http://stackoverflow.com/questions/273261/force-telnet-user-into-character-mode
+ * for discussion.
+ */
+static const telnet_cmd_t telnet_force_character_mode_command[] = {
+	TELNET_IAC, TELNET_WILL, TELNET_ECHO,
+	TELNET_IAC, TELNET_WILL, TELNET_SUPPRESS_GO_AHEAD,
+	TELNET_IAC, TELNET_WONT, TELNET_LINEMODE
+};
+static const size_t telnet_force_character_mode_command_count =
+    sizeof(telnet_force_character_mode_command) / sizeof(telnet_cmd_t);
+
+
+/** Handling client requests (VFS and console interface).
+ *
+ * @param user Telnet user the requests belong to.
+ */
+static void client_connection_message_loop(telnet_user_t *user)
+{
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = 0;
+
+		/*
+		 * The getterm task might terminate while we are here,
+		 * waiting for a call. Also, the socket might be closed
+		 * meanwhile.
+		 * We want to detect this situation early, so we use a
+		 * timeout variant of async_get_call().
+		 */
+		while (callid == 0) {
+			callid = async_get_call_timeout(&call, 1000);
+
+			if (telnet_user_is_zombie(user)) {
+				if (callid != 0) {
+					async_answer_0(callid, EINTR);
+				}
+				return;
+			}
+		}
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			return;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case CONSOLE_GET_SIZE:
+			async_answer_2(callid, EOK, 100, 1);
+			break;
+		case CONSOLE_GET_POS:
+			fibril_mutex_lock(&user->guard);
+			async_answer_2(callid, EOK, user->cursor_x, 0);
+			fibril_mutex_unlock(&user->guard);
+			break;
+		case CONSOLE_GET_EVENT: {
+			kbd_event_t event;
+			int rc = telnet_user_get_next_keyboard_event(user, &event);
+			if (rc != EOK) {
+				/* Silently ignore. */
+				async_answer_0(callid, EOK);
+				break;
+			}
+			async_answer_4(callid, EOK, event.type, event.key, event.mods, event.c);
+			break;
+		}
+		case CONSOLE_GOTO: {
+			int new_x = IPC_GET_ARG1(call);
+			telnet_user_update_cursor_x(user, new_x);
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+		case VFS_OUT_READ:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		case VFS_OUT_WRITE: {
+			uint8_t *buf;
+			size_t size;
+			int rc = async_data_write_accept((void **)&buf, false, 0, 0, 0, &size);
+
+			if (rc != EOK) {
+				async_answer_0(callid, rc);
+				break;
+			}
+
+			rc = telnet_user_send_data(user, buf, size);
+			free(buf);
+
+			if (rc != EOK) {
+				async_answer_0(callid, rc);
+				break;
+			}
+
+			async_answer_1(callid, EOK, size);
+			break;
+		}
+		case VFS_OUT_SYNC:
+			async_answer_0(callid, EOK);
+			break;
+		case CONSOLE_CLEAR:
+			async_answer_0(callid, EOK);
+			break;
+
+		case CONSOLE_GET_COLOR_CAP:
+			async_answer_1(callid, EOK, CONSOLE_CAP_NONE);
+			break;
+		case CONSOLE_SET_STYLE:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		case CONSOLE_SET_COLOR:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		case CONSOLE_SET_RGB_COLOR:
+			async_answer_0(callid, ENOTSUP);
+			break;
+
+		case CONSOLE_CURSOR_VISIBILITY:
+			async_answer_0(callid, ENOTSUP);
+			break;
+
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+}
+
+/** Callback when client connects to a telnet terminal. */
+static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	/* Find the user. */
+	telnet_user_t *user = telnet_user_get_for_client_connection(IPC_GET_ARG1(*icall));
+	if (user == NULL) {
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	async_answer_0(iid, EOK);
+
+	telnet_user_log(user, "New client connected (%" PRIxn").", iid);
+
+	/* Force character mode. */
+	send(user->socket, (void *)telnet_force_character_mode_command,
+	    telnet_force_character_mode_command_count, 0);
+
+	/* Handle messages. */
+	client_connection_message_loop(user);
+
+	telnet_user_notify_client_disconnected(user);
+	telnet_user_log(user, "Client disconnected (%" PRIxn").", iid);
+}
+
+/** Fibril for spawning the task running after user connects.
+ *
+ * @param arg Corresponding @c telnet_user_t structure.
+ */
+static int spawn_task_fibril(void *arg)
+{
+	telnet_user_t *user = arg;
+	int rc;
+
+	char term[LOC_NAME_MAXLEN];
+	snprintf(term, LOC_NAME_MAXLEN, "%s/%s", "/loc", user->service_name);
+
+	task_id_t task;
+	rc = task_spawnl(&task, APP_GETTERM, APP_GETTERM, "-w", term, APP_SHELL, NULL);
+	if (rc != EOK) {
+		telnet_user_error(user, "Spawning `%s -w %s %s' failed: %s.",
+		    APP_GETTERM, term, APP_SHELL, str_error(rc));
+		fibril_mutex_lock(&user->guard);
+		user->task_finished = true;
+		fibril_condvar_signal(&user->refcount_cv);
+		fibril_mutex_unlock(&user->guard);
+		return EOK;
+	}
+
+	fibril_mutex_lock(&user->guard);
+	user->task_id = task;
+	fibril_mutex_unlock(&user->guard);
+
+	task_exit_t task_exit;
+	int task_retval;
+	task_wait(task, &task_exit, &task_retval);
+	telnet_user_log(user, "%s terminated %s, exit code %d.", APP_GETTERM,
+	    task_exit == TASK_EXIT_NORMAL ? "normally" : "unexpectedly",
+	    task_retval);
+
+	/* Announce destruction. */
+	fibril_mutex_lock(&user->guard);
+	user->task_finished = true;
+	fibril_condvar_signal(&user->refcount_cv);
+	fibril_mutex_unlock(&user->guard);
+
+	return EOK;
+}
+
+/** Tell whether given user can be destroyed (has no active clients).
+ *
+ * @param user The telnet user in question.
+ */
+static bool user_can_be_destroyed_no_lock(telnet_user_t *user)
+{
+	return user->task_finished && user->socket_closed &&
+	    (user->locsrv_connection_count == 0);
+}
+
+/** Fibril for each accepted socket.
+ *
+ * @param arg Corresponding @c telnet_user_t structure.
+ */
+static int network_user_fibril(void *arg)
+{
+	int rc;
+	telnet_user_t *user = arg;
+
+	rc = loc_service_register(user->service_name, &user->service_id);
+	if (rc != EOK) {
+		telnet_user_error(user, "Unable to register %s with loc: %s.",
+		    user->service_name, str_error(rc));
+		return EOK;
+	}
+
+	telnet_user_log(user, "Service %s registerd with id %" PRIun ".",
+	    user->service_name, user->service_id);
+
+	fid_t spawn_fibril = fibril_create(spawn_task_fibril, user);
+	assert(spawn_fibril);
+	fibril_add_ready(spawn_fibril);
+
+	/* Wait for all clients to exit. */
+	fibril_mutex_lock(&user->guard);
+	while (!user_can_be_destroyed_no_lock(user)) {
+		if (user->task_finished) {
+			closesocket(user->socket);
+			user->socket_closed = true;
+			continue;
+		} else if (user->socket_closed) {
+			if (user->task_id != 0) {
+				task_kill(user->task_id);
+			}
+		}
+		fibril_condvar_wait_timeout(&user->refcount_cv, &user->guard, 1000);
+	}
+	fibril_mutex_unlock(&user->guard);
+
+	rc = loc_service_unregister(user->service_id);
+	if (rc != EOK) {
+		telnet_user_error(user,
+		    "Unable to unregister %s from loc: %s (ignored).",
+		    user->service_name, str_error(rc));
+	}
+
+	telnet_user_log(user, "Destroying...");
+	telnet_user_destroy(user);
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	int port = 2223;
+	
+	async_set_client_connection(client_connection);
+	int rc = loc_server_register(NAME);
+	if (rc < 0) {
+		fprintf(stderr, NAME ": Unable to register server: %s.\n",
+		    str_error(rc));
+		return 1;
+	}
+
+	struct sockaddr_in addr;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+
+	rc = inet_pton(AF_INET, "127.0.0.1", (void *)
+	    &addr.sin_addr.s_addr);
+	if (rc != EOK) {
+		fprintf(stderr, "Error parsing network address: %s.\n",
+		    str_error(rc));
+		return 2;
+	}
+
+	int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
+	if (listen_sd < 0) {
+		fprintf(stderr, "Error creating listening socket: %s.\n",
+		    str_error(listen_sd));
+		return 3;
+	}
+
+	rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
+	if (rc != EOK) {
+		fprintf(stderr, "Error binding socket: %s.\n",
+		    str_error(rc));
+		return 4;
+	}
+
+	rc = listen(listen_sd, BACKLOG_SIZE);
+	if (rc != EOK) {
+		fprintf(stderr, "listen() failed: %s.\n", str_error(rc));
+		return 5;
+	}
+
+	printf("%s: HelenOS Remote console service\n", NAME);
+
+	while (true) {
+		struct sockaddr_in raddr;
+		socklen_t raddr_len = sizeof(raddr);
+		int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
+		    &raddr_len);
+
+		if (conn_sd < 0) {
+			fprintf(stderr, "accept() failed: %s.\n",
+			    str_error(rc));
+			continue;
+		}
+
+		telnet_user_t *user = telnet_user_create(conn_sd);
+		assert(user);
+
+		fid_t fid = fibril_create(network_user_fibril, user);
+		assert(fid);
+		fibril_add_ready(fid);
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/srv/hid/remcons/remcons.h
===================================================================
--- uspace/srv/hid/remcons/remcons.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/hid/remcons/remcons.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 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 remcons
+ * @{
+ */
+/** @file
+ */
+
+#ifndef REMCONS_H_
+#define REMCONS_H_
+
+#define NAME       "remcons"
+#define NAMESPACE  "term"
+#define BACKLOG_SIZE  5
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/remcons/telnet.h
===================================================================
--- uspace/srv/hid/remcons/telnet.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/hid/remcons/telnet.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 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 remcons
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TELNET_H_
+#define TELNET_H_
+
+#include <inttypes.h>
+
+typedef uint8_t telnet_cmd_t;
+
+/*
+ * Telnet commands.
+ */
+
+#define TELNET_IAC 255
+
+#define TELNET_WILL 251
+#define TELNET_WONT 252
+#define TELNET_DO 253
+#define TELNET_DONT 254
+
+#define TELNET_IS_OPTION_CODE(code) (((code) >= 251) && ((code) <= 254))
+
+#define TELNET_ECHO 1
+#define TELNET_SUPPRESS_GO_AHEAD 3
+#define TELNET_LINEMODE 34
+
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/remcons/user.c
===================================================================
--- uspace/srv/hid/remcons/user.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/hid/remcons/user.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2012 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 remcons
+ * @{
+ */
+/** @file
+ */
+#include <async.h>
+#include <stdio.h>
+#include <adt/prodcons.h>
+#include <ipc/input.h>
+#include <ipc/console.h>
+#include <ipc/vfs.h>
+#include <errno.h>
+#include <str_error.h>
+#include <loc.h>
+#include <event.h>
+#include <io/keycode.h>
+#include <align.h>
+#include <malloc.h>
+#include <as.h>
+#include <fibril_synch.h>
+#include <task.h>
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
+#include <io/console.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "user.h"
+#include "telnet.h"
+
+static FIBRIL_MUTEX_INITIALIZE(users_guard);
+static LIST_INITIALIZE(users);
+
+/** Create new telnet user.
+ *
+ * @param socket Socket the user communicates through.
+ * @return New telnet user or NULL when out of memory.
+ */
+telnet_user_t *telnet_user_create(int socket)
+{
+	static int telnet_user_id_counter = 0;
+
+	telnet_user_t *user = malloc(sizeof(telnet_user_t));
+	if (user == NULL) {
+		return NULL;
+	}
+
+	user->id = ++telnet_user_id_counter;
+
+	int rc = asprintf(&user->service_name, "%s/telnet%d", NAMESPACE, user->id);
+	if (rc < 0) {
+		free(user);
+		return NULL;
+	}
+
+	user->socket = socket;
+	user->service_id = (service_id_t) -1;
+	prodcons_initialize(&user->in_events);
+	link_initialize(&user->link);
+	user->socket_buffer_len = 0;
+	user->socket_buffer_pos = 0;
+
+	fibril_condvar_initialize(&user->refcount_cv);
+	fibril_mutex_initialize(&user->guard);
+	user->task_finished = false;
+	user->socket_closed = false;
+	user->locsrv_connection_count = 0;
+
+
+	fibril_mutex_lock(&users_guard);
+	list_append(&user->link, &users);
+	fibril_mutex_unlock(&users_guard);
+
+	user->cursor_x = 0;
+
+	return user;
+}
+
+/** Destroy telnet user structure.
+ *
+ * @param user User to be destroyed.
+ */
+void telnet_user_destroy(telnet_user_t *user)
+{
+	assert(user);
+
+	fibril_mutex_lock(&users_guard);
+	list_remove(&user->link);
+	fibril_mutex_unlock(&users_guard);
+
+	free(user);
+}
+
+/** Find user by service id and increments reference counter.
+ *
+ * @param id Location service id of the telnet user's terminal.
+ */
+telnet_user_t *telnet_user_get_for_client_connection(service_id_t id)
+{
+	telnet_user_t *user = NULL;
+
+	fibril_mutex_lock(&users_guard);
+	list_foreach(users, link) {
+		telnet_user_t *tmp = list_get_instance(link, telnet_user_t, link);
+		if (tmp->service_id == id) {
+			user = tmp;
+			break;
+		}
+	}
+	if (user == NULL) {
+		fibril_mutex_unlock(&users_guard);
+		return NULL;
+	}
+
+	telnet_user_t *tmp = user;
+	fibril_mutex_lock(&tmp->guard);
+	user->locsrv_connection_count++;
+
+	/*
+	 * Refuse to return user whose task already finished or when
+	 * the socket is already closed().
+	 */
+	if (user->task_finished || user->socket_closed) {
+		user = NULL;
+		user->locsrv_connection_count--;
+	}
+
+	fibril_mutex_unlock(&tmp->guard);
+
+
+	fibril_mutex_unlock(&users_guard);
+
+	return user;
+}
+
+/** Notify that client disconnected from the remote terminal.
+ *
+ * @param user To which user the client was connected.
+ */
+void telnet_user_notify_client_disconnected(telnet_user_t *user)
+{
+	fibril_mutex_lock(&user->guard);
+	assert(user->locsrv_connection_count > 0);
+	user->locsrv_connection_count--;
+	fibril_condvar_signal(&user->refcount_cv);
+	fibril_mutex_unlock(&user->guard);
+}
+
+/** Tell whether the launched task already exited and socket is already closed.
+ *
+ * @param user Telnet user in question.
+ */
+bool telnet_user_is_zombie(telnet_user_t *user)
+{
+	fibril_mutex_lock(&user->guard);
+	bool zombie = user->socket_closed || user->task_finished;
+	fibril_mutex_unlock(&user->guard);
+
+	return zombie;
+}
+
+/** Receive next byte from a socket (use buffering.
+ * We need to return the value via extra argument because the read byte
+ * might be negative.
+ */
+static int telnet_user_recv_next_byte_no_lock(telnet_user_t *user, char *byte)
+{
+	/* No more buffered data? */
+	if (user->socket_buffer_len <= user->socket_buffer_pos) {
+		int recv_length = recv(user->socket, user->socket_buffer, BUFFER_SIZE, 0);
+		if ((recv_length == 0) || (recv_length == ENOTCONN)) {
+			user->socket_closed = true;
+			return ENOENT;
+		}
+		if (recv_length < 0) {
+			return recv_length;
+		}
+		user->socket_buffer_len = recv_length;
+		user->socket_buffer_pos = 0;
+	}
+
+	*byte = user->socket_buffer[user->socket_buffer_pos++];
+
+	return EOK;
+}
+
+/** Creates new keyboard event from given char.
+ *
+ * @param type Event type (press / release).
+ * @param c Pressed character.
+ */
+static kbd_event_t* new_kbd_event(kbd_event_type_t type, wchar_t c) {
+	kbd_event_t *event = malloc(sizeof(kbd_event_t));
+	assert(event);
+
+	link_initialize(&event->link);
+	event->type = type;
+	event->c = c;
+	event->mods = 0;
+
+	switch (c) {
+	case '\n':
+		event->key = KC_ENTER;
+		break;
+	case '\t':
+		event->key = KC_TAB;
+		break;
+	case '\b':
+	case 127: /* This is what Linux telnet sends. */
+		event->key = KC_BACKSPACE;
+		event->c = '\b';
+		break;
+	default:
+		event->key = KC_A;
+		break;
+	}
+
+	return event;
+}
+
+/** Process telnet command (currently only print to screen).
+ *
+ * @param user Telnet user structure.
+ * @param option_code Command option code.
+ * @param cmd Telnet command.
+ */
+static void process_telnet_command(telnet_user_t *user,
+    telnet_cmd_t option_code, telnet_cmd_t cmd)
+{
+	if (option_code != 0) {
+		telnet_user_log(user, "Ignoring telnet command %u %u %u.",
+		    TELNET_IAC, option_code, cmd);
+	} else {
+		telnet_user_log(user, "Ignoring telnet command %u %u.",
+		    TELNET_IAC, cmd);
+	}
+}
+
+/** Get next keyboard event.
+ *
+ * @param user Telnet user.
+ * @param event Where to store the keyboard event.
+ * @return Error code.
+ */
+int telnet_user_get_next_keyboard_event(telnet_user_t *user, kbd_event_t *event)
+{
+	fibril_mutex_lock(&user->guard);
+	if (list_empty(&user->in_events.list)) {
+		char next_byte = 0;
+		bool inside_telnet_command = false;
+
+		telnet_cmd_t telnet_option_code = 0;
+
+		/* Skip zeros, bail-out on error. */
+		while (next_byte == 0) {
+			int rc = telnet_user_recv_next_byte_no_lock(user, &next_byte);
+			if (rc != EOK) {
+				fibril_mutex_unlock(&user->guard);
+				return rc;
+			}
+			uint8_t byte = (uint8_t) next_byte;
+
+			/* Skip telnet commands. */
+			if (inside_telnet_command) {
+				inside_telnet_command = false;
+				next_byte = 0;
+				if (TELNET_IS_OPTION_CODE(byte)) {
+					telnet_option_code = byte;
+					inside_telnet_command = true;
+				} else {
+					process_telnet_command(user,
+					    telnet_option_code, byte);
+				}
+			}
+			if (byte == TELNET_IAC) {
+				inside_telnet_command = true;
+				next_byte = 0;
+			}
+		}
+
+		/* CR-LF conversions. */
+		if (next_byte == 13) {
+			next_byte = 10;
+		}
+
+		kbd_event_t *down = new_kbd_event(KEY_PRESS, next_byte);
+		kbd_event_t *up = new_kbd_event(KEY_RELEASE, next_byte);
+		assert(down);
+		assert(up);
+		prodcons_produce(&user->in_events, &down->link);
+		prodcons_produce(&user->in_events, &up->link);
+	}
+
+	link_t *link = prodcons_consume(&user->in_events);
+	kbd_event_t *tmp = list_get_instance(link, kbd_event_t, link);
+
+	fibril_mutex_unlock(&user->guard);
+
+	*event = *tmp;
+
+	free(tmp);
+
+	return EOK;
+}
+
+/** Send data (convert them first) to the socket, no locking.
+ *
+ * @param user Telnet user.
+ * @param data Data buffer (not zero terminated).
+ * @param size Size of @p data buffer in bytes.
+ */
+static int telnet_user_send_data_no_lock(telnet_user_t *user, uint8_t *data, size_t size)
+{
+	uint8_t *converted = malloc(3 * size + 1);
+	assert(converted);
+	int converted_size = 0;
+
+	/* Convert new-lines. */
+	for (size_t i = 0; i < size; i++) {
+		if (data[i] == 10) {
+			converted[converted_size++] = 13;
+			converted[converted_size++] = 10;
+			user->cursor_x = 0;
+		} else {
+			converted[converted_size++] = data[i];
+			if (data[i] == '\b') {
+				user->cursor_x--;
+			} else {
+				user->cursor_x++;
+			}
+		}
+	}
+
+
+	int rc = send(user->socket, converted, converted_size, 0);
+	free(converted);
+
+	return rc;
+}
+
+/** Send data (convert them first) to the socket.
+ *
+ * @param user Telnet user.
+ * @param data Data buffer (not zero terminated).
+ * @param size Size of @p data buffer in bytes.
+ */
+int telnet_user_send_data(telnet_user_t *user, uint8_t *data, size_t size)
+{
+	fibril_mutex_lock(&user->guard);
+
+	int rc = telnet_user_send_data_no_lock(user, data, size);
+
+	fibril_mutex_unlock(&user->guard);
+
+	return rc;
+}
+
+/** Update cursor X position.
+ *
+ * This call may result in sending control commands over socket.
+ *
+ * @param user Telnet user.
+ * @param new_x New cursor location.
+ */
+void telnet_user_update_cursor_x(telnet_user_t *user, int new_x)
+{
+	fibril_mutex_lock(&user->guard);
+	if (user->cursor_x - 1 == new_x) {
+		uint8_t data = '\b';
+		/* Ignore errors. */
+		telnet_user_send_data_no_lock(user, &data, 1);
+	}
+	user->cursor_x = new_x;
+	fibril_mutex_unlock(&user->guard);
+
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/remcons/user.h
===================================================================
--- uspace/srv/hid/remcons/user.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/hid/remcons/user.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012 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 remcons
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TELNET_USER_H_
+#define TELNET_USER_H_
+
+#include <fibril_synch.h>
+#include <inttypes.h>
+#include "remcons.h"
+
+#define BUFFER_SIZE 32
+
+/** Representation of a connected (human) user. */
+typedef struct {
+	/** Mutex guarding the whole structure. */
+	fibril_mutex_t guard;
+
+	/** Internal id, used for creating locfs entries. */
+	int id;
+	/** Associated socket. */
+	int socket;
+	/** Location service id assigned to the virtual terminal. */
+	service_id_t service_id;
+	/** Path name of the service. */
+	char *service_name;
+
+	/** Producer-consumer of kbd_event_t. */
+	prodcons_t in_events;
+	link_t link;
+	char socket_buffer[BUFFER_SIZE];
+	size_t socket_buffer_len;
+	size_t socket_buffer_pos;
+
+	/** Task id of the launched application. */
+	task_id_t task_id;
+
+	/* Reference counting. */
+	fibril_condvar_t refcount_cv;
+	bool task_finished;
+	int locsrv_connection_count;
+	bool socket_closed;
+
+	/** X position of the cursor. */
+	int cursor_x;
+} telnet_user_t;
+
+telnet_user_t *telnet_user_create(int socket);
+void telnet_user_destroy(telnet_user_t *user);
+telnet_user_t *telnet_user_get_for_client_connection(service_id_t id);
+bool telnet_user_is_zombie(telnet_user_t *user);
+void telnet_user_notify_client_disconnected(telnet_user_t *user);
+int telnet_user_get_next_keyboard_event(telnet_user_t *user, kbd_event_t *event);
+int telnet_user_send_data(telnet_user_t *user, uint8_t *data, size_t size);
+void telnet_user_update_cursor_x(telnet_user_t *user, int new_x);
+
+/** Print informational message about connected user. */
+#ifdef CONFIG_DEBUG
+#define telnet_user_log(user, fmt, ...) \
+	printf(NAME " [console %d (%d)]: " fmt "\n", user->id, (int) user->service_id, ##__VA_ARGS__)
+#else
+#define telnet_user_log(user, fmt, ...) (void)0
+#endif
+
+/** Print error message associated with connected user. */
+#define telnet_user_error(user, fmt, ...) \
+	fprintf(stderr, NAME " [console %d (%d)]: ERROR: " fmt "\n", user->id, (int) user->service_id, ##__VA_ARGS__)
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -85,6 +85,7 @@
 
 	printf(NAME ": S3C24xx touchscreen driver\n");
-
-	rc = loc_server_register(NAME, s3c24xx_ts_connection);
+	
+	async_set_client_connection(s3c24xx_ts_connection);
+	rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -139,5 +140,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -154,5 +154,6 @@
 	}
 
-	rc = loc_server_register(NAME, cuda_connection);
+	async_set_client_connection(cuda_connection);
+	rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf(NAME ": Unable to register server.\n");
@@ -275,5 +276,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: pace/srv/hw/char/i8042/Makefile
===================================================================
--- uspace/srv/hw/char/i8042/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(revision )
@@ -1,36 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../../../..
-BINARY = i8042
-
-SOURCES = \
-	i8042.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/srv/hw/char/i8042/i8042.c
===================================================================
--- uspace/srv/hw/char/i8042/i8042.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(revision )
@@ -1,315 +1,0 @@
-/*
- * Copyright (c) 2001-2004 Jakub Jermar
- * Copyright (c) 2006 Josef Cejka
- * Copyright (c) 2009 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup kbd
- * @{
- */
-/** @file
- * @brief i8042 PS/2 port driver.
- */
-
-#include <ddi.h>
-#include <libarch/ddi.h>
-#include <loc.h>
-#include <async.h>
-#include <unistd.h>
-#include <sysinfo.h>
-#include <stdio.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "i8042.h"
-
-#define NAME       "i8042"
-#define NAMESPACE  "char"
-
-/* Interesting bits for status register */
-#define i8042_OUTPUT_FULL	0x01
-#define i8042_INPUT_FULL	0x02
-#define i8042_AUX_DATA		0x20
-
-/* Command constants */
-#define i8042_CMD_WRITE_CMDB	0x60	/**< write command byte */
-#define i8042_CMD_WRITE_AUX	0xd4	/**< write aux device */
-
-/* Command byte fields */
-#define i8042_KBD_IE		0x01
-#define i8042_AUX_IE		0x02
-#define i8042_KBD_DISABLE	0x10
-#define i8042_AUX_DISABLE	0x20
-#define i8042_KBD_TRANSLATE	0x40
-
-
-enum {
-	DEVID_PRI = 0, /**< primary device */
-        DEVID_AUX = 1, /**< AUX device */
-	MAX_DEVS  = 2
-};
-
-static irq_cmd_t i8042_cmds[] = {
-	{
-		.cmd = CMD_PIO_READ_8,
-		.addr = NULL,	/* will be patched in run-time */
-		.dstarg = 1
-	},
-	{
-		.cmd = CMD_BTEST,
-		.value = i8042_OUTPUT_FULL,
-		.srcarg = 1,
-		.dstarg = 3
-	},
-	{
-		.cmd = CMD_PREDICATE,
-		.value = 2,
-		.srcarg = 3
-	},
-	{
-		.cmd = CMD_PIO_READ_8,
-		.addr = NULL,	/* will be patched in run-time */
-		.dstarg = 2
-	},
-	{
-		.cmd = CMD_ACCEPT
-	}
-};
-
-static irq_code_t i8042_kbd = {
-	sizeof(i8042_cmds) / sizeof(irq_cmd_t),
-	i8042_cmds
-};
-
-static uintptr_t i8042_physical;
-static uintptr_t i8042_kernel;
-static i8042_t * i8042;
-
-static i8042_port_t i8042_port[MAX_DEVS];
-
-static void wait_ready(void)
-{
-	while (pio_read_8(&i8042->status) & i8042_INPUT_FULL);
-}
-
-static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call);
-static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
-static int i8042_init(void);
-static void i8042_port_write(int devid, uint8_t data);
-
-
-int main(int argc, char *argv[])
-{
-	char name[16];
-	int i, rc;
-	char dchar[MAX_DEVS] = { 'a', 'b' };
-
-	printf(NAME ": i8042 PS/2 port driver\n");
-
-	rc = loc_server_register(NAME, i8042_connection);
-	if (rc < 0) {
-		printf(NAME ": Unable to register server.\n");
-		return rc;
-	}
-
-	if (i8042_init() != EOK)
-		return -1;
-
-	for (i = 0; i < MAX_DEVS; i++) {
-		i8042_port[i].client_sess = NULL;
-
-		snprintf(name, 16, "%s/ps2%c", NAMESPACE, dchar[i]);
-		rc = loc_service_register(name, &i8042_port[i].service_id);
-		if (rc != EOK) {
-			printf(NAME ": Unable to register device %s.\n", name);
-			return rc;
-		}
-		printf(NAME ": Registered device %s\n", name);
-	}
-
-	printf(NAME ": Accepting connections\n");
-	task_retval(0);
-	async_manager();
-
-	/* Not reached */
-	return 0;
-}
-
-static int i8042_init(void)
-{
-	if (sysinfo_get_value("i8042.address.physical", &i8042_physical) != EOK)
-		return -1;
-	
-	if (sysinfo_get_value("i8042.address.kernel", &i8042_kernel) != EOK)
-		return -1;
-	
-	void *vaddr;
-	if (pio_enable((void *) i8042_physical, sizeof(i8042_t), &vaddr) != 0)
-		return -1;
-	
-	i8042 = vaddr;
-	
-	sysarg_t inr_a;
-	sysarg_t inr_b;
-	
-	if (sysinfo_get_value("i8042.inr_a", &inr_a) != EOK)
-		return -1;
-	
-	if (sysinfo_get_value("i8042.inr_b", &inr_b) != EOK)
-		return -1;
-	
-	async_set_interrupt_received(i8042_irq_handler);
-	
-	/* Disable kbd and aux */
-	wait_ready();
-	pio_write_8(&i8042->status, i8042_CMD_WRITE_CMDB);
-	wait_ready();
-	pio_write_8(&i8042->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);
-
-	/* Flush all current IO */
-	while (pio_read_8(&i8042->status) & i8042_OUTPUT_FULL)
-		(void) pio_read_8(&i8042->data);
-
-	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);
-	printf("%s: registered for interrupts %" PRIun " and %" PRIun "\n",
-	    NAME, inr_a, inr_b);
-
-	wait_ready();
-	pio_write_8(&i8042->status, i8042_CMD_WRITE_CMDB);
-	wait_ready();
-	pio_write_8(&i8042->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
-	    i8042_AUX_IE);
-
-	return 0;
-}
-
-/** Character device connection handler */
-static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
-	service_id_t dsid;
-	int retval;
-	int dev_id, i;
-
-	printf(NAME ": connection handler\n");
-
-	/* Get the device handle. */
-	dsid = IPC_GET_ARG1(*icall);
-
-	/* Determine which disk device is the client connecting to. */
-	dev_id = -1;
-	for (i = 0; i < MAX_DEVS; i++) {
-		if (i8042_port[i].service_id == dsid)
-			dev_id = i;
-	}
-
-	if (dev_id < 0) {
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	printf(NAME ": accepted connection\n");
-
-	while (1) {
-		callid = async_get_call(&call);
-		method = IPC_GET_IMETHOD(call);
-		
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-		
-		async_sess_t *sess =
-		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
-		if (sess != NULL) {
-			if (i8042_port[dev_id].client_sess == NULL) {
-				i8042_port[dev_id].client_sess = sess;
-				retval = EOK;
-			} else
-				retval = ELIMIT;
-		} else {
-			switch (method) {
-			case IPC_FIRST_USER_METHOD:
-				printf(NAME ": write %" PRIun " to devid %d\n",
-				    IPC_GET_ARG1(call), dev_id);
-				i8042_port_write(dev_id, IPC_GET_ARG1(call));
-				retval = 0;
-				break;
-			default:
-				retval = EINVAL;
-				break;
-			}
-		}
-		
-		async_answer_0(callid, retval);
-	}
-}
-
-void i8042_port_write(int devid, uint8_t data)
-{
-	if (devid == DEVID_AUX) {
-		wait_ready();
-		pio_write_8(&i8042->status, i8042_CMD_WRITE_AUX);
-	}
-	wait_ready();
-	pio_write_8(&i8042->data, data);
-}
-
-static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call)
-{
-	int status, data;
-	int devid;
-
-	status = IPC_GET_ARG1(*call);
-	data = IPC_GET_ARG2(*call);
-
-	if ((status & i8042_AUX_DATA)) {
-		devid = DEVID_AUX;
-	} else {
-		devid = DEVID_PRI;
-	}
-
-	if (i8042_port[devid].client_sess != NULL) {
-		async_exch_t *exch =
-		    async_exchange_begin(i8042_port[devid].client_sess);
-		async_msg_1(exch, IPC_FIRST_USER_METHOD, data);
-		async_exchange_end(exch);
-	}
-}
-
-/**
- * @}
- */
Index: pace/srv/hw/char/i8042/i8042.h
===================================================================
--- uspace/srv/hw/char/i8042/i8042.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(revision )
@@ -1,63 +1,0 @@
-/*
- * Copyright (c) 2006 Josef Cejka
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup  kbd
- * @{
- */
-
-/** @file
- * @brief i8042 port driver.
- */
-
-#ifndef i8042_H_
-#define i8042_H_
-
-#include <sys/types.h>
-#include <libarch/ddi.h>
-#include <async.h>
-
-/** i8042 HW I/O interface */
-struct i8042 {
-	ioport8_t data;
-	uint8_t pad[3];
-	ioport8_t status;
-} __attribute__ ((packed));
-typedef struct i8042 i8042_t;
-
-/** Softstate structure, one for each serial port (primary and aux). */
-typedef struct {
-	service_id_t service_id;
-	async_sess_t *client_sess;
-} i8042_port_t;
-
-#endif
-
-/**
- * @}
- */
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -79,5 +79,6 @@
 	printf(NAME ": S3C24xx on-chip UART driver\n");
 
-	rc = loc_server_register(NAME, s3c24xx_uart_connection);
+	async_set_client_connection(s3c24xx_uart_connection);
+	rc = loc_server_register(NAME);
 	if (rc < 0) {
 		printf(NAME ": Unable to register server.\n");
@@ -194,5 +195,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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/hw/irc/obio/obio.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/loc/loc.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -56,4 +56,10 @@
 #define NULL_SERVICES  256
 
+/** Callback session */
+typedef struct {
+	link_t cb_sess_list;
+	async_sess_t *sess;
+} cb_sess_t;
+
 LIST_INITIALIZE(services_list);
 LIST_INITIALIZE(namespaces_list);
@@ -86,5 +92,5 @@
 
 static FIBRIL_MUTEX_INITIALIZE(callback_sess_mutex);
-static async_sess_t *callback_sess = NULL;
+static LIST_INITIALIZE(callback_sess_list);
 
 service_id_t loc_create_id(void)
@@ -608,4 +614,5 @@
 	size_t act_size;
 	loc_service_t *svc;
+	char *fqn;
 	
 	if (!async_data_read_receive(&callid, &size)) {
@@ -625,6 +632,14 @@
 	}
 	
-	act_size = str_size(svc->name);
+	if (asprintf(&fqn, "%s/%s", svc->namespace->name, svc->name) < 0) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	act_size = str_size(fqn);
 	if (act_size > size) {
+		free(fqn);
 		fibril_mutex_unlock(&services_list_mutex);
 		async_answer_0(callid, EOVERFLOW);
@@ -633,6 +648,7 @@
 	}
 	
-	sysarg_t retval = async_data_read_finalize(callid, svc->name,
+	sysarg_t retval = async_data_read_finalize(callid, fqn,
 	    min(size, act_size));
+	free(fqn);
 	
 	fibril_mutex_unlock(&services_list_mutex);
@@ -790,7 +806,10 @@
 }
 
-/** Find ID for category specified by name.
- *
- * On success, answer will contain EOK int retval and service ID in arg1.
+/** Create callback connection.
+ *
+ * Create callback connection which will be used to send category change
+ * events.
+ *
+ * On success, answer will contain EOK int retval.
  * On failure, error code will be sent in retval.
  *
@@ -798,5 +817,5 @@
 static void loc_callback_create(ipc_callid_t iid, ipc_call_t *icall)
 {
-	async_sess_t *cb_sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	cb_sess_t *cb_sess = calloc(1, sizeof(cb_sess_t));
 	if (cb_sess == NULL) {
 		async_answer_0(iid, ENOMEM);
@@ -804,12 +823,16 @@
 	}
 	
+	async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (sess == NULL) {
+		free(cb_sess);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	cb_sess->sess = sess;
+	link_initialize(&cb_sess->cb_sess_list);
+	
 	fibril_mutex_lock(&callback_sess_mutex);
-	if (callback_sess != NULL) {
-		fibril_mutex_unlock(&callback_sess_mutex);
-		async_answer_0(iid, EEXIST);
-		return;
-	}
-	
-	callback_sess = cb_sess;
+	list_append(&cb_sess->cb_sess_list, &callback_sess_list);
 	fibril_mutex_unlock(&callback_sess_mutex);
 	
@@ -820,11 +843,15 @@
 {
 	fibril_mutex_lock(&callback_sess_mutex);
-
-	if (callback_sess != NULL) {
-		async_exch_t *exch = async_exchange_begin(callback_sess);
+	
+	list_foreach(callback_sess_list, link) {
+		cb_sess_t *cb_sess;
+		
+		cb_sess = list_get_instance(link, cb_sess_t, cb_sess_list);
+		
+		async_exch_t *exch = async_exchange_begin(cb_sess->sess);
 		async_msg_0(exch, LOC_EVENT_CAT_CHANGE);
 		async_exchange_end(exch);
 	}
-
+	
 	fibril_mutex_unlock(&callback_sess_mutex);
 }
Index: uspace/srv/net/cfg/e1k.nic
===================================================================
--- uspace/srv/net/cfg/e1k.nic	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/cfg/e1k.nic	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,21 @@
+# E1000 configuration
+
+NAME=e1k
+
+HWPATH=devices/\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/cfg/lo.nic
===================================================================
--- uspace/srv/net/cfg/lo.nic	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/cfg/lo.nic	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -3,5 +3,5 @@
 NAME=lo
 
-HWPATH=/virt/lo/port0
+HWPATH=devices/\virt\lo\port0
 NIL=nildummy
 IL=ip
Index: uspace/srv/net/cfg/ne2k.nic
===================================================================
--- uspace/srv/net/cfg/ne2k.nic	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/cfg/ne2k.nic	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -3,5 +3,5 @@
 NAME=ne2k
 
-HWPATH=/hw/pci0/00:01.0/ne2k/port0
+HWPATH=devices/\hw\pci0\00:01.0\ne2k\port0
 NIL=eth
 IL=ip
Index: uspace/srv/net/net/Makefile
===================================================================
--- uspace/srv/net/net/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/net/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -31,5 +31,6 @@
 ROOT_PATH = $(USPACE_PREFIX)/..
 LIBS = $(LIBNET_PREFIX)/libnet.a
-EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include
+EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include -I$(LIBNIC_PREFIX)/include \
+    -I$(LIBDRV_PREFIX)/include
 
 COMMON_MAKEFILE = $(ROOT_PATH)/Makefile.common
Index: uspace/srv/net/net/net.c
===================================================================
--- uspace/srv/net/net/net.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/net/net.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -2,4 +2,5 @@
  * Copyright (c) 2009 Lukas Mejdrech
  * Copyright (c) 2011 Radim Vansa
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -41,5 +42,4 @@
 #include <stdio.h>
 #include <str.h>
-#include <devman.h>
 #include <str_error.h>
 #include <ns.h>
@@ -56,4 +56,7 @@
 #include <adt/measured_strings.h>
 #include <adt/module_map.h>
+#include <fibril_synch.h>
+#include <loc.h>
+#include <nic.h>
 #include <nil_remote.h>
 #include <net_interface.h>
@@ -73,4 +76,7 @@
 GENERIC_CHAR_MAP_IMPLEMENT(measured_strings, measured_string_t);
 DEVICE_MAP_IMPLEMENT(netifs, netif_t);
+LIST_INITIALIZE(netif_list);
+
+static FIBRIL_MUTEX_INITIALIZE(discovery_lock);
 
 /** Add the configured setting to the configuration map.
@@ -287,10 +293,10 @@
  *
  */
-static int init_device(netif_t *netif, devman_handle_t handle)
+static int init_device(netif_t *netif, service_id_t sid)
 {
 	printf("%s: Initializing device '%s'\n", NAME, netif->name);
 	
-	netif->handle = handle;
-	netif->sess = devman_device_connect(EXCHANGE_SERIALIZE, netif->handle,
+	netif->sid = sid;
+	netif->sess = loc_service_connect(EXCHANGE_SERIALIZE, netif->sid,
 	    IPC_FLAG_BLOCKING);
 	if (netif->sess == NULL) {
@@ -337,5 +343,5 @@
 		    strtol((const char *) setting->value, NULL, 10) : 0;
 		rc = nil_device_req(netif->nil->sess, netif->id,
-		    netif->handle, mtu);
+		    netif->sid, mtu);
 		if (rc != EOK) {
 			printf("%s: Unable to start network interface layer\n",
@@ -359,22 +365,35 @@
 		break;
 	default:
+		printf("%s: Unknown service\n", NAME);
 		return ENOENT;
 	}
 	
 	printf("%s: Activating device '%s'\n", NAME, netif->name);
+	list_append(&netif->netif_list, &netif_list);
 	return nic_set_state(netif->sess, NIC_STATE_ACTIVE);
 }
 
-static int net_port_ready(devman_handle_t handle)
-{
-	char hwpath[MAX_PATH_LENGTH];
-	int rc = devman_fun_get_path(handle, hwpath, MAX_PATH_LENGTH);
-	if (rc != EOK)
+static int net_nic_ready(service_id_t sid)
+{
+	int rc;
+	char *hwpath;
+	
+	rc = loc_service_get_name(sid, &hwpath);
+	if (rc != EOK) {
+		printf("%s: Failed getting name of service '%u'\n",
+		    NAME, (unsigned) sid);
 		return EINVAL;
+	}
 	
 	int index = char_map_find(&net_globals.netif_hwpaths,
 	    (uint8_t *) hwpath, 0);
-	if (index == CHAR_MAP_NULL)
+	
+	if (index == CHAR_MAP_NULL) {
+		printf("%s: Service '%s' not found in map.\n", NAME, hwpath);
+		free(hwpath);
 		return ENOENT;
+	}
+	
+	free(hwpath);
 	
 	netif_t *netif = netifs_get_index(&net_globals.netifs, index);
@@ -382,5 +401,5 @@
 		return ENOENT;
 	
-	rc = init_device(netif, handle);
+	rc = init_device(netif, sid);
 	if (rc != EOK)
 		return rc;
@@ -391,21 +410,4 @@
 	
 	netif->il->usage++;
-	
-	return EOK;
-}
-
-static int net_driver_ready_local(devman_handle_t handle)
-{
-	devman_handle_t *funs;
-	size_t count;
-	int rc = devman_dev_get_functions(handle, &funs, &count);
-	if (rc != EOK)
-		return rc;
-	
-	for (size_t i = 0; i < count; i++) {
-		rc = net_port_ready(funs[i]);
-		if (rc != EOK)
-			return rc;
-	}
 	
 	return EOK;
@@ -479,8 +481,4 @@
 		net_free_devices(strings, count);
 		return rc;
-	case NET_NET_DRIVER_READY:
-		rc = net_driver_ready_local(IPC_GET_ARG1(*call));
-		*answer_count = 0;
-		return rc;
 	default:
 		return ENOTSUP;
@@ -528,4 +526,71 @@
 		answer_call(callid, res, &answer, count);
 	}
+}
+
+static int nic_check_new(void)
+{
+	category_id_t nic_cat;
+	service_id_t *svcs;
+	size_t count, i;
+	bool already_known;
+	int rc;
+
+	fibril_mutex_lock(&discovery_lock);
+
+	rc = loc_category_get_id(DEVICE_CATEGORY_NIC, &nic_cat, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("%s: Failed resolving category '%s'.\n", NAME,
+		    DEVICE_CATEGORY_NIC);
+		return ENOENT;
+	}
+
+	rc = loc_category_get_svcs(nic_cat, &svcs, &count);
+	if (rc != EOK) {
+		printf("%s: Failed getting list of NIC devices.\n", NAME);
+		return EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		already_known = false;
+
+		list_foreach(netif_list, link) {
+			netif_t *netif = list_get_instance(link, netif_t, netif_list);
+			if (netif->sid == svcs[i]) {
+				already_known = true;
+				break;
+			}
+		}
+
+		if (!already_known) {
+			rc = net_nic_ready(svcs[i]);
+			if (rc != EOK) {
+				printf("%s: Failed adding NIC device #%u.\n",
+				    NAME, (unsigned) svcs[i]);
+			}
+		}
+	}
+
+	free(svcs);
+	fibril_mutex_unlock(&discovery_lock);
+	return EOK;
+}
+
+static void cat_change_cb(void)
+{
+	(void) nic_check_new();
+}
+
+static int net_start_nic_discovery(void)
+{
+	int rc;
+
+	rc = loc_register_cat_change_cb(cat_change_cb);
+	if (rc != EOK) {
+		printf("%s: Failed registering callback for device discovery (%d).\n",
+		    NAME, rc);
+		return rc;
+	}
+
+	return nic_check_new();
 }
 
@@ -573,5 +638,5 @@
 				continue;
 			
-			netif->handle = -1;
+			netif->sid = -1;
 			netif->sess = NULL;
 			
@@ -697,4 +762,11 @@
 	}
 	
+	rc = net_start_nic_discovery();
+	if (rc != EOK) {
+		printf("%s: Error starting NIC discovery\n", NAME);
+		pm_destroy();
+		return rc;
+	}
+	
 	task_retval(0);
 	async_manager();
Index: uspace/srv/net/net/net.h
===================================================================
--- uspace/srv/net/net/net.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/net/net.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -35,4 +35,5 @@
 #define NET_NET_H_
 
+#include <ipc/loc.h>
 #include <net/device.h>
 #include <adt/char_map.h>
@@ -41,5 +42,4 @@
 #include <adt/module_map.h>
 #include <net/packet.h>
-#include <devman.h>
 
 #define NAME  "net"
@@ -96,9 +96,11 @@
 	
 	/** Serving network interface driver module index. */
-	devman_handle_t handle;  /**< Handle for devman */
-	async_sess_t *sess;      /**< Driver session. */
+	service_id_t sid;    /**< Service ID */
+	async_sess_t *sess;  /**< Driver session. */
 	
 	module_t *nil;  /**< Serving link layer module index. */
 	module_t *il;   /**< Serving internet layer module index. */
+	
+	link_t netif_list;
 } netif_t;
 
Index: uspace/srv/net/net/packet_server.c
===================================================================
--- uspace/srv/net/net/packet_server.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/net/packet_server.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/nil/eth/eth.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -48,4 +48,5 @@
 #include <ipc/net.h>
 #include <ipc/services.h>
+#include <loc.h>
 #include <net/modules.h>
 #include <net_checksum.h>
@@ -169,5 +170,8 @@
 INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
 
-int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state)
+static void eth_nic_cb_connection(ipc_callid_t iid, ipc_call_t *icall,
+    void *arg);
+
+static int eth_device_state(eth_device_t *device, sysarg_t state)
 {
 	int index;
@@ -179,6 +183,6 @@
 		proto = eth_protos_get_index(&eth_globals.protos, index);
 		if ((proto) && (proto->sess)) {
-			il_device_state_msg(proto->sess, device_id, state,
-			    proto->service);
+			il_device_state_msg(proto->sess, device->device_id,
+			    state, proto->service);
 		}
 	}
@@ -226,5 +230,5 @@
  *
  * @param[in] device_id New device identifier.
- * @param[in] handle    Device driver handle.
+ * @param[in] sid       NIC service ID.
  * @param[in] mtu       Device maximum transmission unit.
  *
@@ -234,5 +238,5 @@
  *
  */
-static int eth_device_message(nic_device_id_t device_id, devman_handle_t handle,
+static int eth_device_message(nic_device_id_t device_id, service_id_t sid,
     size_t mtu)
 {
@@ -259,5 +263,5 @@
 	device = eth_devices_find(&eth_globals.devices, device_id);
 	if (device) {
-		if (device->handle != handle) {
+		if (device->sid != sid) {
 			printf("Device %d already exists\n", device->device_id);
 			fibril_rwlock_write_unlock(&eth_globals.devices_lock);
@@ -298,5 +302,5 @@
 
 	device->device_id = device_id;
-	device->handle = handle;
+	device->sid = sid;
 	device->flags = 0;
 	if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
@@ -335,5 +339,5 @@
 	
 	/* Bind the device driver */
-	device->sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
+	device->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid,
 	    IPC_FLAG_BLOCKING);
 	if (device->sess == NULL) {
@@ -343,5 +347,11 @@
 	}
 	
-	nic_connect_to_nil(device->sess, SERVICE_ETHERNET, device_id);
+	rc = nic_callback_create(device->sess, eth_nic_cb_connection, device);
+	if (rc != EOK) {
+		fibril_rwlock_write_unlock(&eth_globals.devices_lock);
+		async_hangup(device->sess);
+		free(device);
+		return EIO;
+	}
 	
 	/* Get hardware address */
@@ -362,7 +372,7 @@
 	}
 	
-	printf("%s: Device registered (id: %d, handle: %zu: mtu: %zu, "
+	printf("%s: Device registered (id: %d, sid: %zu: mtu: %zu, "
 	    "mac: " PRIMAC ", flags: 0x%x)\n", NAME,
-	    device->device_id, device->handle, device->mtu,
+	    device->device_id, device->sid, device->mtu,
 	    ARGSMAC(device->addr.address), device->flags);
 
@@ -802,11 +812,11 @@
 			next = tmp;
 		} else {
+			nic_send_frame(device->sess, packet_get_data(next),
+			    packet_get_data_length(next));
 			next = pq_next(next);
 		}
 	} while (next);
 	
-	/* Send packet queue */
-	if (packet)
-		nic_send_message(device->sess, packet_get_id(packet));
+	pq_release_remote(eth_globals.net_sess, packet_get_id(packet));
 	
 	fibril_rwlock_read_unlock(&eth_globals.devices_lock);
@@ -814,5 +824,28 @@
 }
 
-static int eth_addr_changed(nic_device_id_t device_id)
+static int eth_received(eth_device_t *device)
+{
+	void *data;
+	size_t size;
+	int rc;
+	
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		printf("%s: data_write_accept() failed\n", NAME);
+		return rc;
+	}
+	
+	packet_t *packet = packet_get_1_remote(eth_globals.net_sess, size);
+	if (packet == NULL)
+		return ENOMEM;
+	
+	void *pdata = packet_suffix(packet, size);
+	memcpy(pdata, data, size);
+	free(data);
+	
+	return nil_received_msg_local(device->device_id, packet);
+}
+
+static int eth_addr_changed(eth_device_t *device)
 {
 	nic_address_t address;
@@ -832,28 +865,24 @@
 
 	fibril_rwlock_write_lock(&eth_globals.devices_lock);
-	/* An existing device? */
-	eth_device_t *device = eth_devices_find(&eth_globals.devices, device_id);
-	if (device) {
-		printf("Device %d changing address from " PRIMAC " to " PRIMAC "\n",
-			device_id, ARGSMAC(device->addr.address), ARGSMAC(address.address));
-		memcpy(&device->addr, &address, sizeof (nic_address_t));
-		fibril_rwlock_write_unlock(&eth_globals.devices_lock);
-
-		/* Notify all upper layer modules */
-		fibril_rwlock_read_lock(&eth_globals.protos_lock);
-		int index;
-		for (index = 0; index < eth_protos_count(&eth_globals.protos); index++) {
-			eth_proto_t *proto = eth_protos_get_index(&eth_globals.protos, index);
-			if (proto->sess != NULL) {
-				il_addr_changed_msg(proto->sess, device->device_id,
-						ETH_ADDR, address.address);
-			}
-		}
-
-		fibril_rwlock_read_unlock(&eth_globals.protos_lock);
-		return EOK;
-	} else {
-		return ENOENT;
-	}
+
+	printf("Device %d changing address from " PRIMAC " to " PRIMAC "\n",
+		device->device_id, ARGSMAC(device->addr.address),
+		ARGSMAC(address.address));
+	memcpy(&device->addr, &address, sizeof (nic_address_t));
+	fibril_rwlock_write_unlock(&eth_globals.devices_lock);
+
+	/* Notify all upper layer modules */
+	fibril_rwlock_read_lock(&eth_globals.protos_lock);
+	int index;
+	for (index = 0; index < eth_protos_count(&eth_globals.protos); index++) {
+		eth_proto_t *proto = eth_protos_get_index(&eth_globals.protos, index);
+		if (proto->sess != NULL) {
+			il_addr_changed_msg(proto->sess, device->device_id,
+					ETH_ADDR, address.address);
+		}
+	}
+
+	fibril_rwlock_read_unlock(&eth_globals.protos_lock);
+	return EOK;
 }
 
@@ -921,23 +950,40 @@
 		
 		return EOK;
-	case NET_NIL_DEVICE_STATE:
-		nil_device_state_msg_local(IPC_GET_DEVICE(*call), IPC_GET_STATE(*call));
-		async_answer_0(callid, EOK);
-		return EOK;
-	case NET_NIL_RECEIVED:
-		rc = packet_translate_remote(eth_globals.net_sess, &packet,
-		    IPC_GET_ARG2(*call));
-		if (rc == EOK)
-			rc = nil_received_msg_local(IPC_GET_ARG1(*call), packet);
-		
-		async_answer_0(callid, (sysarg_t) rc);
-		return rc;
-	case NET_NIL_ADDR_CHANGED:
-		rc = eth_addr_changed(IPC_GET_DEVICE(*call));
-		async_answer_0(callid, (sysarg_t) rc);
-		return rc;
 	}
 	
 	return ENOTSUP;
+}
+
+static void eth_nic_cb_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	eth_device_t *device = (eth_device_t *)arg;
+	int rc;
+	
+	async_answer_0(iid, EOK);
+	
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case NIC_EV_DEVICE_STATE:
+			rc = eth_device_state(device, IPC_GET_ARG1(call));
+			async_answer_0(callid, (sysarg_t) rc);
+			break;
+		case NIC_EV_RECEIVED:
+			rc = eth_received(device);
+			async_answer_0(callid, (sysarg_t) rc);
+			break;
+		case NIC_EV_ADDR_CHANGED:
+			rc = eth_addr_changed(device);
+			async_answer_0(callid, (sysarg_t) rc);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
 }
 
Index: uspace/srv/net/nil/eth/eth.h
===================================================================
--- uspace/srv/net/nil/eth/eth.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/nil/eth/eth.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,8 +41,8 @@
 #include <async.h>
 #include <fibril_synch.h>
+#include <ipc/loc.h>
 #include <ipc/services.h>
 #include <net/device.h>
 #include <adt/measured_strings.h>
-#include <devman.h>
 
 /** Ethernet address length. */
@@ -224,5 +224,5 @@
 	nic_device_id_t device_id;
 	/** Device handle */
-	devman_handle_t handle;
+	service_id_t sid;
 	/** Driver session. */
 	async_sess_t *sess;
Index: uspace/srv/net/nil/nildummy/nildummy.c
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.c	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/nil/nildummy/nildummy.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -2,4 +2,5 @@
  * Copyright (c) 2009 Lukas Mejdrech
  * Copyright (c) 2011 Radim Vansa
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -53,6 +54,6 @@
 #include <packet_remote.h>
 #include <packet_client.h>
-#include <devman.h>
 #include <device/nic.h>
+#include <loc.h>
 #include <nil_skel.h>
 #include "nildummy.h"
@@ -69,13 +70,21 @@
 DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
 
-int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state)
+static void nildummy_nic_cb_conn(ipc_callid_t iid, ipc_call_t *icall,
+    void *arg);
+
+static int nildummy_device_state(nildummy_device_t *device, sysarg_t state)
 {
 	fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
 	if (nildummy_globals.proto.sess)
-		il_device_state_msg(nildummy_globals.proto.sess, device_id,
-		    state, nildummy_globals.proto.service);
+		il_device_state_msg(nildummy_globals.proto.sess,
+		    device->device_id, state, nildummy_globals.proto.service);
 	fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
 	
 	return EOK;
+}
+
+static int nildummy_addr_changed(nildummy_device_t *device)
+{
+	return ENOTSUP;
 }
 
@@ -115,5 +124,5 @@
  */
 static int nildummy_device_message(nic_device_id_t device_id,
-    devman_handle_t handle, size_t mtu)
+    service_id_t sid, size_t mtu)
 {
 	fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
@@ -123,5 +132,5 @@
 	    nildummy_devices_find(&nildummy_globals.devices, device_id);
 	if (device) {
-		if (device->handle != handle) {
+		if (device->sid != sid) {
 			printf("Device %d exists, handles do not match\n",
 			    device->device_id);
@@ -158,5 +167,5 @@
 	
 	device->device_id = device_id;
-	device->handle = handle;
+	device->sid = sid;
 	if (mtu > 0)
 		device->mtu = mtu;
@@ -165,5 +174,5 @@
 	
 	/* Bind the device driver */
-	device->sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
+	device->sess = loc_service_connect(EXCHANGE_SERIALIZE, sid,
 	    IPC_FLAG_BLOCKING);
 	if (device->sess == NULL) {
@@ -173,8 +182,14 @@
 	}
 	
-	nic_connect_to_nil(device->sess, SERVICE_NILDUMMY, device_id);
+	int rc = nic_callback_create(device->sess, nildummy_nic_cb_conn,
+	    device);
+	if (rc != EOK) {
+		async_hangup(device->sess);
+		
+		return ENOENT;
+	}
 	
 	/* Get hardware address */
-	int rc = nic_get_address(device->sess, &device->addr);
+	rc = nic_get_address(device->sess, &device->addr);
 	if (rc != EOK) {
 		fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
@@ -354,11 +369,37 @@
 	}
 	
-	/* Send packet queue */
-	if (packet)
-		nic_send_message(device->sess, packet_get_id(packet));
+	packet_t *p = packet;
+	do {
+		nic_send_frame(device->sess, packet_get_data(p),
+		    packet_get_data_length(p));
+		p = pq_next(p);
+	} while (p != NULL);
+	
+	pq_release_remote(nildummy_globals.net_sess, packet_get_id(packet));
 	
 	fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
 	
 	return EOK;
+}
+
+static int nildummy_received(nildummy_device_t *device)
+{
+	void *data;
+	size_t size;
+	int rc;
+
+	rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
+	if (rc != EOK)
+		return rc;
+
+	packet_t *packet = packet_get_1_remote(nildummy_globals.net_sess, size);
+	if (packet == NULL)
+		return ENOMEM;
+
+	void *pdata = packet_suffix(packet, size);
+	memcpy(pdata, data, size);
+	free(pdata);
+
+	return nil_received_msg_local(device->device_id, packet);
 }
 
@@ -417,22 +458,42 @@
 		*answer_count = 1;
 		return rc;
-	case NET_NIL_DEVICE_STATE:
-		rc = nil_device_state_msg_local(IPC_GET_DEVICE(*call),
-		    IPC_GET_STATE(*call));
-		async_answer_0(callid, (sysarg_t) rc);
-		return rc;
-	
-	case NET_NIL_RECEIVED:
-		rc = packet_translate_remote(nildummy_globals.net_sess, &packet,
-		    IPC_GET_ARG2(*call));
-		if (rc == EOK)
-			rc = nil_received_msg_local(IPC_GET_ARG1(*call), packet);
-		
-		async_answer_0(callid, (sysarg_t) rc);
-		return rc;
 	}
 	
 	return ENOTSUP;
 }
+
+static void nildummy_nic_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	nildummy_device_t *device = (nildummy_device_t *)arg;
+	int rc;
+	
+	async_answer_0(iid, EOK);
+	
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case NIC_EV_DEVICE_STATE:
+			rc = nildummy_device_state(device, IPC_GET_ARG1(call));
+			async_answer_0(callid, (sysarg_t) rc);
+			break;
+		case NIC_EV_RECEIVED:
+			rc = nildummy_received(device);
+			async_answer_0(callid, (sysarg_t) rc);
+			break;
+		case NIC_EV_ADDR_CHANGED:
+			rc = nildummy_addr_changed(device);
+			async_answer_0(callid, (sysarg_t) rc);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+		}
+	}
+}
+
 
 int main(int argc, char *argv[])
Index: uspace/srv/net/nil/nildummy/nildummy.h
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.h	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/nil/nildummy/nildummy.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -41,6 +41,6 @@
 #include <async.h>
 #include <fibril_synch.h>
+#include <ipc/loc.h>
 #include <ipc/services.h>
-#include <ipc/devman.h>
 #include <net/device.h>
 
@@ -78,6 +78,6 @@
 	/** Device identifier. */
 	nic_device_id_t device_id;
-	/** Device driver handle. */
-	devman_handle_t handle;
+	/** Device service ID. */
+	service_id_t sid;
 	/** Driver session. */
 	async_sess_t *sess;
Index: uspace/srv/net/tl/tcp/Makefile
===================================================================
--- uspace/srv/net/tl/tcp/Makefile	(revision 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/tl/tcp/Makefile	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/conn.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,1282 @@
+/*
+ * 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_cb = NULL;
+
+	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;
+
+	log_msg(LVL_DEBUG, "tcp_conn_state_set(%p)", conn);
+
+	old_state = conn->cstate;
+	conn->cstate = nstate;
+	fibril_condvar_broadcast(&conn->cstate_cv);
+
+	/* Run user callback function */
+	if (conn->cstate_cb != NULL) {
+		log_msg(LVL_DEBUG, "tcp_conn_state_set() - run user CB");
+		conn->cstate_cb(conn, conn->cstate_cb_arg);
+	} else {
+		log_msg(LVL_DEBUG, "tcp_conn_state_set() - no user CB");
+	}
+
+	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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/conn.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/iqueue.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/iqueue.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/ncsim.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/ncsim.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/pdu.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/pdu.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/rqueue.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/rqueue.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/segment.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/segment.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/seq_no.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/seq_no.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/sock.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,832 @@
+/*
+ * 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
+
+#define MAX_BACKLOG 128
+
+/** 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;
+
+static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg);
+
+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;
+	socket_core_t *sock_core;
+	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;
+	}
+
+	fibril_mutex_initialize(&sock->lock);
+	sock->client = client;
+	sock->laddr.ipv4 = TCP_IPV4_ANY;
+	sock->lconn = NULL;
+	sock->backlog = 0;
+	list_initialize(&sock->ready);
+
+	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;
+	}
+
+	sock_core = socket_cores_find(&client->sockets, sock_id);
+	assert(sock_core != NULL);
+	sock->sock_core = sock_core;
+
+	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;
+	tcp_error_t trc;
+	tcp_sock_t lsocket;
+	tcp_sock_t fsocket;
+	tcp_conn_t *conn;
+	tcp_sock_lconn_t *lconn;
+	int i;
+
+	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;
+	}
+
+	if (backlog > MAX_BACKLOG)
+		backlog = MAX_BACKLOG;
+
+	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;
+
+	/*
+	 * Prepare @c backlog listening connections.
+	 */
+	fibril_mutex_lock(&socket->lock);
+
+	socket->backlog = backlog;
+	socket->lconn = calloc(sizeof(tcp_conn_t *), backlog);
+	if (socket->lconn == NULL) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - open connections");
+
+	lsocket.addr.ipv4 = TCP_IPV4_ANY;
+	lsocket.port = sock_core->port;
+	fsocket.addr.ipv4 = TCP_IPV4_ANY;
+	fsocket.port = TCP_PORT_ANY;
+
+	for (i = 0; i < backlog; i++) {
+
+		lconn = calloc(sizeof(tcp_sock_lconn_t), 1);
+		if (lconn == NULL) {
+			/* XXX Clean up */
+			fibril_mutex_unlock(&socket->lock);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+
+		trc = tcp_uc_open(&lsocket, &fsocket, ap_passive,
+		    tcp_open_nonblock, &conn);
+		if (conn == NULL) {
+			/* XXX Clean up */
+			fibril_mutex_unlock(&socket->lock);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+
+		tcp_uc_set_cstate_cb(conn, tcp_sock_cstate_cb, lconn);
+
+		assert(trc == TCP_EOK);
+		conn->name = (char *)"S";
+
+		lconn->conn = conn;
+		lconn->socket = socket;
+		link_initialize(&lconn->ready_list);
+		socket->lconn[i] = lconn;
+	}
+
+	fibril_mutex_unlock(&socket->lock);
+	async_answer_0(callid, EOK);
+}
+
+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;
+	}
+
+	fibril_mutex_lock(&socket->lock);
+
+	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) {
+			fibril_mutex_unlock(&socket->lock);
+			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, 0, &socket->conn);
+
+	if (socket->conn != NULL)
+		socket->conn->name = (char *)"C";
+
+	fibril_mutex_unlock(&socket->lock);
+
+	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;
+	tcp_conn_t *rconn;
+	tcp_sock_lconn_t *lconn;
+	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;
+	fibril_mutex_lock(&socket->lock);
+
+	log_msg(LVL_DEBUG, " - verify socket->conn");
+	if (socket->conn != NULL) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (list_empty(&socket->ready)) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, ENOENT);
+		return;
+	}
+
+	lconn = list_get_instance(list_first(&socket->ready),
+	    tcp_sock_lconn_t, ready_list);
+	list_remove(&lconn->ready_list);
+
+	conn = lconn->conn;
+	tcp_uc_set_cstate_cb(conn, NULL, NULL);
+
+	/* Replenish listening 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, tcp_open_nonblock,
+	    &rconn);
+	if (rconn == NULL) {
+		/* XXX Clean up */
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	tcp_uc_set_cstate_cb(rconn, tcp_sock_cstate_cb, lconn);
+
+	assert(trc == TCP_EOK);
+	rconn->name = (char *)"S";
+
+	lconn->conn = rconn;
+
+	/* Allocate socket for accepted connection */
+
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
+	asocket = calloc(sizeof(tcp_sockdata_t), 1);
+	if (asocket == NULL) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	fibril_mutex_initialize(&asocket->lock);
+	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) {
+		fibril_mutex_unlock(&socket->lock);
+		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 fragment notification to client's queue */
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify data\n");
+	tcp_sock_notify_data(asock_core);
+	fibril_mutex_unlock(&socket->lock);
+}
+
+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;
+	fibril_mutex_lock(&socket->lock);
+
+	if (socket->conn == NULL) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, ENOTCONN);
+		return;
+	}
+
+	for (index = 0; index < fragments; index++) {
+		if (!async_data_write_receive(&wcallid, &length)) {
+			fibril_mutex_unlock(&socket->lock);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+
+		if (length > FRAGMENT_SIZE)
+			length = FRAGMENT_SIZE;
+
+		rc = async_data_write_finalize(wcallid, buffer, length);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&socket->lock);
+			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) {
+			fibril_mutex_unlock(&socket->lock);
+			async_answer_0(callid, rc);
+			return;
+		}
+	}
+
+	refresh_answer(&answer, NULL);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	answer_call(callid, EOK, &answer, 2);
+	fibril_mutex_unlock(&socket->lock);
+}
+
+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;
+	fibril_mutex_lock(&socket->lock);
+
+	if (socket->conn == NULL) {
+		fibril_mutex_unlock(&socket->lock);
+		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) {
+		fibril_mutex_unlock(&socket->lock);
+		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)) {
+			fibril_mutex_unlock(&socket->lock);
+			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) {
+			fibril_mutex_unlock(&socket->lock);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+	}
+
+	log_msg(LVL_DEBUG, "data read receive");
+	if (!async_data_read_receive(&rcallid, &length)) {
+		fibril_mutex_unlock(&socket->lock);
+		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);
+	fibril_mutex_unlock(&socket->lock);
+}
+
+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;
+	fibril_mutex_lock(&socket->lock);
+
+	if (socket->conn != NULL) {
+		trc = tcp_uc_close(socket->conn);
+		if (trc != TCP_EOK && trc != TCP_ENOTEXIST) {
+			fibril_mutex_unlock(&socket->lock);
+			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) {
+		fibril_mutex_unlock(&socket->lock);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	fibril_mutex_unlock(&socket->lock);
+	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);
+}
+
+/** Called when connection state changes. */
+static void tcp_sock_cstate_cb(tcp_conn_t *conn, void *arg)
+{
+	tcp_conn_status_t cstatus;
+	tcp_sock_lconn_t *lconn = (tcp_sock_lconn_t *)arg;
+	tcp_sockdata_t *socket = lconn->socket;
+
+	log_msg(LVL_DEBUG, "tcp_sock_cstate_cb()");
+	fibril_mutex_lock(&socket->lock);
+	assert(conn == lconn->conn);
+
+	tcp_uc_status(conn, &cstatus);
+	if (cstatus.cstate != st_established) {
+		fibril_mutex_unlock(&socket->lock);
+		return;
+	}
+
+	assert_link_not_used(&lconn->ready_list);
+	list_append(&lconn->ready_list, &socket->ready);
+
+	log_msg(LVL_DEBUG, "tcp_sock_cstate_cb(): notify accept");
+
+	/* Push one accept notification to client's queue */
+	tcp_sock_notify_aconn(socket->sock_core);
+	fibril_mutex_unlock(&socket->lock);
+}
+
+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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/sock.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/std.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/net/tl/tcp/tcp.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ 	(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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/tcp_type.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,363 @@
+/*
+ * 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 enum {
+	tcp_open_nonblock = 1
+} tcp_open_flags_t;
+
+typedef struct tcp_conn tcp_conn_t;
+
+/** Connection state change callback function */
+typedef void (*tcp_cstate_cb_t)(tcp_conn_t *, void *);
+
+/** Connection */
+struct tcp_conn {
+	char *name;
+	link_t link;
+
+	/** Connection state change callback function */
+	tcp_cstate_cb_t cstate_cb;
+	/** Argument to @c cstate_cb */
+	void *cstate_cb_arg;
+
+	/** 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;
+};
+
+/** Data returned by Status user call */
+typedef struct {
+	/** Connection state */
+	tcp_cstate_t cstate;
+} 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 tcp_sockdata {
+	/** Lock */
+	fibril_mutex_t lock;
+	/** Socket core */
+	socket_core_t *sock_core;
+	/** Client */
+	tcp_client_t *client;
+	/** Connection */
+	tcp_conn_t *conn;
+	/** Local address */
+	netaddr_t laddr;
+	/** Backlog size */
+	int backlog;
+	/** Array of listening connections, @c backlog elements */
+	struct tcp_sock_lconn **lconn;
+	/** List of connections (from lconn) that are ready to be accepted */
+	list_t ready;
+} tcp_sockdata_t;
+
+typedef struct tcp_sock_lconn {
+	tcp_conn_t *conn;
+	tcp_sockdata_t *socket;
+	int index;
+	link_t ready_list;
+} tcp_sock_lconn_t;
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/test.c
===================================================================
--- uspace/srv/net/tl/tcp/test.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/test.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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, 0, &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, 0, &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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/test.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/tqueue.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/ucall.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,346 @@
+/*
+ * 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 oflags	Open flags
+ * @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_open_flags_t oflags, tcp_conn_t **conn)
+{
+	tcp_conn_t *nconn;
+
+	log_msg(LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %s, %p)",
+	    lsock, fsock, acpass == ap_active ? "active" : "passive",
+	    oflags == tcp_open_nonblock ? "nonblock" : "none", conn);
+
+	nconn = tcp_conn_new(lsock, fsock);
+	tcp_conn_add(nconn);
+
+	if (acpass == ap_active) {
+		/* Synchronize (initiate) connection */
+		tcp_conn_sync(nconn);
+	}
+
+	if (oflags == tcp_open_nonblock) {
+		*conn = nconn;
+		return TCP_EOK;
+	}
+
+	/* 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;
+	log_msg(LVL_DEBUG, "tcp_uc_open -> %p", 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()");
+	cstatus->cstate = conn->cstate;
+}
+
+/** 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);
+}
+
+void tcp_uc_set_cstate_cb(tcp_conn_t *conn, tcp_cstate_cb_t cb, void *arg)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_set_ctate_cb(%p, %p, %p)",
+	    conn, cb, arg);
+
+	conn->cstate_cb = cb;
+	conn->cstate_cb_arg = arg;
+}
+
+/*
+ * 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 b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
+++ uspace/srv/net/tl/tcp/ucall.h	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -0,0 +1,67 @@
+/*
+ * 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_open_flags_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 *);
+extern void tcp_uc_set_cstate_cb(tcp_conn_t *, tcp_cstate_cb_t, void *);
+
+/*
+ * 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 7cede12cf8e5870c5c2f9432b6e31b54cf385253)
+++ uspace/srv/vfs/vfs.c	(revision b7068da1c1b0f9346acb0d25e3778e57ce5a5e28)
@@ -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;
