Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ HelenOS.config	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -441,4 +441,7 @@
 ! [(CONFIG_HID_OUT=generic|CONFIG_HID_OUT=serial)&PLATFORM=arm32&MACHINE=gta02] CONFIG_S3C24XX_UART (y/n)
 
+% Support for Samsung S3C24XX on-chip interrupt controller
+! [PLATFORM=arm32&MACHINE=gta02] CONFIG_S3C24XX_IRQC (y)
+
 % Support for Z8530 controller
 ! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=keyboard)&PLATFORM=sparc64&MACHINE=generic] CONFIG_Z8530 (y/n)
@@ -469,5 +472,5 @@
 
 % Serial line input module
-! [CONFIG_DSRLNIN=y|(PLATFORM=ia64&MACHINE=i460GX&CONFIG_NS16550=y)|(PLATFORM=ia64&MACHINE=ski)|(PLATFORM=sparc64&MACHINE=serengeti&CONFIG_SGCN_KBD=y)|(PLATFORM=sparc64&PROCESSOR=sun4v)] CONFIG_SRLN (y)
+! [CONFIG_DSRLNIN=y|(PLATFORM=arm32&MACHINE=gta02)|(PLATFORM=ia64&MACHINE=i460GX&CONFIG_NS16550=y)|(PLATFORM=ia64&MACHINE=ski)|(PLATFORM=sparc64&MACHINE=serengeti&CONFIG_SGCN_KBD=y)|(PLATFORM=sparc64&PROCESSOR=sun4v)] CONFIG_SRLN (y)
 
 % EGA support
@@ -543,2 +546,4 @@
 ! CONFIG_BAREBONE (n/y)
 
+% Line debugging information
+! [CONFIG_STRIP_BINARIES!=y] CONFIG_LINE_DEBUG (n/y)
Index: boot/Makefile
===================================================================
--- boot/Makefile	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ boot/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -48,5 +48,5 @@
 endif
 ifeq ($(RDFMT),fat)
-	$(MKFAT) $(DIST_PATH) $@
+	$(MKFAT) 1048576 $(DIST_PATH) $@
 endif
 
Index: boot/Makefile.build
===================================================================
--- boot/Makefile.build	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ boot/Makefile.build	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -61,4 +61,11 @@
 	GCC_CFLAGS += -Werror
 	ICC_CFLAGS += -Werror
+endif
+
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	GCC_CFLAGS += -g
+	ICC_CFLAGS += -g
+	SUNCC_CFLAGS += -g
+	CLANG_CFLAGS += -g
 endif
 
Index: boot/arch/arm32/Makefile.inc
===================================================================
--- boot/arch/arm32/Makefile.inc	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ boot/arch/arm32/Makefile.inc	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -41,5 +41,7 @@
 PAGE_SIZE = 4096
 
-RD_SRVS_ESSENTIAL +=
+RD_SRVS_ESSENTIAL += \
+	$(USPACE_PATH)/srv/hid/s3c24xx_ts/s3c24ts \
+	$(USPACE_PATH)/srv/hw/char/s3c24xx_uart/s3c24ser
 
 RD_SRVS_NON_ESSENTIAL += \
Index: boot/arch/mips32/src/Makefile
===================================================================
--- boot/arch/mips32/src/Makefile	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ boot/arch/mips32/src/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -32,9 +32,13 @@
 .PHONY: all clean
 
-all: ../../../../version ../../../../Makefile.config ../../../../config.h ../../../../config.defs
+all: ../../../../version ../../../../Makefile.common ../../../../Makefile.config ../../../../config.h
 	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
 	$(MAKE) -f Makefile.build PRECHECK=$(PRECHECK)
 
 clean:
+	rm -f $(USPACEDIR)/dist/srv/*
+	rm -f $(USPACEDIR)/dist/app/*
+	rm -f $(USPACEDIR)/dist/cfg/net/*
+
 	for file in $(RD_SRVS) ; do \
 		rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
@@ -43,4 +47,7 @@
 		rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
 	done
+	for file in $(NET_CFG) ; do \
+		rm -f $(USPACEDIR)/dist/cfg/net/`basename $$file` ; \
+	done
 	rm -f $(DEPEND) $(DEPEND_PREV) $(JOB) $(OUTPUT) $(RAW) $(COMPS).h $(COMPS).c $(LINK) $(INITRD).img $(INITRD).fs
 	find . -name '*.o' -follow -exec rm \{\} \;
Index: boot/arch/mips32/src/Makefile.build
===================================================================
--- boot/arch/mips32/src/Makefile.build	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ boot/arch/mips32/src/Makefile.build	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -32,6 +32,6 @@
 
 include ../../../../version
+include ../../../../Makefile.common
 include ../../../../Makefile.config
-include ../../../../config.defs
 include Makefile.common
 include Makefile.toolchain
@@ -77,4 +77,8 @@
 
 $(DEPEND):
+	rm -f $(USPACEDIR)/dist/srv/*
+	rm -f $(USPACEDIR)/dist/app/*
+	rm -f $(USPACEDIR)/dist/cfg/net/*
+
 	for file in $(RD_SRVS) ; do \
 		cp $$file $(USPACEDIR)/dist/srv/ ; \
@@ -82,4 +86,7 @@
 	for file in $(RD_APPS) ; do \
 		cp $$file $(USPACEDIR)/dist/app/ ; \
+	done
+	for file in $(NET_CFG) ; do \
+		cp $$file $(USPACEDIR)/dist/cfg/net/ ; \
 	done
 ifeq ($(RDFMT),tmpfs)
Index: boot/arch/mips32/src/Makefile.toolchain
===================================================================
--- boot/arch/mips32/src/Makefile.toolchain	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ boot/arch/mips32/src/Makefile.toolchain	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -27,14 +27,5 @@
 #
 
-## Toolchain configuration
-#
-
-ifndef CROSS_PREFIX
-	CROSS_PREFIX = /usr/local
-endif
-
 BFD_ARCH = mips
-TARGET = mipsel-linux-gnu
-TOOLCHAIN_DIR = $(CROSS_PREFIX)/mips32/bin
 
 JOBFILE = ../../../../tools/jobfile.py
@@ -48,6 +39,4 @@
 	BFD_NAME = elf32-tradbigmips
 	BFD = ecoff-bigmips
-	TOOLCHAIN_DIR = $(CROSS_PREFIX)/mips32eb/bin
-	TARGET = mips-linux-gnu
 endif
 
@@ -55,20 +44,4 @@
 	BFD_NAME = elf32-tradlittlemips
 	BFD = binary
-endif
-
-ifeq ($(COMPILER),gcc_native)
-	CC = gcc
-	AS = as
-	LD = ld
-	OBJCOPY = objcopy
-	OBJDUMP = objdump
-endif
-
-ifeq ($(COMPILER),gcc_cross)
-	CC = $(TOOLCHAIN_DIR)/$(TARGET)-gcc
-	AS = $(TOOLCHAIN_DIR)/$(TARGET)-as
-	LD = $(TOOLCHAIN_DIR)/$(TARGET)-ld
-	OBJCOPY = $(TOOLCHAIN_DIR)/$(TARGET)-objcopy
-	OBJDUMP = $(TOOLCHAIN_DIR)/$(TARGET)-objdump
 endif
 
Index: contrib/conf/ia32-qe.sh
===================================================================
--- contrib/conf/ia32-qe.sh	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ contrib/conf/ia32-qe.sh	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -5,5 +5,5 @@
 # Create a disk image if it does not exist
 if [ ! -f "$DISK_IMG" ]; then
-	tools/mkfat.py uspace/dist/data "$DISK_IMG"
+	tools/mkfat.py 1048576 uspace/dist/data "$DISK_IMG"
 fi
 
Index: contrib/conf/mips32-gx.sh
===================================================================
--- contrib/conf/mips32-gx.sh	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ contrib/conf/mips32-gx.sh	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -5,5 +5,5 @@
 # Create a disk image if it does not exist
 if [ ! -f "$DISK_IMG" ]; then
-	tools/mkfat.py uspace/dist/data "$DISK_IMG"
+	tools/mkfat.py 1048576 uspace/dist/data "$DISK_IMG"
 fi
 
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -120,4 +120,11 @@
 ifeq ($(CONFIG_LTO),y)
 	GCC_CFLAGS += -flto
+endif
+
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	GCC_CFLAGS += -g
+	ICC_CFLAGS += -g
+	SUNCC_CFLAGS += -g
+	CLANG_CFLAGS += -g
 endif
 
@@ -401,5 +408,9 @@
 
 $(DISASM): $(RAW)
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	$(OBJDUMP) -d -S $< > $@
+else
 	$(OBJDUMP) -d $< > $@
+endif
 
 $(RAW): $(LINK) $(ARCH_OBJECTS) $(GENARCH_OBJECTS) $(GENERIC_OBJECTS) $(SYMTAB_OBJECTS)
Index: kernel/arch/amd64/_link.ld.in
===================================================================
--- kernel/arch/amd64/_link.ld.in	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/_link.ld.in	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -53,4 +53,17 @@
 	}
 	
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); }
+	.debug_abbrev 0 : { *(.debug_abbrev); }
+	.debug_aranges 0 : { *(.debug_aranges); }
+	.debug_info 0 : { *(.debug_info); }
+	.debug_line 0 : { *(.debug_line); }
+	.debug_loc 0 : { *(.debug_loc); }
+	.debug_pubnames 0 : { *(.debug_pubnames); }
+	.debug_pubtypes 0 : { *(.debug_pubtypes); }
+	.debug_ranges 0 : { *(.debug_ranges); }
+	.debug_str 0 : { *(.debug_str); }
+#endif
+	
 	/DISCARD/ : {
 		*(*);
Index: kernel/arch/amd64/include/pm.h
===================================================================
--- kernel/arch/amd64/include/pm.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/include/pm.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -65,6 +65,5 @@
 #endif /* CONFIG_FB */
 
-#define gdtselector(des)  ((des) << 3)
-#define idtselector(des)  ((des) << 4)
+#define GDT_SELECTOR(des)  ((des) << 3)
 
 #define PL_KERNEL  0
@@ -168,5 +167,4 @@
 
 extern ptr_16_64_t gdtr;
-extern ptr_16_32_t bootstrap_gdtr;
 extern ptr_16_32_t protected_ap_gdtr;
 
Index: kernel/arch/amd64/src/asm.S
===================================================================
--- kernel/arch/amd64/src/asm.S	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/asm.S	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -244,5 +244,5 @@
 	 */
 	xorq %rdx, %rdx
-	cmpq $(gdtselector(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
+	cmpq $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
 	cmovnzq %rdx, %rbp
 
Index: kernel/arch/amd64/src/boot/boot.S
===================================================================
--- kernel/arch/amd64/src/boot/boot.S	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/boot/boot.S	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -85,5 +85,5 @@
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %ds
@@ -94,9 +94,9 @@
 	 * when _visible_ part of GS does not point to user-mode segment.
 	 */
-	movw $gdtselector(UDATA_DES), %cx
+	movw $GDT_SELECTOR(UDATA_DES), %cx
 	movw %cx, %fs
 	movw %cx, %gs
 	
-	jmpl $gdtselector(KTEXT32_DES), $multiboot_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $multiboot_meeting_point
 	multiboot_meeting_point:
 	
@@ -182,5 +182,5 @@
 	
 	/* At this point we are in compatibility mode */
-	jmpl $gdtselector(KTEXT_DES), $start64
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64
 
 /** Print string to EGA display (in light red) and halt.
@@ -645,7 +645,6 @@
 .section K_DATA_START, "aw", @progbits
 
-.global bootstrap_gdtr
 bootstrap_gdtr:
-	.word gdtselector(GDT_ITEMS)
+	.word GDT_SELECTOR(GDT_ITEMS)
 	.long KA2PA(gdt)
 
Index: kernel/arch/amd64/src/boot/vesa_ret.inc
===================================================================
--- kernel/arch/amd64/src/boot/vesa_ret.inc	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/boot/vesa_ret.inc	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -7,5 +7,5 @@
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %ds
@@ -17,7 +17,7 @@
 	 */
 	
-	movw $gdtselector(UDATA_DES), %cx
+	movw $GDT_SELECTOR(UDATA_DES), %cx
 	movw %cx, %fs
 	movw %cx, %gs
 	
-	jmpl $gdtselector(KTEXT32_DES), $vesa_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $vesa_meeting_point
Index: kernel/arch/amd64/src/ddi/ddi.c
===================================================================
--- kernel/arch/amd64/src/ddi/ddi.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/ddi/ddi.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -153,5 +153,5 @@
 	tss_descriptor_t *tss_desc = (tss_descriptor_t *) &gdt_p[TSS_DES];
 	tss_desc->type = AR_TSS;
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 	
 	/*
Index: kernel/arch/amd64/src/pm.c
===================================================================
--- kernel/arch/amd64/src/pm.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/pm.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -171,5 +171,5 @@
 
 		d->unused = 0;
-		d->selector = gdtselector(KTEXT_DES);
+		d->selector = GDT_SELECTOR(KTEXT_DES);
 
 		d->present = 1;
@@ -291,5 +291,5 @@
 	 * to its own TSS. We just need to load the TR register.
 	 */
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 }
 
Index: kernel/arch/amd64/src/smp/ap.S
===================================================================
--- kernel/arch/amd64/src/smp/ap.S	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/smp/ap.S	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -61,13 +61,13 @@
 	orl $1, %eax
 	movl %eax, %cr0     # switch to protected mode
-	jmpl $gdtselector(KTEXT32_DES), $jump_to_kernel - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $jump_to_kernel - BOOT_OFFSET + AP_BOOT_OFFSET
 
 jump_to_kernel:
 .code32
-	movw $gdtselector(KDATA_DES), %ax
+	movw $GDT_SELECTOR(KDATA_DES), %ax
 	movw %ax, %ds
 	movw %ax, %es
 	movw %ax, %ss
-	movw $gdtselector(UDATA_DES), %ax
+	movw $GDT_SELECTOR(UDATA_DES), %ax
 	movw %ax, %gs
 	
@@ -94,5 +94,5 @@
 	
 	# At this point we are in compatibility mode
-	jmpl $gdtselector(KTEXT_DES), $start64 - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64 - BOOT_OFFSET + AP_BOOT_OFFSET
 
 .code64
Index: kernel/arch/amd64/src/syscall.c
===================================================================
--- kernel/arch/amd64/src/syscall.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/syscall.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -58,6 +58,6 @@
 	 */
 	write_msr(AMD_MSR_STAR,
-	    ((uint64_t)(gdtselector(KDATA_DES) | PL_USER) << 48) |
-	    ((uint64_t)(gdtselector(KTEXT_DES) | PL_KERNEL) << 32));
+	    ((uint64_t) (GDT_SELECTOR(KDATA_DES) | PL_USER) << 48) |
+	    ((uint64_t) (GDT_SELECTOR(KTEXT_DES) | PL_KERNEL) << 32));
 	write_msr(AMD_MSR_LSTAR, (uint64_t)syscall_entry);
 	/* Mask RFLAGS on syscall 
Index: kernel/arch/amd64/src/userspace.c
===================================================================
--- kernel/arch/amd64/src/userspace.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/amd64/src/userspace.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -65,8 +65,8 @@
 		"xorq %%rdi, %%rdi\n"
 		"iretq\n"
-		:: [udata_des] "i" (gdtselector(UDATA_DES) | PL_USER),
+		:: [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
 		   [stack_size] "r" (kernel_uarg->uspace_stack + THREAD_STACK_SIZE),
 		   [ipl] "r" (ipl),
-		   [utext_des] "i" (gdtselector(UTEXT_DES) | PL_USER),
+		   [utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
 		   [entry] "r" (kernel_uarg->uspace_entry),
 		   [uarg] "r" (kernel_uarg->uspace_uarg)
Index: kernel/arch/arm32/include/mach/integratorcp/integratorcp.h
===================================================================
--- kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -105,4 +105,5 @@
 extern void icp_get_memory_extents(uintptr_t *, uintptr_t *);
 extern void icp_frame_init(void);
+extern size_t icp_get_irq_count(void);
 
 extern struct arm_machine_ops icp_machine_ops;
Index: kernel/arch/arm32/include/mach/testarm/testarm.h
===================================================================
--- kernel/arch/arm32/include/mach/testarm/testarm.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/include/mach/testarm/testarm.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -73,4 +73,5 @@
 extern void gxemul_get_memory_extents(uintptr_t *, uintptr_t *);
 extern void gxemul_frame_init(void);
+extern size_t gxemul_get_irq_count(void);
 
 extern struct arm_machine_ops gxemul_machine_ops;
Index: kernel/arch/arm32/include/machine_func.h
===================================================================
--- kernel/arch/arm32/include/machine_func.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/include/machine_func.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -55,4 +55,5 @@
 	void (*machine_output_init)(void);
 	void (*machine_input_init)(void);
+	size_t (*machine_get_irq_count)(void);
 };
 
Index: kernel/arch/arm32/src/mach/gta02/gta02.c
===================================================================
--- kernel/arch/arm32/src/mach/gta02/gta02.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/src/mach/gta02/gta02.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -43,4 +43,6 @@
 #include <genarch/drivers/s3c24xx_irqc/s3c24xx_irqc.h>
 #include <genarch/drivers/s3c24xx_timer/s3c24xx_timer.h>
+#include <genarch/srln/srln.h>
+#include <sysinfo/sysinfo.h>
 #include <interrupt.h>
 #include <ddi/ddi.h>
@@ -68,4 +70,5 @@
 static void gta02_output_init(void);
 static void gta02_input_init(void);
+static size_t gta02_get_irq_count(void);
 
 static void gta02_timer_irq_init(void);
@@ -74,6 +77,6 @@
 static void gta02_timer_irq_handler(irq_t *irq);
 
-static void *gta02_scons_out;
-static s3c24xx_irqc_t *gta02_irqc;
+static outdev_t *gta02_scons_dev;
+static s3c24xx_irqc_t gta02_irqc;
 static s3c24xx_timer_t *gta02_timer;
 
@@ -88,21 +91,17 @@
 	gta02_frame_init,
 	gta02_output_init,
-	gta02_input_init
+	gta02_input_init,
+	gta02_get_irq_count
 };
 
 static void gta02_init(void)
 {
-	gta02_scons_out = (void *) hw_map(GTA02_SCONS_BASE, PAGE_SIZE);
-	gta02_irqc = (void *) hw_map(S3C24XX_IRQC_ADDRESS, PAGE_SIZE);
+	s3c24xx_irqc_regs_t *irqc_regs;
+
 	gta02_timer = (void *) hw_map(S3C24XX_TIMER_ADDRESS, PAGE_SIZE);
-
-	/* Make all interrupt sources use IRQ mode (not FIQ). */
-	pio_write_32(&gta02_irqc->intmod, 0x00000000);
-
-	/* Disable all interrupt sources. */
-	pio_write_32(&gta02_irqc->intmsk, 0xffffffff);
-
-	/* Disable interrupts from all sub-sources. */
-	pio_write_32(&gta02_irqc->intsubmsk, 0xffffffff);
+	irqc_regs = (void *) hw_map(S3C24XX_IRQC_ADDRESS, PAGE_SIZE);
+
+	/* Initialize interrupt controller. */
+	s3c24xx_irqc_init(&gta02_irqc, irqc_regs);
 }
 
@@ -132,5 +131,9 @@
 	uint32_t inum;
 
-	inum = pio_read_32(&gta02_irqc->intoffset);
+	/* Determine IRQ number. */
+	inum = s3c24xx_irqc_inum_get(&gta02_irqc);
+
+	/* Clear interrupt condition in the interrupt controller. */
+	s3c24xx_irqc_clear(&gta02_irqc, inum);
 
 	irq_t *irq = irq_dispatch_and_lock(inum);
@@ -144,8 +147,4 @@
 		    CPU->id, inum);
 	}
-
-	/* Clear interrupt condition in the interrupt controller. */
-	pio_write_32(&gta02_irqc->srcpnd, S3C24XX_INT_BIT(inum));
-	pio_write_32(&gta02_irqc->intpnd, S3C24XX_INT_BIT(inum));
 }
 
@@ -176,13 +175,62 @@
 	}
 #endif
-	outdev_t *scons_dev;
-
-	scons_dev = s3c24xx_uart_init((ioport8_t *) gta02_scons_out);
-	if (scons_dev)
-		stdout_wire(scons_dev);
+
+	/* Initialize serial port of the debugging console. */
+	s3c24xx_uart_io_t *scons_io;
+
+	scons_io = (void *) hw_map(GTA02_SCONS_BASE, PAGE_SIZE);
+	gta02_scons_dev = s3c24xx_uart_init(scons_io, S3C24XX_INT_UART2);
+
+	if (gta02_scons_dev) {
+		/* Create output device. */
+		stdout_wire(gta02_scons_dev);
+	}
+
+	/*
+	 * This is the necessary evil until the userspace driver is entirely
+	 * self-sufficient.
+	 */
+	sysinfo_set_item_val("s3c24xx_uart", NULL, true);
+	sysinfo_set_item_val("s3c24xx_uart.inr", NULL, S3C24XX_INT_UART2);
+	sysinfo_set_item_val("s3c24xx_uart.address.physical", NULL,
+	    (uintptr_t) GTA02_SCONS_BASE);
+
 }
 
 static void gta02_input_init(void)
 {
+	s3c24xx_uart_t *scons_inst;
+
+	if (gta02_scons_dev) {
+		/* Create input device. */
+		scons_inst = (void *) gta02_scons_dev->data;
+
+		srln_instance_t *srln_instance = srln_init();
+		if (srln_instance) {
+			indev_t *sink = stdin_wire();
+			indev_t *srln = srln_wire(srln_instance, sink);
+			s3c24xx_uart_input_wire(scons_inst, srln);
+
+			/* Enable interrupts from UART2 */
+			s3c24xx_irqc_src_enable(&gta02_irqc,
+			    S3C24XX_INT_UART2);
+
+			/* Enable interrupts from UART2 RXD */
+			s3c24xx_irqc_subsrc_enable(&gta02_irqc,
+			    S3C24XX_SUBINT_RXD2);
+		}
+	}
+
+	/* Enable interrupts from ADC */
+	s3c24xx_irqc_src_enable(&gta02_irqc, S3C24XX_INT_ADC);
+
+	/* Enable interrupts from ADC sub-sources */
+	s3c24xx_irqc_subsrc_enable(&gta02_irqc, S3C24XX_SUBINT_ADC_S);
+	s3c24xx_irqc_subsrc_enable(&gta02_irqc, S3C24XX_SUBINT_TC);
+}
+
+size_t gta02_get_irq_count(void)
+{
+	return GTA02_IRQ_COUNT;
 }
 
@@ -248,6 +296,5 @@
 
 	/* Enable interrupts from timer0 */
-	pio_write_32(&gta02_irqc->intmsk, pio_read_32(&gta02_irqc->intmsk) &
-	    ~S3C24XX_INT_BIT(S3C24XX_INT_TIMER0));
+	s3c24xx_irqc_src_enable(&gta02_irqc, S3C24XX_INT_TIMER0);
 
 	/* Load data from tcntb0/tcmpb0 into tcnt0/tcmp0. */
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -64,5 +64,6 @@
 	icp_frame_init,
 	icp_output_init,
-	icp_input_init
+	icp_input_init,
+	icp_get_irq_count
 };
 
@@ -336,4 +337,8 @@
 }
 
+size_t icp_get_irq_count(void)
+{
+	return ICP_IRQ_COUNT;
+}
 
 /** @}
Index: kernel/arch/arm32/src/mach/testarm/testarm.c
===================================================================
--- kernel/arch/arm32/src/mach/testarm/testarm.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/src/mach/testarm/testarm.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -64,5 +64,6 @@
 	gxemul_frame_init,
 	gxemul_output_init,
-	gxemul_input_init
+	gxemul_input_init,
+	gxemul_get_irq_count
 };
 
@@ -126,4 +127,9 @@
 }
 
+size_t gxemul_get_irq_count(void)
+{
+	return GXEMUL_IRQ_COUNT;
+}
+
 /** Starts gxemul Real Time Clock device, which asserts regular interrupts.
  *
Index: kernel/arch/arm32/src/machine_func.c
===================================================================
--- kernel/arch/arm32/src/machine_func.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/arm32/src/machine_func.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -128,16 +128,5 @@
 size_t machine_get_irq_count(void)
 {
-	size_t irq_count;
- 
-#if defined(MACHINE_gta02)
-	irq_count = GTA02_IRQ_COUNT;
-#elif defined(MACHINE_testarm)
-	irq_count = GXEMUL_IRQ_COUNT;
-#elif defined(MACHINE_integratorcp)
-	irq_count = ICP_IRQ_COUNT;
-#else
-#error Machine type not defined.
-#endif
-	return irq_count;
+	return (machine_ops->machine_get_irq_count)();
 }
 
Index: kernel/arch/ia32/include/bios/bios.h
===================================================================
--- kernel/arch/ia32/include/bios/bios.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/include/bios/bios.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -38,6 +38,4 @@
 #include <typedefs.h>
 
-#define BIOS_EBDA_PTR  0x40e
-
 extern uintptr_t ebda;
 
Index: kernel/arch/ia32/include/mm/as.h
===================================================================
--- kernel/arch/ia32/include/mm/as.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/include/mm/as.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup ia32mm	
+/** @addtogroup ia32mm
  * @{
  */
Index: kernel/arch/ia32/include/mm/page.h
===================================================================
--- kernel/arch/ia32/include/mm/page.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/include/mm/page.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup ia32mm	
+/** @addtogroup ia32mm
  * @{
  */
@@ -106,5 +106,5 @@
 
 /* Set PTE flags accessors for each level. */
-#define SET_PTL1_FLAGS_ARCH(ptl0, i, x)	\
+#define SET_PTL1_FLAGS_ARCH(ptl0, i, x) \
 	set_pt_flags((pte_t *) (ptl0), (size_t) (i), (x))
 #define SET_PTL2_FLAGS_ARCH(ptl1, i, x)
Index: kernel/arch/ia32/include/pm.h
===================================================================
--- kernel/arch/ia32/include/pm.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/include/pm.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -58,5 +58,5 @@
 #endif /* CONFIG_FB */
 
-#define gdtselector(des)  ((des) << 3)
+#define GDT_SELECTOR(des)  ((des) << 3)
 
 #define PL_KERNEL  0
@@ -153,5 +153,4 @@
 
 extern ptr_16_32_t gdtr;
-extern ptr_16_32_t bootstrap_gdtr;
 extern ptr_16_32_t protected_ap_gdtr;
 extern tss_t *tss_p;
Index: kernel/arch/ia32/src/asm.S
===================================================================
--- kernel/arch/ia32/src/asm.S	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/asm.S	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -225,5 +225,5 @@
 	 * Switch to kernel selectors.
 	 */
-	movw $(gdtselector(KDATA_DES)), %ax
+	movw $(GDT_SELECTOR(KDATA_DES)), %ax
 	movw %ax, %ds
 	movw %ax, %es
@@ -304,5 +304,5 @@
 	 * Switch to kernel selectors.
 	 */
-	movl $(gdtselector(KDATA_DES)), %eax
+	movl $(GDT_SELECTOR(KDATA_DES)), %eax
 	movl %eax, %ds
 	movl %eax, %es
@@ -407,5 +407,5 @@
 	 * Switch to kernel selectors.
 	 */
-	movl $(gdtselector(KDATA_DES)), %eax
+	movl $(GDT_SELECTOR(KDATA_DES)), %eax
 	movl %eax, %ds
 	movl %eax, %es
@@ -416,5 +416,5 @@
 	 */
 	xorl %eax, %eax
-	cmpl $(gdtselector(KTEXT_DES)), ISTATE_OFFSET_CS(%esp)
+	cmpl $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%esp)
 	cmovnzl %eax, %ebp
 
Index: kernel/arch/ia32/src/bios/bios.c
===================================================================
--- kernel/arch/ia32/src/bios/bios.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/bios/bios.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -36,4 +36,6 @@
 #include <typedefs.h>
 
+#define BIOS_EBDA_PTR  0x40e
+
 uintptr_t ebda = 0;
 
Index: kernel/arch/ia32/src/boot/boot.S
===================================================================
--- kernel/arch/ia32/src/boot/boot.S	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/boot/boot.S	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -78,8 +78,8 @@
 	
 	/* Initialize Global Descriptor Table register */
-	lgdtl KA2PA(bootstrap_gdtr)
+	lgdtl bootstrap_gdtr
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %fs
@@ -88,5 +88,5 @@
 	movw %cx, %ss
 	
-	jmpl $gdtselector(KTEXT_DES), $multiboot_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot_meeting_point
 	multiboot_meeting_point:
 	
@@ -514,4 +514,8 @@
 page_directory:
 	.space 4096, 0
+
+bootstrap_gdtr:
+	.word GDT_SELECTOR(GDT_ITEMS)
+	.long KA2PA(gdt)
 
 grub_eax:
Index: kernel/arch/ia32/src/boot/vesa_real.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_real.inc	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/boot/vesa_real.inc	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -30,5 +30,5 @@
 .code32
 vesa_init:
-	jmp $gdtselector(VESA_INIT_DES), $vesa_init_real - vesa_init
+	jmp $GDT_SELECTOR(VESA_INIT_DES), $vesa_init_real - vesa_init
 
 .code16
@@ -335,5 +335,5 @@
 		vesa_leave_real2:
 		
-			ljmpl $gdtselector(KTEXT32_DES), $(vesa_init_protected - vesa_init + VESA_INIT_SEGMENT << 4)
+			ljmpl $GDT_SELECTOR(KTEXT32_DES), $(vesa_init_protected - vesa_init + VESA_INIT_SEGMENT << 4)
 	
 	no_mode:
Index: kernel/arch/ia32/src/boot/vesa_ret.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_ret.inc	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/boot/vesa_ret.inc	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -7,5 +7,5 @@
 	
 	/* Kernel data + stack */
-	movw $gdtselector(KDATA_DES), %cx
+	movw $GDT_SELECTOR(KDATA_DES), %cx
 	movw %cx, %es
 	movw %cx, %fs
@@ -14,3 +14,3 @@
 	movw %cx, %ss
 	
-	jmpl $gdtselector(KTEXT_DES), $vesa_meeting_point
+	jmpl $GDT_SELECTOR(KTEXT_DES), $vesa_meeting_point
Index: kernel/arch/ia32/src/ddi/ddi.c
===================================================================
--- kernel/arch/ia32/src/ddi/ddi.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/ddi/ddi.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -153,5 +153,5 @@
 	 */
 	gdt_p[TSS_DES].access = AR_PRESENT | AR_TSS | DPL_KERNEL;
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 	
 	/*
Index: kernel/arch/ia32/src/mm/frame.c
===================================================================
--- kernel/arch/ia32/src/mm/frame.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/mm/frame.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -131,7 +131,14 @@
 			if (last_frame < ALIGN_UP(new_base + new_size, FRAME_SIZE))
 				last_frame = ALIGN_UP(new_base + new_size, FRAME_SIZE);
-		}
-		
-		if (e820table[i].type == MEMMAP_MEMORY_RESERVED) {
+		} else if ((e820table[i].type == MEMMAP_MEMORY_ACPI) ||
+		    (e820table[i].type == MEMMAP_MEMORY_NVS)) {
+			/* To be safe, make the firmware zone possibly larger */
+			uint64_t new_base = ALIGN_DOWN(base, FRAME_SIZE);
+			uint64_t new_size = ALIGN_UP(size + (base - new_base),
+			    FRAME_SIZE);
+			
+			zone_create(ADDR2PFN(new_base), SIZE2FRAMES(new_size), 0,
+			    ZONE_FIRMWARE);
+		} else {
 			/* To be safe, make the reserved zone possibly larger */
 			uint64_t new_base = ALIGN_DOWN(base, FRAME_SIZE);
@@ -141,14 +148,4 @@
 			zone_create(ADDR2PFN(new_base), SIZE2FRAMES(new_size), 0,
 			    ZONE_RESERVED);
-		}
-		
-		if (e820table[i].type == MEMMAP_MEMORY_ACPI) {
-			/* To be safe, make the firmware zone possibly larger */
-			uint64_t new_base = ALIGN_DOWN(base, FRAME_SIZE);
-			uint64_t new_size = ALIGN_UP(size + (base - new_base),
-			    FRAME_SIZE);
-			
-			zone_create(ADDR2PFN(new_base), SIZE2FRAMES(new_size), 0,
-			    ZONE_FIRMWARE);
 		}
 	}
@@ -203,5 +200,5 @@
 #ifdef CONFIG_SMP
 		/* Reserve AP real mode bootstrap memory */
-		frame_mark_unavailable(AP_BOOT_OFFSET >> FRAME_WIDTH, 
+		frame_mark_unavailable(AP_BOOT_OFFSET >> FRAME_WIDTH,
 		    (hardcoded_unmapped_ktext_size +
 		    hardcoded_unmapped_kdata_size) >> FRAME_WIDTH);
Index: kernel/arch/ia32/src/pm.c
===================================================================
--- kernel/arch/ia32/src/pm.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/pm.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -75,6 +75,6 @@
 	/* VESA Init descriptor */
 #ifdef CONFIG_FB
-	{ 0xffff, 0, VESA_INIT_SEGMENT>>12, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
-#endif	
+	{ 0xffff, 0, VESA_INIT_SEGMENT >> 12, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
+#endif
 };
 
@@ -86,6 +86,8 @@
 
 /* gdtr is changed by kmp before next CPU is initialized */
-ptr_16_32_t bootstrap_gdtr = { .limit = sizeof(gdt), .base = KA2PA((uintptr_t) gdt) };
-ptr_16_32_t gdtr = { .limit = sizeof(gdt), .base = (uintptr_t) gdt };
+ptr_16_32_t gdtr = {
+	.limit = sizeof(gdt),
+	.base = (uintptr_t) gdt
+};
 
 void gdt_setbase(descriptor_t *d, uintptr_t base)
@@ -128,5 +130,5 @@
 
 		d->unused = 0;
-		d->selector = gdtselector(KTEXT_DES);
+		d->selector = GDT_SELECTOR(KTEXT_DES);
 
 		if (i == VECTOR_SYSCALL) {
@@ -283,5 +285,5 @@
 	 * to its own TSS. We just need to load the TR register.
 	 */
-	tr_load(gdtselector(TSS_DES));
+	tr_load(GDT_SELECTOR(TSS_DES));
 	
 	clean_IOPL_NT_flags();    /* Disable I/O on nonprivileged levels and clear NT flag. */
Index: kernel/arch/ia32/src/proc/scheduler.c
===================================================================
--- kernel/arch/ia32/src/proc/scheduler.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/proc/scheduler.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -67,5 +67,5 @@
 	/* Set kernel stack for CPL3 -> CPL0 switch via interrupt */
 	CPU->arch.tss->esp0 = kstk;
-	CPU->arch.tss->ss0 = gdtselector(KDATA_DES);
+	CPU->arch.tss->ss0 = GDT_SELECTOR(KDATA_DES);
 	
 	/* Set up TLS in GS register */
Index: kernel/arch/ia32/src/syscall.c
===================================================================
--- kernel/arch/ia32/src/syscall.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/syscall.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -45,5 +45,5 @@
 
 	/* set kernel mode CS selector */
-	write_msr(IA32_MSR_SYSENTER_CS, gdtselector(KTEXT_DES));
+	write_msr(IA32_MSR_SYSENTER_CS, GDT_SELECTOR(KTEXT_DES));
 	/* set kernel mode entry point */
 	write_msr(IA32_MSR_SYSENTER_EIP, (uint32_t) sysenter_handler);
Index: kernel/arch/ia32/src/userspace.c
===================================================================
--- kernel/arch/ia32/src/userspace.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/arch/ia32/src/userspace.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -75,11 +75,11 @@
 		"iret\n"
 		:
-		: [udata_des] "i" (gdtselector(UDATA_DES) | PL_USER),
+		: [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
 		  [stack_size] "r" ((uint8_t *) kernel_uarg->uspace_stack + THREAD_STACK_SIZE),
 		  [ipl] "r" (ipl),
-		  [utext_des] "i" (gdtselector(UTEXT_DES) | PL_USER),
+		  [utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
 		  [entry] "r" (kernel_uarg->uspace_entry),
 		  [uarg] "r" (kernel_uarg->uspace_uarg),
-		  [tls_des] "r" (gdtselector(TLS_DES))
+		  [tls_des] "r" (GDT_SELECTOR(TLS_DES))
 		: "eax");
 	
Index: kernel/genarch/Makefile.inc
===================================================================
--- kernel/genarch/Makefile.inc	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/genarch/Makefile.inc	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -90,4 +90,9 @@
 endif
 
+ifeq ($(CONFIG_S3C24XX_IRQC),y)
+	GENARCH_SOURCES += \
+		genarch/src/drivers/s3c24xx_irqc/s3c24xx_irqc.c
+endif
+
 ifeq ($(CONFIG_S3C24XX_UART),y)
 	GENARCH_SOURCES += \
Index: kernel/genarch/include/drivers/s3c24xx_irqc/s3c24xx_irqc.h
===================================================================
--- kernel/genarch/include/drivers/s3c24xx_irqc/s3c24xx_irqc.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/genarch/include/drivers/s3c24xx_irqc/s3c24xx_irqc.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -53,5 +53,5 @@
 	ioport32_t subsrcpnd;	/**< Sub source pending */
 	ioport32_t intsubmsk;	/** Interrupt sub mask */
-} s3c24xx_irqc_t;
+} s3c24xx_irqc_regs_t;
 
 /** S3C24xx Interrupt source numbers.
@@ -120,4 +120,16 @@
 #define S3C24XX_SUBINT_BIT(subsource) (1 << (subsource))
 
+typedef struct {
+	s3c24xx_irqc_regs_t *regs;
+} s3c24xx_irqc_t;
+
+extern void s3c24xx_irqc_init(s3c24xx_irqc_t *, s3c24xx_irqc_regs_t *);
+extern unsigned s3c24xx_irqc_inum_get(s3c24xx_irqc_t *);
+extern void s3c24xx_irqc_clear(s3c24xx_irqc_t *, unsigned);
+extern void s3c24xx_irqc_src_enable(s3c24xx_irqc_t *, unsigned);
+extern void s3c24xx_irqc_src_disable(s3c24xx_irqc_t *, unsigned);
+extern void s3c24xx_irqc_subsrc_enable(s3c24xx_irqc_t *, unsigned);
+extern void s3c24xx_irqc_subsrc_disable(s3c24xx_irqc_t *, unsigned);
+
 #endif
 
Index: kernel/genarch/include/drivers/s3c24xx_uart/s3c24xx_uart.h
===================================================================
--- kernel/genarch/include/drivers/s3c24xx_uart/s3c24xx_uart.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/genarch/include/drivers/s3c24xx_uart/s3c24xx_uart.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -38,8 +38,54 @@
 #define KERN_S3C24XX_UART_H_
 
+#include <ddi/irq.h>
+#include <console/chardev.h>
 #include <typedefs.h>
-#include <console/chardev.h>
 
-extern outdev_t *s3c24xx_uart_init(ioport8_t *);
+/** S3C24xx UART I/O */
+typedef struct {
+	uint32_t ulcon;
+	uint32_t ucon;
+	uint32_t ufcon;
+	uint32_t umcon;
+
+	uint32_t utrstat;
+	uint32_t uerstat;
+	uint32_t ufstat;
+	uint32_t umstat;
+
+	uint32_t utxh;
+	uint32_t urxh;
+
+	uint32_t ubrdiv;
+} s3c24xx_uart_io_t;
+
+/* Bits in UTRSTAT register */
+#define S3C24XX_UTRSTAT_TX_EMPTY	0x4
+#define S3C24XX_UTRSTAT_RDATA		0x1
+
+/* Bits in UFSTAT register */
+#define S3C24XX_UFSTAT_TX_FULL		0x4000
+#define S3C24XX_UFSTAT_RX_FULL		0x0040
+#define S3C24XX_UFSTAT_RX_COUNT		0x002f
+
+/* Bits in UCON register */
+#define UCON_RX_INT_LEVEL		0x100
+
+/* Bits in UFCON register */
+#define UFCON_TX_FIFO_TLEVEL_EMPTY	0x00
+#define UFCON_RX_FIFO_TLEVEL_1B		0x00
+#define UFCON_FIFO_ENABLE		0x01
+
+
+/** S3C24xx UART instance */
+typedef struct {
+	s3c24xx_uart_io_t *io;
+	indev_t *indev;
+	irq_t irq;
+} s3c24xx_uart_t;
+
+extern outdev_t *s3c24xx_uart_init(s3c24xx_uart_io_t *, inr_t inr);
+extern void s3c24xx_uart_input_wire(s3c24xx_uart_t *,
+    indev_t *);
 
 #endif
Index: kernel/genarch/src/drivers/s3c24xx_irqc/s3c24xx_irqc.c
===================================================================
--- kernel/genarch/src/drivers/s3c24xx_irqc/s3c24xx_irqc.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ kernel/genarch/src/drivers/s3c24xx_irqc/s3c24xx_irqc.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief Samsung S3C24xx on-chip interrupt controller.
+ *
+ * This IRQC is present on the Samsung S3C24xx CPU (on the gta02 platform).
+ */
+
+#include <genarch/drivers/s3c24xx_irqc/s3c24xx_irqc.h>
+#include <arch/asm.h>
+
+/** Correspondence between interrupt sources and sub-sources. */
+static unsigned s3c24xx_subsrc_src[][2] = {
+	{ S3C24XX_SUBINT_CAM_P, S3C24XX_INT_CAM },
+	{ S3C24XX_SUBINT_CAM_C, S3C24XX_INT_CAM },
+	{ S3C24XX_SUBINT_ADC_S, S3C24XX_INT_ADC },
+	{ S3C24XX_SUBINT_TC, S3C24XX_INT_ADC },
+	{ S3C24XX_SUBINT_ERR2, S3C24XX_INT_UART2 },
+	{ S3C24XX_SUBINT_TXD2, S3C24XX_INT_UART2 },
+	{ S3C24XX_SUBINT_RXD2, S3C24XX_INT_UART2 },
+	{ S3C24XX_SUBINT_ERR1, S3C24XX_INT_UART1 },
+	{ S3C24XX_SUBINT_TXD1, S3C24XX_INT_UART1 },
+	{ S3C24XX_SUBINT_RXD1, S3C24XX_INT_UART1 },
+	{ S3C24XX_SUBINT_ERR0, S3C24XX_INT_UART0 },
+	{ S3C24XX_SUBINT_TXD0, S3C24XX_INT_UART0 },
+	{ S3C24XX_SUBINT_RXD0, S3C24XX_INT_UART0 }
+};
+
+/** Initialize S3C24xx interrupt controller.
+ *
+ * @param irqc	Instance structure
+ * @param regs	Register I/O structure
+ */
+void s3c24xx_irqc_init(s3c24xx_irqc_t *irqc, s3c24xx_irqc_regs_t *regs)
+{
+	irqc->regs = regs;
+
+	/* Make all interrupt sources use IRQ mode (not FIQ). */
+	pio_write_32(&regs->intmod, 0x00000000);
+
+	/* Disable all interrupt sources. */
+	pio_write_32(&regs->intmsk, 0xffffffff);
+
+	/* Disable interrupts from all sub-sources. */
+	pio_write_32(&regs->intsubmsk, 0xffffffff);
+}
+
+/** Obtain number of pending interrupt. */
+unsigned s3c24xx_irqc_inum_get(s3c24xx_irqc_t *irqc)
+{
+	return pio_read_32(&irqc->regs->intoffset);
+}
+
+/** Clear pending interrupt condition including sub-sources.
+ *
+ * Clear source and interrupt pending condition and also automatically clear
+ * any sub-source pending condition pertaining to the source.
+ */
+void s3c24xx_irqc_clear(s3c24xx_irqc_t *irqc, unsigned inum)
+{
+	unsigned src, subsrc;
+	unsigned entries, i;
+
+	entries = sizeof(s3c24xx_subsrc_src) / sizeof(s3c24xx_subsrc_src[0]);
+
+	for (i = 0; i < entries; i++) {
+		subsrc = s3c24xx_subsrc_src[i][0];
+		src = s3c24xx_subsrc_src[i][1];
+
+		if (src == inum) {
+			pio_write_32(&irqc->regs->subsrcpnd,
+			    S3C24XX_SUBINT_BIT(subsrc));
+		}
+	}
+
+	pio_write_32(&irqc->regs->srcpnd, S3C24XX_INT_BIT(inum));
+	pio_write_32(&irqc->regs->intpnd, S3C24XX_INT_BIT(inum));
+}
+
+/** Enable interrupts from the specified source. */
+void s3c24xx_irqc_src_enable(s3c24xx_irqc_t *irqc, unsigned src)
+{
+	pio_write_32(&irqc->regs->intmsk, pio_read_32(&irqc->regs->intmsk) &
+	    ~S3C24XX_INT_BIT(src));
+}
+
+/** Disable interrupts from the specified source. */
+void s3c24xx_irqc_src_disable(s3c24xx_irqc_t *irqc, unsigned src)
+{
+	pio_write_32(&irqc->regs->intmsk, pio_read_32(&irqc->regs->intmsk) |
+	    S3C24XX_INT_BIT(src));
+}
+
+/** Enable interrupts from the specified sub-source. */
+void s3c24xx_irqc_subsrc_enable(s3c24xx_irqc_t *irqc, unsigned subsrc)
+{
+	pio_write_32(&irqc->regs->intsubmsk,
+	    pio_read_32(&irqc->regs->intsubmsk) &
+	    ~S3C24XX_SUBINT_BIT(subsrc));
+}
+
+/** Disable interrupts from the specified sub-source. */
+void s3c24xx_irqc_subsrc_disable(s3c24xx_irqc_t *irqc, unsigned subsrc)
+{
+	pio_write_32(&irqc->regs->intsubmsk,
+	    pio_read_32(&irqc->regs->intsubmsk) |
+	    S3C24XX_SUBINT_BIT(subsrc));
+}
+
+/** @}
+ */
Index: kernel/genarch/src/drivers/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- kernel/genarch/src/drivers/s3c24xx_uart/s3c24xx_uart.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/genarch/src/drivers/s3c24xx_uart/s3c24xx_uart.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -40,35 +40,21 @@
 #include <genarch/drivers/s3c24xx_uart/s3c24xx_uart.h>
 #include <console/chardev.h>
+#include <console/console.h>
+#include <ddi/device.h>
 #include <arch/asm.h>
 #include <mm/slab.h>
-#include <console/console.h>
 #include <sysinfo/sysinfo.h>
 #include <str.h>
 
-/** S3C24xx UART register offsets */
-#define S3C24XX_UTRSTAT		0x10
-#define S3C24XX_UTXH		0x20
-
-/* Bits in UTXH register */
-#define S3C24XX_UTXH_TX_EMPTY	0x4
-
-typedef struct {
-	ioport8_t *base;
-} s3c24xx_uart_instance_t;
-
 static void s3c24xx_uart_sendb(outdev_t *dev, uint8_t byte)
 {
-	s3c24xx_uart_instance_t *instance =
-	    (s3c24xx_uart_instance_t *) dev->data;
-	ioport32_t *utrstat, *utxh;
+	s3c24xx_uart_t *uart =
+	    (s3c24xx_uart_t *) dev->data;
 
-	utrstat = (ioport32_t *) (instance->base + S3C24XX_UTRSTAT);
-	utxh = (ioport32_t *) (instance->base + S3C24XX_UTXH);
-
-	/* Wait for transmitter to be empty. */
-	while ((pio_read_32(utrstat) & S3C24XX_UTXH_TX_EMPTY) == 0)
+	/* Wait for space becoming available in Tx FIFO. */
+	while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_TX_FULL) != 0)
 		;
 
-	pio_write_32(utxh, byte);
+	pio_write_32(&uart->io->utxh, byte);
 }
 
@@ -86,4 +72,20 @@
 }
 
+static irq_ownership_t s3c24xx_uart_claim(irq_t *irq)
+{
+	return IRQ_ACCEPT;
+}
+
+static void s3c24xx_uart_irq_handler(irq_t *irq)
+{
+	s3c24xx_uart_t *uart = irq->instance;
+
+	while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_RX_COUNT) != 0) {
+		uint32_t data = pio_read_32(&uart->io->urxh);
+		pio_read_32(&uart->io->uerstat);
+		indev_push_character(uart->indev, data & 0xff);
+	}
+}
+
 static outdev_operations_t s3c24xx_uart_ops = {
 	.write = s3c24xx_uart_putchar,
@@ -91,5 +93,5 @@
 };
 
-outdev_t *s3c24xx_uart_init(ioport8_t *base)
+outdev_t *s3c24xx_uart_init(s3c24xx_uart_io_t *io, inr_t inr)
 {
 	outdev_t *uart_dev = malloc(sizeof(outdev_t), FRAME_ATOMIC);
@@ -97,7 +99,7 @@
 		return NULL;
 
-	s3c24xx_uart_instance_t *instance =
-	    malloc(sizeof(s3c24xx_uart_instance_t), FRAME_ATOMIC);
-	if (!instance) {
+	s3c24xx_uart_t *uart =
+	    malloc(sizeof(s3c24xx_uart_t), FRAME_ATOMIC);
+	if (!uart) {
 		free(uart_dev);
 		return NULL;
@@ -105,7 +107,24 @@
 
 	outdev_initialize("s3c24xx_uart_dev", uart_dev, &s3c24xx_uart_ops);
-	uart_dev->data = instance;
+	uart_dev->data = uart;
 
-	instance->base = base;
+	uart->io = io;
+	uart->indev = NULL;
+
+	/* Initialize IRQ structure. */
+	irq_initialize(&uart->irq);
+	uart->irq.devno = device_assign_devno();
+	uart->irq.inr = inr;
+	uart->irq.claim = s3c24xx_uart_claim;
+	uart->irq.handler = s3c24xx_uart_irq_handler;
+	uart->irq.instance = uart;
+
+	/* Enable FIFO, Tx trigger level: empty, Rx trigger level: 1 byte. */
+	pio_write_32(&uart->io->ufcon, UFCON_FIFO_ENABLE |
+	    UFCON_TX_FIFO_TLEVEL_EMPTY | UFCON_RX_FIFO_TLEVEL_1B);
+
+	/* Set RX interrupt to pulse mode */
+	pio_write_32(&uart->io->ucon,
+	    pio_read_32(&uart->io->ucon) & ~UCON_RX_INT_LEVEL);
 
 	if (!fb_exported) {
@@ -116,5 +135,5 @@
 		sysinfo_set_item_val("fb", NULL, true);
 		sysinfo_set_item_val("fb.kind", NULL, 3);
-		sysinfo_set_item_val("fb.address.physical", NULL, KA2PA(base));
+		sysinfo_set_item_val("fb.address.physical", NULL, KA2PA(io));
 
 		fb_exported = true;
@@ -124,4 +143,13 @@
 }
 
+void s3c24xx_uart_input_wire(s3c24xx_uart_t *uart, indev_t *indev)
+{
+	ASSERT(uart);
+	ASSERT(indev);
+
+	uart->indev = indev;
+	irq_register(&uart->irq);
+}
+
 /** @}
  */
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ kernel/generic/src/mm/frame.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -161,6 +161,7 @@
 	for (j = zones.count; j > i; j--) {
 		zones.info[j] = zones.info[j - 1];
-		zones.info[j].buddy_system->data =
-		    (void *) &zones.info[j - 1];
+		if (zones.info[j].buddy_system != NULL)
+			zones.info[j].buddy_system->data =
+			    (void *) &zones.info[j];
 	}
 	
@@ -762,6 +763,7 @@
 	for (i = z2 + 1; i < zones.count; i++) {
 		zones.info[i - 1] = zones.info[i];
-		zones.info[i - 1].buddy_system->data =
-		    (void *) &zones.info[i - 1];
+		if (zones.info[i - 1].buddy_system != NULL)
+			zones.info[i - 1].buddy_system->data =
+			    (void *) &zones.info[i - 1];
 	}
 	
Index: tools/mkfat.py
===================================================================
--- tools/mkfat.py	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ tools/mkfat.py	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -343,12 +343,18 @@
 def usage(prname):
 	"Print usage syntax"
-	print prname + " <PATH> <IMAGE>"
+	print prname + " <EXTRA_BYTES> <PATH> <IMAGE>"
 
 def main():
-	if (len(sys.argv) < 3):
+	if (len(sys.argv) < 4):
 		usage(sys.argv[0])
 		return
 	
-	path = os.path.abspath(sys.argv[1])
+	if (not sys.argv[1].isdigit()):
+		print "<EXTRA_BYTES> must be a number"
+		return
+	
+	extra_bytes = int(sys.argv[1])
+	
+	path = os.path.abspath(sys.argv[2])
 	if (not os.path.isdir(path)):
 		print "<PATH> must be a directory"
@@ -365,9 +371,9 @@
 	
 	# Make sure the filesystem is large enought for FAT16
-	size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
+	size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size + extra_bytes
 	while (size / cluster_size < fat16_clusters):
 		if (cluster_size > sector_size):
 			cluster_size /= 2
-			size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size
+			size = subtree_size(path, cluster_size, dirent_size) + reserved_clusters * cluster_size + extra_bytes
 		else:
 			size = fat16_clusters * cluster_size + reserved_clusters * cluster_size
@@ -381,5 +387,5 @@
 	data_start = root_start + root_size
 	
-	outf = file(sys.argv[2], "w")
+	outf = file(sys.argv[3], "w")
 	
 	boot_sector = xstruct.create(BOOT_SECTOR)
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -66,7 +66,9 @@
 	srv/hid/adb_mouse \
 	srv/hid/char_mouse \
+	srv/hid/s3c24xx_ts \
 	srv/hid/fb \
 	srv/hid/kbd \
 	srv/hw/char/i8042 \
+	srv/hw/char/s3c24xx_uart \
 	srv/hw/netif/dp8390 \
 	srv/net/cfg \
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/Makefile.common	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -172,5 +172,9 @@
 ifneq ($(BINARY),)
 %.disasm: $(BINARY)
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	$(OBJDUMP) -d -S $< > $@
+else
 	$(OBJDUMP) -d $< > $@
+endif
 
 $(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBS) $(BASE_LIBS)
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/app/init/init.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -274,6 +274,8 @@
 	srv_start("/srv/cuda_adb");
 	srv_start("/srv/i8042");
+	srv_start("/srv/s3c24ser");
 	srv_start("/srv/adb_ms");
 	srv_start("/srv/char_ms");
+	srv_start("/srv/s3c24ts");
 	
 	spawn("/srv/fb");
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/app/klog/klog.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -43,11 +43,15 @@
 #include <event.h>
 #include <errno.h>
+#include <str_error.h>
 #include <io/klog.h>
 
-#define NAME  "klog"
+#define NAME       "klog"
+#define LOG_FNAME  "/log/klog"
 
 /* Pointer to klog area */
 static wchar_t *klog;
 static size_t klog_length;
+
+static FILE *log;
 
 static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
@@ -58,6 +62,17 @@
 	size_t i;
 	
-	for (i = klog_len - klog_stored; i < klog_len; i++)
-		putchar(klog[(klog_start + i) % klog_length]);
+	for (i = klog_len - klog_stored; i < klog_len; i++) {
+		wchar_t ch = klog[(klog_start + i) % klog_length];
+		
+		putchar(ch);
+		
+		if (log != NULL)
+			fputc(ch, log);
+	}
+	
+	if (log != NULL) {
+		fflush(log);
+		fsync(fileno(log));
+	}
 }
 
@@ -91,4 +106,14 @@
 	}
 	
+	/*
+	 * Mode "a" would be definitively much better here, but it is
+	 * not well supported by the FAT driver.
+	 *
+	 */
+	log = fopen(LOG_FNAME, "w");
+	if (log == NULL)
+		printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
+		    str_error(errno));
+	
 	async_set_interrupt_received(interrupt_received);
 	klog_update();
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/lib/c/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -84,4 +84,5 @@
 	generic/ipc.c \
 	generic/async.c \
+	generic/async_rel.c \
 	generic/loader.c \
 	generic/getopt.c \
Index: pace/lib/c/Makefile.toolchain
===================================================================
--- uspace/lib/c/Makefile.toolchain	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,128 +1,0 @@
-#
-# Copyright (C) 2005 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.
-#
-
-GCC_CFLAGS = -I$(LIBC_PREFIX)/include -O3 -imacros $(LIBC_PREFIX)/../../../config.h \
-	-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32$(ENDIANESS) \
-	-finput-charset=UTF-8 -ffreestanding -fno-builtin -nostdlib -nostdinc \
-	-Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes \
-	-Werror-implicit-function-declaration -pipe -g -D__$(ENDIANESS)__
-
-ICC_CFLAGS = -I$(LIBC_PREFIX)/include -O3 -imacros $(LIBC_PREFIX)/../../../config.h \
-	-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32$(ENDIANESS) \
-	-finput-charset=UTF-8 -ffreestanding -fno-builtin -nostdlib -nostdinc \
-	-Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes \
-	-Werror-implicit-function-declaration -pipe -g -D__$(ENDIANESS)__
-
-CLANG_CFLAGS = -I$(LIBC_PREFIX)/include -O3 -imacros $(LIBC_PREFIX)/../../../config.h \
-	-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32$(ENDIANESS) \
-	-finput-charset=UTF-8 -ffreestanding -fno-builtin -nostdlib -nostdinc \
-	-Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes \
-	-Werror-implicit-function-declaration -pipe -g -arch $(CLANG_ARCH) \
-	-D__$(ENDIANESS)__
-
-LFLAGS = -M -N $(SOFTINT_PREFIX)/libsoftint.a
-AFLAGS =
-
-## Cross-toolchain prefix
-#
-
-ifndef CROSS_PREFIX
-	CROSS_PREFIX = /usr/local
-endif
-
-## Setup platform configuration
-#
-
--include $(LIBC_PREFIX)/../../../Makefile.config
--include $(LIBC_PREFIX)/../../../config.defs
--include $(LIBC_PREFIX)/arch/$(UARCH)/Makefile.inc
-
-## Simple detection of the host system
-#
-HOST = $(shell uname)
-
-## On Solaris, some utilities have different names
-#
-ifeq ($(HOST),SunOS)
-	BINUTILS_PREFIX = "g"
-else
-	BINUTILS_PREFIX = ""
-endif
-
-## Toolchain configuration
-#
-
-JOBFILE = $(LIBC_PREFIX)/../../../tools/jobfile.py
-
-ifeq ($(COMPILER),gcc_cross)
-	CC = $(TOOLCHAIN_DIR)/$(TARGET)-gcc
-	GCC = $(CC)
-	AS = $(TOOLCHAIN_DIR)/$(TARGET)-as
-	LD = $(TOOLCHAIN_DIR)/$(TARGET)-ld
-	AR = $(TOOLCHAIN_DIR)/$(TARGET)-ar
-	OBJCOPY = $(TOOLCHAIN_DIR)/$(TARGET)-objcopy
-	OBJDUMP = $(TOOLCHAIN_DIR)/$(TARGET)-objdump
-	CFLAGS = $(GCC_CFLAGS)
-	DEPEND_DEFS = $(DEFS) $(CONFIG_DEFS)
-endif
-
-ifeq ($(COMPILER),gcc_native)
-	CC = gcc
-	GCC = $(CC)
-	AS = $(BINUTILS_PREFIX)as
-	LD = $(BINUTILS_PREFIX)ld
-	AR = $(BINUTILS_PREFIX)ar
-	OBJCOPY = $(BINUTILS_PREFIX)objcopy
-	OBJDUMP = $(BINUTILS_PREFIX)objdump
-	CFLAGS = $(GCC_CFLAGS)
-	DEPEND_DEFS = $(DEFS) $(CONFIG_DEFS)
-endif
-
-ifeq ($(COMPILER),icc)
-	CC = icc
-	GCC = gcc
-	AS = as
-	LD = ld
-	AR = ar
-	OBJCOPY = objcopy
-	OBJDUMP = objdump
-	CFLAGS = $(ICC_CFLAGS)
-	DEPEND_DEFS = $(DEFS) $(CONFIG_DEFS)
-endif
-
-ifeq ($(COMPILER),clang)
-	CC = clang
-	GCC = gcc
-	AS = $(BINUTILS_PREFIX)as
-	LD = $(BINUTILS_PREFIX)ld
-	AR = $(BINUTILS_PREFIX)ar
-	OBJCOPY = $(BINUTILS_PREFIX)objcopy
-	OBJDUMP = $(BINUTILS_PREFIX)objdump
-	CFLAGS = $(CLANG_CFLAGS)
-	DEPEND_DEFS = $(DEFS) $(CONFIG_DEFS)
-endif
Index: pace/lib/c/arch/amd64/include/limits.h
===================================================================
--- uspace/lib/c/arch/amd64/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,46 +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 libcamd64
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_amd64_LIMITS_H_
-#define LIBC_amd64_LIMITS_H_
-
-# define LONG_MIN MIN_INT64
-# define LONG_MAX MAX_INT64
-# define ULONG_MIN MIN_UINT64
-# define ULONG_MAX MAX_UINT64
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/arch/arm32/include/limits.h
===================================================================
--- uspace/lib/c/arch/arm32/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2007 Michal Kebrt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libcarm32	
- * @{
- */
-/** @file 
- *  @brief Limits declarations.
- */
-
-#ifndef LIBC_arm32__LIMITS_H_
-#define LIBC_arm32__LIMITS_H_
-
-#define LONG_MIN MIN_INT32
-#define LONG_MAX MAX_INT32
-#define ULONG_MIN MIN_UINT32
-#define ULONG_MAX MAX_UINT32
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/arch/ia32/include/limits.h
===================================================================
--- uspace/lib/c/arch/ia32/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,46 +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 libcia32
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_ia32__LIMITS_H_
-#define LIBC_ia32__LIMITS_H_
-
-# define LONG_MIN MIN_INT32
-# define LONG_MAX MAX_INT32
-# define ULONG_MIN MIN_UINT32
-# define ULONG_MAX MAX_UINT32
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/arch/ia64/include/limits.h
===================================================================
--- uspace/lib/c/arch/ia64/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,46 +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 libcia64	
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_ia64_LIMITS_H_
-#define LIBC_ia64_LIMITS_H_
-
-# define LONG_MIN MIN_INT64
-# define LONG_MAX MAX_INT64
-# define ULONG_MIN MIN_UINT64
-# define ULONG_MAX MAX_UINT64
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/arch/mips32/include/limits.h
===================================================================
--- uspace/lib/c/arch/mips32/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,47 +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 libcmips32	
- * @{
- */
-/** @file
- * @ingroup libcmips32eb	
- */
-
-#ifndef LIBC_mips32__LIMITS_H_
-#define LIBC_mips32__LIMITS_H_
-
-# define LONG_MIN MIN_INT32
-# define LONG_MAX MAX_INT32
-# define ULONG_MIN MIN_UINT32
-# define ULONG_MAX MAX_UINT32
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/arch/mips32eb/include/limits.h
===================================================================
--- uspace/lib/c/arch/mips32eb/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../../mips32/include/limits.h
Index: pace/lib/c/arch/ppc32/include/limits.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,46 +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 libcppc32	
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_ppc32_LIMITS_H_
-#define LIBC_ppc32_LIMITS_H_
-
-#define LONG_MIN MIN_INT32
-#define LONG_MAX MAX_INT32
-#define ULONG_MIN MIN_UINT32
-#define ULONG_MAX MAX_UINT32
-
-#endif
-
-/** @}
- */
Index: pace/lib/c/arch/sparc64/include/limits.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,46 +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 libcsparc64	
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_sparc64_LIMITS_H_
-#define LIBC_sparc64_LIMITS_H_
-
-#define LONG_MIN MIN_INT64
-#define LONG_MAX MAX_INT64
-#define ULONG_MIN MIN_UINT64
-#define ULONG_MAX MAX_UINT64
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/generic/async_rel.c
===================================================================
--- uspace/lib/c/generic/async_rel.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/lib/c/generic/async_rel.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2010 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+/**
+ * This file implements simple relation support for the async framework.
+ *
+ * By the term "relation", we mean a logical data path between a client and a
+ * server over which the client can send multiple, potentially blocking,
+ * requests to the server.
+ *
+ * Clients and servers are naturally connected using IPC phones, thus an IPC
+ * phone represents a connection between a client and a server. In one
+ * connection, there can be many relations.
+ *
+ * Relations are useful in situations in which there is only one IPC connection
+ * between the client and the server, but the client wants to be able to make
+ * multiple parallel requests. Using only a single phone and without any other
+ * provisions, all requests would have to be serialized. On the other hand, the
+ * client can make as many parallel requests as there are active relations.
+ *
+ * There are several possible implementations of relations. This implementation
+ * uses additional phones to represent relations. Using phones both for the
+ * primary connection and also for its relations has several advantages:
+ *
+ * - to make a series of requests over a relation, the client can continue to
+ *   use the existing async framework APIs
+ * - the server supports relations by the virtue of spawning a new connection
+ *   fibril, just as it does for every new connection even without relations
+ * - the implementation is pretty straightforward; a very naive implementation
+ *   would be to make each request using a fresh phone (that is what we have
+ *   done in the past); a slightly better approach would be to cache connected
+ *   phones so that they can be reused by a later relation within the same
+ *   connection (that is what this implementation does)
+ *
+ * The main disadvantages of using phones to represent relations are:
+ *
+ * - if there are too many relations (even cached ones), the task may hit its
+ *   limit on the maximum number of connected phones, which could prevent the
+ *   task from making new IPC connections to other tasks
+ * - if there are too many IPC connections already, it may be impossible to
+ *   create a relation by connecting a new phone thanks to the task's limit on
+ *   the maximum number of connected phones
+ *
+ * These problems can be helped by increasing the limit on the maximum number of
+ * connected phones to some reasonable value and by limiting the number of
+ * phones cached to some fraction of this limit.
+ *
+ * The cache itself has a mechanism to close some number of unused phones if a
+ * new phone cannot be connected, but the outter world currently does not have a
+ * way to ask the phone cache to shrink.
+ *
+ * To minimize the confusion stemming from the fact that we use phones for two
+ * things (the primary IPC connection and also each relation), this file makes
+ * the distinction by using the term 'key phone' for the former and 'relation
+ * phone' for the latter. Under the hood, all phones remain equal, of course.
+ *
+ * There is a small inefficiency in that the cache repeatedly allocates and
+ * deallocated the rel_node_t structures when in fact it could keep the
+ * allocated structures around and reuse them later. But such a solution would
+ * be effectively implementing a poor man's slab allocator while it would be
+ * better to have the slab allocator ported to uspace so that everyone could
+ * benefit from it.
+ */
+
+#include <async_rel.h>
+#include <ipc/ipc.h>
+#include <fibril_synch.h>
+#include <adt/list.h>
+#include <adt/hash_table.h>
+#include <malloc.h>
+#include <errno.h>
+#include <assert.h>
+
+#define KEY_NODE_HASH_BUCKETS	16
+
+typedef struct {
+	link_t link;		/**< Key node hash table link. */
+	int key_phone;		/**< The phone serving as a key. */
+	link_t rel_head;	/**< List of open relation phones. */
+} key_node_t;
+
+typedef struct {
+	link_t rel_link;	/**< Link for the list of relation phones. */
+	link_t global_link;	/**< Link for the global list of phones. */
+	int rel_phone;		/**< Connected relation phone. */
+} rel_node_t;
+
+/**
+ * Mutex protecting the global_rel_head list and the key_node_hash hash table.
+ */
+static fibril_mutex_t async_rel_mutex;
+
+/**
+ * List of all currently unused relation phones.
+ */
+static LIST_INITIALIZE(global_rel_head);
+
+/**
+ * Hash table containing lists of available relation phones for all key
+ * phones.
+ */
+static hash_table_t key_node_hash;
+
+static hash_index_t kn_hash(unsigned long *key)
+{
+	return *key % KEY_NODE_HASH_BUCKETS;
+}
+
+static int kn_compare(unsigned long *key, hash_count_t keys, link_t *item)
+{
+	key_node_t *knp = hash_table_get_instance(item, key_node_t, link);
+
+	return *key == (unsigned long) knp->key_phone;
+}
+
+static void kn_remove_callback(link_t *item)
+{
+}
+
+static hash_table_operations_t key_node_hash_ops = {
+	.hash = kn_hash,
+	.compare = kn_compare,
+	.remove_callback = kn_remove_callback
+};
+
+/** Initialize the async_rel subsystem.
+ *
+ * Needs to be called prior to any other interface in this file.
+ */
+int async_rel_init(void)
+{
+	fibril_mutex_initialize(&async_rel_mutex);
+	list_initialize(&global_rel_head);
+	return hash_table_create(&key_node_hash, KEY_NODE_HASH_BUCKETS, 1,
+	    &key_node_hash_ops);
+}
+
+static void key_node_initialize(key_node_t *knp)
+{
+	link_initialize(&knp->link);
+	knp->key_phone = -1;
+	list_initialize(&knp->rel_head);
+}
+
+static void rel_node_initialize(rel_node_t *rnp)
+{
+	link_initialize(&rnp->rel_link);
+	link_initialize(&rnp->global_link);
+	rnp->rel_phone = -1;
+}
+
+/** Create a new relation for a connection represented by a key phone.
+ *
+ * @param key_phone	Phone representing the connection.
+ * @return		Phone representing the new relation or a negative error
+ *			code.
+ */
+int async_relation_create(int key_phone)
+{
+	unsigned long key = (unsigned long) key_phone;
+	link_t *lnk;
+	key_node_t *knp;
+	rel_node_t *rnp;
+	int rel_phone;
+
+	fibril_mutex_lock(&async_rel_mutex);
+	lnk = hash_table_find(&key_node_hash, &key);
+	if (!lnk) {
+		/*
+		 * The key node was not found in the hash table. Try to allocate
+		 * and hash in a new one.
+		 */
+		knp = (key_node_t *) malloc(sizeof(key_node_t));
+		if (!knp) {
+			/*
+			 * As a possible improvement, we could make a one-time
+			 * attempt to create a phone without trying to add the
+			 * key node into the hash.
+			 */
+			fibril_mutex_unlock(&async_rel_mutex);
+			return ENOMEM;
+		}
+		key_node_initialize(knp);
+		knp->key_phone = key_phone;
+		hash_table_insert(&key_node_hash, &key, &knp->link);
+	} else {
+		/*
+		 * Found the key node.
+		 */
+		knp = hash_table_get_instance(lnk, key_node_t, link);
+	}
+
+	if (!list_empty(&knp->rel_head)) {
+		/*
+		 * There are available relation phones for the key phone.
+		 */
+		rnp = list_get_instance(knp->rel_head.next, rel_node_t,
+		    rel_link);
+		list_remove(&rnp->rel_link);
+		list_remove(&rnp->global_link);
+		
+		rel_phone = rnp->rel_phone;
+		free(rnp);
+	} else {
+		/*
+		 * There are no available relation phones for the key phone.
+		 * Make a one-time attempt to connect a new relation phone.
+		 */
+retry:
+		rel_phone = ipc_connect_me_to(key_phone, 0, 0, 0);
+		if (rel_phone >= 0) {
+			/* success, do nothing */
+		} else if (!list_empty(&global_rel_head)) {
+			/*
+			 * We did not manage to connect a new phone. But we can
+			 * try to hangup some currently unused phones and try
+			 * again.
+			 */
+			rnp = list_get_instance(global_rel_head.next,
+			    rel_node_t, global_link);
+			list_remove(&rnp->global_link);
+			list_remove(&rnp->rel_link);
+			rel_phone = rnp->rel_phone;
+			free(rnp);
+			ipc_hangup(rel_phone);
+			goto retry;
+		} else {
+			/*
+			 * This is unfortunate. We failed both to find a cached
+			 * phone or to create a new one even after cleaning up
+			 * the cache. This is most likely due to too many key
+			 * phones being kept connected.
+			 */
+			rel_phone = ELIMIT;
+		}
+	}
+
+	fibril_mutex_unlock(&async_rel_mutex);
+	return rel_phone;
+}
+
+/** Destroy a relation.
+ *
+ * @param key_phone	Phone representing the connection.
+ * @param rel_phone	Phone representing the relation within the connection.
+ */
+void async_relation_destroy(int key_phone, int rel_phone)
+{
+	unsigned long key = (unsigned long) key_phone;
+	key_node_t *knp;
+	rel_node_t *rnp;
+	link_t *lnk;
+
+	fibril_mutex_lock(&async_rel_mutex);
+	lnk = hash_table_find(&key_node_hash, &key);
+	assert(lnk);
+	knp = hash_table_get_instance(lnk, key_node_t, link);
+	rnp = (rel_node_t *) malloc(sizeof(rel_node_t));
+	if (!rnp) {
+		/*
+		 * Being unable to remember the connected relation phone here
+		 * means that we simply hangup.
+		 */
+		fibril_mutex_unlock(&async_rel_mutex);
+		ipc_hangup(rel_phone);
+		return;
+	}
+	rel_node_initialize(rnp);
+	rnp->rel_phone = rel_phone;
+	list_append(&rnp->rel_link, &knp->rel_head);
+	list_append(&rnp->global_link, &global_rel_head);
+	fibril_mutex_unlock(&async_rel_mutex);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/lib/c/generic/io/io.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -757,4 +757,14 @@
 }
 
+int fileno(FILE *stream)
+{
+	if (stream->klog) {
+		errno = EBADF;
+		return -1;
+	}
+	
+	return stream->fd;
+}
+
 int fphone(FILE *stream)
 {
Index: uspace/lib/c/generic/libc.c
===================================================================
--- uspace/lib/c/generic/libc.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/lib/c/generic/libc.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -50,4 +50,5 @@
 #include <ipc/ipc.h>
 #include <async.h>
+#include <async_rel.h>
 #include <as.h>
 #include <loader/pcb.h>
@@ -65,4 +66,5 @@
 	__heap_init();
 	__async_init();
+	(void) async_rel_init();
 	fibril_t *fibril = fibril_setup();
 	__tcb_set(fibril->tcb);
Index: uspace/lib/c/include/async_rel.h
===================================================================
--- uspace/lib/c/include/async_rel.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/lib/c/include/async_rel.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ASYNC_REL_H_
+#define LIBC_ASYNC_REL_H_
+
+extern int async_rel_init(void);
+extern int async_relation_create(int);
+extern void async_relation_destroy(int, int);
+
+#endif
+
+/** @}
+ */
Index: pace/lib/c/include/limits.h
===================================================================
--- uspace/lib/c/include/limits.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,74 +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 libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_LIMITS_H_
-#define LIBC_LIMITS_H_
-
-#include <stdint.h>
-#include <libarch/limits.h>
-
-/* char */
-#define SCHAR_MIN MIN_INT8
-#define SCHAR_MAX MAX_INT8
-#define UCHAR_MIN MIN_UINT8
-#define UCHAR_MAX MAX_UINT8
-
-#ifdef __CHAR_UNSIGNED__
-# define CHAR_MIN UCHAR_MIN
-# define CHAR_MAX UCHAR_MAX
-#else
-# define CHAR_MIN SCHAR_MIN
-# define CHAR_MAX SCHAR_MAX
-#endif
-
-/* short int */
-#define SHRT_MIN MIN_INT16
-#define SHRT_MAX MAX_INT16
-#define USHRT_MIN MIN_UINT16
-#define USHRT_MAX MAX_UINT16
-
-#define INT_MIN MIN_INT32
-#define INT_MAX MAX_INT32
-#define UINT_MIN MIN_UINT32
-#define UINT_MAX MAX_UINT32
-
-#define LLONG_MIN MIN_INT64
-#define LLONG_MAX MAX_INT64
-#define ULLONG_MIN MIN_UINT64
-#define ULLONG_MAX MAX_UINT64
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/lib/c/include/stdio.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -171,4 +171,5 @@
 extern off64_t ftell(FILE *);
 extern int feof(FILE *);
+extern int fileno(FILE *);
 
 extern int fflush(FILE *);
Index: pace/lib/libpci/Makefile.build
===================================================================
--- uspace/lib/libpci/Makefile.build	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,64 +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.
-#
-
-## Setup toolchain
-#
-
-include Makefile.common
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-## Sources
-#
-
-SOURCES = \
-	access.c \
-	generic.c \
-	names.c \
-	i386-ports.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all
-
-all: $(LIBPCI)
-
--include $(DEPEND)
-
-$(LIBPCI): $(OBJECTS)
-	$(AR) rc $@ $(OBJECTS)
-
-%.o: %.c $(DEPEND)
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
-ifeq ($(PRECHECK),y)
-	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
-endif
-
-$(DEPEND):
-	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
-	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: pace/lib/libpci/Makefile.common
===================================================================
--- uspace/lib/libpci/Makefile.common	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2005 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.
-#
-
-
-## Common names
-#
-
-LIBC_PREFIX = ../../../../../lib/libc
-DEPEND = Makefile.depend
-DEPEND_PREV = $(DEPEND).prev
-JOB = libpci.job
-LIBPCI = libpci.a
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -1527,6 +1527,25 @@
 void fat_sync(ipc_callid_t rid, ipc_call_t *request)
 {
-	/* Dummy implementation */
-	ipc_answer_0(rid, EOK);
+	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	fs_node_t *fn;
+	int rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
+	if (!fn) {
+		ipc_answer_0(rid, ENOENT);
+		return;
+	}
+	
+	fat_node_t *nodep = FAT_NODE(fn);
+	
+	nodep->dirty = true;
+	rc = fat_node_sync(nodep);
+	
+	fat_node_put(fn);
+	ipc_answer_0(rid, rc);
 }
 
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -736,5 +736,8 @@
 void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request)
 {
-	/* Dummy implementation */
+	/*
+	 * TMPFS keeps its data structures always consistent,
+	 * thus the sync operation is a no-op.
+	 */
 	ipc_answer_0(rid, EOK);
 }
Index: uspace/srv/hid/console/gcons.c
===================================================================
--- uspace/srv/hid/console/gcons.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/hid/console/gcons.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -286,4 +286,7 @@
 	ssize_t nx = (ssize_t) mouse_x + dx;
 	ssize_t ny = (ssize_t) mouse_y + dy;
+
+	if (!use_gcons)
+		return;
 	
 	mouse_x = (size_t) limit(nx, 0, xres);
Index: uspace/srv/hid/fb/fb.c
===================================================================
--- uspace/srv/hid/fb/fb.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/hid/fb/fb.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -1347,6 +1347,6 @@
 {
 	mouse_hide();
-	pointer_x = x;
-	pointer_y = y;
+	pointer_x = x % screen.xres;
+	pointer_y = y % screen.yres;
 	mouse_show();
 }
Index: uspace/srv/hid/kbd/Makefile
===================================================================
--- uspace/srv/hid/kbd/Makefile	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/hid/kbd/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -60,6 +60,6 @@
 	ifeq ($(MACHINE),gta02)
 		SOURCES += \
-			port/dummy.c \
-			ctl/pc.c
+			port/chardev.c \
+			ctl/stty.c
 	endif
 	ifeq ($(MACHINE),testarm)
Index: uspace/srv/hid/kbd/port/chardev.c
===================================================================
--- uspace/srv/hid/kbd/port/chardev.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/hid/kbd/port/chardev.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -41,4 +41,5 @@
 #include <kbd.h>
 #include <vfs/vfs.h>
+#include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -50,21 +51,41 @@
 #define NAME "kbd"
 
+/** List of devices to try connecting to. */
+static const char *in_devs[] = {
+	"/dev/char/ps2a",
+	"/dev/char/s3c24ser"
+};
+
+static const int num_devs = sizeof(in_devs) / sizeof(in_devs[0]);
+
 int kbd_port_init(void)
 {
-	const char *input = "/dev/char/ps2a";
 	int input_fd;
+	int i;
 
-	printf(NAME ": open %s\n", input);
+	input_fd = -1;
+	for (i = 0; i < num_devs; i++) {
+		struct stat s;
 
-	input_fd = open(input, O_RDONLY);
+		if (stat(in_devs[i], &s) == EOK)
+			break;
+	}
+
+	if (i >= num_devs) {
+		printf(NAME ": Could not find any suitable input device.\n");
+		return -1;
+	}
+
+	input_fd = open(in_devs[i], O_RDONLY);
 	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s (%d)\n", input, input_fd);
-		return false;
+		printf(NAME ": failed opening device %s (%d).\n", in_devs[i],
+		    input_fd);
+		return -1;
 	}
 
 	dev_phone = fd_phone(input_fd);
 	if (dev_phone < 0) {
-		printf(NAME ": Failed to connect to device\n");
-		return false;
+		printf(NAME ": Failed connecting to device\n");
+		return -1;
 	}
 
@@ -73,5 +94,5 @@
 	if (ipc_connect_to_me(dev_phone, 0, 0, 0, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from device\n");
-		return false;
+		return -1;
 	}
 
Index: pace/srv/hid/kbd/port/i8042.h
===================================================================
--- uspace/srv/hid/kbd/port/i8042.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ 	(revision )
@@ -1,55 +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 KBD_PORT_i8042_H_
-#define KBD_PORT_i8042_H_
-
-#include <libarch/ddi.h>
-#include <libarch/types.h>
-
-struct i8042 {
-	ioport8_t data;
-	uint8_t pad[3];
-	ioport8_t status;
-} __attribute__ ((packed));
-typedef struct i8042 i8042_t;
-
-#endif
-
-/**
- * @}
- */ 
Index: uspace/srv/hid/s3c24xx_ts/Makefile
===================================================================
--- uspace/srv/hid/s3c24xx_ts/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/srv/hid/s3c24xx_ts/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+
+# Need to use short name because of FAT 8+3 limit
+BINARY = s3c24ts
+
+SOURCES = \
+	s3c24xx_ts.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup mouse
+ * @{
+ */
+/**
+ * @file
+ * @brief Samsung Samsung S3C24xx on-chip ADC and touch-screen interface driver.
+ *
+ * This interface is present on the Samsung S3C24xx CPU (on the gta02 platform).
+ */
+
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <devmap.h>
+#include <io/console.h>
+#include <vfs/vfs.h>
+#include <ipc/ipc.h>
+#include <ipc/mouse.h>
+#include <async.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysinfo.h>
+#include <errno.h>
+
+#include "s3c24xx_ts.h"
+
+#define NAME "s3c24ser"
+#define NAMESPACE "hid_in"
+
+static irq_cmd_t ts_irq_cmds[] = {
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+static irq_code_t ts_irq_code = {
+	sizeof(ts_irq_cmds) / sizeof(irq_cmd_t),
+	ts_irq_cmds
+};
+
+/** S3C24xx touchscreen instance structure */
+static s3c24xx_ts_t *ts;
+
+static void s3c24xx_ts_connection(ipc_callid_t iid, ipc_call_t *icall);
+static void s3c24xx_ts_irq_handler(ipc_callid_t iid, ipc_call_t *call);
+static void s3c24xx_ts_pen_down(s3c24xx_ts_t *ts);
+static void s3c24xx_ts_pen_up(s3c24xx_ts_t *ts);
+static void s3c24xx_ts_eoc(s3c24xx_ts_t *ts);
+static int s3c24xx_ts_init(s3c24xx_ts_t *ts);
+static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *ts, ts_updn_t updn);
+static void s3c24xx_ts_convert_samples(int smp0, int smp1, int *x, int *y);
+static int lin_map_range(int v, int i0, int i1, int o0, int o1);
+
+int main(int argc, char *argv[])
+{
+	int rc;
+
+	printf(NAME ": S3C24xx touchscreen driver\n");
+
+	rc = devmap_driver_register(NAME, s3c24xx_ts_connection);
+	if (rc < 0) {
+		printf(NAME ": Unable to register driver.\n");
+		return -1;
+	}
+
+	ts = malloc(sizeof(s3c24xx_ts_t));
+	if (ts == NULL)
+		return -1;
+
+	if (s3c24xx_ts_init(ts) != EOK)
+		return -1;
+
+	rc = devmap_device_register(NAMESPACE "/mouse", &ts->dev_handle);
+	if (rc != EOK) {
+		devmap_hangup_phone(DEVMAP_DRIVER);
+		printf(NAME ": Unable to register device %s.\n",
+		    NAMESPACE "/mouse");
+		return -1;
+	}
+
+	printf(NAME ": Registered device %s.\n", NAMESPACE "/mouse");
+
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
+	return 0;
+}
+
+/** Initialize S3C24xx touchscreen interface. */
+static int s3c24xx_ts_init(s3c24xx_ts_t *ts)
+{
+	void *vaddr;
+	sysarg_t inr;
+
+	inr = S3C24XX_TS_INR;
+	ts->paddr = S3C24XX_TS_ADDR;
+
+	if (pio_enable((void *) ts->paddr, sizeof(s3c24xx_adc_io_t),
+	    &vaddr) != 0)
+		return -1;
+
+	ts->io = vaddr;
+	ts->client_phone = -1;
+	ts->state = ts_wait_pendown;
+	ts->last_x = 0;
+	ts->last_y = 0;
+
+	printf(NAME ": device at physical address 0x%x, inr %d.\n",
+	    ts->paddr, inr);
+
+	async_set_interrupt_received(s3c24xx_ts_irq_handler);
+	ipc_register_irq(inr, device_assign_devno(), 0, &ts_irq_code);
+
+	s3c24xx_ts_wait_for_int_mode(ts, updn_down);
+
+	return EOK;
+}
+
+/** Switch interface to wait for interrupt mode.
+ *
+ * In this mode we receive an interrupt when pen goes up/down, depending
+ * on @a updn.
+ *
+ * @param ts	Touchscreen instance
+ * @param updn	@c updn_up to wait for pen up, @c updn_down to wait for pen
+ *		down.
+ */
+static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *ts, ts_updn_t updn)
+{
+	uint32_t con, tsc;
+
+	/*
+	 * Configure ADCCON register
+	 */
+
+	con = pio_read_32(&ts->io->con);
+
+	/* Disable standby, disable start-by-read, clear manual start bit */
+	con = con & ~(ADCCON_STDBM | ADCCON_READ_START | ADCCON_ENABLE_START);
+
+	/* Set prescaler value 0xff, XP for input. */
+	con = con | (ADCCON_PRSCVL(0xff) << 6) | ADCCON_SEL_MUX(SMUX_XP);
+
+	/* Enable prescaler. */
+	con = con | ADCCON_PRSCEN;
+
+ 	pio_write_32(&ts->io->con, con);
+
+	/*
+	 * Configure ADCTSC register
+	 */
+
+	tsc = pio_read_32(&ts->io->tsc);
+
+	/* Select whether waiting for pen up or pen down. */
+	if (updn == updn_up)
+		tsc |= ADCTSC_DSUD_UP;
+	else
+		tsc &= ~ADCTSC_DSUD_UP;
+
+	/*
+	 * Enable XP pull-up and disable all drivers except YM. This is
+	 * according to the manual. This gives us L on XP input when touching
+	 * and (pulled up to) H when not touching.
+	 */
+	tsc = tsc & ~(ADCTSC_XM_ENABLE | ADCTSC_AUTO_PST |
+	    ADCTSC_PULLUP_DISABLE);
+	tsc = tsc | ADCTSC_YP_DISABLE | ADCTSC_XP_DISABLE | ADCTSC_YM_ENABLE;
+
+	/* Select wait-for-interrupt mode. */
+	tsc = (tsc & ~ADCTSC_XY_PST_MASK) | ADCTSC_XY_PST_WAITINT;
+
+	pio_write_32(&ts->io->tsc, tsc);
+}
+
+/** Handle touchscreen interrupt */
+static void s3c24xx_ts_irq_handler(ipc_callid_t iid, ipc_call_t *call)
+{
+	ts_updn_t updn;
+
+	(void) iid; (void) call;
+
+	/* Read up/down interrupt flags. */
+	updn = pio_read_32(&ts->io->updn);
+
+	if (updn & (ADCUPDN_TSC_DN | ADCUPDN_TSC_UP)) {
+		/* Clear up/down interrupt flags. */
+		pio_write_32(&ts->io->updn, updn &
+		    ~(ADCUPDN_TSC_DN | ADCUPDN_TSC_UP));
+	}
+
+	if (updn & ADCUPDN_TSC_DN) {
+		/* Pen-down interrupt */
+		s3c24xx_ts_pen_down(ts);
+	} else if (updn & ADCUPDN_TSC_UP) {
+		/* Pen-up interrupt */
+		s3c24xx_ts_pen_up(ts);
+	} else {
+		/* Presumably end-of-conversion interrupt */
+
+		/* Check end-of-conversion flag. */
+		if ((pio_read_32(&ts->io->con) & ADCCON_ECFLG) == 0) {
+			printf(NAME ": Unrecognized ts int.\n");
+			return;
+		}
+
+		if (ts->state != ts_sample_pos) {
+			/*
+			 * We got an extra interrupt ater switching to
+			 * wait for interrupt mode.
+			 */
+			return;
+		}
+
+		/* End-of-conversion interrupt */
+		s3c24xx_ts_eoc(ts);
+	}
+}
+
+/** Handle pen-down interrupt.
+ *
+ * @param ts	Touchscreen instance
+ */
+static void s3c24xx_ts_pen_down(s3c24xx_ts_t *ts)
+{
+	/* Pen-down interrupt */
+
+	ts->state = ts_sample_pos;
+
+	/* Enable auto xy-conversion mode */
+	pio_write_32(&ts->io->tsc, (pio_read_32(&ts->io->tsc)
+	    & ~3) | 4);
+
+	/* Start the conversion. */
+	pio_write_32(&ts->io->con, pio_read_32(&ts->io->con)
+	    | ADCCON_ENABLE_START);
+}
+
+/** Handle pen-up interrupt.
+ *
+ * @param ts	Touchscreen instance
+ */
+static void s3c24xx_ts_pen_up(s3c24xx_ts_t *ts)
+{
+	int button, press;
+
+	/* Pen-up interrupt */
+
+	ts->state = ts_wait_pendown;
+
+	button = 1;
+	press = 0;
+	async_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
+
+	s3c24xx_ts_wait_for_int_mode(ts, updn_down);
+}
+
+/** Handle end-of-conversion interrupt.
+ *
+ * @param ts	Touchscreen instance
+ */
+static void s3c24xx_ts_eoc(s3c24xx_ts_t *ts)
+{
+	uint32_t data;
+	int button, press;
+	int smp0, smp1;
+	int x_pos, y_pos;
+	int dx, dy;
+
+	ts->state = ts_wait_penup;
+
+	/* Read in sampled data. */
+
+	data = pio_read_32(&ts->io->dat0);
+	smp0 = data & 0x3ff;
+
+	data = pio_read_32(&ts->io->dat1);
+	smp1 = data & 0x3ff;
+
+	/* Convert to screen coordinates. */
+	s3c24xx_ts_convert_samples(smp0, smp1, &x_pos, &y_pos);
+
+	printf("s0: 0x%03x, s1:0x%03x -> x:%d,y:%d\n", smp0, smp1,
+	    x_pos, y_pos);
+
+	/* Get differences. */
+	dx = x_pos - ts->last_x;
+	dy = y_pos - ts->last_y;
+
+	button = 1;
+	press = 1;
+
+	/* Send notifications to client. */
+	async_msg_2(ts->client_phone, MEVENT_MOVE, dx, dy);
+	async_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
+
+	ts->last_x = x_pos;
+	ts->last_y = y_pos;
+
+	s3c24xx_ts_wait_for_int_mode(ts, updn_up);
+}
+
+/** Convert sampled data to screen coordinates. */
+static void s3c24xx_ts_convert_samples(int smp0, int smp1, int *x, int *y)
+{
+	/*
+	 * The orientation and display dimensions are GTA02-specific and the
+	 * calibration values might even specific to the individual piece
+	 * of hardware.
+	 *
+	 * The calibration values can be obtained by touching corners
+	 * of the screen with the stylus and noting the sampled values.
+	 */
+	*x = lin_map_range(smp1, 0xa1, 0x396, 0, 479);
+	*y = lin_map_range(smp0, 0x69, 0x38a, 639, 0);
+}
+
+/** Map integer from one range to another range in a linear fashion.
+ *
+ * i0 < i1 is required. i0 is mapped to o0, i1 to o1. If o1 < o0, then the
+ * mapping will be descending. If v is outside of [i0, i1], it is clamped.
+ *
+ * @param v	Value to map.
+ * @param i0	Lower bound of input range.
+ * @param i1	Upper bound of input range.
+ * @param o0	First bound of output range.
+ * @param o1	Second bound of output range.
+ *
+ * @return	Mapped value ov, o0 <= ov <= o1.
+ */
+static int lin_map_range(int v, int i0, int i1, int o0, int o1)
+{
+	if (v < i0)
+		v = i0;
+
+	if (v > i1)
+		v = i1;
+
+	return o0 + (o1 - o0) * (v - i0) / (i1 - i0);
+}
+
+/** Handle mouse client connection. */
+static void s3c24xx_ts_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	int retval;
+
+	ipc_answer_0(iid, EOK);
+
+	while (1) {
+		callid = async_get_call(&call);
+		switch (IPC_GET_METHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			if (ts->client_phone != -1) {
+				ipc_hangup(ts->client_phone);
+				ts->client_phone = -1;
+			}
+
+			ipc_answer_0(callid, EOK);
+			return;
+		case IPC_M_CONNECT_TO_ME:
+			if (ts->client_phone != -1) {
+				retval = ELIMIT;
+				break;
+			}
+			ts->client_phone = IPC_GET_ARG5(call);
+			retval = 0;
+			break;
+		default:
+			retval = EINVAL;
+		}
+		ipc_answer_0(callid, retval);
+	}
+}
+
+/** @}
+ */
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief Samsung S3C24xx on-chip ADC and touch-screen interface driver.
+ */
+
+#ifndef S3C24XX_TS_H_
+#define S3C24XX_TS_H_
+
+#include <sys/types.h>
+
+/** S3C24xx ADC and touch-screen I/O */
+typedef struct {
+	uint32_t con;
+	uint32_t tsc;
+	uint32_t dly;
+	uint32_t dat0;
+	uint32_t dat1;
+	uint32_t updn;
+} s3c24xx_adc_io_t;
+
+/* Fields in ADCCON register */
+#define ADCCON_ECFLG		0x8000
+#define ADCCON_PRSCEN		0x4000
+
+#define ADCCON_PRSCVL(val)	(((val) & 0xff) << 6)
+
+#define ADCCON_SEL_MUX(smux)	(((smux) & 7) << 3)
+
+#define ADCCON_STDBM		0x0004
+#define ADCCON_READ_START	0x0002
+#define ADCCON_ENABLE_START	0x0001
+
+/* Values for ADCCON_SEL_MUX */
+#define SMUX_AIN0		0
+#define SMUX_AIN1		1
+#define SMUX_AIN2		2
+#define SMUX_AIN3		3
+#define SMUX_YM			4
+#define SMUX_YP			5
+#define SMUX_XM			6
+#define SMUX_XP			7
+
+
+/* Fields in ADCTSC register */
+#define ADCTSC_DSUD_UP		0x0100
+#define ADCTSC_YM_ENABLE	0x0080
+#define ADCTSC_YP_DISABLE	0x0040
+#define ADCTSC_XM_ENABLE	0x0020
+#define ADCTSC_XP_DISABLE	0x0010
+#define ADCTSC_PULLUP_DISABLE	0x0008
+#define ADCTSC_AUTO_PST		0x0004
+
+#define ADCTSC_XY_PST_NOOP	0x0000
+#define ADCTSC_XY_PST_X		0x0001
+#define ADCTSC_XY_PST_Y		0x0002
+#define ADCTSC_XY_PST_WAITINT	0x0003
+#define ADCTSC_XY_PST_MASK	0x0003
+
+/* Fields in ADCDAT0, ADCDAT1 registers */
+#define ADCDAT_UPDOWN		0x8000
+#define ADCDAT_AUTO_PST		0x4000
+
+/* Fields in ADCUPDN register */
+#define ADCUPDN_TSC_UP		0x0002
+#define ADCUPDN_TSC_DN		0x0001
+
+/** Touchscreen interrupt number */
+#define S3C24XX_TS_INR		31
+
+/** Touchscreen I/O address */
+#define S3C24XX_TS_ADDR		0x58000000
+
+typedef enum {
+	ts_wait_pendown,
+	ts_sample_pos,
+	ts_wait_penup
+} ts_state_t;
+
+typedef enum {
+	updn_up,
+	updn_down
+} ts_updn_t;
+
+/** S3C24xx touchscreen driver instance */
+typedef struct {
+	/** Physical device address */
+	uintptr_t paddr;
+
+	/** Device I/O structure */
+	s3c24xx_adc_io_t *io;
+
+	/** Callback phone to the client */
+	int client_phone;
+
+	/** Device handle */
+	dev_handle_t dev_handle;
+
+	/** Device/driver state */
+	ts_state_t state;
+
+	/** Previous position reported to client. */
+	int last_x;
+	int last_y;
+} s3c24xx_ts_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/char/s3c24xx_uart/Makefile
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/srv/hw/char/s3c24xx_uart/Makefile	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../../..
+
+# Need to use short name because of FAT 8+3 limit
+BINARY = s3c24ser
+
+SOURCES = \
+	s3c24xx_uart.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup driver_serial
+ * @{
+ */
+/**
+ * @file
+ * @brief Samsung S3C24xx on-chip UART driver.
+ *
+ * This UART is present on the Samsung S3C24xx CPU (on the gta02 platform).
+ */
+
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <devmap.h>
+#include <ipc/ipc.h>
+#include <ipc/char.h>
+#include <async.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysinfo.h>
+#include <errno.h>
+
+#include "s3c24xx_uart.h"
+
+#define NAME "s3c24ser"
+#define NAMESPACE "char"
+
+static irq_cmd_t uart_irq_cmds[] = {
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+static irq_code_t uart_irq_code = {
+	sizeof(uart_irq_cmds) / sizeof(irq_cmd_t),
+	uart_irq_cmds
+};
+
+/** S3C24xx UART instance structure */
+static s3c24xx_uart_t *uart;
+
+static void s3c24xx_uart_connection(ipc_callid_t iid, ipc_call_t *icall);
+static void s3c24xx_uart_irq_handler(ipc_callid_t iid, ipc_call_t *call);
+static int s3c24xx_uart_init(s3c24xx_uart_t *uart);
+static void s3c24xx_uart_sendb(s3c24xx_uart_t *uart, uint8_t byte);
+
+int main(int argc, char *argv[])
+{
+	int rc;
+
+	printf(NAME ": S3C24xx on-chip UART driver\n");
+
+	rc = devmap_driver_register(NAME, s3c24xx_uart_connection);
+	if (rc < 0) {
+		printf(NAME ": Unable to register driver.\n");
+		return -1;
+	}
+
+	uart = malloc(sizeof(s3c24xx_uart_t));
+	if (uart == NULL)
+		return -1;
+
+	if (s3c24xx_uart_init(uart) != EOK)
+		return -1;
+
+	rc = devmap_device_register(NAMESPACE "/" NAME, &uart->dev_handle);
+	if (rc != EOK) {
+		devmap_hangup_phone(DEVMAP_DRIVER);
+		printf(NAME ": Unable to register device %s.\n");
+		return -1;
+	}
+
+	printf(NAME ": Registered device %s.\n", NAMESPACE "/" NAME);
+
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
+	return 0;
+}
+
+/** Character device connection handler. */
+static void s3c24xx_uart_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	ipcarg_t method;
+	int retval;
+
+	/* Answer the IPC_M_CONNECT_ME_TO call. */
+	ipc_answer_0(iid, EOK);
+
+	while (1) {
+		callid = async_get_call(&call);
+		method = IPC_GET_METHOD(call);
+		switch (method) {
+		case IPC_M_PHONE_HUNGUP:
+			/* The other side has hung up. */
+			ipc_answer_0(callid, EOK);
+			return;
+		case IPC_M_CONNECT_TO_ME:
+			printf(NAME ": creating callback connection\n");
+			uart->client_phone = IPC_GET_ARG5(call);
+			retval = 0;
+			break;
+		case CHAR_WRITE_BYTE:
+			printf(NAME ": write %d to device\n",
+			    IPC_GET_ARG1(call));
+			s3c24xx_uart_sendb(uart, (uint8_t) IPC_GET_ARG1(call));
+			retval = 0;
+			break;
+		default:
+			retval = EINVAL;
+			break;
+		}
+		ipc_answer_0(callid, retval);
+	}
+}
+
+static void s3c24xx_uart_irq_handler(ipc_callid_t iid, ipc_call_t *call)
+{
+	(void) iid; (void) call;
+
+	while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_RX_COUNT) != 0) {
+		uint32_t data = pio_read_32(&uart->io->urxh) & 0xff;
+		uint32_t status = pio_read_32(&uart->io->uerstat);
+
+		if (uart->client_phone != -1) {
+			async_msg_1(uart->client_phone, CHAR_NOTIF_BYTE,
+			    data);
+		}
+
+		if (status != 0)
+			printf(NAME ": Error status 0x%x\n", status);
+	}
+}
+
+/** Initialize S3C24xx on-chip UART. */
+static int s3c24xx_uart_init(s3c24xx_uart_t *uart)
+{
+	void *vaddr;
+	sysarg_t inr;
+
+	if (sysinfo_get_value("s3c24xx_uart.address.physical",
+	    &uart->paddr) != EOK)
+		return -1;
+
+	if (pio_enable((void *) uart->paddr, sizeof(s3c24xx_uart_io_t),
+	    &vaddr) != 0)
+		return -1;
+
+	if (sysinfo_get_value("s3c24xx_uart.inr", &inr) != EOK)
+		return -1;
+
+	uart->io = vaddr;
+	uart->client_phone = -1;
+
+	printf(NAME ": device at physical address 0x%x, inr %d.\n",
+	    uart->paddr, inr);
+
+	async_set_interrupt_received(s3c24xx_uart_irq_handler);
+
+	ipc_register_irq(inr, device_assign_devno(), 0, &uart_irq_code);
+
+	/* Enable FIFO, Tx trigger level: empty, Rx trigger level: 1 byte. */
+	pio_write_32(&uart->io->ufcon, UFCON_FIFO_ENABLE |
+	    UFCON_TX_FIFO_TLEVEL_EMPTY | UFCON_RX_FIFO_TLEVEL_1B);
+
+	/* Set RX interrupt to pulse mode */
+	pio_write_32(&uart->io->ucon,
+	    pio_read_32(&uart->io->ucon) & ~UCON_RX_INT_LEVEL);
+
+	return EOK;
+}
+
+/** Send a byte to the UART. */
+static void s3c24xx_uart_sendb(s3c24xx_uart_t *uart, uint8_t byte)
+{
+	/* Wait for space becoming available in Tx FIFO. */
+	while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_TX_FULL) != 0)
+		;
+
+	pio_write_32(&uart->io->utxh, byte);
+}
+
+/** @}
+ */
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief Samsung S3C24xx on-chip UART driver.
+ */
+
+#ifndef S3C24XX_UART_H_
+#define S3C24XX_UART_H_
+
+#include <sys/types.h>
+
+/** S3C24xx UART I/O */
+typedef struct {
+	uint32_t ulcon;
+	uint32_t ucon;
+	uint32_t ufcon;
+	uint32_t umcon;
+
+	uint32_t utrstat;
+	uint32_t uerstat;
+	uint32_t ufstat;
+	uint32_t umstat;
+
+	uint32_t utxh;
+	uint32_t urxh;
+
+	uint32_t ubrdiv;
+} s3c24xx_uart_io_t;
+
+/* Bits in UTRSTAT register */
+#define S3C24XX_UTRSTAT_TX_EMPTY	0x4
+#define S3C24XX_UTRSTAT_RDATA		0x1
+
+/* Bits in UFSTAT register */
+#define S3C24XX_UFSTAT_TX_FULL		0x4000
+#define S3C24XX_UFSTAT_RX_FULL		0x0040
+#define S3C24XX_UFSTAT_RX_COUNT		0x002f
+
+/* Bits in UCON register */
+#define UCON_RX_INT_LEVEL		0x100
+
+/* Bits in UFCON register */
+#define UFCON_TX_FIFO_TLEVEL_EMPTY	0x00
+#define UFCON_RX_FIFO_TLEVEL_1B		0x00
+#define UFCON_FIFO_ENABLE		0x01
+
+
+/** S3C24xx UART instance */
+typedef struct {
+	/** Physical device address */
+	uintptr_t paddr;
+
+	/** Device I/O structure */
+	s3c24xx_uart_io_t *io;
+
+	/** Callback phone to the client */
+	int client_phone;
+
+	/** Device handle */
+	dev_handle_t dev_handle;
+} s3c24xx_uart_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/vfs/vfs.h	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -169,5 +169,5 @@
 
 extern int vfs_grab_phone(fs_handle_t);
-extern void vfs_release_phone(int);
+extern void vfs_release_phone(fs_handle_t, int);
 
 extern fs_handle_t fs_name_to_handle(char *, bool);
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -168,5 +168,5 @@
 	ipcarg_t rc;
 	async_wait_for(req, &rc);
-	vfs_release_phone(phone);
+	vfs_release_phone(root->fs_handle, phone);
 	
 	fibril_mutex_lock(&plb_mutex);
@@ -215,5 +215,5 @@
 	ipcarg_t rc;
 	async_wait_for(req, &rc);
-	vfs_release_phone(phone);
+	vfs_release_phone(result->triplet.fs_handle, phone);
 	
 	if (rc == EOK) {
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/vfs/vfs_node.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -133,5 +133,5 @@
 		    (ipcarg_t)node->dev_handle, (ipcarg_t)node->index);
 		assert(rc == EOK);
-		vfs_release_phone(phone);
+		vfs_release_phone(node->fs_handle, phone);
 	}
 	if (free_vfs_node)
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/vfs/vfs_ops.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -131,5 +131,5 @@
 			if (rc != EOK) {
 				async_wait_for(msg, NULL);
-				vfs_release_phone(phone);
+				vfs_release_phone(fs_handle, phone);
 				fibril_rwlock_write_unlock(&namespace_rwlock);
 				ipc_answer_0(rid, rc);
@@ -137,5 +137,5 @@
 			}
 			async_wait_for(msg, &rc);
-			vfs_release_phone(phone);
+			vfs_release_phone(fs_handle, phone);
 			
 			if (rc != EOK) {
@@ -196,6 +196,6 @@
 	if (rc != EOK) {
 		async_wait_for(msg, NULL);
-		vfs_release_phone(mountee_phone);
-		vfs_release_phone(phone);
+		vfs_release_phone(fs_handle, mountee_phone);
+		vfs_release_phone(mp_res.triplet.fs_handle, phone);
 		/* Mount failed, drop reference to mp_node. */
 		if (mp_node)
@@ -206,5 +206,5 @@
 	}
 
-	vfs_release_phone(mountee_phone);
+	vfs_release_phone(fs_handle, mountee_phone);
 	
 	/* send the mount options */
@@ -212,5 +212,5 @@
 	if (rc != EOK) {
 		async_wait_for(msg, NULL);
-		vfs_release_phone(phone);
+		vfs_release_phone(mp_res.triplet.fs_handle, phone);
 		/* Mount failed, drop reference to mp_node. */
 		if (mp_node)
@@ -221,5 +221,5 @@
 	}
 	async_wait_for(msg, &rc);
-	vfs_release_phone(phone);
+	vfs_release_phone(mp_res.triplet.fs_handle, phone);
 	
 	if (rc == EOK) {
@@ -423,5 +423,5 @@
 		rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,
 		    mr_node->dev_handle);
-		vfs_release_phone(phone);
+		vfs_release_phone(mr_node->fs_handle, phone);
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
@@ -460,5 +460,5 @@
 		rc = async_req_2_0(phone, VFS_OUT_UNMOUNT, mp_node->dev_handle,
 		    mp_node->index);
-		vfs_release_phone(phone);
+		vfs_release_phone(mp_node->fs_handle, phone);
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
@@ -716,5 +716,5 @@
 	async_wait_for(msg, &rc);
 	
-	vfs_release_phone(fs_phone);
+	vfs_release_phone(file->node->fs_handle, fs_phone);
 	fibril_mutex_unlock(&file->lock);
 	
@@ -747,5 +747,5 @@
 		async_wait_for(msg, &rc);
 		
-		vfs_release_phone(fs_phone);
+		vfs_release_phone(file->node->fs_handle, fs_phone);
 		fibril_mutex_unlock(&file->lock);
 		
@@ -846,5 +846,5 @@
 	}
 	
-	vfs_release_phone(fs_phone);
+	vfs_release_phone(file->node->fs_handle, fs_phone);
 	
 	size_t bytes = IPC_GET_ARG1(answer);
@@ -970,5 +970,5 @@
 	rc = async_req_4_0(fs_phone, VFS_OUT_TRUNCATE, (ipcarg_t) dev_handle,
 	    (ipcarg_t) index, LOWER32(size), UPPER32(size));
-	vfs_release_phone(fs_phone);
+	vfs_release_phone(fs_handle, fs_phone);
 	return (int)rc;
 }
@@ -1026,5 +1026,5 @@
 	ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
 	async_wait_for(msg, &rc);
-	vfs_release_phone(fs_phone);
+	vfs_release_phone(file->node->fs_handle, fs_phone);
 
 	fibril_mutex_unlock(&file->lock);
@@ -1077,5 +1077,5 @@
 	ipcarg_t rv;
 	async_wait_for(msg, &rv);
-	vfs_release_phone(fs_phone);
+	vfs_release_phone(node->fs_handle, fs_phone);
 
 	ipc_answer_0(rid, rv);
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision db4ec8d433d5a57e9661bceeab3b1ffff2adb1ff)
+++ uspace/srv/vfs/vfs_register.c	(revision 7431b66531a16a53dda757d3e07d0ac028368f72)
@@ -39,5 +39,7 @@
 #include <ipc/services.h>
 #include <async.h>
+#include <async_rel.h>
 #include <fibril.h>
+#include <fibril_synch.h>
 #include <errno.h>
 #include <stdio.h>
@@ -46,5 +48,4 @@
 #include <ctype.h>
 #include <bool.h>
-#include <fibril_synch.h>
 #include <adt/list.h>
 #include <as.h>
@@ -252,4 +253,6 @@
 int vfs_grab_phone(fs_handle_t handle)
 {
+	link_t *cur;
+	fs_info_t *fs;
 	int phone;
 
@@ -262,6 +265,4 @@
 	 */
 	fibril_mutex_lock(&fs_head_lock);
-	link_t *cur;
-	fs_info_t *fs;
 	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
 		fs = list_get_instance(cur, fs_info_t, fs_link);
@@ -269,5 +270,5 @@
 			fibril_mutex_unlock(&fs_head_lock);
 			fibril_mutex_lock(&fs->phone_lock);
-			phone = ipc_connect_me_to(fs->phone, 0, 0, 0);
+			phone = async_relation_create(fs->phone);
 			fibril_mutex_unlock(&fs->phone_lock);
 
@@ -284,8 +285,23 @@
  * @param phone		Phone to FS task.
  */
-void vfs_release_phone(int phone)
-{
-	/* TODO: implement connection caching */
-	ipc_hangup(phone);
+void vfs_release_phone(fs_handle_t handle, int phone)
+{
+	link_t *cur;
+	fs_info_t *fs;
+
+	fibril_mutex_lock(&fs_head_lock);
+	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
+		fs = list_get_instance(cur, fs_info_t, fs_link);
+		if (fs->fs_handle == handle) {
+			fibril_mutex_unlock(&fs_head_lock);
+			fibril_mutex_lock(&fs->phone_lock);
+			async_relation_destroy(fs->phone, phone);
+			fibril_mutex_unlock(&fs->phone_lock);
+			return;
+		}
+	}
+	/* should not really get here */
+	abort();
+	fibril_mutex_unlock(&fs_head_lock);
 }
 
