Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ HelenOS.config	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -417,4 +417,7 @@
 ! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=keyboard)&PLATFORM=ia64&MACHINE=i460GX] CONFIG_PC_KBD (y/n)
 
+% PC keyboard support
+! [(CONFIG_HID_IN=generic|CONFIG_HID_IN=keyboard)&PLATFORM=arm32&MACHINE=integratorcp] CONFIG_PC_KBD (y/n)
+
 % Support for msim/GXemul keyboard
 ! [CONFIG_HID_IN=generic&PLATFORM=mips32] CONFIG_MIPS_KBD (y/n)
Index: Makefile
===================================================================
--- Makefile	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ Makefile	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -42,5 +42,5 @@
 CONFIG_HEADER = config.h
 
-.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check
+.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check releasefile release
 
 all: $(COMMON_MAKEFILE) $(COMMON_HEADER) $(CONFIG_MAKEFILE) $(CONFIG_HEADER)
@@ -64,4 +64,6 @@
 endif
 
+# Autotool (detects compiler features)
+
 $(COMMON_MAKEFILE): autotool
 $(COMMON_HEADER): autotool
@@ -70,4 +72,6 @@
 	$(AUTOTOOL)
 	-[ -f $(COMMON_HEADER_PREV) ] && diff -q $(COMMON_HEADER_PREV) $(COMMON_HEADER) && mv -f $(COMMON_HEADER_PREV) $(COMMON_HEADER)
+
+# Build-time configuration
 
 $(CONFIG_MAKEFILE): config_default
@@ -84,6 +88,16 @@
 	$(CONFIG) $<
 
+# Release files
+
+releasefile: all
+	$(MAKE) -C release releasefile
+
+release:
+	$(MAKE) -C release release
+
+# Cleaning
+
 distclean: clean
-	rm -f $(CSCOPE).out $(COMMON_MAKEFILE) $(COMMON_HEADER) $(COMMON_HEADER_PREV) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) tools/*.pyc tools/checkers/*.pyc
+	rm -f $(CSCOPE).out $(COMMON_MAKEFILE) $(COMMON_HEADER) $(COMMON_HEADER_PREV) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) tools/*.pyc tools/checkers/*.pyc release/HelenOS-*
 
 clean:
Index: boot/arch/mips32/src/asm.S
===================================================================
--- boot/arch/mips32/src/asm.S	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ boot/arch/mips32/src/asm.S	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -41,7 +41,20 @@
 
 start:
-	/* Setup CPU map (on msim this code
-	   is executed in parallel on all CPUs,
-	   but it not an issue) */
+	/*
+	 * Setup the CP0 configuration
+	 *  - Disable 64-bit kernel addressing mode
+	 *  - DIsable 64-bit supervisor adressing mode
+	 *  - Disable 64-bit user addressing mode
+	 */
+	mfc0 $a0, $status
+	la $a1, 0xffffff1f
+	and $a0, $a1, $a0
+	mtc0 $a0, $status
+	
+	/*
+	 * Setup CPU map (on msim this code
+	 * is executed in parallel on all CPUs,
+	 * but it not an issue).
+	 */
 	la $a0, PA2KA(CPUMAP_OFFSET)
 	
@@ -94,6 +107,8 @@
 	lw $k1, ($k0)
 	
-	/* If we are not running on BSP
-	   then end in an infinite loop  */
+	/*
+	 * If we are not running on BSP
+	 * then end in an infinite loop.
+	 */
 	beq $k1, $zero, bsp
 	nop
@@ -127,9 +142,10 @@
 
 jump_to_kernel:
-	#
-	# TODO:
-	# Make sure that the I-cache, D-cache and memory are mutually coherent
-	# before passing control to the copied code.
-	#
+	/*
+	 * TODO:
+	 *
+	 * Make sure that the I-cache, D-cache and memory are mutually
+	 * coherent before passing control to the copied code.
+	 */
 	j $a0
 	nop
Index: boot/arch/sparc64/include/arch.h
===================================================================
--- boot/arch/sparc64/include/arch.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ boot/arch/sparc64/include/arch.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -41,4 +41,5 @@
 #define STACK_BIAS                   2047
 #define STACK_WINDOW_SAVE_AREA_SIZE  (16 * 8)
+#define STACK_ARG_SAVE_AREA_SIZE     (6 * 8)
 
 #define NWINDOWS  8
Index: boot/arch/sparc64/src/asm.S
===================================================================
--- boot/arch/sparc64/src/asm.S	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ boot/arch/sparc64/src/asm.S	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -152,5 +152,5 @@
 .global ofw
 ofw:
-	save %sp, -STACK_WINDOW_SAVE_AREA_SIZE, %sp
+	save %sp, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
 	set ofw_cif, %l0
 	ldx [%l0], %l0
Index: boot/arch/sparc64/src/main.c
===================================================================
--- boot/arch/sparc64/src/main.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ boot/arch/sparc64/src/main.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -190,4 +190,5 @@
 	bootinfo.memmap.zones[0].start += OBP_BIAS;
 	bootinfo.memmap.zones[0].size -= OBP_BIAS;
+	bootinfo.memmap.total -= OBP_BIAS;
 }
 
@@ -204,4 +205,7 @@
 	bootinfo.physmem_start = ofw_get_physmem_start();
 	ofw_memmap(&bootinfo.memmap);
+
+	if (arch == ARCH_SUN4V)
+		sun4v_fixups();
 	
 	void *bootinfo_pa = ofw_translate(&bootinfo);
@@ -253,21 +257,16 @@
 		
 		/*
-		 * At this point, we claim the physical memory that we are
-		 * going to use. We should be safe in case of the virtual
+		 * At this point, we claim and map the physical memory that we
+		 * are going to use. We should be safe in case of the virtual
 		 * address space because the OpenFirmware, according to its
-		 * SPARC binding, should restrict its use of virtual memory
-		 * to addresses from [0xffd00000; 0xffefffff] and
-		 * [0xfe000000; 0xfeffffff].
-		 *
-		 * We don't map this piece of memory. We simply rely on
-		 * SILO to have it done for us already in this case.
-		 *
-		 * XXX SILO only maps 8 MB for us here. We should improve
-		 *     this code to be totally independent on the behavior
-		 *     of SILO.
-		 *
+		 * SPARC binding, should restrict its use of virtual memory to
+		 * addresses from [0xffd00000; 0xffefffff] and [0xfe000000;
+		 * 0xfeffffff].
 		 */
 		ofw_claim_phys(bootinfo.physmem_start + dest[i - 1],
 		    ALIGN_UP(components[i - 1].inflated, PAGE_SIZE));
+		
+		ofw_map(bootinfo.physmem_start + dest[i - 1], dest[i - 1],
+		    ALIGN_UP(components[i - 1].inflated, PAGE_SIZE), -1);
 		
 		int err = inflate(components[i - 1].start, components[i - 1].size,
@@ -304,7 +303,4 @@
 		sun4u_smp();
 	
-	if (arch == ARCH_SUN4V)
-		sun4v_fixups();
-	
 	printf("Booting the kernel ...\n");
 	jump_to_kernel(bootinfo.physmem_start | BSP_PROCESSOR, &bootinfo, subarch,
Index: boot/generic/src/balloc.c
===================================================================
--- boot/generic/src/balloc.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ boot/generic/src/balloc.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -65,4 +65,4 @@
 void *balloc_rebase(void *ptr)
 {
-	return (void *) ((uintptr_t) ptr - phys_base + ballocs->base);
+	return (void *) (((uintptr_t) ptr - phys_base) + ballocs->base);
 }
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -292,5 +292,5 @@
 		.y = 480,
 		.scan = 2560,
-		.visual = VISUAL_BGR_0_8_8_8,
+		.visual = VISUAL_RGB_8_8_8_0,
 	};
 	
Index: kernel/arch/ia32/_link.ld.in
===================================================================
--- kernel/arch/ia32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/arch/ia32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -49,7 +49,19 @@
 	}
 	
+#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/ : {
-		*(.note.GNU-stack);
-		*(.comment);
+		*(*);
 	}
 	
Index: kernel/arch/mips32/src/mm/tlb.c
===================================================================
--- kernel/arch/mips32/src/mm/tlb.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/arch/mips32/src/mm/tlb.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -557,6 +557,7 @@
 	entry_hi_t hi, hi_save;
 	tlb_index_t index;
-
-	ASSERT(asid != ASID_INVALID);
+	
+	if (asid == ASID_INVALID)
+		return;
 
 	hi_save.value = cp0_entry_hi_read();
Index: kernel/arch/sparc64/src/sun4v/asm.S
===================================================================
--- kernel/arch/sparc64/src/sun4v/asm.S	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/arch/sparc64/src/sun4v/asm.S	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -41,6 +41,5 @@
 .global switch_to_userspace
 switch_to_userspace:
-	wrpr PSTATE_PRIV_BIT, %pstate
-	save %o1, -STACK_WINDOW_SAVE_AREA_SIZE, %sp
+	save %o1, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
 	flushw
 	wrpr %g0, 0, %cleanwin		! avoid information leak
Index: kernel/genarch/Makefile.inc
===================================================================
--- kernel/genarch/Makefile.inc	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/genarch/Makefile.inc	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -122,10 +122,4 @@
 endif
 
-ifeq ($(CONFIG_PL050),y)
-	GENARCH_SOURCES += \
-		genarch/src/kbrd/kbrd_pl050.c \
-		genarch/src/kbrd/scanc_pl050.c
-endif
-
 ifeq ($(CONFIG_MAC_KBD),y)
 	GENARCH_SOURCES += \
Index: rnel/genarch/src/kbrd/kbrd_pl050.c
===================================================================
--- kernel/genarch/src/kbrd/kbrd_pl050.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ 	(revision )
@@ -1,209 +1,0 @@
-/*
- * Copyright (c) 2009 Vineeth Pillai
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING 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 pl050 Keyboard processing.
- */
-
-#include <genarch/kbrd/kbrd.h>
-#include <genarch/kbrd/scanc.h>
-
-#include <genarch/kbrd/scanc_pl050.h>
-
-#include <synch/spinlock.h>
-#include <console/chardev.h>
-#include <console/console.h>
-#include <proc/thread.h>
-#include <arch.h>
-#include <macros.h>
-
-#define PRESSED_SHIFT     (1 << 0)
-#define PRESSED_CAPSLOCK  (1 << 1)
-#define LOCKED_CAPSLOCK   (1 << 0)
-
-#define PL050_KEY_RELEASE 0xF0
-#define PL050_ESC_KEY   0xE0
-#define PL050_CAPS_SCAN_CODE   0x58
-#define PL050_NUM_SCAN_CODE   0x77
-#define PL050_SCROLL_SCAN_CODE   0x7E
-
-static bool is_lock_key(wchar_t);
-
-static indev_operations_t kbrd_raw_ops = {
-	.poll = NULL
-};
-
-/** Process release of key.
- *
- * @param sc Scancode of the key being released.
- */
-static void key_released(kbrd_instance_t *instance, wchar_t sc)
-{
-	spinlock_lock(&instance->keylock);
-	
-	switch (sc) {
-	case SC_LSHIFT:
-	case SC_RSHIFT:
-		instance->keyflags &= ~PRESSED_SHIFT;
-		break;
-	case SC_CAPSLOCK:
-		instance->keyflags &= ~PRESSED_CAPSLOCK;
-		if (instance->lockflags & LOCKED_CAPSLOCK)
-			instance->lockflags &= ~LOCKED_CAPSLOCK;
-		else
-			instance->lockflags |= LOCKED_CAPSLOCK;
-		break;
-	default:
-		break;
-	}
-	
-	spinlock_unlock(&instance->keylock);
-}
-
-/** Process keypress.
- *
- * @param sc Scancode of the key being pressed.
- */
-static void key_pressed(kbrd_instance_t *instance, wchar_t sc)
-{
-	bool letter;
-	bool shift;
-	bool capslock;
-	
-	spinlock_lock(&instance->keylock);
-	
-	switch (sc) {
-	case SC_LSHIFT:
-	case SC_RSHIFT:
-		instance->keyflags |= PRESSED_SHIFT;
-		break;
-	case SC_CAPSLOCK:
-		instance->keyflags |= PRESSED_CAPSLOCK;
-		break;
-	case SC_SCAN_ESCAPE:
-		break;
-	default:
-		letter = islower(sc_primary_map[sc]);
-		shift = instance->keyflags & PRESSED_SHIFT;
-		capslock = (instance->keyflags & PRESSED_CAPSLOCK) ||
-		    (instance->lockflags & LOCKED_CAPSLOCK);
-		
-		if ((letter) && (capslock))
-			shift = !shift;
-		
-		if (shift)
-			indev_push_character(instance->sink, sc_secondary_map[sc]);
-		else
-			indev_push_character(instance->sink, sc_primary_map[sc]);
-		break;
-	}
-	
-	spinlock_unlock(&instance->keylock);
-}
-
-static void kkbrd(void *arg)
-{
-	static int key_released_flag = 0;
-	static int is_locked = 0;
-	kbrd_instance_t *instance = (kbrd_instance_t *) arg;
-	
-	while (true) {
-		wchar_t sc = indev_pop_character(&instance->raw);
-
-		if (sc == PL050_KEY_RELEASE) {
-			key_released_flag = 1;
-		} else {
-			if (key_released_flag) {
-				key_released_flag = 0;
-				if (is_lock_key(sc)) {
-					if (!is_locked) {
-						is_locked = 1;
-					} else {
-						is_locked = 0;
-						continue;
-					}
-				}
-				key_released(instance, sc);
-
-			} else {
-				if (is_lock_key(sc) && is_locked)
-					continue;
-				key_pressed(instance, sc);
-			}
-		}
-		
-	}
-}
-
-kbrd_instance_t *kbrd_init(void)
-{
-	kbrd_instance_t *instance
-	    = malloc(sizeof(kbrd_instance_t), FRAME_ATOMIC);
-	if (instance) {
-		instance->thread
-			= thread_create(kkbrd, (void *) instance, TASK, 0, "kkbrd", false);
-		
-		if (!instance->thread) {
-			free(instance);
-			return NULL;
-		}
-		
-		instance->sink = NULL;
-		indev_initialize("kbrd", &instance->raw, &kbrd_raw_ops);
-		
-		spinlock_initialize(&instance->keylock, "kbrd_pl050.instance.keylock");
-		instance->keyflags = 0;
-		instance->lockflags = 0;
-	}
-	
-	return instance;
-}
-
-indev_t *kbrd_wire(kbrd_instance_t *instance, indev_t *sink)
-{
-	ASSERT(instance);
-	ASSERT(sink);
-	
-	instance->sink = sink;
-	thread_ready(instance->thread);
-	
-	return &instance->raw;
-}
-
-static bool is_lock_key(wchar_t sc)
-{
-	return ((sc == PL050_CAPS_SCAN_CODE) || (sc == PL050_NUM_SCAN_CODE) ||
-		(sc == PL050_SCROLL_SCAN_CODE));
-}
-
-/** @}
- */
Index: rnel/genarch/src/kbrd/scanc_pl050.c
===================================================================
--- kernel/genarch/src/kbrd/scanc_pl050.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ 	(revision )
@@ -1,234 +1,0 @@
-/*
- * Copyright (c) 2009 Vineeth Pillai
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, U_SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING 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	Scan codes for pl050 keyboards.
- */
-#include <genarch/kbrd/scanc.h>
-#include <typedefs.h>
-#include <str.h>
-
-
-/** Primary meaning of scancodes. */
-wchar_t sc_primary_map[] = {
-	U_NULL, /* 0x00 */
-	U_SPECIAL, /* 0x01 - F9 */
-	U_SPECIAL, /* 0x02 - F7 */
-	U_SPECIAL, /* 0x03 - F5 */
-	U_SPECIAL, /* 0x04 - F3 */
-	U_SPECIAL, /* 0x05 - F1 */
-	U_SPECIAL, /* 0x06 - F2 */
-	U_SPECIAL, /* 0x07 - F12 */
-	U_SPECIAL, /* 0x08 -  */
-	U_SPECIAL, /* 0x09 - F10 */
-	U_SPECIAL, /* 0x0A - F8 */
-	U_SPECIAL, /* 0x0B - F10 */
-	U_SPECIAL, /* 0x0C - F4 */
-	'\t', /* 0x0D - Tab */
-	'`',
-	U_SPECIAL, /* 0x0F */
-	U_SPECIAL, /* 0x10 */
-	U_SPECIAL, /* 0x11 - LAlt */
-	U_SPECIAL, /* 0x12 - LShift */
-	U_SPECIAL, /* ox13 */
-	U_SPECIAL, /* 0x14 Ctrl */
-	'q', '1',
-	U_SPECIAL, /* 0x17 */
-	U_SPECIAL, /* 0x18 */
-	U_SPECIAL, /* 0x19 */
-	'z', 's', 'a', 'w', '2',
-	U_SPECIAL, /* 0x1F */
-	U_SPECIAL, /* 0x20 */
-	'c', 'x', 'd', 'e', '4', '3',
-	U_SPECIAL, /* 0x27 */
-	U_SPECIAL, /* 0x28 */
-	' ', 'v', 'f', 't', 'r', '5',
-	U_SPECIAL, /* 0x2F */
-	U_SPECIAL, /* 0x30 */
-	'n', 'b', 'h', 'g', 'y', '6',
-	U_SPECIAL, /* 0x37 */
-	U_SPECIAL, /* 0x38 */
-	U_SPECIAL, /* 0x39 */
-	'm', 'j', 'u', '7', '8',
-	U_SPECIAL, /* 0x3F */
-	U_SPECIAL, /* 0x40 */
-	',', 'k', 'i', 'o', '0', '9',
-	U_SPECIAL, /* 0x47 */
-	U_SPECIAL, /* 0x48 */
-	'.', '/', 'l', ';', 'p', '-',
-	U_SPECIAL, /* 0x4F */
-	U_SPECIAL, /* 0x50 */
-	U_SPECIAL, /* 0x51 */
-	'\'',
-	U_SPECIAL, /* 0x53 */
-	'[', '=',
-	U_SPECIAL, /* 0x56 */
-	U_SPECIAL, /* 0x57 */
-	U_SPECIAL, /* 0x58 - Caps Lock */
-	U_SPECIAL, /* 0x59 - RShift */
-	'\n', ']',
-	U_SPECIAL, /* 0x5C */
-	'\\',
-	U_SPECIAL, /* 0x5E */
-	U_SPECIAL, /* 0x5F */
-	U_SPECIAL, /* 0x60 */
-	U_SPECIAL, /* 0x61 */
-	U_SPECIAL, /* 0x62 */
-	U_SPECIAL, /* 0x63 */
-	U_SPECIAL, /* 0x64 */
-	U_SPECIAL, /* 0x65 */
-	'\b', /* 0x66  - backspace*/
-	U_SPECIAL, /* 0x67 */
-	U_SPECIAL, /* 0x68 */
-	U_END_ARROW, /* 0x69 */
-	U_SPECIAL, /* 0x6a */
-	U_LEFT_ARROW, /* 0x6b - Left Arrow */
-	U_SPECIAL, /* 0x6c */
-	U_SPECIAL, /* 0x6d */
-	U_SPECIAL, /* 0x6e */
-	U_SPECIAL, /* 0x6f */
-	U_SPECIAL, /* 0x70 */
-	U_DELETE, /* 0x71 - Del*/
-	U_DOWN_ARROW, /* 0x72 Down Arrow */
-	U_SPECIAL, /* 0x73 */
-	U_RIGHT_ARROW, /* 0x74  - Right Arrow */
-	U_UP_ARROW, /* 0x75  Up Arrow */
-	U_ESCAPE, /* 0x76 Esc */
-	U_SPECIAL, /* 0x77 - NumLock*/
-	U_SPECIAL, /* 0x78  F11*/
-	U_SPECIAL, /* 0x79 */
-	U_PAGE_DOWN, /* 0x7a */
-	U_SPECIAL, /* 0x7b */
-	U_SPECIAL, /* 0x7c */
-	U_PAGE_UP, /* 0x7d */
-	U_SPECIAL, /* 0x7e */
-	U_SPECIAL /* 0x7f */
-};
-
-/** Secondary meaning of scancodes. */
-wchar_t sc_secondary_map[] = {
-	U_NULL, /* 0x00 */
-	U_SPECIAL, /* 0x01 - F9 */
-	U_SPECIAL, /* 0x02 - F7 */
-	U_SPECIAL, /* 0x03 - F5 */
-	U_SPECIAL, /* 0x04 - F3 */
-	U_SPECIAL, /* 0x05 - F1 */
-	U_SPECIAL, /* 0x06 - F2 */
-	U_SPECIAL, /* 0x07 - F12 */
-	U_SPECIAL, /* 0x08 -  */
-	U_SPECIAL, /* 0x09 - F10 */
-	U_SPECIAL, /* 0x0A - F8 */
-	U_SPECIAL, /* 0x0B - F10 */
-	U_SPECIAL, /* 0x0C - F4 */
-	'\t', /* 0x0D - Tab */
-	'~',
-	U_SPECIAL, /* 0x0F */
-	U_SPECIAL, /* 0x10 */
-	U_SPECIAL, /* 0x11 - LAlt */
-	U_SPECIAL, /* 0x12 - LShift */
-	U_SPECIAL, /* ox13 */
-	U_SPECIAL, /* 0x14 Ctrl */
-	'Q', '!',
-	U_SPECIAL, /* 0x17 */
-	U_SPECIAL, /* 0x18 */
-	U_SPECIAL, /* 0x19 */
-	'Z', 'S', 'A', 'W', '@',
-	U_SPECIAL, /* 0x1F */
-	U_SPECIAL, /* 0x20 */
-	'C', 'X', 'D', 'E', '$', '#',
-	U_SPECIAL, /* 0x27 */
-	U_SPECIAL, /* 0x28 */
-	' ', 'V', 'F', 'T', 'R', '%',
-	U_SPECIAL, /* 0x2F */
-	U_SPECIAL, /* 0x30 */
-	'N', 'B', 'H', 'G', 'Y', '^',
-	U_SPECIAL, /* 0x37 */
-	U_SPECIAL, /* 0x38 */
-	U_SPECIAL, /* 0x39 */
-	'M', 'J', 'U', '&', '*',
-	U_SPECIAL, /* 0x3F */
-	U_SPECIAL, /* 0x40 */
-	'<', 'K', 'I', 'O', ')', '(',
-	U_SPECIAL, /* 0x47 */
-	U_SPECIAL, /* 0x48 */
-	'>', '?', 'L', ':', 'P', '_',
-	U_SPECIAL, /* 0x4F */
-	U_SPECIAL, /* 0x50 */
-	U_SPECIAL, /* 0x51 */
-	'"',
-	U_SPECIAL, /* 0x53 */
-	'{', '+',
-	U_SPECIAL, /* 0x56 */
-	U_SPECIAL, /* 0x57 */
-	U_SPECIAL, /* 0x58 - Caps Lock */
-	U_SPECIAL, /* 0x59 - RShift */
-	'\n', '}',
-	U_SPECIAL, /* 0x5C */
-	'|',
-	U_SPECIAL, /* 0x5E */
-	U_SPECIAL, /* 0x5F */
-	U_SPECIAL, /* 0x60 */
-	U_SPECIAL, /* 0x61 */
-	U_SPECIAL, /* 0x62 */
-	U_SPECIAL, /* 0x63 */
-	U_SPECIAL, /* 0x64 */
-	U_SPECIAL, /* 0x65 */
-	'\b', /* 0x66  - backspace*/
-	U_SPECIAL, /* 0x67 */
-	U_SPECIAL, /* 0x68 */
-	U_END_ARROW, /* 0x69 */
-	U_SPECIAL, /* 0x6a */
-	U_LEFT_ARROW, /* 0x6b - Left Arrow */
-	U_SPECIAL, /* 0x6c */
-	U_SPECIAL, /* 0x6d */
-	U_SPECIAL, /* 0x6e */
-	U_SPECIAL, /* 0x6f */
-	U_SPECIAL, /* 0x70 */
-	U_DELETE, /* 0x71 - Del*/
-	U_DOWN_ARROW, /* 0x72 Down Arrow */
-	U_SPECIAL, /* 0x73 */
-	U_RIGHT_ARROW, /* 0x74  - Right Arrow */
-	U_UP_ARROW, /* 0x75  Up Arrow */
-	U_ESCAPE, /* 0x76 Esc */
-	U_SPECIAL, /* 0x77 - NumLock*/
-	U_SPECIAL, /* 0x78  F11*/
-	U_SPECIAL, /* 0x79 */
-	U_PAGE_DOWN, /* 0x7a */
-	U_SPECIAL, /* 0x7b */
-	U_SPECIAL, /* 0x7c */
-	U_PAGE_UP, /* 0x7d */
-	U_SPECIAL, /* 0x7e */
-	U_SPECIAL /* 0x7f */
-};
-
-/** @}
- */
Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/include/mm/as.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -115,17 +115,19 @@
 	
 	/**
-	 * Number of processors on wich is this address space active.
-	 * Protected by asidlock.
+	 * Number of processors on which this
+	 * address space is active. Protected by
+	 * asidlock.
 	 */
 	size_t cpu_refcount;
 	
-	/**
-	 * Address space identifier.
-	 * Constant on architectures that do not support ASIDs.
-	 * Protected by asidlock.
+	/** Address space identifier.
+	 *
+	 * Constant on architectures that do not
+	 * support ASIDs. Protected by asidlock.
+	 *
 	 */
 	asid_t asid;
 	
-	/** Number of references (i.e tasks that reference this as). */
+	/** Number of references (i.e. tasks that reference this as). */
 	atomic_t refcount;
 	
@@ -199,24 +201,29 @@
 typedef struct {
 	mutex_t lock;
+	
 	/** Containing address space. */
 	as_t *as;
 	
-	/**
-	 * Flags related to the memory represented by the address space area.
-	 */
+	/** Memory flags. */
 	unsigned int flags;
 	
-	/** Attributes related to the address space area itself. */
+	/** Address space area attributes. */
 	unsigned int attributes;
-	/** Size of this area in multiples of PAGE_SIZE. */
+	
+	/** Number of pages in the area. */
 	size_t pages;
+	
+	/** Number of resident pages in the area. */
+	size_t resident;
+	
 	/** Base address of this area. */
 	uintptr_t base;
+	
 	/** Map of used space. */
 	btree_t used_space;
 	
 	/**
-	 * If the address space area has been shared, this pointer will
-	 * reference the share info structure.
+	 * If the address space area is shared. this is
+	 * a reference to the share info structure.
 	 */
 	share_info_t *sh_info;
@@ -261,7 +268,6 @@
 extern bool as_area_check_access(as_area_t *, pf_access_t);
 extern size_t as_area_get_size(uintptr_t);
-extern int used_space_insert(as_area_t *, uintptr_t, size_t);
-extern int used_space_remove(as_area_t *, uintptr_t, size_t);
-
+extern bool used_space_insert(as_area_t *, uintptr_t, size_t);
+extern bool used_space_remove(as_area_t *, uintptr_t, size_t);
 
 /* Interface to be implemented by architectures. */
@@ -307,4 +313,5 @@
 extern sysarg_t sys_as_area_change_flags(uintptr_t, unsigned int);
 extern sysarg_t sys_as_area_destroy(uintptr_t);
+extern sysarg_t sys_as_get_unmapped_area(uintptr_t, size_t);
 
 /* Introspection functions. */
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/include/syscall/syscall.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -59,4 +59,5 @@
 	SYS_AS_AREA_CHANGE_FLAGS,
 	SYS_AS_AREA_DESTROY,
+	SYS_AS_GET_UNMAPPED_AREA,
 	
 	SYS_IPC_CALL_SYNC_FAST,
Index: kernel/generic/src/console/cmd.c
===================================================================
--- kernel/generic/src/console/cmd.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/src/console/cmd.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -553,6 +553,11 @@
 	for (i = 0; basic_commands[i]; i++) {
 		cmd_initialize(basic_commands[i]);
-		if (!cmd_register(basic_commands[i]))
-			printf("Cannot register command %s\n", basic_commands[i]->name);
+	}
+
+	for (i = 0; basic_commands[i]; i++) {
+		if (!cmd_register(basic_commands[i])) {
+			printf("Cannot register command %s\n",
+			    basic_commands[i]->name);
+		}
 	}
 }
Index: kernel/generic/src/lib/elf.c
===================================================================
--- kernel/generic/src/lib/elf.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/src/lib/elf.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -157,4 +157,5 @@
 	case PT_NULL:
 	case PT_PHDR:
+	case PT_NOTE:
 		break;
 	case PT_LOAD:
@@ -173,5 +174,4 @@
 		break;
 	case PT_SHLIB:
-	case PT_NOTE:
 	case PT_LOPROC:
 	case PT_HIPROC:
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/src/mm/as.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -71,4 +71,5 @@
 #include <memstr.h>
 #include <macros.h>
+#include <bitops.h>
 #include <arch.h>
 #include <errno.h>
@@ -86,17 +87,15 @@
  * Each architecture decides what functions will be used to carry out
  * address space operations such as creating or locking page tables.
- *
  */
 as_operations_t *as_operations = NULL;
 
-/**
- * Slab for as_t objects.
+/** Slab for as_t objects.
  *
  */
 static slab_cache_t *as_slab;
 
-/**
- * This lock serializes access to the ASID subsystem.
- * It protects:
+/** ASID subsystem lock.
+ *
+ * This lock protects:
  * - inactive_as_with_asid_head list
  * - as->asid for each as of the as_t type
@@ -107,7 +106,6 @@
 
 /**
- * This list contains address spaces that are not active on any
- * processor and that have valid ASID.
- *
+ * Inactive address spaces (on all processors)
+ * that have valid ASID.
  */
 LIST_INITIALIZE(inactive_as_with_asid_head);
@@ -123,13 +121,10 @@
 	mutex_initialize(&as->lock, MUTEX_PASSIVE);
 	
-	int rc = as_constructor_arch(as, flags);
-	
-	return rc;
+	return as_constructor_arch(as, flags);
 }
 
 NO_TRACE static size_t as_destructor(void *obj)
 {
-	as_t *as = (as_t *) obj;
-	return as_destructor_arch(as);
+	return as_destructor_arch((as_t *) obj);
 }
 
@@ -146,5 +141,6 @@
 		panic("Cannot create kernel address space.");
 	
-	/* Make sure the kernel address space
+	/*
+	 * Make sure the kernel address space
 	 * reference count never drops to zero.
 	 */
@@ -195,5 +191,5 @@
 {
 	DEADLOCK_PROBE_INIT(p_asidlock);
-
+	
 	ASSERT(as != AS);
 	ASSERT(atomic_get(&as->refcount) == 0);
@@ -203,5 +199,5 @@
 	 * lock its mutex.
 	 */
-
+	
 	/*
 	 * We need to avoid deadlock between TLB shootdown and asidlock.
@@ -210,5 +206,4 @@
 	 * disabled to prevent nested context switches. We also depend on the
 	 * fact that so far no spinlocks are held.
-	 *
 	 */
 	preemption_disable();
@@ -235,5 +230,5 @@
 	spinlock_unlock(&asidlock);
 	interrupts_restore(ipl);
-
+	
 	
 	/*
@@ -241,5 +236,4 @@
 	 * The B+tree must be walked carefully because it is
 	 * also being destroyed.
-	 *
 	 */
 	bool cond = true;
@@ -268,6 +262,6 @@
 /** Hold a reference to an address space.
  *
- * Holding a reference to an address space prevents destruction of that address
- * space.
+ * Holding a reference to an address space prevents destruction
+ * of that address space.
  *
  * @param as Address space to be held.
@@ -281,6 +275,6 @@
 /** Release a reference to an address space.
  *
- * The last one to release a reference to an address space destroys the address
- * space.
+ * The last one to release a reference to an address space
+ * destroys the address space.
  *
  * @param asAddress space to be released.
@@ -295,22 +289,22 @@
 /** Check area conflicts with other areas.
  *
- * @param as         Address space.
- * @param va         Starting virtual address of the area being tested.
- * @param size       Size of the area being tested.
- * @param avoid_area Do not touch this area.
+ * @param as    Address space.
+ * @param addr  Starting virtual address of the area being tested.
+ * @param count Number of pages in the area being tested.
+ * @param avoid Do not touch this area.
  *
  * @return True if there is no conflict, false otherwise.
  *
  */
-NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,
-    as_area_t *avoid_area)
-{
+NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
+    size_t count, as_area_t *avoid)
+{
+	ASSERT((addr % PAGE_SIZE) == 0);
 	ASSERT(mutex_locked(&as->lock));
 	
 	/*
 	 * We don't want any area to have conflicts with NULL page.
-	 *
-	 */
-	if (overlaps(va, size, (uintptr_t) NULL, PAGE_SIZE))
+	 */
+	if (overlaps(addr, count << PAGE_WIDTH, (uintptr_t) NULL, PAGE_SIZE))
 		return false;
 	
@@ -321,11 +315,10 @@
 	 * record in the left neighbour, the leftmost record in the right
 	 * neighbour and all records in the leaf node itself.
-	 *
 	 */
 	btree_node_t *leaf;
 	as_area_t *area =
-	    (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
+	    (as_area_t *) btree_search(&as->as_area_btree, addr, &leaf);
 	if (area) {
-		if (area != avoid_area)
+		if (area != avoid)
 			return false;
 	}
@@ -337,12 +330,15 @@
 		area = (as_area_t *) node->value[node->keys - 1];
 		
-		mutex_lock(&area->lock);
-		
-		if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
+		if (area != avoid) {
+			mutex_lock(&area->lock);
+			
+			if (overlaps(addr, count << PAGE_WIDTH,
+			    area->base, area->pages << PAGE_WIDTH)) {
+				mutex_unlock(&area->lock);
+				return false;
+			}
+			
 			mutex_unlock(&area->lock);
-			return false;
-		}
-		
-		mutex_unlock(&area->lock);
+		}
 	}
 	
@@ -351,12 +347,15 @@
 		area = (as_area_t *) node->value[0];
 		
-		mutex_lock(&area->lock);
-		
-		if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
+		if (area != avoid) {
+			mutex_lock(&area->lock);
+			
+			if (overlaps(addr, count << PAGE_WIDTH,
+			    area->base, area->pages << PAGE_WIDTH)) {
+				mutex_unlock(&area->lock);
+				return false;
+			}
+			
 			mutex_unlock(&area->lock);
-			return false;
-		}
-		
-		mutex_unlock(&area->lock);
+		}
 	}
 	
@@ -366,10 +365,11 @@
 		area = (as_area_t *) leaf->value[i];
 		
-		if (area == avoid_area)
+		if (area == avoid)
 			continue;
 		
 		mutex_lock(&area->lock);
 		
-		if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {
+		if (overlaps(addr, count << PAGE_WIDTH,
+		    area->base, area->pages << PAGE_WIDTH)) {
 			mutex_unlock(&area->lock);
 			return false;
@@ -382,8 +382,7 @@
 	 * So far, the area does not conflict with other areas.
 	 * Check if it doesn't conflict with kernel address space.
-	 *
 	 */
 	if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
-		return !overlaps(va, size,
+		return !overlaps(addr, count << PAGE_WIDTH,
 		    KERNEL_ADDRESS_SPACE_START,
 		    KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
@@ -412,9 +411,11 @@
     mem_backend_data_t *backend_data)
 {
-	if (base % PAGE_SIZE)
+	if ((base % PAGE_SIZE) != 0)
 		return NULL;
 	
-	if (!size)
+	if (size == 0)
 		return NULL;
+	
+	size_t pages = SIZE2FRAMES(size);
 	
 	/* Writeable executable areas are not supported. */
@@ -424,5 +425,5 @@
 	mutex_lock(&as->lock);
 	
-	if (!check_area_conflicts(as, base, size, NULL)) {
+	if (!check_area_conflicts(as, base, pages, NULL)) {
 		mutex_unlock(&as->lock);
 		return NULL;
@@ -436,5 +437,6 @@
 	area->flags = flags;
 	area->attributes = attrs;
-	area->pages = SIZE2FRAMES(size);
+	area->pages = pages;
+	area->resident = 0;
 	area->base = base;
 	area->sh_info = NULL;
@@ -479,5 +481,4 @@
 	 * to find out whether this is a miss or va belongs to an address
 	 * space area found there.
-	 *
 	 */
 	
@@ -490,5 +491,6 @@
 		mutex_lock(&area->lock);
 		
-		if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))
+		if ((area->base <= va) &&
+		    (va < area->base + (area->pages << PAGE_WIDTH)))
 			return area;
 		
@@ -499,5 +501,4 @@
 	 * Second, locate the left neighbour and test its last record.
 	 * Because of its position in the B+tree, it must have base < va.
-	 *
 	 */
 	btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
@@ -507,5 +508,5 @@
 		mutex_lock(&area->lock);
 		
-		if (va < area->base + area->pages * PAGE_SIZE)
+		if (va < area->base + (area->pages << PAGE_WIDTH))
 			return area;
 		
@@ -534,5 +535,4 @@
 	/*
 	 * Locate the area.
-	 *
 	 */
 	as_area_t *area = find_area_and_lock(as, address);
@@ -546,5 +546,4 @@
 		 * Remapping of address space areas associated
 		 * with memory mapped devices is not supported.
-		 *
 		 */
 		mutex_unlock(&area->lock);
@@ -557,5 +556,4 @@
 		 * Remapping of shared address space areas
 		 * is not supported.
-		 *
 		 */
 		mutex_unlock(&area->lock);
@@ -568,5 +566,4 @@
 		/*
 		 * Zero size address space areas are not allowed.
-		 *
 		 */
 		mutex_unlock(&area->lock);
@@ -576,10 +573,9 @@
 	
 	if (pages < area->pages) {
-		uintptr_t start_free = area->base + pages * PAGE_SIZE;
+		uintptr_t start_free = area->base + (pages << PAGE_WIDTH);
 		
 		/*
 		 * Shrinking the area.
 		 * No need to check for overlaps.
-		 *
 		 */
 		
@@ -588,8 +584,7 @@
 		/*
 		 * Start TLB shootdown sequence.
-		 *
 		 */
 		ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,
-		    area->base + pages * PAGE_SIZE, area->pages - pages);
+		    area->base + (pages << PAGE_WIDTH), area->pages - pages);
 		
 		/*
@@ -599,5 +594,4 @@
 		 * is also the right way to remove part of the used_space
 		 * B+tree leaf list.
-		 *
 		 */
 		bool cond = true;
@@ -615,13 +609,12 @@
 				size_t i = 0;
 				
-				if (overlaps(ptr, size * PAGE_SIZE, area->base,
-				    pages * PAGE_SIZE)) {
+				if (overlaps(ptr, size << PAGE_WIDTH, area->base,
+				    pages << PAGE_WIDTH)) {
 					
-					if (ptr + size * PAGE_SIZE <= start_free) {
+					if (ptr + (size << PAGE_WIDTH) <= start_free) {
 						/*
 						 * The whole interval fits
 						 * completely in the resized
 						 * address space area.
-						 *
 						 */
 						break;
@@ -632,5 +625,4 @@
 					 * to b and c overlaps with the resized
 					 * address space area.
-					 *
 					 */
 					
@@ -652,5 +644,5 @@
 				for (; i < size; i++) {
 					pte_t *pte = page_mapping_find(as, ptr +
-					    i * PAGE_SIZE);
+					    (i << PAGE_WIDTH));
 					
 					ASSERT(pte);
@@ -661,10 +653,10 @@
 					    (area->backend->frame_free)) {
 						area->backend->frame_free(area,
-						    ptr + i * PAGE_SIZE,
+						    ptr + (i << PAGE_WIDTH),
 						    PTE_GET_FRAME(pte));
 					}
 					
 					page_mapping_remove(as, ptr +
-					    i * PAGE_SIZE);
+					    (i << PAGE_WIDTH));
 				}
 			}
@@ -673,16 +665,14 @@
 		/*
 		 * Finish TLB shootdown sequence.
-		 *
-		 */
-		
-		tlb_invalidate_pages(as->asid, area->base + pages * PAGE_SIZE,
+		 */
+		
+		tlb_invalidate_pages(as->asid, area->base + (pages << PAGE_WIDTH),
 		    area->pages - pages);
 		
 		/*
 		 * Invalidate software translation caches (e.g. TSB on sparc64).
-		 *
 		 */
 		as_invalidate_translation_cache(as, area->base +
-		    pages * PAGE_SIZE, area->pages - pages);
+		    (pages << PAGE_WIDTH), area->pages - pages);
 		tlb_shootdown_finalize(ipl);
 		
@@ -692,8 +682,6 @@
 		 * Growing the area.
 		 * Check for overlaps with other address space areas.
-		 *
-		 */
-		if (!check_area_conflicts(as, address, pages * PAGE_SIZE,
-		    area)) {
+		 */
+		if (!check_area_conflicts(as, address, pages, area)) {
 			mutex_unlock(&area->lock);
 			mutex_unlock(&as->lock);
@@ -794,5 +782,6 @@
 			
 			for (size = 0; size < (size_t) node->value[i]; size++) {
-				pte_t *pte = page_mapping_find(as, ptr + size * PAGE_SIZE);
+				pte_t *pte =
+				    page_mapping_find(as, ptr + (size << PAGE_WIDTH));
 				
 				ASSERT(pte);
@@ -803,8 +792,8 @@
 				    (area->backend->frame_free)) {
 					area->backend->frame_free(area,
-					    ptr + size * PAGE_SIZE, PTE_GET_FRAME(pte));
+					    ptr + (size << PAGE_WIDTH), PTE_GET_FRAME(pte));
 				}
 				
-				page_mapping_remove(as, ptr + size * PAGE_SIZE);
+				page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
 			}
 		}
@@ -813,5 +802,4 @@
 	/*
 	 * Finish TLB shootdown sequence.
-	 *
 	 */
 	
@@ -821,5 +809,4 @@
 	 * Invalidate potential software translation caches (e.g. TSB on
 	 * sparc64).
-	 *
 	 */
 	as_invalidate_translation_cache(as, area->base, area->pages);
@@ -839,5 +826,4 @@
 	/*
 	 * Remove the empty area from address space.
-	 *
 	 */
 	btree_remove(&as->as_area_btree, base, NULL);
@@ -881,5 +867,4 @@
 		/*
 		 * Could not find the source address space area.
-		 *
 		 */
 		mutex_unlock(&src_as->lock);
@@ -891,5 +876,4 @@
 		 * There is no backend or the backend does not
 		 * know how to share the area.
-		 *
 		 */
 		mutex_unlock(&src_area->lock);
@@ -898,5 +882,5 @@
 	}
 	
-	size_t src_size = src_area->pages * PAGE_SIZE;
+	size_t src_size = src_area->pages << PAGE_WIDTH;
 	unsigned int src_flags = src_area->flags;
 	mem_backend_t *src_backend = src_area->backend;
@@ -918,5 +902,4 @@
 	 * First, prepare the area for sharing.
 	 * Then it will be safe to unlock it.
-	 *
 	 */
 	share_info_t *sh_info = src_area->sh_info;
@@ -930,5 +913,4 @@
 		/*
 		 * Call the backend to setup sharing.
-		 *
 		 */
 		src_area->backend->share(src_area);
@@ -949,5 +931,4 @@
 	 * The flags of the source area are masked against dst_flags_mask
 	 * to support sharing in less privileged mode.
-	 *
 	 */
 	as_area_t *dst_area = as_area_create(dst_as, dst_flags_mask, src_size,
@@ -966,5 +947,4 @@
 	 * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
 	 * attribute and set the sh_info.
-	 *
 	 */
 	mutex_lock(&dst_as->lock);
@@ -989,4 +969,6 @@
 NO_TRACE bool as_area_check_access(as_area_t *area, pf_access_t access)
 {
+	ASSERT(mutex_locked(&area->lock));
+	
 	int flagmap[] = {
 		[PF_ACCESS_READ] = AS_AREA_READ,
@@ -994,6 +976,4 @@
 		[PF_ACCESS_EXEC] = AS_AREA_EXEC
 	};
-
-	ASSERT(mutex_locked(&area->lock));
 	
 	if (!(area->flags & flagmap[access]))
@@ -1066,5 +1046,4 @@
 	/*
 	 * Compute total number of used pages in the used_space B+tree
-	 *
 	 */
 	size_t used_pages = 0;
@@ -1088,5 +1067,4 @@
 	/*
 	 * Start TLB shootdown sequence.
-	 *
 	 */
 	ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
@@ -1096,5 +1074,4 @@
 	 * Remove used pages from page tables and remember their frame
 	 * numbers.
-	 *
 	 */
 	size_t frame_idx = 0;
@@ -1111,5 +1088,6 @@
 			
 			for (size = 0; size < (size_t) node->value[i]; size++) {
-				pte_t *pte = page_mapping_find(as, ptr + size * PAGE_SIZE);
+				pte_t *pte =
+				    page_mapping_find(as, ptr + (size << PAGE_WIDTH));
 				
 				ASSERT(pte);
@@ -1120,5 +1098,5 @@
 				
 				/* Remove old mapping */
-				page_mapping_remove(as, ptr + size * PAGE_SIZE);
+				page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
 			}
 		}
@@ -1127,5 +1105,4 @@
 	/*
 	 * Finish TLB shootdown sequence.
-	 *
 	 */
 	
@@ -1135,5 +1112,4 @@
 	 * Invalidate potential software translation caches (e.g. TSB on
 	 * sparc64).
-	 *
 	 */
 	as_invalidate_translation_cache(as, area->base, area->pages);
@@ -1168,5 +1144,5 @@
 				
 				/* Insert the new mapping */
-				page_mapping_insert(as, ptr + size * PAGE_SIZE,
+				page_mapping_insert(as, ptr + (size << PAGE_WIDTH),
 				    old_frame[frame_idx++], page_flags);
 				
@@ -1217,5 +1193,4 @@
 		 * No area contained mapping for 'page'.
 		 * Signal page fault to low-level handler.
-		 *
 		 */
 		mutex_unlock(&AS->lock);
@@ -1237,5 +1212,4 @@
 		 * The address space area is not backed by any backend
 		 * or the backend cannot handle page faults.
-		 *
 		 */
 		mutex_unlock(&area->lock);
@@ -1249,5 +1223,4 @@
 	 * To avoid race condition between two page faults on the same address,
 	 * we need to make sure the mapping has not been already inserted.
-	 *
 	 */
 	pte_t *pte;
@@ -1267,5 +1240,4 @@
 	/*
 	 * Resort to the backend page fault handler.
-	 *
 	 */
 	if (area->backend->page_fault(area, page, access) != AS_PF_OK) {
@@ -1322,5 +1294,4 @@
 		 * preemption is disabled. We should not be
 		 * holding any other lock.
-		 *
 		 */
 		(void) interrupts_enable();
@@ -1342,5 +1313,4 @@
 			 * list of inactive address spaces with assigned
 			 * ASID.
-			 *
 			 */
 			ASSERT(old_as->asid != ASID_INVALID);
@@ -1353,5 +1323,4 @@
 		 * Perform architecture-specific tasks when the address space
 		 * is being removed from the CPU.
-		 *
 		 */
 		as_deinstall_arch(old_as);
@@ -1360,5 +1329,4 @@
 	/*
 	 * Second, prepare the new address space.
-	 *
 	 */
 	if ((new_as->cpu_refcount++ == 0) && (new_as != AS_KERNEL)) {
@@ -1376,5 +1344,4 @@
 	 * Perform architecture-specific steps.
 	 * (e.g. write ASID to hardware register etc.)
-	 *
 	 */
 	as_install_arch(new_as);
@@ -1395,5 +1362,5 @@
 {
 	ASSERT(mutex_locked(&area->lock));
-
+	
 	return area_flags_to_page_flags(area->flags);
 }
@@ -1499,5 +1466,5 @@
 	
 	if (src_area) {
-		size = src_area->pages * PAGE_SIZE;
+		size = src_area->pages << PAGE_WIDTH;
 		mutex_unlock(&src_area->lock);
 	} else
@@ -1516,8 +1483,8 @@
  * @param count Number of page to be marked.
  *
- * @return Zero on failure and non-zero on success.
- *
- */
-int used_space_insert(as_area_t *area, uintptr_t page, size_t count)
+ * @return False on failure or true on success.
+ *
+ */
+bool used_space_insert(as_area_t *area, uintptr_t page, size_t count)
 {
 	ASSERT(mutex_locked(&area->lock));
@@ -1530,12 +1497,11 @@
 		/*
 		 * We hit the beginning of some used space.
-		 *
-		 */
-		return 0;
+		 */
+		return false;
 	}
 	
 	if (!leaf->keys) {
 		btree_insert(&area->used_space, page, (void *) count, leaf);
-		return 1;
+		goto success;
 	}
 	
@@ -1551,54 +1517,49 @@
 		 * somewhere between the rightmost interval of
 		 * the left neigbour and the first interval of the leaf.
-		 *
 		 */
 		
 		if (page >= right_pg) {
 			/* Do nothing. */
-		} else if (overlaps(page, count * PAGE_SIZE, left_pg,
-		    left_cnt * PAGE_SIZE)) {
+		} else if (overlaps(page, count << PAGE_WIDTH, left_pg,
+		    left_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the left interval. */
-			return 0;
-		} else if (overlaps(page, count * PAGE_SIZE, right_pg,
-		    right_cnt * PAGE_SIZE)) {
+			return false;
+		} else if (overlaps(page, count << PAGE_WIDTH, right_pg,
+		    right_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the right interval. */
-			return 0;
-		} else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
-		    (page + count * PAGE_SIZE == right_pg)) {
+			return false;
+		} else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
+		    (page + (count << PAGE_WIDTH) == right_pg)) {
 			/*
 			 * The interval can be added by merging the two already
 			 * present intervals.
-			 *
 			 */
 			node->value[node->keys - 1] += count + right_cnt;
 			btree_remove(&area->used_space, right_pg, leaf);
-			return 1;
-		} else if (page == left_pg + left_cnt * PAGE_SIZE) {
+			goto success;
+		} else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
 			/*
 			 * The interval can be added by simply growing the left
 			 * interval.
-			 *
 			 */
 			node->value[node->keys - 1] += count;
-			return 1;
-		} else if (page + count * PAGE_SIZE == right_pg) {
+			goto success;
+		} else if (page + (count << PAGE_WIDTH) == right_pg) {
 			/*
 			 * The interval can be addded by simply moving base of
 			 * the right interval down and increasing its size
 			 * accordingly.
-			 *
 			 */
 			leaf->value[0] += count;
 			leaf->key[0] = page;
-			return 1;
+			goto success;
 		} else {
 			/*
 			 * The interval is between both neigbouring intervals,
 			 * but cannot be merged with any of them.
-			 *
 			 */
 			btree_insert(&area->used_space, page, (void *) count,
 			    leaf);
-			return 1;
+			goto success;
 		}
 	} else if (page < leaf->key[0]) {
@@ -1609,30 +1570,27 @@
 		 * Investigate the border case in which the left neighbour does
 		 * not exist but the interval fits from the left.
-		 *
-		 */
-		
-		if (overlaps(page, count * PAGE_SIZE, right_pg,
-		    right_cnt * PAGE_SIZE)) {
+		 */
+		
+		if (overlaps(page, count << PAGE_WIDTH, right_pg,
+		    right_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the right interval. */
-			return 0;
-		} else if (page + count * PAGE_SIZE == right_pg) {
+			return false;
+		} else if (page + (count << PAGE_WIDTH) == right_pg) {
 			/*
 			 * The interval can be added by moving the base of the
 			 * right interval down and increasing its size
 			 * accordingly.
-			 *
 			 */
 			leaf->key[0] = page;
 			leaf->value[0] += count;
-			return 1;
+			goto success;
 		} else {
 			/*
 			 * The interval doesn't adjoin with the right interval.
 			 * It must be added individually.
-			 *
 			 */
 			btree_insert(&area->used_space, page, (void *) count,
 			    leaf);
-			return 1;
+			goto success;
 		}
 	}
@@ -1649,54 +1607,49 @@
 		 * somewhere between the leftmost interval of
 		 * the right neigbour and the last interval of the leaf.
-		 *
 		 */
 		
 		if (page < left_pg) {
 			/* Do nothing. */
-		} else if (overlaps(page, count * PAGE_SIZE, left_pg,
-		    left_cnt * PAGE_SIZE)) {
+		} else if (overlaps(page, count << PAGE_WIDTH, left_pg,
+		    left_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the left interval. */
-			return 0;
-		} else if (overlaps(page, count * PAGE_SIZE, right_pg,
-		    right_cnt * PAGE_SIZE)) {
+			return false;
+		} else if (overlaps(page, count << PAGE_WIDTH, right_pg,
+		    right_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the right interval. */
-			return 0;
-		} else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
-		    (page + count * PAGE_SIZE == right_pg)) {
+			return false;
+		} else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
+		    (page + (count << PAGE_WIDTH) == right_pg)) {
 			/*
 			 * The interval can be added by merging the two already
 			 * present intervals.
-			 *
 			 */
 			leaf->value[leaf->keys - 1] += count + right_cnt;
 			btree_remove(&area->used_space, right_pg, node);
-			return 1;
-		} else if (page == left_pg + left_cnt * PAGE_SIZE) {
+			goto success;
+		} else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
 			/*
 			 * The interval can be added by simply growing the left
 			 * interval.
-			 *
 			 */
-			leaf->value[leaf->keys - 1] +=  count;
-			return 1;
-		} else if (page + count * PAGE_SIZE == right_pg) {
+			leaf->value[leaf->keys - 1] += count;
+			goto success;
+		} else if (page + (count << PAGE_WIDTH) == right_pg) {
 			/*
 			 * The interval can be addded by simply moving base of
 			 * the right interval down and increasing its size
 			 * accordingly.
-			 *
 			 */
 			node->value[0] += count;
 			node->key[0] = page;
-			return 1;
+			goto success;
 		} else {
 			/*
 			 * The interval is between both neigbouring intervals,
 			 * but cannot be merged with any of them.
-			 *
 			 */
 			btree_insert(&area->used_space, page, (void *) count,
 			    leaf);
-			return 1;
+			goto success;
 		}
 	} else if (page >= leaf->key[leaf->keys - 1]) {
@@ -1707,28 +1660,25 @@
 		 * Investigate the border case in which the right neighbour
 		 * does not exist but the interval fits from the right.
-		 *
-		 */
-		
-		if (overlaps(page, count * PAGE_SIZE, left_pg,
-		    left_cnt * PAGE_SIZE)) {
+		 */
+		
+		if (overlaps(page, count << PAGE_WIDTH, left_pg,
+		    left_cnt << PAGE_WIDTH)) {
 			/* The interval intersects with the left interval. */
-			return 0;
-		} else if (left_pg + left_cnt * PAGE_SIZE == page) {
+			return false;
+		} else if (left_pg + (left_cnt << PAGE_WIDTH) == page) {
 			/*
 			 * The interval can be added by growing the left
 			 * interval.
-			 *
 			 */
 			leaf->value[leaf->keys - 1] += count;
-			return 1;
+			goto success;
 		} else {
 			/*
 			 * The interval doesn't adjoin with the left interval.
 			 * It must be added individually.
-			 *
 			 */
 			btree_insert(&area->used_space, page, (void *) count,
 			    leaf);
-			return 1;
+			goto success;
 		}
 	}
@@ -1738,5 +1688,4 @@
 	 * only between two other intervals of the leaf. The two border cases
 	 * were already resolved.
-	 *
 	 */
 	btree_key_t i;
@@ -1750,51 +1699,45 @@
 			/*
 			 * The interval fits between left_pg and right_pg.
-			 *
 			 */
 			
-			if (overlaps(page, count * PAGE_SIZE, left_pg,
-			    left_cnt * PAGE_SIZE)) {
+			if (overlaps(page, count << PAGE_WIDTH, left_pg,
+			    left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval intersects with the left
 				 * interval.
-				 *
 				 */
-				return 0;
-			} else if (overlaps(page, count * PAGE_SIZE, right_pg,
-			    right_cnt * PAGE_SIZE)) {
+				return false;
+			} else if (overlaps(page, count << PAGE_WIDTH, right_pg,
+			    right_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval intersects with the right
 				 * interval.
-				 *
 				 */
-				return 0;
-			} else if ((page == left_pg + left_cnt * PAGE_SIZE) &&
-			    (page + count * PAGE_SIZE == right_pg)) {
+				return false;
+			} else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
+			    (page + (count << PAGE_WIDTH) == right_pg)) {
 				/*
 				 * The interval can be added by merging the two
 				 * already present intervals.
-				 *
 				 */
 				leaf->value[i - 1] += count + right_cnt;
 				btree_remove(&area->used_space, right_pg, leaf);
-				return 1;
-			} else if (page == left_pg + left_cnt * PAGE_SIZE) {
+				goto success;
+			} else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval can be added by simply growing
 				 * the left interval.
-				 *
 				 */
 				leaf->value[i - 1] += count;
-				return 1;
-			} else if (page + count * PAGE_SIZE == right_pg) {
+				goto success;
+			} else if (page + (count << PAGE_WIDTH) == right_pg) {
 				/*
 				 * The interval can be addded by simply moving
 				 * base of the right interval down and
 				 * increasing its size accordingly.
-				 *
 				 */
 				leaf->value[i] += count;
 				leaf->key[i] = page;
-				return 1;
+				goto success;
 			} else {
 				/*
@@ -1802,9 +1745,8 @@
 				 * intervals, but cannot be merged with any of
 				 * them.
-				 *
 				 */
 				btree_insert(&area->used_space, page,
 				    (void *) count, leaf);
-				return 1;
+				goto success;
 			}
 		}
@@ -1813,4 +1755,8 @@
 	panic("Inconsistency detected while adding %zu pages of used "
 	    "space at %p.", count, (void *) page);
+	
+success:
+	area->resident += count;
+	return true;
 }
 
@@ -1823,8 +1769,8 @@
  * @param count Number of page to be marked.
  *
- * @return Zero on failure and non-zero on success.
- *
- */
-int used_space_remove(as_area_t *area, uintptr_t page, size_t count)
+ * @return False on failure or true on success.
+ *
+ */
+bool used_space_remove(as_area_t *area, uintptr_t page, size_t count)
 {
 	ASSERT(mutex_locked(&area->lock));
@@ -1837,25 +1783,24 @@
 		/*
 		 * We are lucky, page is the beginning of some interval.
-		 *
 		 */
 		if (count > pages) {
-			return 0;
+			return false;
 		} else if (count == pages) {
 			btree_remove(&area->used_space, page, leaf);
-			return 1;
+			goto success;
 		} else {
 			/*
 			 * Find the respective interval.
 			 * Decrease its size and relocate its start address.
-			 *
 			 */
 			btree_key_t i;
 			for (i = 0; i < leaf->keys; i++) {
 				if (leaf->key[i] == page) {
-					leaf->key[i] += count * PAGE_SIZE;
+					leaf->key[i] += count << PAGE_WIDTH;
 					leaf->value[i] -= count;
-					return 1;
+					goto success;
 				}
 			}
+			
 			goto error;
 		}
@@ -1867,8 +1812,8 @@
 		size_t left_cnt = (size_t) node->value[node->keys - 1];
 		
-		if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
-		    count * PAGE_SIZE)) {
-			if (page + count * PAGE_SIZE ==
-			    left_pg + left_cnt * PAGE_SIZE) {
+		if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
+		    count << PAGE_WIDTH)) {
+			if (page + (count << PAGE_WIDTH) ==
+			    left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1876,10 +1821,9 @@
 				 * removed by updating the size of the bigger
 				 * interval.
-				 *
 				 */
 				node->value[node->keys - 1] -= count;
-				return 1;
-			} else if (page + count * PAGE_SIZE <
-			    left_pg + left_cnt*PAGE_SIZE) {
+				goto success;
+			} else if (page + (count << PAGE_WIDTH) <
+			    left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1888,17 +1832,17 @@
 				 * the original interval and also inserting a
 				 * new interval.
-				 *
 				 */
-				size_t new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
-				    (page + count*PAGE_SIZE)) >> PAGE_WIDTH;
+				size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
+				    (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
 				node->value[node->keys - 1] -= count + new_cnt;
 				btree_insert(&area->used_space, page +
-				    count * PAGE_SIZE, (void *) new_cnt, leaf);
-				return 1;
+				    (count << PAGE_WIDTH), (void *) new_cnt, leaf);
+				goto success;
 			}
 		}
-		return 0;
+		
+		return false;
 	} else if (page < leaf->key[0])
-		return 0;
+		return false;
 	
 	if (page > leaf->key[leaf->keys - 1]) {
@@ -1906,18 +1850,17 @@
 		size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
 		
-		if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
-		    count * PAGE_SIZE)) {
-			if (page + count * PAGE_SIZE ==
-			    left_pg + left_cnt * PAGE_SIZE) {
+		if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
+		    count << PAGE_WIDTH)) {
+			if (page + (count << PAGE_WIDTH) ==
+			    left_pg + (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
 				 * interval of the leaf and can be removed by
 				 * updating the size of the bigger interval.
-				 *
 				 */
 				leaf->value[leaf->keys - 1] -= count;
-				return 1;
-			} else if (page + count * PAGE_SIZE < left_pg +
-			    left_cnt * PAGE_SIZE) {
+				goto success;
+			} else if (page + (count << PAGE_WIDTH) < left_pg +
+			    (left_cnt << PAGE_WIDTH)) {
 				/*
 				 * The interval is contained in the rightmost
@@ -1926,20 +1869,20 @@
 				 * original interval and also inserting a new
 				 * interval.
-				 *
 				 */
-				size_t new_cnt = ((left_pg + left_cnt * PAGE_SIZE) -
-				    (page + count * PAGE_SIZE)) >> PAGE_WIDTH;
+				size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
+				    (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
 				leaf->value[leaf->keys - 1] -= count + new_cnt;
 				btree_insert(&area->used_space, page +
-				    count * PAGE_SIZE, (void *) new_cnt, leaf);
-				return 1;
+				    (count << PAGE_WIDTH), (void *) new_cnt, leaf);
+				goto success;
 			}
 		}
-		return 0;
+		
+		return false;
 	}
 	
 	/*
 	 * The border cases have been already resolved.
-	 * Now the interval can be only between intervals of the leaf. 
+	 * Now the interval can be only between intervals of the leaf.
 	 */
 	btree_key_t i;
@@ -1953,8 +1896,8 @@
 			 * to (i - 1) and i.
 			 */
-			if (overlaps(left_pg, left_cnt * PAGE_SIZE, page,
-			    count * PAGE_SIZE)) {
-				if (page + count * PAGE_SIZE ==
-				    left_pg + left_cnt*PAGE_SIZE) {
+			if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
+			    count << PAGE_WIDTH)) {
+				if (page + (count << PAGE_WIDTH) ==
+				    left_pg + (left_cnt << PAGE_WIDTH)) {
 					/*
 					 * The interval is contained in the
@@ -1962,10 +1905,9 @@
 					 * be removed by updating the size of
 					 * the bigger interval.
-					 *
 					 */
 					leaf->value[i - 1] -= count;
-					return 1;
-				} else if (page + count * PAGE_SIZE <
-				    left_pg + left_cnt * PAGE_SIZE) {
+					goto success;
+				} else if (page + (count << PAGE_WIDTH) <
+				    left_pg + (left_cnt << PAGE_WIDTH)) {
 					/*
 					 * The interval is contained in the
@@ -1976,15 +1918,16 @@
 					 */
 					size_t new_cnt = ((left_pg +
-					    left_cnt * PAGE_SIZE) -
-					    (page + count * PAGE_SIZE)) >>
+					    (left_cnt << PAGE_WIDTH)) -
+					    (page + (count << PAGE_WIDTH))) >>
 					    PAGE_WIDTH;
 					leaf->value[i - 1] -= count + new_cnt;
 					btree_insert(&area->used_space, page +
-					    count * PAGE_SIZE, (void *) new_cnt,
+					    (count << PAGE_WIDTH), (void *) new_cnt,
 					    leaf);
-					return 1;
+					goto success;
 				}
 			}
-			return 0;
+			
+			return false;
 		}
 	}
@@ -1993,4 +1936,8 @@
 	panic("Inconsistency detected while removing %zu pages of used "
 	    "space from %p.", count, (void *) page);
+	
+success:
+	area->resident -= count;
+	return true;
 }
 
@@ -2027,4 +1974,70 @@
 }
 
+/** Return pointer to unmapped address space area
+ *
+ * @param base Lowest address bound.
+ * @param size Requested size of the allocation.
+ *
+ * @return Pointer to the beginning of unmapped address space area.
+ *
+ */
+sysarg_t sys_as_get_unmapped_area(uintptr_t base, size_t size)
+{
+	if (size == 0)
+		return 0;
+	
+	/*
+	 * Make sure we allocate from page-aligned
+	 * address. Check for possible overflow in
+	 * each step.
+	 */
+	
+	size_t pages = SIZE2FRAMES(size);
+	uintptr_t ret = 0;
+	
+	/*
+	 * Find the lowest unmapped address aligned on the sz
+	 * boundary, not smaller than base and of the required size.
+	 */
+	
+	mutex_lock(&AS->lock);
+	
+	/* First check the base address itself */
+	uintptr_t addr = ALIGN_UP(base, PAGE_SIZE);
+	if ((addr >= base) &&
+	    (check_area_conflicts(AS, addr, pages, NULL)))
+		ret = addr;
+	
+	/* Eventually check the addresses behind each area */
+	link_t *cur;
+	for (cur = AS->as_area_btree.leaf_head.next;
+	    (ret == 0) && (cur != &AS->as_area_btree.leaf_head);
+	    cur = cur->next) {
+		btree_node_t *node =
+		    list_get_instance(cur, btree_node_t, leaf_link);
+		
+		btree_key_t i;
+		for (i = 0; (ret == 0) && (i < node->keys); i++) {
+			as_area_t *area = (as_area_t *) node->value[i];
+			
+			mutex_lock(&area->lock);
+			
+			uintptr_t addr =
+			    ALIGN_UP(area->base + (area->pages << PAGE_WIDTH),
+			    PAGE_SIZE);
+			
+			if ((addr >= base) && (addr >= area->base) &&
+			    (check_area_conflicts(AS, addr, pages, area)))
+				ret = addr;
+			
+			mutex_unlock(&area->lock);
+		}
+	}
+	
+	mutex_unlock(&AS->lock);
+	
+	return (sysarg_t) ret;
+}
+
 /** Get list of adress space areas.
  *
@@ -2093,5 +2106,5 @@
 	mutex_lock(&as->lock);
 	
-	/* print out info about address space areas */
+	/* Print out info about address space areas */
 	link_t *cur;
 	for (cur = as->as_area_btree.leaf_head.next;
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/src/proc/program.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -171,4 +171,5 @@
 	void *loader = program_loader;
 	if (!loader) {
+		as_destroy(as);
 		printf("Cannot spawn loader as none was registered\n");
 		return ENOENT;
@@ -179,4 +180,5 @@
 	if (rc != EE_OK) {
 		as_destroy(as);
+		printf("Cannot spawn loader (%s)\n", elf_error(rc));
 		return ENOENT;
 	}
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/src/syscall/syscall.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -143,4 +143,5 @@
 	(syshandler_t) sys_as_area_change_flags,
 	(syshandler_t) sys_as_area_destroy,
+	(syshandler_t) sys_as_get_unmapped_area,
 	
 	/* IPC related syscalls. */
Index: kernel/generic/src/sysinfo/stats.c
===================================================================
--- kernel/generic/src/sysinfo/stats.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/generic/src/sysinfo/stats.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -160,69 +160,17 @@
 static size_t get_task_virtmem(as_t *as)
 {
-	size_t result = 0;
-
 	/*
-	 * We are holding some spinlocks here and therefore are not allowed to
-	 * block. Only attempt to lock the address space and address space area
-	 * mutexes conditionally. If it is not possible to lock either object,
-	 * allow the statistics to be inexact by skipping the respective object.
-	 *
-	 * Note that it may be infinitely better to let the address space
-	 * management code compute these statistics as it proceeds instead of
-	 * having them calculated over and over again here.
+	 * We are holding spinlocks here and therefore are not allowed to
+	 * block. Only attempt to lock the address space and address space
+	 * area mutexes conditionally. If it is not possible to lock either
+	 * object, return inexact statistics by skipping the respective object.
 	 */
-
+	
 	if (SYNCH_FAILED(mutex_trylock(&as->lock)))
-		return result * PAGE_SIZE;
+		return 0;
+	
+	size_t pages = 0;
 	
 	/* Walk the B+ tree and count pages */
-	link_t *cur;
-	for (cur = as->as_area_btree.leaf_head.next;
-	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
-		btree_node_t *node =
-		    list_get_instance(cur, btree_node_t, leaf_link);
-		
-		unsigned int i;
-		for (i = 0; i < node->keys; i++) {
-			as_area_t *area = node->value[i];
-			
-			if (SYNCH_FAILED(mutex_trylock(&area->lock)))
-				continue;
-			result += area->pages;
-			mutex_unlock(&area->lock);
-		}
-	}
-	
-	mutex_unlock(&as->lock);
-	
-	return result * PAGE_SIZE;
-}
-
-/** Get the resident (used) size of a virtual address space
- *
- * @param as Address space.
- *
- * @return Size of the resident (used) virtual address space (bytes).
- *
- */
-static size_t get_task_resmem(as_t *as)
-{
-	size_t result = 0;
-	
-	/*
-	 * We are holding some spinlocks here and therefore are not allowed to
-	 * block. Only attempt to lock the address space and address space area
-	 * mutexes conditionally. If it is not possible to lock either object,
-	 * allow the statistics to be inexact by skipping the respective object.
-	 *
-	 * Note that it may be infinitely better to let the address space
-	 * management code compute these statistics as it proceeds instead of
-	 * having them calculated over and over again here.
-	 */
-	
-	if (SYNCH_FAILED(mutex_trylock(&as->lock)))
-		return result * PAGE_SIZE;
-	
-	/* Walk the B+ tree of AS areas */
 	link_t *cur;
 	for (cur = as->as_area_btree.leaf_head.next;
@@ -238,16 +186,5 @@
 				continue;
 			
-			/* Walk the B+ tree of resident pages */
-			link_t *rcur;
-			for (rcur = area->used_space.leaf_head.next;
-			    rcur != &area->used_space.leaf_head; rcur = rcur->next) {
-				btree_node_t *rnode =
-				    list_get_instance(rcur, btree_node_t, leaf_link);
-				
-				unsigned int j;
-				for (j = 0; j < rnode->keys; j++)
-					result += (size_t) rnode->value[i];
-			}
-			
+			pages += area->pages;
 			mutex_unlock(&area->lock);
 		}
@@ -256,5 +193,50 @@
 	mutex_unlock(&as->lock);
 	
-	return result * PAGE_SIZE;
+	return (pages << PAGE_WIDTH);
+}
+
+/** Get the resident (used) size of a virtual address space
+ *
+ * @param as Address space.
+ *
+ * @return Size of the resident (used) virtual address space (bytes).
+ *
+ */
+static size_t get_task_resmem(as_t *as)
+{
+	/*
+	 * We are holding spinlocks here and therefore are not allowed to
+	 * block. Only attempt to lock the address space and address space
+	 * area mutexes conditionally. If it is not possible to lock either
+	 * object, return inexact statistics by skipping the respective object.
+	 */
+	
+	if (SYNCH_FAILED(mutex_trylock(&as->lock)))
+		return 0;
+	
+	size_t pages = 0;
+	
+	/* Walk the B+ tree and count pages */
+	link_t *cur;
+	for (cur = as->as_area_btree.leaf_head.next;
+	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
+		btree_node_t *node =
+		    list_get_instance(cur, btree_node_t, leaf_link);
+		
+		unsigned int i;
+		for (i = 0; i < node->keys; i++) {
+			as_area_t *area = node->value[i];
+			
+			if (SYNCH_FAILED(mutex_trylock(&area->lock)))
+				continue;
+			
+			pages += area->resident;
+			mutex_unlock(&area->lock);
+		}
+	}
+	
+	mutex_unlock(&as->lock);
+	
+	return (pages << PAGE_WIDTH);
 }
 
Index: kernel/tools/genmap.py
===================================================================
--- kernel/tools/genmap.py	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ kernel/tools/genmap.py	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -100,8 +100,9 @@
 			for addr, symbol in symbols:
 				value = fname + ':' + symbol
-				data = struct.pack(symtabfmt, addr + offset, value[:MAXSTRING])
+				value_bytes = value.encode('ascii')
+				data = struct.pack(symtabfmt, addr + offset, value_bytes[:MAXSTRING])
 				out.write(data)
 			
-	out.write(struct.pack(symtabfmt, 0, ''))
+	out.write(struct.pack(symtabfmt, 0, b''))
 
 def main():
Index: release/Makefile
===================================================================
--- release/Makefile	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ release/Makefile	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2011 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+-include ../version
+
+EXPORT_DIR = /var/tmp/helenos/HelenOS-$(RELEASE)
+SRC_ARCHIVE = HelenOS-$(RELEASE).tar.bz2
+
+PROFILES = amd64 arm32/GXemul arm32/integratorcp arm32/gta02 ia32 \
+    ia64/i460GX ia64/ski mips32/GXemul mips32/msim sparc64/niagara \
+    sparc64/serengeti sparc64/ultra
+
+BZR = bzr
+TAR = tar
+
+# To determine IMG_FILE
+-include $(EXPORT_DIR)/Makefile.config
+-include $(EXPORT_DIR)/boot/arch/$(BARCH)/Makefile.inc
+-include $(EXPORT_DIR)/boot/Makefile.common
+
+ifdef POST_OUTPUT
+	IMG_FILE = $(EXPORT_DIR)/boot/$(POST_OUTPUT)
+else
+	IMG_FILE = $(EXPORT_DIR)/boot/$(BOOT_OUTPUT)
+endif
+
+SUFFIX = $(suffix $(IMG_FILE))
+
+ifdef PROFILE
+	RELEASE_FILE = HelenOS-$(RELEASE)-$(shell echo $(PROFILE) | tr '/' '-')$(SUFFIX)
+else
+	RELEASE_FILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX)
+endif
+
+.PHONY: all clean release releasefile export src_rel
+
+all: releasefile
+releasefile: $(RELEASE_FILE)
+
+$(RELEASE_FILE): $(IMG_FILE)
+	cp $< $@
+
+$(IMG_FILE):
+	$(MAKE) -C $(EXPORT_DIR)
+
+release: src_rel
+	for profile in $(PROFILES); do \
+		$(MAKE) -C $(EXPORT_DIR) clean ; \
+		$(MAKE) -C $(EXPORT_DIR) PROFILE=$$profile ; \
+		$(MAKE) PROFILE=$$profile releasefile ; \
+	done
+
+$(EXPORT_DIR) export:
+	rm -rf $(EXPORT_DIR)
+	mkdir -p $(EXPORT_DIR)
+	$(BZR) export $(EXPORT_DIR)
+
+src_rel $(SRC_ARCHIVE): export
+	$(TAR) -C $(shell dirname $(EXPORT_DIR)) \
+	    -cjf $(SRC_ARCHIVE) $(shell basename $(EXPORT_DIR))
+
+clean:
+	rm -f $(RELEASE_FILE)
Index: tools/mkfat.py
===================================================================
--- tools/mkfat.py	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ tools/mkfat.py	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -211,6 +211,6 @@
 	dir_entry = xstruct.create(DIR_ENTRY)
 	
-	dir_entry.name = mangle_fname(name)
-	dir_entry.ext = mangle_ext(name)
+	dir_entry.name = mangle_fname(name).encode('ascii')
+	dir_entry.ext = mangle_ext(name).encode('ascii')
 	
 	if (directory):
@@ -239,6 +239,6 @@
 	
 	dir_entry.signature = 0x2e
-	dir_entry.name = '       '
-	dir_entry.ext = '   '
+	dir_entry.name = b'       '
+	dir_entry.ext = b'   '
 	dir_entry.attr = 0x10
 	
@@ -258,6 +258,6 @@
 	
 	dir_entry.signature = [0x2e, 0x2e]
-	dir_entry.name = '      '
-	dir_entry.ext = '   '
+	dir_entry.name = b'      '
+	dir_entry.ext = b'   '
 	dir_entry.attr = 0x10
 	
Index: tools/mkhord.py
===================================================================
--- tools/mkhord.py	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ tools/mkhord.py	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -84,5 +84,5 @@
 	payload_size_aligned = align_up(payload_size, align)
 	
-	header.tag = "HORD"
+	header.tag = b"HORD"
 	header.version = 1
 	header.encoding = HORD_LSB
Index: tools/mktmpfs.py
===================================================================
--- tools/mktmpfs.py	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ tools/mktmpfs.py	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -80,5 +80,5 @@
 			dentry.kind = TMPFS_FILE
 			dentry.fname_len = len(name)
-			dentry.fname = name
+			dentry.fname = name.encode('ascii')
 			dentry.flen = size
 			
@@ -97,5 +97,5 @@
 			dentry.kind = TMPFS_DIRECTORY
 			dentry.fname_len = len(name)
-			dentry.fname = name
+			dentry.fname = name.encode('ascii')
 			
 			outf.write(dentry.pack())
@@ -122,5 +122,5 @@
 	
 	header = xstruct.create(HEADER)
-	header.tag = "TMPFS"
+	header.tag = b"TMPFS"
 	
 	outf.write(header.pack())
Index: tools/toolchain.sh
===================================================================
--- tools/toolchain.sh	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ tools/toolchain.sh	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -28,4 +28,74 @@
 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
+
+GMP_MAIN=<<EOF
+#define GCC_GMP_VERSION_NUM(a, b, c) \
+	(((a) << 16L) | ((b) << 8) | (c))
+
+#define GCC_GMP_VERSION \
+	GCC_GMP_VERSION_NUM(__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL)
+
+#if GCC_GMP_VERSION < GCC_GMP_VERSION_NUM(4,3,2)
+	choke me
+#endif
+EOF
+
+MPFR_MAIN=<<EOF
+#if MPFR_VERSION < MPFR_VERSION_NUM(2, 4, 2)
+choke me
+	#endif
+EOF
+
+MPC_MAIN=<<EOF
+#if MPC_VERSION < MPC_VERSION_NUM(0, 8, 1)
+	choke me
+#endif
+EOF
+
+#
+# Check if the library described in the argument
+# exists and has acceptable version.
+#
+check_dependency() {
+	DEPENDENCY="$1"
+	HEADER="$2"
+	BODY="$3"
+	
+	FNAME="/tmp/conftest-$$"
+	
+	echo "#include ${HEADER}" > "${FNAME}.c"
+	echo >> "${FNAME}.c"
+	echo "int main()" >> "${FNAME}.c"
+	echo "{" >> "${FNAME}.c"
+	echo "${BODY}" >> "${FNAME}.c"
+	echo "	return 0;" >> "${FNAME}.c"
+	echo "}" >> "${FNAME}.c"
+	
+	cc -c -o "${FNAME}.o" "${FNAME}.c" 2> "${FNAME}.log"
+	RC="$?"
+	
+	if [ "$RC" -ne "0" ] ; then
+		echo " ${DEPENDENCY} not found, too old or compiler error."
+		echo " Please recheck manually the source file \"${FNAME}.c\"."
+		echo " The compilation of the toolchain is probably going to fail,"
+		echo " you have been warned."
+		echo
+		echo " ===== Compiler output ====="
+		cat "${FNAME}.log"
+		echo " ==========================="
+		echo
+	else
+		echo " ${DEPENDENCY} found"
+		rm -f "${FNAME}.log" "${FNAME}.o" "${FNAME}.c"
+	fi
+}
+
+check_dependecies() {
+	echo ">>> Basic dependency check"
+	check_dependency "GMP" "<gmp.h>" "${GMP_MAIN}"
+	check_dependency "MPFR" "<mpfr.h>" "${MPFR_MAIN}"
+	check_dependency "MPC" "<mpc.h>" "${MPC_MAIN}"
+	echo
+}
 
 check_error() {
@@ -69,4 +139,8 @@
 	echo " sparc64    SPARC V9"
 	echo " all        build all targets"
+	echo
+	echo "The toolchain will be installed to the directory specified by"
+	echo "the CROSS_PREFIX environment variable. If the variable is not"
+	echo "defined, /usr/local will be used by default."
 	echo
 	
@@ -118,6 +192,4 @@
 	echo " - native C library with headers"
 	echo
-	
-	show_countdown 10
 }
 
@@ -281,4 +353,6 @@
 
 show_dependencies
+check_dependecies
+show_countdown 10
 
 case "$1" in
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/Makefile.common	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -135,4 +135,11 @@
 endif
 
+ifeq ($(CONFIG_LINE_DEBUG),y)
+	GCC_CFLAGS += -g
+	ICC_CFLAGS += -g
+	SUNCC_CFLAGS += -g
+	CLANG_CFLAGS += -g
+endif
+
 ## Setup platform configuration
 #
@@ -210,2 +217,8 @@
 	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
 	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
+
+##
+# This explicit dependecy of the output binary on the object files seems to be
+# necessary to prevent parallel build failures (GNU make bug #26893 ???).
+$(OUTPUT): $(OBJECTS)
+
Index: uspace/app/bdsh/cmds/modules/bdd/bdd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -70,4 +70,5 @@
 	unsigned int i, j;
 	devmap_handle_t handle;
+	aoff64_t offset;
 	uint8_t *blk;
 	size_t size, bytes, rows;
@@ -120,4 +121,6 @@
 	}
 
+	offset = ba * block_size;
+
 	while (size > 0) {
 		rc = block_read_direct(handle, ba, 1, blk);
@@ -133,4 +136,5 @@
 
 		for (j = 0; j < rows; j++) {
+			printf("[%06" PRIxOFF64 "] ", offset);
 			for (i = 0; i < BPR; i++) {
 				if (j * BPR + i < bytes)
@@ -152,4 +156,5 @@
 				}
 			}
+			offset += BPR;
 			putchar('\n');
 		}
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -144,14 +144,14 @@
 			return CMD_SUCCESS;
 		case 'H':
-			printf(cat_oops);
+			printf("%s", cat_oops);
 			return CMD_FAILURE;
 		case 't':
-			printf(cat_oops);
+			printf("%s", cat_oops);
 			return CMD_FAILURE;
 		case 'b':
-			printf(cat_oops);
+			printf("%s", cat_oops);
 			break;
 		case 'm':
-			printf(cat_oops);
+			printf("%s", cat_oops);
 			return CMD_FAILURE;
 		}
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -125,5 +125,5 @@
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "s:h", long_options, &opt_ind);
 		switch (c) {
 		case 'h':
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -31,4 +31,5 @@
 #include <vfs/vfs.h>
 #include <errno.h>
+#include <getopt.h>
 #include "config.h"
 #include "util.h"
@@ -40,5 +41,11 @@
 static const char *cmdname = "mount";
 
-/* Dispays help for mount in various levels */
+static struct option const long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+
+/* Displays help for mount in various levels */
 void help_cmd_mount(unsigned int level)
 {
@@ -59,10 +66,19 @@
 	unsigned int argc;
 	const char *mopts = "";
-	int rc;
+	int rc, c, opt_ind;
 
 	argc = cli_count_args(argv);
 
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "h", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_mount(HELP_LONG);
+			return CMD_SUCCESS;
+		}
+	}
+
 	if ((argc < 4) || (argc > 5)) {
-		printf("%s: invalid number of arguments.\n",
+		printf("%s: invalid number of arguments. Try `mount --help'\n",
 		    cmdname);
 		return CMD_FAILURE;
Index: uspace/app/bdsh/cmds/modules/rm/rm.c
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -227,5 +227,5 @@
 		}
 		memset(buff, 0, sizeof(buff));
-		snprintf(buff, len, argv[i]);
+		snprintf(buff, len, "%s", argv[i]);
 
 		scope = rm_scope(buff);
Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/Makefile	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -35,8 +35,9 @@
 SOURCES = \
 	src/builtin/bi_boxed.c \
+	src/builtin/bi_error.c \
 	src/builtin/bi_char.c \
-	src/builtin/bi_error.c \
-	src/builtin/bi_fun.c \
+	src/builtin/bi_console.c \
 	src/builtin/bi_int.c \
+	src/builtin/bi_task.c \
 	src/builtin/bi_textfile.c \
 	src/builtin/bi_string.c \
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/builtin.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -43,6 +43,7 @@
 #include "builtin/bi_error.h"
 #include "builtin/bi_char.h"
-#include "builtin/bi_fun.h"
+#include "builtin/bi_console.h"
 #include "builtin/bi_int.h"
+#include "builtin/bi_task.h"
 #include "builtin/bi_textfile.h"
 #include "builtin/bi_string.h"
@@ -93,6 +94,7 @@
 	bi_error_declare(bi);
 	bi_char_declare(bi);
-	bi_fun_declare(bi);
+	bi_console_declare(bi);
 	bi_int_declare(bi);
+	bi_task_declare(bi);
 	bi_textfile_declare(bi);
 	bi_string_declare(bi);
@@ -111,6 +113,7 @@
 	bi_error_bind(bi);
 	bi_char_bind(bi);
-	bi_fun_bind(bi);
+	bi_console_bind(bi);
 	bi_int_bind(bi);
+	bi_task_bind(bi);
 	bi_textfile_bind(bi);
 	bi_string_bind(bi);
Index: uspace/app/sbi/src/builtin/bi_console.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_console.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/app/sbi/src/builtin/bi_console.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+/** @file Console builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../bigint.h"
+#include "../builtin.h"
+#include "../list.h"
+#include "../mytypes.h"
+#include "../run.h"
+#include "../stree.h"
+#include "../strtab.h"
+#include "../symbol.h"
+
+#include "bi_console.h"
+
+static void bi_console_write(run_t *run);
+static void bi_console_writeline(run_t *run);
+
+/** Declare Console builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_console_declare(builtin_t *bi)
+{
+	stree_modm_t *modm;
+	stree_csi_t *csi;
+	stree_ident_t *ident;
+	stree_symbol_t *symbol;
+	stree_symbol_t *fun_sym;
+
+	/* Declare class Builtin */
+
+	ident = stree_ident_new();
+	ident->sid = strtab_get_sid("Console");
+
+	csi = stree_csi_new(csi_class);
+	csi->name = ident;
+	list_init(&csi->targ);
+	list_init(&csi->members);
+
+	modm = stree_modm_new(mc_csi);
+	modm->u.csi = csi;
+
+	symbol = stree_symbol_new(sc_csi);
+	symbol->u.csi = csi;
+	symbol->outer_csi = NULL;
+	csi->symbol = symbol;
+
+	list_append(&bi->program->module->members, modm);
+
+	/* Declare Builtin.Write(). */
+
+	fun_sym = builtin_declare_fun(csi, "Write");
+	builtin_fun_add_arg(fun_sym, "arg");
+
+	/* Declare Builtin.WriteLine(). */
+
+	fun_sym = builtin_declare_fun(csi, "WriteLine");
+	builtin_fun_add_arg(fun_sym, "arg");
+}
+
+/** Bind builtin functions.
+ *
+ * @param bi	Builtin object
+ */
+void bi_console_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Console", "Write", bi_console_write);
+	builtin_fun_bind(bi, "Console", "WriteLine", bi_console_writeline);
+}
+
+/** Write to the console.
+ *
+ * @param run	Runner object
+ */
+static void bi_console_write(run_t *run)
+{
+	rdata_var_t *var;
+	int char_val;
+	int rc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Console.Write()\n");
+#endif
+	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
+	assert(var);
+
+	switch (var->vc) {
+	case vc_bool:
+		printf("%s", var->u.bool_v->value ? "true" : "false");
+		break;
+	case vc_char:
+		rc = bigint_get_value_int(&var->u.char_v->value, &char_val);
+		if (rc == EOK)
+			printf("%lc", char_val);
+		else
+			printf("???");
+		break;
+	case vc_int:
+		bigint_print(&var->u.int_v->value);
+		break;
+	case vc_string:
+		printf("%s", var->u.string_v->value);
+		break;
+	default:
+		printf("Unimplemented: Write() with unsupported type.\n");
+		exit(1);
+	}
+}
+
+/** Write a line of output.
+ *
+ * @param run	Runner object
+ */
+static void bi_console_writeline(run_t *run)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Console.WriteLine()\n");
+#endif
+	bi_console_write(run);
+	putchar('\n');
+}
Index: uspace/app/sbi/src/builtin/bi_console.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_console.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/app/sbi/src/builtin/bi_console.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -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.
+ */
+
+#ifndef BI_CONSOLE_H_
+#define BI_CONSOLE_H_
+
+#include "../mytypes.h"
+
+void bi_console_declare(builtin_t *bi);
+void bi_console_bind(builtin_t *bi);
+
+#endif
Index: pace/app/sbi/src/builtin/bi_fun.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ 	(revision )
@@ -1,219 +1,0 @@
-/*
- * 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.
- */
-
-/** @file Builtin functions. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "../bigint.h"
-#include "../builtin.h"
-#include "../list.h"
-#include "../mytypes.h"
-#include "../os/os.h"
-#include "../run.h"
-#include "../stree.h"
-#include "../strtab.h"
-#include "../symbol.h"
-
-#include "bi_fun.h"
-
-static void bi_fun_builtin_write(run_t *run);
-static void bi_fun_builtin_writeline(run_t *run);
-static void bi_fun_task_exec(run_t *run);
-
-/** Declare builtin functions.
- *
- * @param bi	Builtin object
- */
-void bi_fun_declare(builtin_t *bi)
-{
-	stree_modm_t *modm;
-	stree_csi_t *csi;
-	stree_ident_t *ident;
-	stree_symbol_t *symbol;
-	stree_symbol_t *fun_sym;
-
-	/* Declare class Builtin */
-
-	ident = stree_ident_new();
-	ident->sid = strtab_get_sid("Builtin");
-
-	csi = stree_csi_new(csi_class);
-	csi->name = ident;
-	list_init(&csi->targ);
-	list_init(&csi->members);
-
-	modm = stree_modm_new(mc_csi);
-	modm->u.csi = csi;
-
-	symbol = stree_symbol_new(sc_csi);
-	symbol->u.csi = csi;
-	symbol->outer_csi = NULL;
-	csi->symbol = symbol;
-
-	list_append(&bi->program->module->members, modm);
-
-	/* Declare Builtin.Write(). */
-
-	fun_sym = builtin_declare_fun(csi, "Write");
-	builtin_fun_add_arg(fun_sym, "arg");
-
-	/* Declare Builtin.WriteLine(). */
-
-	fun_sym = builtin_declare_fun(csi, "WriteLine");
-	builtin_fun_add_arg(fun_sym, "arg");
-
-	/* Declare class Task. */
-
-	builtin_code_snippet(bi,
-		"class Task is\n"
-			"fun Exec(args : string[], packed), static, builtin;\n"
-		"end\n");
-}
-
-/** Bind builtin functions.
- *
- * @param bi	Builtin object
- */
-void bi_fun_bind(builtin_t *bi)
-{
-	builtin_fun_bind(bi, "Builtin", "Write", bi_fun_builtin_write);
-	builtin_fun_bind(bi, "Builtin", "WriteLine", bi_fun_builtin_writeline);
-	builtin_fun_bind(bi, "Task", "Exec", bi_fun_task_exec);
-}
-
-/** Write to the console.
- *
- * @param run	Runner object
- */
-static void bi_fun_builtin_write(run_t *run)
-{
-	rdata_var_t *var;
-	int char_val;
-	int rc;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Builtin.Write()\n");
-#endif
-	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
-	assert(var);
-
-	switch (var->vc) {
-	case vc_bool:
-		printf("%s", var->u.bool_v->value ? "true" : "false");
-		break;
-	case vc_char:
-		rc = bigint_get_value_int(&var->u.char_v->value, &char_val);
-		if (rc == EOK)
-			printf("%lc", char_val);
-		else
-			printf("???");
-		break;
-	case vc_int:
-		bigint_print(&var->u.int_v->value);
-		break;
-	case vc_string:
-		printf("%s", var->u.string_v->value);
-		break;
-	default:
-		printf("Unimplemented: Write() with unsupported type.\n");
-		exit(1);
-	}
-}
-
-/** Write a line of output.
- *
- * @param run	Runner object
- */
-static void bi_fun_builtin_writeline(run_t *run)
-{
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Builtin.WriteLine()\n");
-#endif
-	bi_fun_builtin_write(run);
-	putchar('\n');
-}
-
-/** Start an executable and wait for it to finish.
- *
- * @param run	Runner object
- */
-static void bi_fun_task_exec(run_t *run)
-{
-	rdata_var_t *args;
-	rdata_var_t *var;
-	rdata_array_t *array;
-	rdata_var_t *arg;
-	int idx, dim;
-	const char **cmd;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Task.Exec()\n");
-#endif
-	args = run_local_vars_lookup(run, strtab_get_sid("args"));
-
-	assert(args);
-	assert(args->vc == vc_ref);
-
-	var = args->u.ref_v->vref;
-	assert(var->vc == vc_array);
-
-	array = var->u.array_v;
-	assert(array->rank == 1);
-	dim = array->extent[0];
-
-	if (dim == 0) {
-		printf("Error: Builtin.Exec() expects at least one argument.\n");
-		exit(1);
-	}
-
-	cmd = calloc(dim + 1, sizeof(char *));
-	if (cmd == NULL) {
-		printf("Memory allocation failed.\n");
-		exit(1);
-	}
-
-	for (idx = 0; idx < dim; ++idx) {
-		arg = array->element[idx];
-		if (arg->vc != vc_string) {
-			printf("Error: Argument to Builtin.Exec() must be "
-			    "string (found %d).\n", arg->vc);
-			exit(1);
-		}
-
-		cmd[idx] = arg->u.string_v->value;
-	}
-
-	cmd[dim] = '\0';
-
-	if (os_exec((char * const *)cmd) != EOK) {
-		printf("Error: Exec failed.\n");
-		exit(1);
-	}
-}
Index: pace/app/sbi/src/builtin/bi_fun.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ 	(revision )
@@ -1,37 +1,0 @@
-/*
- * 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.
- */
-
-#ifndef BI_FUN_H_
-#define BI_FUN_H_
-
-#include "../mytypes.h"
-
-void bi_fun_declare(builtin_t *bi);
-void bi_fun_bind(builtin_t *bi);
-
-#endif
Index: uspace/app/sbi/src/builtin/bi_task.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_task.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/app/sbi/src/builtin/bi_task.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+/** @file Task builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../builtin.h"
+#include "../list.h"
+#include "../mytypes.h"
+#include "../os/os.h"
+#include "../run.h"
+#include "../strtab.h"
+
+#include "bi_task.h"
+
+static void bi_task_exec(run_t *run);
+
+/** Declare task builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_task_declare(builtin_t *bi)
+{
+	builtin_code_snippet(bi,
+		"class Task is\n"
+			"fun Exec(args : string[], packed), static, builtin;\n"
+		"end\n");
+}
+
+/** Bind builtin functions.
+ *
+ * @param bi	Builtin object
+ */
+void bi_task_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Task", "Exec", bi_task_exec);
+}
+
+/** Start an executable and wait for it to finish.
+ *
+ * @param run	Runner object
+ */
+static void bi_task_exec(run_t *run)
+{
+	rdata_var_t *args;
+	rdata_var_t *var;
+	rdata_array_t *array;
+	rdata_var_t *arg;
+	int idx, dim;
+	const char **cmd;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Task.Exec()\n");
+#endif
+	args = run_local_vars_lookup(run, strtab_get_sid("args"));
+
+	assert(args);
+	assert(args->vc == vc_ref);
+
+	var = args->u.ref_v->vref;
+	assert(var->vc == vc_array);
+
+	array = var->u.array_v;
+	assert(array->rank == 1);
+	dim = array->extent[0];
+
+	if (dim == 0) {
+		printf("Error: Builtin.Exec() expects at least one argument.\n");
+		exit(1);
+	}
+
+	cmd = calloc(dim + 1, sizeof(char *));
+	if (cmd == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	for (idx = 0; idx < dim; ++idx) {
+		arg = array->element[idx];
+		if (arg->vc != vc_string) {
+			printf("Error: Argument to Builtin.Exec() must be "
+			    "string (found %d).\n", arg->vc);
+			exit(1);
+		}
+
+		cmd[idx] = arg->u.string_v->value;
+	}
+
+	cmd[dim] = '\0';
+
+	if (os_exec((char * const *)cmd) != EOK) {
+		printf("Error: Exec failed.\n");
+		exit(1);
+	}
+}
Index: uspace/app/sbi/src/builtin/bi_task.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_task.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/app/sbi/src/builtin/bi_task.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -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.
+ */
+
+#ifndef BI_TASK_H_
+#define BI_TASK_H_
+
+#include "../mytypes.h"
+
+void bi_task_declare(builtin_t *bi);
+void bi_task_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/imode.c
===================================================================
--- uspace/app/sbi/src/imode.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/imode.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -178,4 +178,17 @@
 			/* Convert expression result to value item. */
 			run_cvt_value_item(&run, rexpr, &rexpr_vi);
+			rdata_item_destroy(rexpr);
+
+			/* Check for unhandled exceptions. */
+			run_exc_check_unhandled(&run);
+		} else {
+			rexpr_vi = NULL;
+		}
+
+		/*
+		 * rexpr_vi can be NULL if either repxr was null or
+		 * if the conversion to value item raised an exception.
+		 */
+		if (rexpr_vi != NULL) {
 			assert(rexpr_vi->ic == ic_value);
 
@@ -184,6 +197,10 @@
 			rdata_value_print(rexpr_vi->u.value);
 			printf("\n");
+
+			rdata_item_destroy(rexpr_vi);
 		}
 	}
+
+	run_proc_ar_destroy(&run, proc_ar);
 
 	/* Remove block visit record from the stack, */
Index: uspace/app/sbi/src/intmap.c
===================================================================
--- uspace/app/sbi/src/intmap.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/intmap.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -50,4 +50,15 @@
 }
 
+/** Deinitialize map.
+ *
+ * The map must be already empty.
+ *
+ * @param intmap	Map to initialize.
+ */
+void intmap_fini(intmap_t *intmap)
+{
+	list_fini(&intmap->elem);
+}
+
 /** Set value corresponding to a key.
  *
@@ -56,7 +67,7 @@
  * is removed from the map.
  *
- * @param intmap	Map.
- * @param key		Key (integer).
- * @param value		Value (must be a pointer) or @c NULL.
+ * @param intmap	Map
+ * @param key		Key (integer)
+ * @param value		Value (must be a pointer) or @c NULL
  */
 void intmap_set(intmap_t *intmap, int key, void *value)
@@ -75,6 +86,5 @@
 				/* Remove map element. */
 				list_remove(&intmap->elem, node);
-				node->data = NULL;
-				free(node);
+				free(elem);
 			}
 			return;
@@ -98,6 +108,6 @@
 /** Get value corresponding to a key.
  *
- * @param intmap	Map.
- * @param key		Key for which to retrieve mapping.
+ * @param intmap	Map
+ * @param key		Key for which to retrieve mapping
  *
  * @return		Value correspoding to @a key or @c NULL if no mapping
@@ -121,2 +131,45 @@
 	return NULL;
 }
+
+/** Get first element in the map.
+ *
+ * For iterating over the map, this returns the first element (in no
+ * particular order).
+ *
+ * @param intmap	Map
+ * @return		Map element or NULL if the map is empty
+ */
+map_elem_t *intmap_first(intmap_t *intmap)
+{
+	list_node_t *node;
+
+	node = list_first(&intmap->elem);
+	if (node == NULL)
+		return NULL;
+
+	return list_node_data(node, map_elem_t *);
+}
+
+/** Get element key.
+ *
+ * Giver a map element, return the key.
+ *
+ * @param elem		Map element
+ * @return		Key
+ */
+int intmap_elem_get_key(map_elem_t *elem)
+{
+	return elem->key;
+}
+
+/** Get element value.
+ *
+ * Giver a map element, return the value.
+ *
+ * @param elem		Map element
+ * @return		Value
+ */
+void *intmap_elem_get_value(map_elem_t *elem)
+{
+	return elem->value;
+}
Index: uspace/app/sbi/src/intmap.h
===================================================================
--- uspace/app/sbi/src/intmap.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/intmap.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -33,6 +33,10 @@
 
 void intmap_init(intmap_t *intmap);
+void intmap_fini(intmap_t *intmap);
 void intmap_set(intmap_t *intmap, int key, void *data);
 void *intmap_get(intmap_t *intmap, int key);
+map_elem_t *intmap_first(intmap_t *intmap);
+int intmap_elem_get_key(map_elem_t *elem);
+void *intmap_elem_get_value(map_elem_t *elem);
 
 #endif
Index: uspace/app/sbi/src/lex.c
===================================================================
--- uspace/app/sbi/src/lex.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/lex.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -45,4 +45,9 @@
 #define TAB_WIDTH 8
 
+typedef enum {
+	cs_chr,
+	cs_str
+} chr_str_t;
+
 static void lex_touch(lex_t *lex);
 static bool_t lex_read_try(lex_t *lex);
@@ -57,4 +62,5 @@
 static void lex_number(lex_t *lex);
 static void lex_string(lex_t *lex);
+static void lex_char_string_core(lex_t *lex, chr_str_t cs);
 static int digit_value(char c);
 
@@ -117,4 +123,5 @@
 	{ lc_string,	"string" },
 	{ lc_struct,	"struct" },
+	{ lc_switch,	"switch" },
 	{ lc_then,	"then" },
 	{ lc_this,	"this" },
@@ -122,4 +129,5 @@
 	{ lc_var,	"var" },
 	{ lc_with,	"with" },
+	{ lc_when,	"when" },
 	{ lc_while,	"while" },
 	{ lc_yield,	"yield" },
@@ -535,30 +543,9 @@
 static void lex_char(lex_t *lex)
 {
-	char *bp;
-	int idx;
 	size_t len;
 	int char_val;
 
-	bp = lex->ibp + 1;
-	idx = 0;
-
-	while (bp[idx] != '\'') {
-		if (idx >= SLBUF_SIZE) {
-			printf("Error: Character literal too long.\n");
-			exit(1);
-		}
-
-		if (bp[idx] == '\0') {
-			printf("Error: Unterminated character literal.\n");
-			exit(1);
-		}
-
-		strlit_buf[idx] = bp[idx];
-		++idx;
-	}
-
-	lex->ibp = bp + idx + 1;
-
-	strlit_buf[idx] = '\0';
+	lex_char_string_core(lex, cs_chr);
+
 	len = os_str_length(strlit_buf);
 	if (len != 1) {
@@ -620,31 +607,84 @@
 static void lex_string(lex_t *lex)
 {
-	char *bp;
-	int idx;
-
-	bp = lex->ibp + 1;
-	idx = 0;
-
-	while (bp[idx] != '"') {
-		if (idx >= SLBUF_SIZE) {
-			printf("Error: String literal too long.\n");
-			exit(1);
-		}
-
-		if (bp[idx] == '\0') {
-			printf("Error: Unterminated string literal.\n");
-			exit(1);
-		}
-
-		strlit_buf[idx] = bp[idx];
-		++idx;
-	}
-
-	lex->ibp = bp + idx + 1;
-
-	strlit_buf[idx] = '\0';
+	lex_char_string_core(lex, cs_str);
 
 	lex->current.lclass = lc_lit_string;
 	lex->current.u.lit_string.value = os_str_dup(strlit_buf);
+}
+
+static void lex_char_string_core(lex_t *lex, chr_str_t cs)
+{
+	char *bp;
+	int sidx, didx;
+	char term;
+	const char *descr, *cap_descr;
+	char spchar;
+
+	/* Make compiler happy */
+	term = '\0';
+	descr = NULL;
+	cap_descr = NULL;
+
+	switch (cs) {
+	case cs_chr:
+		term = '\'';
+		descr = "character";
+		cap_descr = "Character";
+		break;
+	case cs_str:
+		term = '"';
+		descr = "string";
+		cap_descr = "String";
+		break;
+	}
+
+	bp = lex->ibp + 1;
+	sidx = didx = 0;
+
+	while (bp[sidx] != term) {
+		if (didx >= SLBUF_SIZE) {
+			printf("Error: %s literal too long.\n", cap_descr);
+			exit(1);
+		}
+
+		if (bp[sidx] == '\0') {
+			printf("Error: Unterminated %s literal.\n", descr);
+			exit(1);
+		}
+
+		if (bp[sidx] == '\\') {
+			switch (bp[sidx + 1]) {
+			case '\\':
+				spchar = '\\';
+				break;
+			case '\'':
+				spchar = '\'';
+				break;
+			case '"':
+				spchar = '"';
+				break;
+			case 'n':
+				spchar = '\n';
+				break;
+			case 't':
+				spchar = '\t';
+				break;
+			default:
+				printf("Error: Unknown character escape sequence.\n");
+				exit(1);
+			}
+
+			strlit_buf[didx] = spchar;
+			++didx;
+			sidx += 2;
+		} else {
+			strlit_buf[didx] = bp[sidx];
+			++sidx; ++didx;
+		}
+	}
+
+	lex->ibp = bp + sidx + 1;
+
+	strlit_buf[didx] = '\0';
 }
 
Index: uspace/app/sbi/src/lex_t.h
===================================================================
--- uspace/app/sbi/src/lex_t.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/lex_t.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -85,4 +85,5 @@
 	lc_string,
 	lc_struct,
+	lc_switch,
 	lc_then,
 	lc_this,
@@ -90,4 +91,5 @@
 	lc_var,
 	lc_with,
+	lc_when,
 	lc_while,
 	lc_yield,
Index: uspace/app/sbi/src/list.c
===================================================================
--- uspace/app/sbi/src/list.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/list.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -57,4 +57,16 @@
 }
 
+/** Deinitialize list.
+ *
+ * @param list	List to deinitialize.
+ */
+void list_fini(list_t *list)
+{
+	assert(list_is_empty(list));
+
+	list->head.prev = NULL;
+	list->head.next = NULL;
+}
+
 /** Append data to list.
  *
Index: uspace/app/sbi/src/list.h
===================================================================
--- uspace/app/sbi/src/list.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/list.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -34,4 +34,5 @@
 
 void list_init(list_t *list);
+void list_fini(list_t *list);
 void list_append(list_t *list, void *data);
 void list_prepend(list_t *list, void *data);
Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/parse.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -82,4 +82,5 @@
 static stree_vdecl_t *parse_vdecl(parse_t *parse);
 static stree_if_t *parse_if(parse_t *parse);
+static stree_switch_t *parse_switch(parse_t *parse);
 static stree_while_t *parse_while(parse_t *parse);
 static stree_for_t *parse_for(parse_t *parse);
@@ -667,5 +668,4 @@
 	stree_prop_t *prop;
 	stree_symbol_t *symbol;
-	bool_t body_expected;
 
 	stree_ident_t *ident;
@@ -720,6 +720,4 @@
 	/* Parse attributes. */
 	parse_symbol_attrs(parse, symbol);
-
-	body_expected = (outer_csi->cc != csi_interface);
 
 	lmatch(parse, lc_is);
@@ -1070,4 +1068,5 @@
 	stree_vdecl_t *vdecl_s;
 	stree_if_t *if_s;
+	stree_switch_t *switch_s;
 	stree_while_t *while_s;
 	stree_for_t *for_s;
@@ -1092,4 +1091,9 @@
 		stat->u.if_s = if_s;
 		break;
+	case lc_switch:
+		switch_s = parse_switch(parse);
+		stat = stree_stat_new(st_switch);
+		stat->u.switch_s = switch_s;
+		break;
 	case lc_while:
 		while_s = parse_while(parse);
@@ -1214,4 +1218,58 @@
 	lmatch(parse, lc_end);
 	return if_s;
+}
+
+/** Parse @c switch statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_switch_t *parse_switch(parse_t *parse)
+{
+	stree_switch_t *switch_s;
+	stree_when_t *when_c;
+	stree_expr_t *expr;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'switch' statement.\n");
+#endif
+	lmatch(parse, lc_switch);
+
+	switch_s = stree_switch_new();
+	list_init(&switch_s->when_clauses);
+
+	switch_s->expr = parse_expr(parse);
+	lmatch(parse, lc_is);
+
+	/* Parse @c when clauses. */
+	while (lcur_lc(parse) == lc_when) {
+		lskip(parse);
+		when_c = stree_when_new();
+		list_init(&when_c->exprs);
+		while (b_true) {
+			expr = parse_expr(parse);
+			list_append(&when_c->exprs, expr);
+			if (lcur_lc(parse) != lc_comma)
+				break;
+			lskip(parse);
+		}
+
+		lmatch(parse, lc_do);
+		when_c->block = parse_block(parse);
+
+		list_append(&switch_s->when_clauses, when_c);
+	}
+
+	/* Parse @c else clause. */
+	if (lcur_lc(parse) == lc_else) {
+		lskip(parse);
+		lmatch(parse, lc_do);
+		switch_s->else_block = parse_block(parse);
+	} else {
+		switch_s->else_block = NULL;
+	}
+
+	lmatch(parse, lc_end);
+	return switch_s;
 }
 
@@ -1654,4 +1712,5 @@
 	case lc_except:
 	case lc_finally:
+	case lc_when:
 		return b_true;
 	default:
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/rdata.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,4 +49,5 @@
 #include <assert.h>
 #include "bigint.h"
+#include "list.h"
 #include "mytypes.h"
 #include "stree.h"
@@ -69,5 +70,20 @@
 static void rdata_symbol_copy(rdata_symbol_t *src, rdata_symbol_t **dest);
 
+static void rdata_var_destroy_inner(rdata_var_t *var);
+
+static void rdata_bool_destroy(rdata_bool_t *bool_v);
+static void rdata_char_destroy(rdata_char_t *char_v);
+static void rdata_int_destroy(rdata_int_t *int_v);
+static void rdata_string_destroy(rdata_string_t *string_v);
+static void rdata_ref_destroy(rdata_ref_t *ref_v);
+static void rdata_deleg_destroy(rdata_deleg_t *deleg_v);
+static void rdata_enum_destroy(rdata_enum_t *enum_v);
+static void rdata_array_destroy(rdata_array_t *array_v);
+static void rdata_object_destroy(rdata_object_t *object_v);
+static void rdata_resource_destroy(rdata_resource_t *resource_v);
+static void rdata_symbol_destroy(rdata_symbol_t *symbol_v);
+
 static int rdata_array_get_dim(rdata_array_t *array);
+static void rdata_var_copy_to(rdata_var_t *src, rdata_var_t *dest);
 
 static void rdata_address_print(rdata_address_t *address);
@@ -414,5 +430,5 @@
 /** Allocate array elements.
  *
- * Allocates var nodes for elements of @a array.
+ * Allocates element array of @a array.
  *
  * @param array		Array.
@@ -420,5 +436,5 @@
 void rdata_array_alloc_element(rdata_array_t *array)
 {
-	int dim, idx;
+	int dim;
 
 	dim = rdata_array_get_dim(array);
@@ -428,12 +444,4 @@
 		printf("Memory allocation failed.\n");
 		exit(1);
-	}
-
-	for (idx = 0; idx < dim; ++idx) {
-		array->element[idx] = calloc(1, sizeof(rdata_var_t));
-		if (array->element[idx] == NULL) {
-			printf("Memory allocation failed.\n");
-			exit(1);
-		}
 	}
 }
@@ -457,4 +465,207 @@
 }
 
+/** Deallocate item.
+ *
+ * @param item	Item node
+ */
+void rdata_item_delete(rdata_item_t *item)
+{
+	assert(item != NULL);
+	free(item);
+}
+
+/** Deallocate variable address.
+ *
+ * @param addr_var	Variable address node
+ */
+void rdata_addr_var_delete(rdata_addr_var_t *addr_var)
+{
+	assert(addr_var != NULL);
+	free(addr_var);
+}
+
+/** Deallocate property address.
+ *
+ * @param addr_prop	Variable address node
+ */
+void rdata_addr_prop_delete(rdata_addr_prop_t *addr_prop)
+{
+	assert(addr_prop != NULL);
+	free(addr_prop);
+}
+
+/** Deallocate named property address.
+ *
+ * @param aprop_named	Variable address node
+ */
+void rdata_aprop_named_delete(rdata_aprop_named_t *aprop_named)
+{
+	assert(aprop_named != NULL);
+	free(aprop_named);
+}
+
+/** Deallocate indexed property address.
+ *
+ * @param aprop_indexed	Variable address node
+ */
+void rdata_aprop_indexed_delete(rdata_aprop_indexed_t *aprop_indexed)
+{
+	assert(aprop_indexed != NULL);
+	free(aprop_indexed);
+}
+
+/** Deallocate address.
+ *
+ * @param address	Address node
+ */
+void rdata_address_delete(rdata_address_t *address)
+{
+	assert(address != NULL);
+	free(address);
+}
+
+/** Deallocate value.
+ *
+ * @param value		Value node
+ */
+void rdata_value_delete(rdata_value_t *value)
+{
+	assert(value != NULL);
+	free(value);
+}
+
+/** Deallocate var node.
+ *
+ * @param var	Var node
+ */
+void rdata_var_delete(rdata_var_t *var)
+{
+	assert(var != NULL);
+	free(var);
+}
+
+/** Deallocate boolean.
+ *
+ * @param bool_v		Boolean
+ */
+void rdata_bool_delete(rdata_bool_t *bool_v)
+{
+	assert(bool_v != NULL);
+	free(bool_v);
+}
+
+/** Deallocate character.
+ *
+ * @param char_v	Character
+ */
+void rdata_char_delete(rdata_char_t *char_v)
+{
+	assert(char_v != NULL);
+	free(char_v);
+}
+
+/** Deallocate integer.
+ *
+ * @param int_v		Integer
+ */
+void rdata_int_delete(rdata_int_t *int_v)
+{
+	assert(int_v != NULL);
+	free(int_v);
+}
+
+/** Deallocate string.
+ *
+ * @param string_v	String
+ */
+void rdata_string_delete(rdata_string_t *string_v)
+{
+	assert(string_v != NULL);
+	free(string_v);
+}
+
+/** Deallocate reference.
+ *
+ * @param ref_v		Reference
+ */
+void rdata_ref_delete(rdata_ref_t *ref_v)
+{
+	assert(ref_v != NULL);
+	free(ref_v);
+}
+
+/** Deallocate delegate.
+ *
+ * @param deleg_v		Reference
+ */
+void rdata_deleg_delete(rdata_deleg_t *deleg_v)
+{
+	assert(deleg_v != NULL);
+	free(deleg_v);
+}
+
+/** Deallocate enum.
+ *
+ * @param enum_v		Reference
+ */
+void rdata_enum_delete(rdata_enum_t *enum_v)
+{
+	assert(enum_v != NULL);
+	free(enum_v);
+}
+
+/** Deallocate array.
+ *
+ * @param array_v		Array
+ */
+void rdata_array_delete(rdata_array_t *array_v)
+{
+	assert(array_v != NULL);
+	free(array_v);
+}
+
+/** Deallocate object.
+ *
+ * @param object_v		Object
+ */
+void rdata_object_delete(rdata_object_t *object_v)
+{
+	assert(object_v != NULL);
+	free(object_v);
+}
+
+/** Deallocate resource.
+ *
+ * @param resource_v		Resource
+ */
+void rdata_resource_delete(rdata_resource_t *resource_v)
+{
+	assert(resource_v != NULL);
+	free(resource_v);
+}
+
+/** Deallocate symbol.
+ *
+ * @param symbol_v		Symbol
+ */
+void rdata_symbol_delete(rdata_symbol_t *symbol_v)
+{
+	assert(symbol_v != NULL);
+	free(symbol_v);
+}
+
+/** Copy value.
+ *
+ * @param src		Input value
+ * @param dest		Place to store pointer to new value
+ */
+void rdata_value_copy(rdata_value_t *src, rdata_value_t **dest)
+{
+	assert(src != NULL);
+
+	*dest = rdata_value_new();
+	rdata_var_copy(src->var, &(*dest)->var);
+}
+
 /** Make copy of a variable.
  *
@@ -470,48 +681,64 @@
 
 	nvar = rdata_var_new(src->vc);
+	rdata_var_copy_to(src, nvar);
+
+	*dest = nvar;
+}
+
+/** Copy variable content to another variable.
+ *
+ * Writes an exact copy of an existing var node to another var node.
+ * The varclass of @a src and @a dest must match. The content of
+ * @a dest.u must be invalid.
+ *
+ * @param src		Source var node.
+ * @param dest		Destination var node.
+ */
+static void rdata_var_copy_to(rdata_var_t *src, rdata_var_t *dest)
+{
+	dest->vc = src->vc;
 
 	switch (src->vc) {
 	case vc_bool:
-		rdata_bool_copy(src->u.bool_v, &nvar->u.bool_v);
+		rdata_bool_copy(src->u.bool_v, &dest->u.bool_v);
 		break;
 	case vc_char:
-		rdata_char_copy(src->u.char_v, &nvar->u.char_v);
+		rdata_char_copy(src->u.char_v, &dest->u.char_v);
 		break;
 	case vc_int:
-		rdata_int_copy(src->u.int_v, &nvar->u.int_v);
+		rdata_int_copy(src->u.int_v, &dest->u.int_v);
 		break;
 	case vc_string:
-		rdata_string_copy(src->u.string_v, &nvar->u.string_v);
+		rdata_string_copy(src->u.string_v, &dest->u.string_v);
 		break;
 	case vc_ref:
-		rdata_ref_copy(src->u.ref_v, &nvar->u.ref_v);
+		rdata_ref_copy(src->u.ref_v, &dest->u.ref_v);
 		break;
 	case vc_deleg:
-		rdata_deleg_copy(src->u.deleg_v, &nvar->u.deleg_v);
+		rdata_deleg_copy(src->u.deleg_v, &dest->u.deleg_v);
 		break;
 	case vc_enum:
-		rdata_enum_copy(src->u.enum_v, &nvar->u.enum_v);
+		rdata_enum_copy(src->u.enum_v, &dest->u.enum_v);
 		break;
 	case vc_array:
-		rdata_array_copy(src->u.array_v, &nvar->u.array_v);
+		rdata_array_copy(src->u.array_v, &dest->u.array_v);
 		break;
 	case vc_object:
-		rdata_object_copy(src->u.object_v, &nvar->u.object_v);
+		rdata_object_copy(src->u.object_v, &dest->u.object_v);
 		break;
 	case vc_resource:
-		rdata_resource_copy(src->u.resource_v, &nvar->u.resource_v);
+		rdata_resource_copy(src->u.resource_v, &dest->u.resource_v);
 		break;
 	case vc_symbol:
-		rdata_symbol_copy(src->u.symbol_v, &nvar->u.symbol_v);
-		break;
-	}
-
-	*dest = nvar;
-}
+		rdata_symbol_copy(src->u.symbol_v, &dest->u.symbol_v);
+		break;
+	}
+}
+
 
 /** Copy boolean.
  *
- * @param src		Source boolean.
- * @param dest		Place to store pointer to new boolean.
+ * @param src		Source boolean
+ * @param dest		Place to store pointer to new boolean
  */
 static void rdata_bool_copy(rdata_bool_t *src, rdata_bool_t **dest)
@@ -523,6 +750,6 @@
 /** Copy character.
  *
- * @param src		Source character.
- * @param dest		Place to store pointer to new character.
+ * @param src		Source character
+ * @param dest		Place to store pointer to new character
  */
 static void rdata_char_copy(rdata_char_t *src, rdata_char_t **dest)
@@ -534,6 +761,6 @@
 /** Copy integer.
  *
- * @param src		Source integer.
- * @param dest		Place to store pointer to new integer.
+ * @param src		Source integer
+ * @param dest		Place to store pointer to new integer
  */
 static void rdata_int_copy(rdata_int_t *src, rdata_int_t **dest)
@@ -632,4 +859,355 @@
 	*dest = rdata_symbol_new();
 	(*dest)->sym = src->sym;
+}
+
+/** Destroy var node.
+ *
+ * @param var	Var node
+ */
+void rdata_var_destroy(rdata_var_t *var)
+{
+	/* First destroy class-specific part */
+	rdata_var_destroy_inner(var);
+
+	/* Deallocate var node */
+	rdata_var_delete(var);
+}
+
+/** Destroy inside of var node.
+ *
+ * Destroy content of var node, but do not deallocate the var node
+ * itself.
+ *
+ * @param var	Var node
+ */
+static void rdata_var_destroy_inner(rdata_var_t *var)
+{
+	/* First destroy class-specific part */
+
+	switch (var->vc) {
+	case vc_bool:
+		rdata_bool_destroy(var->u.bool_v);
+		break;
+	case vc_char:
+		rdata_char_destroy(var->u.char_v);
+		break;
+	case vc_int:
+		rdata_int_destroy(var->u.int_v);
+		break;
+	case vc_string:
+		rdata_string_destroy(var->u.string_v);
+		break;
+	case vc_ref:
+		rdata_ref_destroy(var->u.ref_v);
+		break;
+	case vc_deleg:
+		rdata_deleg_destroy(var->u.deleg_v);
+		break;
+	case vc_enum:
+		rdata_enum_destroy(var->u.enum_v);
+		break;
+	case vc_array:
+		rdata_array_destroy(var->u.array_v);
+		break;
+	case vc_object:
+		rdata_object_destroy(var->u.object_v);
+		break;
+	case vc_resource:
+		rdata_resource_destroy(var->u.resource_v);
+		break;
+	case vc_symbol:
+		rdata_symbol_destroy(var->u.symbol_v);
+		break;
+	}
+}
+
+/** Destroy item.
+ *
+ * Destroy an item including the value or address within.
+ *
+ * @param item	Item
+ */
+void rdata_item_destroy(rdata_item_t *item)
+{
+	/* First destroy class-specific part */
+
+	switch (item->ic) {
+	case ic_address:
+		rdata_address_destroy(item->u.address);
+		break;
+	case ic_value:
+		rdata_value_destroy(item->u.value);
+		break;
+	}
+
+	/* Deallocate item node */
+	rdata_item_delete(item);
+}
+
+/** Destroy address.
+ *
+ * Destroy an address node.
+ *
+ * @param address	Address
+ */
+void rdata_address_destroy(rdata_address_t *address)
+{
+	switch (address->ac) {
+	case ac_var:
+		rdata_addr_var_destroy(address->u.var_a);
+		break;
+	case ac_prop:
+		rdata_addr_prop_destroy(address->u.prop_a);
+		break;
+	}
+
+	/* Deallocate address node */
+	rdata_address_delete(address);
+}
+
+/** Destroy variable address.
+ *
+ * Destroy a variable address node.
+ *
+ * @param addr_var	Variable address
+ */
+void rdata_addr_var_destroy(rdata_addr_var_t *addr_var)
+{
+	addr_var->vref = NULL;
+
+	/* Deallocate variable address node */
+	rdata_addr_var_delete(addr_var);
+}
+
+/** Destroy property address.
+ *
+ * Destroy a property address node.
+ *
+ * @param addr_prop	Property address
+ */
+void rdata_addr_prop_destroy(rdata_addr_prop_t *addr_prop)
+{
+	switch (addr_prop->apc) {
+	case apc_named:
+		rdata_aprop_named_destroy(addr_prop->u.named);
+		break;
+	case apc_indexed:
+		rdata_aprop_indexed_destroy(addr_prop->u.indexed);
+		break;
+	}
+
+	if (addr_prop->tvalue != NULL) {
+		rdata_value_destroy(addr_prop->tvalue);
+		addr_prop->tvalue = NULL;
+	}
+
+	addr_prop->tpos = NULL;
+
+	/* Deallocate property address node */
+	rdata_addr_prop_delete(addr_prop);
+}
+
+/** Destroy named property address.
+ *
+ * Destroy a named property address node.
+ *
+ * @param aprop_named	Named property address
+ */
+void rdata_aprop_named_destroy(rdata_aprop_named_t *aprop_named)
+{
+	rdata_deleg_destroy(aprop_named->prop_d);
+
+	/* Deallocate named property address node */
+	rdata_aprop_named_delete(aprop_named);
+}
+
+/** Destroy indexed property address.
+ *
+ * Destroy a indexed property address node.
+ *
+ * @param aprop_indexed		Indexed property address
+ */
+void rdata_aprop_indexed_destroy(rdata_aprop_indexed_t *aprop_indexed)
+{
+	list_node_t *arg_node;
+	rdata_item_t *arg_i;
+
+	/* Destroy the object delegate. */
+	rdata_deleg_destroy(aprop_indexed->object_d);
+
+	/*
+	 * Walk through all argument items (indices) and destroy them,
+	 * removing them from the list as well.
+	 */
+	while (!list_is_empty(&aprop_indexed->args)) {
+		arg_node = list_first(&aprop_indexed->args);
+		arg_i = list_node_data(arg_node, rdata_item_t *);
+
+		rdata_item_destroy(arg_i);
+		list_remove(&aprop_indexed->args, arg_node);
+	}
+
+	/* Destroy the now empty list */
+	list_fini(&aprop_indexed->args);
+
+	/* Deallocate indexed property address node */
+	rdata_aprop_indexed_delete(aprop_indexed);
+}
+
+/** Destroy value.
+ *
+ * Destroy a value node.
+ *
+ * @param value		Value
+ */
+void rdata_value_destroy(rdata_value_t *value)
+{
+	/* Assumption: Var nodes in values are not shared. */
+	rdata_var_destroy(value->var);
+
+	/* Deallocate value node */
+	rdata_value_delete(value);
+}
+
+/** Destroy boolean.
+ *
+ * @param bool_v		Boolean
+ */
+static void rdata_bool_destroy(rdata_bool_t *bool_v)
+{
+	rdata_bool_delete(bool_v);
+}
+
+/** Destroy character.
+ *
+ * @param char_v	Character
+ */
+static void rdata_char_destroy(rdata_char_t *char_v)
+{
+	bigint_destroy(&char_v->value);
+	rdata_char_delete(char_v);
+}
+
+/** Destroy integer.
+ *
+ * @param int_v		Integer
+ */
+static void rdata_int_destroy(rdata_int_t *int_v)
+{
+	bigint_destroy(&int_v->value);
+	rdata_int_delete(int_v);
+}
+
+/** Destroy string.
+ *
+ * @param string_v	String
+ */
+static void rdata_string_destroy(rdata_string_t *string_v)
+{
+	/*
+	 * String values are shared so we cannot free them. Just deallocate
+	 * the node.
+	 */
+	rdata_string_delete(string_v);
+}
+
+/** Destroy reference.
+ *
+ * @param ref_v		Reference
+ */
+static void rdata_ref_destroy(rdata_ref_t *ref_v)
+{
+	ref_v->vref = NULL;
+	rdata_ref_delete(ref_v);
+}
+
+/** Destroy delegate.
+ *
+ * @param deleg_v		Reference
+ */
+static void rdata_deleg_destroy(rdata_deleg_t *deleg_v)
+{
+	deleg_v->obj = NULL;
+	deleg_v->sym = NULL;
+	rdata_deleg_delete(deleg_v);
+}
+
+/** Destroy enum.
+ *
+ * @param enum_v		Reference
+ */
+static void rdata_enum_destroy(rdata_enum_t *enum_v)
+{
+	enum_v->value = NULL;
+	rdata_enum_delete(enum_v);
+}
+
+/** Destroy array.
+ *
+ * @param array_v		Array
+ */
+static void rdata_array_destroy(rdata_array_t *array_v)
+{
+	int d;
+	size_t n_elems, p;
+
+	/*
+	 * Compute total number of elements in array.
+	 * At the same time zero out the extent array.
+	 */
+	n_elems = 1;
+	for (d = 0; d < array_v->rank; d++) {
+		n_elems = n_elems * array_v->extent[d];
+		array_v->extent[d] = 0;
+	}
+
+	/* Destroy all elements and zero out the array */
+	for (p = 0; p < n_elems; p++) {
+		rdata_var_delete(array_v->element[p]);
+		array_v->element[p] = NULL;
+	}
+
+	/* Free the arrays */
+	free(array_v->element);
+	free(array_v->extent);
+
+	array_v->rank = 0;
+
+	/* Deallocate the node */
+	rdata_array_delete(array_v);
+}
+
+/** Destroy object.
+ *
+ * @param object_v		Object
+ */
+static void rdata_object_destroy(rdata_object_t *object_v)
+{
+	/* XXX TODO */
+	rdata_object_delete(object_v);
+}
+
+/** Destroy resource.
+ *
+ * @param resource_v		Resource
+ */
+static void rdata_resource_destroy(rdata_resource_t *resource_v)
+{
+	/*
+	 * XXX Presumably this should be handled by the appropriate
+	 * built-in module, so, some call-back function would be required.
+	 */
+	resource_v->data = NULL;
+	rdata_resource_delete(resource_v);
+}
+
+/** Destroy symbol.
+ *
+ * @param symbol_v		Symbol
+ */
+static void rdata_symbol_destroy(rdata_symbol_t *symbol_v)
+{
+	symbol_v->sym = NULL;
+	rdata_symbol_delete(symbol_v);
 }
 
@@ -671,27 +1249,9 @@
 void rdata_var_write(rdata_var_t *var, rdata_value_t *value)
 {
-	rdata_var_t *nvar;
+	/* Free old content of var->u */
+	rdata_var_destroy_inner(var);
 
 	/* Perform a shallow copy of @c value->var. */
-	rdata_var_copy(value->var, &nvar);
-
-	/* XXX do this in a prettier way. */
-
-	var->vc = nvar->vc;
-	switch (nvar->vc) {
-	case vc_bool: var->u.bool_v = nvar->u.bool_v; break;
-	case vc_char: var->u.char_v = nvar->u.char_v; break;
-	case vc_int: var->u.int_v = nvar->u.int_v; break;
-	case vc_string: var->u.string_v = nvar->u.string_v; break;
-	case vc_ref: var->u.ref_v = nvar->u.ref_v; break;
-	case vc_deleg: var->u.deleg_v = nvar->u.deleg_v; break;
-	case vc_enum: var->u.enum_v = nvar->u.enum_v; break;
-	case vc_array: var->u.array_v = nvar->u.array_v; break;
-	case vc_object: var->u.object_v = nvar->u.object_v; break;
-	case vc_resource: var->u.resource_v = nvar->u.resource_v; break;
-	case vc_symbol: var->u.symbol_v = nvar->u.symbol_v; break;
-	}
-
-	/* XXX We should free some stuff around here. */
+	rdata_var_copy_to(value->var, var);
 }
 
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/rdata.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -41,4 +41,5 @@
 
 rdata_var_t *rdata_var_new(var_class_t vc);
+void rdata_var_delete(rdata_var_t *var);
 rdata_ref_t *rdata_ref_new(void);
 rdata_deleg_t *rdata_deleg_new(void);
@@ -53,6 +54,37 @@
 rdata_symbol_t *rdata_symbol_new(void);
 
+void rdata_address_delete(rdata_address_t *address);
+void rdata_value_delete(rdata_value_t *value);
+void rdata_var_delete(rdata_var_t *var);
+void rdata_item_delete(rdata_item_t *item);
+void rdata_addr_var_delete(rdata_addr_var_t *addr_var);
+void rdata_addr_prop_delete(rdata_addr_prop_t *addr_prop);
+void rdata_aprop_named_delete(rdata_aprop_named_t *aprop_named);
+void rdata_aprop_indexed_delete(rdata_aprop_indexed_t *aprop_indexed);
+
+void rdata_bool_delete(rdata_bool_t *bool_v);
+void rdata_char_delete(rdata_char_t *char_v);
+void rdata_int_delete(rdata_int_t *int_v);
+void rdata_string_delete(rdata_string_t *string_v);
+void rdata_ref_delete(rdata_ref_t *ref_v);
+void rdata_deleg_delete(rdata_deleg_t *deleg_v);
+void rdata_enum_delete(rdata_enum_t *enum_v);
+void rdata_array_delete(rdata_array_t *array_v);
+void rdata_object_delete(rdata_object_t *object_v);
+void rdata_resource_delete(rdata_resource_t *resource_v);
+void rdata_symbol_delete(rdata_symbol_t *symbol_v);
+
 void rdata_array_alloc_element(rdata_array_t *array);
+void rdata_value_copy(rdata_value_t *val, rdata_value_t **rval);
 void rdata_var_copy(rdata_var_t *src, rdata_var_t **dest);
+
+void rdata_address_destroy(rdata_address_t *address);
+void rdata_addr_var_destroy(rdata_addr_var_t *addr_var);
+void rdata_addr_prop_destroy(rdata_addr_prop_t *addr_prop);
+void rdata_aprop_named_destroy(rdata_aprop_named_t *aprop_named);
+void rdata_aprop_indexed_destroy(rdata_aprop_indexed_t *aprop_indexed);
+void rdata_value_destroy(rdata_value_t *value);
+void rdata_var_destroy(rdata_var_t *var);
+void rdata_item_destroy(rdata_item_t *item);
 
 void rdata_var_read(rdata_var_t *var, rdata_item_t **ritem);
Index: uspace/app/sbi/src/rdata_t.h
===================================================================
--- uspace/app/sbi/src/rdata_t.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/rdata_t.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -272,6 +272,9 @@
 typedef struct rdata_value {
 	/**
-	 * Read-only Variable holding a copy of the data. The same @c var
-	 * can be shared between different instances of @c rdata_value_t.
+	 * Read-only Variable holding a copy of the data. Currently we don't
+	 * allow sharing the same @c var node between different value nodes
+	 * so that when destroying the value we can destroy the var.
+	 *
+	 * We could share this, but would need to reference-count it.
 	 */
 	rdata_var_t *var;
Index: uspace/app/sbi/src/run.c
===================================================================
--- uspace/app/sbi/src/run.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/run.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -53,4 +53,5 @@
 static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
 static void run_if(run_t *run, stree_if_t *if_s);
+static void run_switch(run_t *run, stree_switch_t *switch_s);
 static void run_while(run_t *run, stree_while_t *while_s);
 static void run_raise(run_t *run, stree_raise_t *raise_s);
@@ -142,4 +143,5 @@
 	run_proc_ar_set_args(run, proc_ar, &main_args);
 	run_proc(run, proc_ar, &res);
+	run_proc_ar_destroy(run, proc_ar);
 
 	run_exc_check_unhandled(run);
@@ -272,4 +274,7 @@
 	assert(list_node_data(node, run_block_ar_t *) == block_ar);
 	list_remove(&proc_ar->block_ar, node);
+
+	/* Deallocate block activation record. */
+	run_block_ar_destroy(run, block_ar);
 }
 
@@ -303,4 +308,7 @@
 		run_if(run, stat->u.if_s);
 		break;
+	case st_switch:
+		run_switch(run, stat->u.switch_s);
+		break;
 	case st_while:
 		run_while(run, stat->u.while_s);
@@ -342,4 +350,9 @@
 	run_expr(run, exps->expr, &rexpr);
 
+	/*
+	 * If the expression has a value, the caller should have asked for it.
+	 */
+	assert(res != NULL || rexpr == NULL);
+
 	if (res != NULL)
 		*res = rexpr;
@@ -355,15 +368,10 @@
 	run_block_ar_t *block_ar;
 	rdata_var_t *var, *old_var;
-	tdata_item_t *var_ti;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Executing variable declaration statement.\n");
 #endif
-	/* Compute variable type. XXX Memoize. */
-	run_texpr(run->program, run_get_current_csi(run), vdecl->type,
-	    &var_ti);
-
 	/* Create variable and initialize with default value. */
-	run_var_new(run, var_ti, &var);
+	run_var_new(run, vdecl->titem, &var);
 
 	block_ar = run_get_current_block_ar(run);
@@ -393,5 +401,5 @@
 	list_node_t *ifc_node;
 	stree_if_clause_t *ifc;
-	bool_t clause_fired;
+	bool_t rcond_b, clause_fired;
 
 #ifdef DEBUG_RUN_TRACE
@@ -411,5 +419,8 @@
 			return;
 
-		if (run_item_boolean_value(run, rcond) == b_true) {
+		rcond_b = run_item_boolean_value(run, rcond);
+		rdata_item_destroy(rcond);
+
+		if (rcond_b == b_true) {
 #ifdef DEBUG_RUN_TRACE
 			printf("Taking non-default path.\n");
@@ -436,4 +447,106 @@
 }
 
+/** Run @c switch statement.
+ *
+ * @param run		Runner object
+ * @param switch_s	Switch statement to run
+ */
+static void run_switch(run_t *run, stree_switch_t *switch_s)
+{
+	rdata_item_t *rsexpr, *rsexpr_vi;
+	rdata_item_t *rwexpr, *rwexpr_vi;
+	list_node_t *whenc_node;
+	stree_when_t *whenc;
+	list_node_t *expr_node;
+	stree_expr_t *expr;
+	bool_t clause_fired;
+	bool_t equal;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing switch statement.\n");
+#endif
+	rsexpr_vi = NULL;
+
+	/* Evaluate switch expression */
+	run_expr(run, switch_s->expr, &rsexpr);
+	if (run_is_bo(run))
+		goto cleanup;
+
+	/* Convert to value item */
+	run_cvt_value_item(run, rsexpr, &rsexpr_vi);
+	rdata_item_destroy(rsexpr);
+	if (run_is_bo(run))
+		goto cleanup;
+
+	clause_fired = b_false;
+	whenc_node = list_first(&switch_s->when_clauses);
+
+	/* Walk through all when clauses and see if they fire. */
+
+	while (whenc_node != NULL) {
+		/* Get when clause */
+		whenc = list_node_data(whenc_node, stree_when_t *);
+
+		expr_node = list_first(&whenc->exprs);
+
+		/* Walk through all expressions in the when clause */
+		while (expr_node != NULL) {
+			/* Get expression */
+			expr = list_node_data(expr_node, stree_expr_t *);
+
+			/* Evaluate expression */
+			run_expr(run, expr, &rwexpr);
+			if (run_is_bo(run))
+				goto cleanup;
+
+			/* Convert to value item */
+			run_cvt_value_item(run, rwexpr, &rwexpr_vi);
+			rdata_item_destroy(rwexpr);
+			if (run_is_bo(run)) {
+				rdata_item_destroy(rwexpr_vi);
+				goto cleanup;
+			}
+
+			/* Check if values are equal ('==') */
+			run_equal(run, rsexpr_vi->u.value,
+			    rwexpr_vi->u.value, &equal);
+			rdata_item_destroy(rwexpr_vi);
+			if (run_is_bo(run))
+				goto cleanup;
+
+			if (equal) {
+#ifdef DEBUG_RUN_TRACE
+				printf("Taking non-default path.\n");
+#endif
+				run_block(run, whenc->block);
+				clause_fired = b_true;
+				break;
+			}
+
+			expr_node = list_next(&whenc->exprs, expr_node);
+		}
+
+		if (clause_fired)
+			break;
+
+		whenc_node = list_next(&switch_s->when_clauses, whenc_node);
+	}
+
+	/* If no when clause fired, invoke the else clause. */
+	if (clause_fired == b_false && switch_s->else_block != NULL) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Taking default path.\n");
+#endif
+		run_block(run, switch_s->else_block);
+	}
+cleanup:
+	if (rsexpr_vi != NULL)
+		rdata_item_destroy(rsexpr_vi);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Switch statement terminated.\n");
+#endif
+}
+
 /** Run @c while statement.
  *
@@ -453,4 +566,5 @@
 
 	while (run_item_boolean_value(run, rcond) == b_true) {
+		rdata_item_destroy(rcond);
 		run_block(run, while_s->body);
 		run_expr(run, while_s->cond, &rcond);
@@ -459,4 +573,7 @@
 	}
 
+	if (rcond != NULL)
+		rdata_item_destroy(rcond);
+
 	if (run->thread_ar->bo_mode == bm_stat) {
 		/* Bailout due to break statement */
@@ -487,4 +604,7 @@
 
 	run_cvt_value_item(run, rexpr, &rexpr_vi);
+	rdata_item_destroy(rexpr);
+	if (run_is_bo(run))
+		return;
 
 	/* Store expression cspan in thread AR. */
@@ -492,4 +612,5 @@
 
 	/* Store expression result in thread AR. */
+	/* XXX rexpr_vi is leaked here, we only return ->u.value */
 	run->thread_ar->exc_payload = rexpr_vi->u.value;
 
@@ -541,4 +662,7 @@
 
 		run_cvt_value_item(run, rexpr, &rexpr_vi);
+		rdata_item_destroy(rexpr);
+		if (run_is_bo(run))
+			return;
 
 		/* Store expression result in procedure AR. */
@@ -632,16 +756,11 @@
 {
 	stree_csi_t *exc_csi;
-	tdata_item_t *etype;
 
 	/* Get CSI of active exception. */
 	exc_csi = run_exc_payload_get_csi(run);
 
-	/* Evaluate type expression in except clause. */
-	run_texpr(run->program, run_get_current_csi(run), except_c->etype,
-	    &etype);
-
 	/* Determine if active exc. is derived from type in exc. clause. */
 	/* XXX This is wrong, it does not work with generics. */
-	return tdata_is_csi_derived_from_ti(exc_csi, etype);
+	return tdata_is_csi_derived_from_ti(exc_csi, except_c->titem);
 }
 
@@ -1009,5 +1128,5 @@
 	(void) run;
 
-	/* Create function activation record. */
+	/* Create procedure activation record. */
 	proc_ar = run_proc_ar_new();
 	proc_ar->obj = obj;
@@ -1024,4 +1143,31 @@
 	*rproc_ar = proc_ar;
 }
+
+/** Destroy a procedure AR.
+ *
+ * @param run		Runner object
+ * @param proc_ar	Pointer to procedure activation record
+ */
+void run_proc_ar_destroy(run_t *run, run_proc_ar_t *proc_ar)
+{
+	list_node_t *ar_node;
+	run_block_ar_t *block_ar;
+
+	(void) run;
+
+	/* Destroy special block activation record. */
+	ar_node = list_first(&proc_ar->block_ar);
+	block_ar = list_node_data(ar_node, run_block_ar_t *);
+	list_remove(&proc_ar->block_ar, ar_node);
+	run_block_ar_destroy(run, block_ar);
+
+	/* Destroy procedure activation record. */
+	proc_ar->obj = NULL;
+	proc_ar->proc = NULL;
+	list_fini(&proc_ar->block_ar);
+	proc_ar->retval = NULL;
+	run_proc_ar_delete(proc_ar);
+}
+
 
 /** Fill arguments in a procedure AR.
@@ -1055,4 +1201,5 @@
 	rdata_ref_t *ref;
 	rdata_array_t *array;
+	rdata_var_t *elem_var;
 	int n_vargs, idx;
 
@@ -1147,5 +1294,6 @@
 			assert(rarg->ic == ic_value);
 
-			rdata_var_write(array->element[idx], rarg->u.value);
+			run_value_item_to_var(rarg, &elem_var);
+			array->element[idx] = elem_var;
 
 			rarg_n = list_next(arg_vals, rarg_n);
@@ -1241,4 +1389,34 @@
 }
 
+/** Destroy a block AR.
+ *
+ * @param run		Runner object
+ * @param proc_ar	Pointer to block activation record
+ */
+void run_block_ar_destroy(run_t *run, run_block_ar_t *block_ar)
+{
+	map_elem_t *elem;
+	rdata_var_t *var;
+	int key;
+
+	(void) run;
+
+	elem = intmap_first(&block_ar->vars);
+	while (elem != NULL) {
+		/* Destroy the variable */
+		var = intmap_elem_get_value(elem);
+		rdata_var_destroy(var);
+
+		/* Remove the map element */
+		key = intmap_elem_get_key(elem);
+		intmap_set(&block_ar->vars, key, NULL);
+
+		elem = intmap_first(&block_ar->vars);
+	}
+
+	intmap_fini(&block_ar->vars);
+	run_block_ar_delete(block_ar);
+}
+
 /** Convert item to value item.
  *
@@ -1269,7 +1447,7 @@
 	}
 
-	/* It already is a value, we can share the @c var. */
+	/* Make a copy of the var node within. */
 	value = rdata_value_new();
-	value->var = item->u.value->var;
+	rdata_var_copy(item->u.value->var, &value->var);
 	*ritem = rdata_item_new(ic_value);
 	(*ritem)->u.value = value;
@@ -1358,4 +1536,5 @@
 {
 	(void) run;
+	assert(ritem != NULL);
 
 	switch (address->ac) {
@@ -1368,5 +1547,5 @@
 	}
 
-	assert((*ritem)->ic == ic_value);
+	assert(*ritem == NULL || (*ritem)->ic == ic_value);
 }
 
@@ -1457,4 +1636,7 @@
 	run_proc(run, proc_ar, ritem);
 
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Getter returns ");
@@ -1529,4 +1711,7 @@
 	/* Setter should not return a value. */
 	assert(ritem == NULL);
+
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
 
 #ifdef DEBUG_RUN_TRACE
@@ -1590,4 +1775,9 @@
 #endif
 	run_cvt_value_item(run, ref, &ref_val);
+	if (run_is_bo(run)) {
+		*ritem = run_recovery_item(run);
+		return;
+	}
+
 	assert(ref_val->u.value->var->vc == vc_ref);
 
@@ -1598,4 +1788,6 @@
 	address->u.var_a = addr_var;
 	addr_var->vref = ref_val->u.value->var->u.ref_v->vref;
+
+	rdata_item_destroy(ref_val);
 
 	if (addr_var->vref == NULL) {
@@ -1840,7 +2032,6 @@
 }
 
-/** Construct a new procedure activation record.
- *
- * @param run	Runner object
+/** Allocate a new procedure activation record.
+ *
  * @return	New procedure AR.
  */
@@ -1858,5 +2049,15 @@
 }
 
-/** Construct a new block activation record.
+/** Deallocate a procedure activation record.
+ *
+ * @return	New procedure AR.
+ */
+void run_proc_ar_delete(run_proc_ar_t *proc_ar)
+{
+	assert(proc_ar != NULL);
+	free(proc_ar);
+}
+
+/** Allocate a new block activation record.
  *
  * @param run	Runner object
@@ -1875,2 +2076,13 @@
 	return block_ar;
 }
+
+/** Deallocate a new block activation record.
+ *
+ * @param run	Runner object
+ * @return	New block AR.
+ */
+void run_block_ar_delete(run_block_ar_t *block_ar)
+{
+	assert(block_ar != NULL);
+	free(block_ar);
+}
Index: uspace/app/sbi/src/run.h
===================================================================
--- uspace/app/sbi/src/run.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/run.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -61,4 +61,5 @@
 void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
     run_proc_ar_t **rproc_ar);
+void run_proc_ar_destroy(run_t *run, run_proc_ar_t *proc_ar);
 
 var_class_t run_item_get_vc(run_t *run, rdata_item_t *item);
@@ -79,5 +80,10 @@
 run_thread_ar_t *run_thread_ar_new(void);
 run_proc_ar_t *run_proc_ar_new(void);
+void run_proc_ar_delete(run_proc_ar_t *proc_ar);
 run_block_ar_t *run_block_ar_new(void);
+void run_block_ar_delete(run_block_ar_t *block_ar);
+void run_proc_ar_delete(run_proc_ar_t *proc_ar);
+void run_block_ar_destroy(run_t *run, run_block_ar_t *block_ar);
+
 
 #endif
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/run_expr.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -113,4 +113,5 @@
 static void run_call(run_t *run, stree_call_t *call, rdata_item_t **res);
 static void run_call_args(run_t *run, list_t *args, list_t *arg_vals);
+static void run_destroy_arg_vals(list_t *arg_vals);
 
 static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res);
@@ -200,4 +201,7 @@
 	rdata_address_t *address;
 	rdata_addr_var_t *addr_var;
+	rdata_addr_prop_t *addr_prop;
+	rdata_aprop_named_t *aprop_named;
+	rdata_deleg_t *deleg_p;
 	rdata_value_t *value;
 	rdata_var_t *var;
@@ -334,13 +338,17 @@
 		break;
 	case sc_var:
-#ifdef DEBUG_RUN_TRACE
-		printf("Referencing member variable.\n");
-#endif
-		/* There should be no global variables. */
+	case sc_prop:
+#ifdef DEBUG_RUN_TRACE
+		if (sym->sc == sc_var)
+			printf("Referencing member variable.\n");
+		else
+			printf("Referencing unqualified property.\n");
+#endif
+		/* There should be no global variables or properties. */
 		assert(csi != NULL);
 
 		if (symbol_search_csi(run->program, csi, nameref->name)
 		    == NULL && !stree_symbol_is_static(sym)) {
-			/* Variable is not in the current object. */
+			/* Symbol is not in the current object. */
 			printf("Error: Cannot access non-static member "
 			    "variable '");
@@ -352,6 +360,10 @@
 		}
 
+		/*
+		 * Determine object in which the symbol resides
+		 */
 		if (stree_symbol_is_static(sym)) {
 			/*
+			 * Class object
 			 * XXX This is too slow!
 			 *
@@ -365,26 +377,46 @@
 			aobj = sobj->u.object_v;
 		} else {
-			aobj = obj;
+			/*
+			 * Instance object. Currently we don't support
+			 * true inner classes, thus we know the symbol is
+			 * in the active object (there is no dynamic parent).
+			 */
+			sobj = proc_ar->obj;
+			aobj = sobj->u.object_v;;
 		}
 
-		/* Find member variable in object. */
-		member_var = intmap_get(&aobj->fields, nameref->name->sid);
-		assert(member_var != NULL);
-
-		/* Return address of the variable. */
-		item = rdata_item_new(ic_address);
-		address = rdata_address_new(ac_var);
-		addr_var = rdata_addr_var_new();
-
-		item->u.address = address;
-		address->u.var_a = addr_var;
-		addr_var->vref = member_var;
-
-		*res = item;
-		break;
-	case sc_prop:
-		/* XXX TODO */
-		printf("Unimplemented: Property name reference.\n");
-		abort();
+		if (sym->sc == sc_var) {
+			/* Find member variable in object. */
+			member_var = intmap_get(&aobj->fields,
+			    nameref->name->sid);
+			assert(member_var != NULL);
+
+			/* Return address of the variable. */
+			item = rdata_item_new(ic_address);
+			address = rdata_address_new(ac_var);
+			addr_var = rdata_addr_var_new();
+
+			item->u.address = address;
+			address->u.var_a = addr_var;
+			addr_var->vref = member_var;
+
+			*res = item;
+		} else {
+			/* Construct named property address. */
+			item = rdata_item_new(ic_address);
+			address = rdata_address_new(ac_prop);
+			addr_prop = rdata_addr_prop_new(apc_named);
+			aprop_named = rdata_aprop_named_new();
+			item->u.address = address;
+			address->u.prop_a = addr_prop;
+			addr_prop->u.named = aprop_named;
+
+			deleg_p = rdata_deleg_new();
+			deleg_p->obj = sobj;
+			deleg_p->sym = sym;
+			addr_prop->u.named->prop_d = deleg_p;
+
+			*res = item;
+		}
 		break;
 	}
@@ -611,4 +643,9 @@
 	rdata_value_t *v1, *v2;
 
+	rarg1_i = NULL;
+	rarg2_i = NULL;
+	rarg1_vi = NULL;
+	rarg2_vi = NULL;
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Run binary operation.\n");
@@ -616,20 +653,31 @@
 	run_expr(run, binop->arg1, &rarg1_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Check binop argument result.\n");
+#endif
+	run_cvt_value_item(run, rarg1_i, &rarg1_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
 	run_expr(run, binop->arg2, &rarg2_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
-	}
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Check binop argument results.\n");
-#endif
-
-	run_cvt_value_item(run, rarg1_i, &rarg1_vi);
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Check binop argument result.\n");
+#endif
 	run_cvt_value_item(run, rarg2_i, &rarg2_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
 
 	v1 = rarg1_vi->u.value;
@@ -668,4 +716,14 @@
 		assert(b_false);
 	}
+
+cleanup:
+	if (rarg1_i != NULL)
+		rdata_item_destroy(rarg1_i);
+	if (rarg2_i != NULL)
+		rdata_item_destroy(rarg2_i);
+	if (rarg1_vi != NULL)
+		rdata_item_destroy(rarg1_vi);
+	if (rarg2_vi != NULL)
+		rdata_item_destroy(rarg2_vi);
 }
 
@@ -1054,5 +1112,5 @@
 	rdata_bool_t *bool_v;
 
-	rdata_var_t *ref1, *ref2;
+	stree_embr_t *e1, *e2;
 
 	(void) run;
@@ -1067,13 +1125,13 @@
 	var->u.bool_v = bool_v;
 
-	ref1 = v1->var->u.ref_v->vref;
-	ref2 = v2->var->u.ref_v->vref;
+	e1 = v1->var->u.enum_v->value;
+	e2 = v2->var->u.enum_v->value;
 
 	switch (binop->bc) {
 	case bo_equal:
-		bool_v->value = (ref1 == ref2);
+		bool_v->value = (e1 == e2);
 		break;
 	case bo_notequal:
-		bool_v->value = (ref1 != ref2);
+		bool_v->value = (e1 != e2);
 		break;
 	default:
@@ -1100,8 +1158,11 @@
 	printf("Run unary operation.\n");
 #endif
+	rarg_i = NULL;
+	rarg_vi = NULL;
+
 	run_expr(run, unop->arg, &rarg_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
@@ -1110,4 +1171,8 @@
 #endif
 	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
 
 	val = rarg_vi->u.value;
@@ -1124,7 +1189,12 @@
 		    "type %d.\n", val->var->vc);
 		run_raise_error(run);
-		*res = NULL;
-		break;
-	}
+		*res = run_recovery_item(run);
+		break;
+	}
+cleanup:
+	if (rarg_i != NULL)
+		rdata_item_destroy(rarg_i);
+	if (rarg_vi != NULL)
+		rdata_item_destroy(rarg_vi);
 }
 
@@ -1208,4 +1278,77 @@
 	*res = item;
 }
+
+/** Run equality comparison of two values
+ *
+ * This should be equivalent to equality ('==') binary operation.
+ * XXX Duplicating code of run_binop_xxx().
+ *
+ * @param run		Runner object
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result (plain boolean value)
+ */
+void run_equal(run_t *run, rdata_value_t *v1, rdata_value_t *v2, bool_t *res)
+{
+	bool_t b1, b2;
+	bigint_t *c1, *c2;
+	bigint_t *i1, *i2;
+	bigint_t diff;
+	const char *s1, *s2;
+	rdata_var_t *ref1, *ref2;
+	stree_embr_t *e1, *e2;
+
+	(void) run;
+	assert(v1->var->vc == v2->var->vc);
+
+	switch (v1->var->vc) {
+	case vc_bool:
+		b1 = v1->var->u.bool_v->value;
+		b2 = v2->var->u.bool_v->value;
+
+		*res = (b1 == b2);
+		break;
+	case vc_char:
+		c1 = &v1->var->u.char_v->value;
+		c2 = &v2->var->u.char_v->value;
+
+    		bigint_sub(c1, c2, &diff);
+		*res = bigint_is_zero(&diff);
+		break;
+	case vc_int:
+		i1 = &v1->var->u.int_v->value;
+		i2 = &v2->var->u.int_v->value;
+
+		bigint_sub(i1, i2, &diff);
+		*res = bigint_is_zero(&diff);
+		break;
+	case vc_string:
+		s1 = v1->var->u.string_v->value;
+		s2 = v2->var->u.string_v->value;
+
+		*res = os_str_cmp(s1, s2) == 0;
+		break;
+	case vc_ref:
+		ref1 = v1->var->u.ref_v->vref;
+		ref2 = v2->var->u.ref_v->vref;
+
+		*res = (ref1 == ref2);
+		break;
+	case vc_enum:
+		e1 = v1->var->u.enum_v->value;
+		e2 = v2->var->u.enum_v->value;
+
+		*res = (e1 == e2);
+		break;
+
+	case vc_deleg:
+	case vc_array:
+	case vc_object:
+	case vc_resource:
+	case vc_symbol:
+		assert(b_false);
+	}
+}
+
 
 /** Evaluate @c new operation.
@@ -1297,9 +1440,14 @@
 		run_expr(run, expr, &rexpr);
 		if (run_is_bo(run)) {
-			*res = NULL;
+			*res = run_recovery_item(run);
 			return;
 		}
 
 		run_cvt_value_item(run, rexpr, &rexpr_vi);
+		if (run_is_bo(run)) {
+			*res = run_recovery_item(run);
+			return;
+		}
+
 		assert(rexpr_vi->ic == ic_value);
 		rexpr_var = rexpr_vi->u.value->var;
@@ -1375,5 +1523,5 @@
 	run_call_args(run, &new_op->ctor_args, &arg_vals);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
@@ -1387,4 +1535,8 @@
 	assert(obj_i->u.address->ac == ac_var);
 	run_object_ctor(run, obj_i->u.address->u.var_a->vref, &arg_vals);
+	rdata_item_destroy(obj_i);
+
+	/* Destroy argument values */
+	run_destroy_arg_vals(&arg_vals);
 }
 
@@ -1404,8 +1556,10 @@
 	printf("Run access operation.\n");
 #endif
+	rarg = NULL;
+
 	run_expr(run, access->arg, &rarg);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
     	}
 
@@ -1416,4 +1570,7 @@
 
 	run_access_item(run, access, rarg, res);
+cleanup:
+	if (rarg != NULL)
+		rdata_item_destroy(rarg);
 }
 
@@ -1484,4 +1641,7 @@
 	/* Try again. */
 	run_access_item(run, access, darg, res);
+
+	/* Destroy temporary */
+	rdata_item_destroy(darg);
 }
 
@@ -1790,4 +1950,9 @@
 #endif
 	run_cvt_value_item(run, arg, &arg_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	arg_val = arg_vi->u.value;
 	assert(arg_val->var->vc == vc_symbol);
@@ -1800,4 +1965,6 @@
 	embr = stree_enum_find_mbr(symbol_v->sym->u.enum_d,
 	    access->member_name);
+
+	rdata_item_destroy(arg_vi);
 
 	/* Member existence should be ensured by static type checking. */
@@ -1841,16 +2008,19 @@
 	printf("Run call operation.\n");
 #endif
+	rdeleg = NULL;
+	rdeleg_vi = NULL;
+
 	run_expr(run, call->fun, &rdeleg);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
-	}
-
-	if (run->thread_ar->bo_mode != bm_none) {
 		*res = run_recovery_item(run);
-		return;
+		goto cleanup;
 	}
 
 	run_cvt_value_item(run, rdeleg, &rdeleg_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
 	assert(rdeleg_vi->ic == ic_value);
 
@@ -1877,6 +2047,6 @@
 	run_call_args(run, &call->args, &arg_vals);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
@@ -1889,4 +2059,7 @@
 	/* Fill in argument values. */
 	run_proc_ar_set_args(run, proc_ar, &arg_vals);
+
+	/* Destroy arg_vals, they are no longer needed. */
+	run_destroy_arg_vals(&arg_vals);
 
 	/* Run the function. */
@@ -1900,4 +2073,13 @@
 	}
 
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
+
+cleanup:
+	if (rdeleg != NULL)
+		rdata_item_destroy(rdeleg);
+	if (rdeleg_vi != NULL)
+		rdata_item_destroy(rdeleg_vi);
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Returned from function call.\n");
@@ -1928,11 +2110,51 @@
 		run_expr(run, arg, &rarg_i);
 		if (run_is_bo(run))
-			return;
+			goto error;
 
 		run_cvt_value_item(run, rarg_i, &rarg_vi);
+		rdata_item_destroy(rarg_i);
+		if (run_is_bo(run))
+			goto error;
 
 		list_append(arg_vals, rarg_vi);
 		arg_n = list_next(args, arg_n);
 	}
+	return;
+
+error:
+	/*
+	 * An exception or error occured while evaluating one of the
+	 * arguments. Destroy already obtained argument values and
+	 * dismantle the list.
+	 */
+	run_destroy_arg_vals(arg_vals);
+}
+
+/** Destroy list of evaluated arguments.
+ *
+ * Provided a list of evaluated arguments, destroy them, removing them
+ * from the list and fini the list itself.
+ *
+ * @param arg_vals	List of evaluated arguments (value items,
+ *			rdata_item_t).
+ */
+static void run_destroy_arg_vals(list_t *arg_vals)
+{
+	list_node_t *val_n;
+	rdata_item_t *val_i;
+
+	/*
+	 * An exception or error occured while evaluating one of the
+	 * arguments. Destroy already obtained argument values and
+	 * dismantle the list.
+	 */
+	while (!list_is_empty(arg_vals)) {
+		val_n = list_first(arg_vals);
+		val_i = list_node_data(val_n, rdata_item_t *);
+
+		rdata_item_destroy(val_i);
+		list_remove(arg_vals, val_n);
+	}
+	list_fini(arg_vals);
 }
 
@@ -1954,4 +2176,6 @@
 	var_class_t vc;
 	list_t arg_vals;
+	list_node_t *val_n;
+	rdata_item_t *val_i;
 
 #ifdef DEBUG_RUN_TRACE
@@ -1960,5 +2184,5 @@
 	run_expr(run, index->base, &rbase);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
@@ -1969,6 +2193,7 @@
 	if (vc == vc_ref) {
 		run_dereference(run, rbase, index->base->cspan, &base_i);
+		rdata_item_destroy(rbase);
 		if (run_is_bo(run)) {
-			*res = NULL;
+			*res = run_recovery_item(run);
 			return;
 		}
@@ -1987,9 +2212,14 @@
 		run_expr(run, arg, &rarg_i);
 		if (run_is_bo(run)) {
-			*res = NULL;
-			return;
+			*res = run_recovery_item(run);
+			goto cleanup;
 		}
 
 		run_cvt_value_item(run, rarg_i, &rarg_vi);
+		rdata_item_destroy(rarg_i);
+		if (run_is_bo(run)) {
+			*res = run_recovery_item(run);
+			goto cleanup;
+		}
 
 		list_append(&arg_vals, rarg_vi);
@@ -2012,4 +2242,22 @@
 		exit(1);
 	}
+
+	/* Destroy the indexing base temporary */
+	rdata_item_destroy(base_i);
+cleanup:
+	/*
+	 * An exception or error occured while evaluating one of the
+	 * arguments. Destroy already obtained argument values and
+	 * dismantle the list.
+	 */
+	while (!list_is_empty(&arg_vals)) {
+		val_n = list_first(&arg_vals);
+		val_i = list_node_data(val_n, rdata_item_t *);
+
+		rdata_item_destroy(val_i);
+		list_remove(&arg_vals, val_n);
+	}
+
+	list_fini(&arg_vals);
 }
 
@@ -2136,5 +2384,5 @@
 
 	list_node_t *node;
-	rdata_item_t *arg;
+	rdata_item_t *arg, *arg_copy;
 
 #ifdef DEBUG_RUN_TRACE
@@ -2186,5 +2434,14 @@
 	while (node != NULL) {
 		arg = list_node_data(node, rdata_item_t *);
-		list_append(&aprop_indexed->args, arg);
+
+		/*
+		 * Clone argument so that original can
+		 * be freed.
+		 */
+		assert(arg->ic == ic_value);
+		arg_copy = rdata_item_new(ic_value);
+		rdata_value_copy(arg->u.value, &arg_copy->u.value);
+
+		list_append(&aprop_indexed->args, arg_copy);
 		node = list_next(args, node);
 	}
@@ -2225,4 +2482,9 @@
 
 	run_cvt_value_item(run, base, &base_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	assert(base_vi->u.value->var->vc == vc_string);
 	string = base_vi->u.value->var->u.string_v;
@@ -2277,5 +2539,5 @@
 		    index->expr->cspan);
 		*res = run_recovery_item(run);
-		return;
+		goto cleanup;
 	}
 
@@ -2291,4 +2553,6 @@
 
 	*res = ritem;
+cleanup:
+	rdata_item_destroy(base_vi);
 }
 
@@ -2310,17 +2574,26 @@
 	printf("Run assign operation.\n");
 #endif
+	rdest_i = NULL;
+	rsrc_i = NULL;
+	rsrc_vi = NULL;
+
 	run_expr(run, assign->dest, &rdest_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
 	run_expr(run, assign->src, &rsrc_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
 	run_cvt_value_item(run, rsrc_i, &rsrc_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
 	assert(rsrc_vi->ic == ic_value);
 
@@ -2334,4 +2607,11 @@
 
 	*res = NULL;
+cleanup:
+	if (rdest_i != NULL)
+		rdata_item_destroy(rdest_i);
+	if (rsrc_i != NULL)
+		rdata_item_destroy(rsrc_i);
+	if (rsrc_vi != NULL)
+		rdata_item_destroy(rsrc_vi);
 }
 
@@ -2359,5 +2639,5 @@
 	run_expr(run, as_op->arg, &rarg_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
@@ -2369,4 +2649,11 @@
 	assert(run_item_get_vc(run, rarg_i) == vc_ref);
 	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	rdata_item_destroy(rarg_i);
+
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	assert(rarg_vi->ic == ic_value);
 
@@ -2405,4 +2692,7 @@
 	}
 
+	/* The dereferenced item is not used anymore. */
+	rdata_item_destroy(rarg_di);
+
 	*res = rarg_vi;
 }
@@ -2435,9 +2725,15 @@
 	run_expr(run, box->arg, &rarg_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
 
 	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	rdata_item_destroy(rarg_i);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	assert(rarg_vi->ic == ic_value);
 
@@ -2482,4 +2778,5 @@
 
 	rdata_var_write(mbr_var, rarg_vi->u.value);
+	rdata_item_destroy(rarg_vi);
 }
 
@@ -2657,4 +2954,7 @@
 	assert(res == NULL);
 
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Returned from constructor..\n");
@@ -2675,7 +2975,10 @@
 	rdata_item_t *vitem;
 	rdata_var_t *var;
+	bool_t res;
 
 	(void) run;
 	run_cvt_value_item(run, item, &vitem);
+	if (run_is_bo(run))
+		return b_true;
 
 	assert(vitem->ic == ic_value);
@@ -2683,4 +2986,8 @@
 
 	assert(var->vc == vc_bool);
-	return var->u.bool_v->value;
-}
+	res = var->u.bool_v->value;
+
+	/* Free value item */
+	rdata_item_destroy(vitem);
+	return res;
+}
Index: uspace/app/sbi/src/run_expr.h
===================================================================
--- uspace/app/sbi/src/run_expr.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/run_expr.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +39,5 @@
     rdata_var_t **res);
 
+void run_equal(run_t *run, rdata_value_t *v1, rdata_value_t *v2, bool_t *res);
 bool_t run_item_boolean_value(run_t *run, rdata_item_t *item);
 
Index: uspace/app/sbi/src/stree.c
===================================================================
--- uspace/app/sbi/src/stree.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/stree.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -397,4 +397,21 @@
 }
 
+/** Allocate new @c switch statement.
+ *
+ * @return	New @c if statement
+ */
+stree_switch_t *stree_switch_new(void)
+{
+	stree_switch_t *switch_s;
+
+	switch_s = calloc(1, sizeof(stree_switch_t));
+	if (switch_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return switch_s;
+}
+
 /** Allocate new @c while statement.
  *
@@ -548,4 +565,21 @@
 
 	return if_clause;
+}
+
+/** Allocate new @c when clause.
+ *
+ * @return	New @c when clause
+ */
+stree_when_t *stree_when_new(void)
+{
+	stree_when_t *when_c;
+
+	when_c = calloc(1, sizeof(stree_when_t));
+	if (when_c == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return when_c;
 }
 
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/stree.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -55,4 +55,5 @@
 stree_vdecl_t *stree_vdecl_new(void);
 stree_if_t *stree_if_new(void);
+stree_switch_t *stree_switch_new(void);
 stree_while_t *stree_while_new(void);
 stree_for_t *stree_for_new(void);
@@ -65,4 +66,5 @@
 stree_except_t *stree_except_new(void);
 stree_if_clause_t *stree_if_clause_new(void);
+stree_when_t *stree_when_new(void);
 stree_block_t *stree_block_new(void);
 
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/stree_t.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -364,5 +364,5 @@
 } texpr_class_t;
 
-/** Arithmetic expression */
+/** Type expression */
 typedef struct stree_texpr {
 	texpr_class_t tc;
@@ -394,4 +394,7 @@
 	stree_ident_t *name;
 	stree_texpr_t *type;
+
+	/** Type of this variable or @c NULL if not typed yet */
+	struct tdata_item *titem;
 } stree_vdecl_t;
 
@@ -401,4 +404,7 @@
 	stree_texpr_t *etype;
 	stree_block_t *block;
+
+	/** Evaluated etype or @c NULL if not typed yet */
+	struct tdata_item *titem;
 } stree_except_t;
 
@@ -418,4 +424,23 @@
 } stree_if_t;
 
+/** @c when clause */
+typedef struct {
+	/** List of expressions -- cases -- for this clause */
+	list_t exprs; /* of stree_expr_t */
+	stree_block_t *block;
+} stree_when_t;
+
+/** Switch statement */
+typedef struct {
+	/** Switch expression */
+	stree_expr_t *expr;
+
+	/** When clauses */
+	list_t when_clauses; /* of stree_when_t */
+
+	/** Else block */
+	stree_block_t *else_block;
+} stree_switch_t;
+
 /** While statement */
 typedef struct {
@@ -448,5 +473,5 @@
 } stree_exps_t;
 
-/** With-try-except-finally statement (WEF) */
+/** With-try-except-finally (WEF) statement */
 typedef struct {
 	stree_block_t *with_block;
@@ -459,4 +484,5 @@
 	st_vdecl,
 	st_if,
+	st_switch,
 	st_while,
 	st_for,
@@ -475,4 +501,5 @@
 		stree_vdecl_t *vdecl_s;
 		stree_if_t *if_s;
+		stree_switch_t *switch_s;
 		stree_while_t *while_s;
 		stree_for_t *for_s;
@@ -510,5 +537,5 @@
 /** Function signature.
  *
- * Foormal parameters and return type. This is common to function and delegate
+ * Formal parameters and return type. This is common to function and delegate
  * delcarations.
  */
@@ -788,11 +815,8 @@
 	} u;
 
-	/** Containing CSI (for all symbols) */
+	/** Containing CSI */
 	stree_csi_t *outer_csi;
 
-	/** Containing block (for block-level symbols) */
-	stree_block_t *outer_block;
-
-	/** Symbol attributes. */
+	/** Symbol attributes */
 	list_t attr; /* of stree_symbol_attr_t */
 } stree_symbol_t;
Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/stype.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -76,4 +76,5 @@
 static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s);
 static void stype_if(stype_t *stype, stree_if_t *if_s);
+static void stype_switch(stype_t *stype, stree_switch_t *switch_s);
 static void stype_while(stype_t *stype, stree_while_t *while_s);
 static void stype_for(stype_t *stype, stree_for_t *for_s);
@@ -889,4 +890,5 @@
 	case st_vdecl: stype_vdecl(stype, stat->u.vdecl_s); break;
 	case st_if: stype_if(stype, stat->u.if_s); break;
+	case st_switch: stype_switch(stype, stat->u.switch_s); break;
 	case st_while: stype_while(stype, stat->u.while_s); break;
 	case st_for: stype_for(stype, stat->u.for_s); break;
@@ -931,4 +933,7 @@
 	}
 
+	/* Annotate with variable type */
+	vdecl_s->titem = titem;
+
 	intmap_set(&block_vr->vdecls, vdecl_s->name->sid, vdecl_s);
 }
@@ -973,4 +978,71 @@
 	if (if_s->else_block != NULL)
 		stype_block(stype, if_s->else_block);
+}
+
+/** Type @c switch statement.
+ *
+ * @param stype		Static typing object
+ * @param switch_s	@c switch statement
+ */
+static void stype_switch(stype_t *stype, stree_switch_t *switch_s)
+{
+	stree_expr_t *expr, *cexpr;
+	list_node_t *whenc_node;
+	stree_when_t *whenc;
+	list_node_t *expr_node;
+	tdata_item_t *titem1, *titem2;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'switch' statement.\n");
+#endif
+	stype_expr(stype, switch_s->expr);
+
+	titem1 = switch_s->expr->titem;
+	if (titem1 == NULL) {
+		cspan_print(switch_s->expr->cspan);
+		printf(" Error: Switch expression has no value.\n");
+		stype_note_error(stype);
+		return;
+	}
+
+	/* Walk through all when clauses. */
+	whenc_node = list_first(&switch_s->when_clauses);
+
+	while (whenc_node != NULL) {
+		/* Get when clause */
+		whenc = list_node_data(whenc_node, stree_when_t *);
+
+		/* Walk through all expressions of the when clause */
+		expr_node = list_first(&whenc->exprs);
+		while (expr_node != NULL) {
+			expr = list_node_data(expr_node, stree_expr_t *);
+
+			stype_expr(stype, expr);
+			titem2 = expr->titem;
+			if (titem2 == NULL) {
+				cspan_print(expr->cspan);
+				printf(" Error: When expression has no value.\n");
+				stype_note_error(stype);
+				return;
+			}
+
+			/* Convert expression to same type as switch expr. */
+			cexpr = stype_convert(stype, expr, titem1);
+
+			/* Patch code with augmented expression. */
+			list_node_setdata(expr_node, cexpr);
+
+			expr_node = list_next(&whenc->exprs, expr_node);
+		}
+
+		/* Type the @c when block */
+		stype_block(stype, whenc->block);
+
+		whenc_node = list_next(&switch_s->when_clauses, whenc_node);
+	}
+
+	/* Type the @c else block */
+	if (switch_s->else_block != NULL)
+		stype_block(stype, switch_s->else_block);
 }
 
@@ -1168,4 +1240,6 @@
 	while (ec_n != NULL) {
 		ec = list_node_data(ec_n, stree_except_t *);
+		run_texpr(stype->program, stype->current_csi, ec->etype,
+		    &ec->titem);
 		stype_block(stype, ec->block);
 
Index: uspace/app/sbi/src/stype_expr.c
===================================================================
--- uspace/app/sbi/src/stype_expr.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/sbi/src/stype_expr.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -894,4 +894,11 @@
 
 	titem = unop->arg->titem;
+	if (titem == NULL) {
+		cspan_print(unop->arg->cspan);
+		printf(" Error: Argument of unary operation has no value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
 
 	if (titem->tic == tic_ignore) {
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/taskdump/taskdump.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -406,4 +406,17 @@
 	}
 
+	rc = asprintf(&file_name, "/drv/%s/%s", app_name, app_name);
+	if (rc < 0) {
+		printf("Memory allocation failure.\n");
+		exit(1);
+	}
+
+	rc = symtab_load(file_name, &app_symtab);
+	if (rc == EOK) {
+		printf("Loaded symbol table from %s\n", file_name);
+		free(file_name);
+		return;
+	}
+
 	free(file_name);
 	printf("Failed autoloading symbol table.\n");
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -47,5 +47,5 @@
 #include "../../tester.h"
 
-#define DEVICE_PATH_NORMAL "/dev/devices/\\virt\\null"
+#define DEVICE_PATH_NORMAL "/dev/devices/\\virt\\null\\a"
 #define DEVICE_PATH_CLASSES "/dev/class/virt-null\\1"
 #define BUFFER_SIZE 64
Index: uspace/app/tester/hw/serial/serial1.c
===================================================================
--- uspace/app/tester/hw/serial/serial1.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/app/tester/hw/serial/serial1.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -74,5 +74,5 @@
 	
 	devman_handle_t handle;
-	res = devman_device_get_handle("/hw/pci0/00:01.0/com1", &handle,
+	res = devman_device_get_handle("/hw/pci0/00:01.0/com1/a", &handle,
 	    IPC_FLAG_BLOCKING);
 	if (res != EOK)
Index: uspace/dist/src/sysel/demos/arith.sy
===================================================================
--- uspace/dist/src/sysel/demos/arith.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/arith.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -30,57 +30,57 @@
 	fun Main(), static is
 		-- Test addition, multiplication and precedence.
-		Builtin.Write("2*2 + 2*2 = ");
-		Builtin.Write(2*2 + 2*2);
-		Builtin.WriteLine(" (expected: 8)");
+		Console.Write("2*2 + 2*2 = ");
+		Console.Write(2*2 + 2*2);
+		Console.WriteLine(" (expected: 8)");
 
 		-- Test subtraction, multiplication and precedence.
-		Builtin.Write("1111 - 1 - 10 - 10*10 - 10*10*10 = ");
-		Builtin.Write(1111 - 1 - 10 - 10*10 - 10*10*10);
-		Builtin.WriteLine(" (expected: 0)");
+		Console.Write("1111 - 1 - 10 - 10*10 - 10*10*10 = ");
+		Console.Write(1111 - 1 - 10 - 10*10 - 10*10*10);
+		Console.WriteLine(" (expected: 0)");
 
 		-- Test parenthesized sub-expressions.
-		Builtin.Write("10 * (1 - 1) = ");
-		Builtin.Write(10 * (1 - 1));
-		Builtin.WriteLine(" (expected: 0)");
+		Console.Write("10 * (1 - 1) = ");
+		Console.Write(10 * (1 - 1));
+		Console.WriteLine(" (expected: 0)");
 
 		-- Test unary plus and minus.
-		Builtin.Write("(+1) - (-1) - (+(+1)) + (+(-1)) = ");
-		Builtin.Write((+1) - (-1) - (+(+1)) + (+(-1)));
-		Builtin.WriteLine(" (expected: 0)");
+		Console.Write("(+1) - (-1) - (+(+1)) + (+(-1)) = ");
+		Console.Write((+1) - (-1) - (+(+1)) + (+(-1)));
+		Console.WriteLine(" (expected: 0)");
 
 		-- Test signed multiplication.
-		Builtin.Write("+1 * +1 = ");
-		Builtin.Write(+1 * +1);
-		Builtin.WriteLine(" (expected: 1)");
+		Console.Write("+1 * +1 = ");
+		Console.Write(+1 * +1);
+		Console.WriteLine(" (expected: 1)");
 
-		Builtin.Write("-1 * -1 = ");
-		Builtin.Write(-1 * -1);
-		Builtin.WriteLine(" (expected: 1)");
+		Console.Write("-1 * -1 = ");
+		Console.Write(-1 * -1);
+		Console.WriteLine(" (expected: 1)");
 
-		Builtin.Write("+1 * -1 = ");
-		Builtin.Write(+1 * -1);
-		Builtin.WriteLine(" (expected: -1)");
+		Console.Write("+1 * -1 = ");
+		Console.Write(+1 * -1);
+		Console.WriteLine(" (expected: -1)");
 
-		Builtin.Write("-1 * +1 = ");
-		Builtin.Write(-1 * +1);
-		Builtin.WriteLine(" (expected: -1)");
+		Console.Write("-1 * +1 = ");
+		Console.Write(-1 * +1);
+		Console.WriteLine(" (expected: -1)");
 
 		-- Test multiplication with large result.
-		Builtin.Write("1000000 * 1000000 * 1000000 * 1000000 = ");
-		Builtin.Write(1000000 * 1000000 * 1000000 * 1000000);
-		Builtin.WriteLine(" (expected: 1000000000000000000000000)");
+		Console.Write("1000000 * 1000000 * 1000000 * 1000000 = ");
+		Console.Write(1000000 * 1000000 * 1000000 * 1000000);
+		Console.WriteLine(" (expected: 1000000000000000000000000)");
 
 		-- Test large literals.
-		Builtin.Write("1000000000000000000000000 = ");
-		Builtin.Write(1000000000000000000000000);
-		Builtin.WriteLine(" (expected: 1000000000000000000000000)");
+		Console.Write("1000000000000000000000000 = ");
+		Console.Write(1000000000000000000000000);
+		Console.WriteLine(" (expected: 1000000000000000000000000)");
 
 		-- Test large factorials.
 		var n : int;
 
-		Builtin.WriteLine("Factorials:");
+		Console.WriteLine("Factorials:");
 		n = 1;
 		while n <= 40 do
-			Builtin.WriteLine(Factorial(n));
+			Console.WriteLine(Factorial(n));
 			n = n + 1;
 		end
Index: uspace/dist/src/sysel/demos/array.sy
===================================================================
--- uspace/dist/src/sysel/demos/array.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/array.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -40,5 +40,5 @@
 		i = 0;
 		while i < 3 do
-			Builtin.WriteLine(a[i, 0]);
+			Console.WriteLine(a[i, 0]);
 			i = i + 1;
 		end
Index: uspace/dist/src/sysel/demos/autobox.sy
===================================================================
--- uspace/dist/src/sysel/demos/autobox.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/autobox.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -39,11 +39,11 @@
 		--
 		b = true;
-		Builtin.WriteLine(b.Value);
+		Console.WriteLine(b.Value);
 		c = 'a';
-		Builtin.WriteLine(c.Value);
+		Console.WriteLine(c.Value);
 		i = 1;
-		Builtin.WriteLine(i.Value);
+		Console.WriteLine(i.Value);
 		s = "Hello";
-		Builtin.WriteLine(s.Value);
+		Console.WriteLine(s.Value);
 
 		-- Anything can be converted to Object.
Index: uspace/dist/src/sysel/demos/count.sy
===================================================================
--- uspace/dist/src/sysel/demos/count.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/count.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -33,5 +33,5 @@
 		i = a;
 		while i < b do
-			Builtin.WriteLine(i);
+			Console.WriteLine(i);
 			i = i + 1;
 		end
Index: uspace/dist/src/sysel/demos/ctor.sy
===================================================================
--- uspace/dist/src/sysel/demos/ctor.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/ctor.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -32,6 +32,6 @@
 
 		a = new A(1);
-		Builtin.Write("a.v = ");
-		Builtin.WriteLine(a.v);
+		Console.Write("a.v = ");
+		Console.WriteLine(a.v);
 	end
 end
@@ -41,5 +41,5 @@
 
 	new(i : int) is
-		Builtin.WriteLine("A.new()");
+		Console.WriteLine("A.new()");
 		v = i;
 	end
Index: uspace/dist/src/sysel/demos/deleg.sy
===================================================================
--- uspace/dist/src/sysel/demos/deleg.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/deleg.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -55,6 +55,6 @@
 	-- Function having delegate as the first parameger
 	fun Operate(op : BinaryOp; opName : string) is
-		Builtin.Write(opName + "(1, 2): ");
-		Builtin.WriteLine(op(1, 2));
+		Console.Write(opName + "(1, 2): ");
+		Console.WriteLine(op(1, 2));
 	end
 
Index: uspace/dist/src/sysel/demos/enum.sy
===================================================================
--- uspace/dist/src/sysel/demos/enum.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/enum.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -31,40 +31,40 @@
 		var color : ChessColor;
 
-		Builtin.WriteLine("Set color to ChessColor.Black.");
+		Console.WriteLine("Set color to ChessColor.Black.");
 		color = ChessColor.Black;
 
-		Builtin.Write("Test color == ChessColor.Black.. ");
+		Console.Write("Test color == ChessColor.Black.. ");
 		if color == ChessColor.Black then
-			Builtin.WriteLine("True - OK");
+			Console.WriteLine("True - OK");
 		else
-			Builtin.WriteLine("False - Fail!");
+			Console.WriteLine("False - Fail!");
 			raise new Error.Base();
 		end
 
-		Builtin.Write("Test color != ChessColor.Black.. ");
+		Console.Write("Test color != ChessColor.Black.. ");
 		if color != ChessColor.Black then
-			Builtin.WriteLine("True - Fail!");
+			Console.WriteLine("True - Fail!");
 			raise new Error.Base();
 		else
-			Builtin.WriteLine("False - OK");
+			Console.WriteLine("False - OK");
 		end
 
-		Builtin.Write("Test color == ChessColor.White.. ");
+		Console.Write("Test color == ChessColor.White.. ");
 		if color == ChessColor.White then
-			Builtin.WriteLine("True - Fail!");
+			Console.WriteLine("True - Fail!");
 			raise new Error.Base();
 		else
-			Builtin.WriteLine("False - OK");
+			Console.WriteLine("False - OK");
 		end
 
-		Builtin.Write("Test color != ChessColor.White.. ");
+		Console.Write("Test color != ChessColor.White.. ");
 		if color != ChessColor.White then
-			Builtin.WriteLine("True - OK");
+			Console.WriteLine("True - OK");
 		else
-			Builtin.WriteLine("False - Fail!");
+			Console.WriteLine("False - Fail!");
 			raise new Error.Base();
 		end
 
-		Builtin.WriteLine("Success");
+		Console.WriteLine("Success");
 
 		-- Test enum declared in non-CSI scope
Index: uspace/dist/src/sysel/demos/except.sy
===================================================================
--- uspace/dist/src/sysel/demos/except.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/except.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -29,5 +29,5 @@
 class ExceptionDemo is
 	fun foo(), static is
-	        Builtin.WriteLine("Entered foo().");
+	        Console.WriteLine("Entered foo().");
 		raise new BaseException();
 	end
@@ -38,9 +38,9 @@
 			foo();
 		except e : DerivedException do
-			Builtin.WriteLine("Caught derived exception.");
+			Console.WriteLine("Caught derived exception.");
 		except e : BaseException do
-			Builtin.WriteLine("Caught base exception.");
+			Console.WriteLine("Caught base exception.");
 		finally do
-			Builtin.WriteLine("Finally.");
+			Console.WriteLine("Finally.");
 		end
 	end
Index: uspace/dist/src/sysel/demos/gen.sy
===================================================================
--- uspace/dist/src/sysel/demos/gen.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/gen.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -31,5 +31,5 @@
 class GenericsDemo is
 	fun Main(), static is
-		Builtin.WriteLine("Let's try some generics.");
+		Console.WriteLine("Let's try some generics.");
 
 		var f : B/int/string;
Index: uspace/dist/src/sysel/demos/hello.sy
===================================================================
--- uspace/dist/src/sysel/demos/hello.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/hello.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -29,5 +29,5 @@
 class HelloWorld is
 	fun Main(), static is
-		Builtin.WriteLine("Hello world!");
+		Console.WriteLine("Hello world!");
 	end
 end
Index: uspace/dist/src/sysel/demos/htxtfile.sy
===================================================================
--- uspace/dist/src/sysel/demos/htxtfile.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/htxtfile.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -45,5 +45,5 @@
 		while not in_file.EOF do
 			line = in_file.ReadLine();
-			Builtin.WriteLine(name + ": " + line);
+			Console.WriteLine(name + ": " + line);
 			out_file.WriteLine(name + ": " + line);
 		end
Index: uspace/dist/src/sysel/demos/iface.sy
===================================================================
--- uspace/dist/src/sysel/demos/iface.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/iface.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -43,5 +43,5 @@
 		f = g as Foo;
 
-		Builtin.WriteLine(g.a());
+		Console.WriteLine(g.a());
 	end
 end
Index: uspace/dist/src/sysel/demos/inherit.sy
===================================================================
--- uspace/dist/src/sysel/demos/inherit.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/inherit.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -29,5 +29,5 @@
 class A is
 	fun Foo() is
-		Builtin.WriteLine("A.Foo()");
+		Console.WriteLine("A.Foo()");
 	end
 end
@@ -35,5 +35,5 @@
 class B : A is
 	fun Foo() is
-		Builtin.WriteLine("B.Foo()");
+		Console.WriteLine("B.Foo()");
 	end
 end
Index: uspace/dist/src/sysel/demos/list.sy
===================================================================
--- uspace/dist/src/sysel/demos/list.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/list.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -43,5 +43,5 @@
 		e = list.GetEnumerator();
 		while e.MoveNext() do
-			Builtin.WriteLine(e.Data);
+			Console.WriteLine(e.Data);
 		end
 	end
Index: uspace/dist/src/sysel/demos/map.sy
===================================================================
--- uspace/dist/src/sysel/demos/map.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/map.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -43,7 +43,7 @@
 		e = map.GetEnumerator();
 		while e.MoveNext() do
-			Builtin.Write(e.Data);
-			Builtin.Write(" -> ");
-			Builtin.WriteLine(map[e.Data]);
+			Console.Write(e.Data);
+			Console.Write(" -> ");
+			Console.WriteLine(map[e.Data]);
 		end
 	end
Index: uspace/dist/src/sysel/demos/property.sy
===================================================================
--- uspace/dist/src/sysel/demos/property.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/property.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -33,14 +33,25 @@
 	prop X : int is
 		get is
-			Builtin.Write("Getting value of X which is ");
-			Builtin.WriteLine(x);
+			Console.Write("Getting value of X which is ");
+			Console.WriteLine(x);
 			return x;
 		end
 
 		set value is
-			Builtin.Write("Setting value of X to ");
-			Builtin.WriteLine(value);
+			Console.Write("Setting value of X to ");
+			Console.WriteLine(value);
 			x = value;
 		end
+	end
+
+	-- Test accessing property via an unqualified name
+	fun TestUnqualPropAcc() is
+		var i : int;
+
+		X = 1;
+		i = X;
+
+		Console.Write("TestUnqualPropAcc(): Got ");
+		Console.WriteLine(i);
 	end
 
@@ -51,8 +62,8 @@
 	prop self[index : int] : int is
 		get is
-			Builtin.Write("Getting property with index ");
-			Builtin.Write(index);
-			Builtin.Write(" which is ");
-			Builtin.WriteLine(iprops[index]);
+			Console.Write("Getting property with index ");
+			Console.Write(index);
+			Console.Write(" which is ");
+			Console.WriteLine(iprops[index]);
 
 			return iprops[index];
@@ -60,8 +71,8 @@
 
 		set value is
-			Builtin.Write("Setting property with index ");
-			Builtin.Write(index);
-			Builtin.Write(" to ");
-			Builtin.WriteLine(value);
+			Console.Write("Setting property with index ");
+			Console.Write(index);
+			Console.Write(" to ");
+			Console.WriteLine(value);
 
 			iprops[index] = value;
@@ -82,9 +93,9 @@
 	prop B : Bar is
 		get is
-			Builtin.WriteLine("Getting B");
+			Console.WriteLine("Getting B");
 			return bprop;
 		end
 		set value is
-			Builtin.WriteLine("Setting B");
+			Console.WriteLine("Setting B");
 			bprop = value;
 		end
@@ -110,6 +121,8 @@
 		i = a.X;
 
-		Builtin.Write("Main(): Got ");
-		Builtin.WriteLine(i);
+		Console.Write("Main(): Got ");
+		Console.WriteLine(i);
+
+		a.TestUnqualPropAcc();
 
 		a.iprops = new int[5];
@@ -121,6 +134,6 @@
 		i = a[1];
 
-		Builtin.Write("Main(): Got ");
-		Builtin.WriteLine(i);
+		Console.Write("Main(): Got ");
+		Console.WriteLine(i);
 
 		-- Property field access
@@ -132,7 +145,7 @@
 		a.bprop = b;
 
-		Builtin.WriteLine(a.bprop.i);
+		Console.WriteLine(a.bprop.i);
 		a.bprop.i = 2;
-		Builtin.WriteLine(a.bprop.i);
+		Console.WriteLine(a.bprop.i);
 	end
 end
Index: uspace/dist/src/sysel/demos/string.sy
===================================================================
--- uspace/dist/src/sysel/demos/string.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/string.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -30,5 +30,5 @@
 	fun Main(), static is
 		-- Concatenate some strings.
-		Builtin.WriteLine("One-" + "two-" + "three!");
+		Console.WriteLine("One-" + "two-" + "three!");
 
 		-- Extract characters from a string.
@@ -36,9 +36,9 @@
 		i = 0;
 		while i < 5 do
-			Builtin.WriteLine("ABCDE"[i]);
+			Console.WriteLine("ABCDE"[i]);
 			i = i + 1;
 		end
 
-		Builtin.WriteLine("Abracadabra".Slice(2, 4));
+		Console.WriteLine("Abracadabra".Slice(2, 4));
 	end
 end
Index: uspace/dist/src/sysel/demos/svar.sy
===================================================================
--- uspace/dist/src/sysel/demos/svar.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/svar.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -31,13 +31,13 @@
 		-- Test static member variable
 		A.B.a = 1;
-		Builtin.WriteLine(A.B.a);
+		Console.WriteLine(A.B.a);
 		A.B.a = 2;
-		Builtin.WriteLine(A.B.a);
+		Console.WriteLine(A.B.a);
 
 		-- Test static property
 		A.B.P = 1;
-		Builtin.WriteLine(A.B.P);
+		Console.WriteLine(A.B.P);
 		A.B.P = 2;
-		Builtin.WriteLine(A.B.P);
+		Console.WriteLine(A.B.P);
 	end
 end
Index: uspace/dist/src/sysel/demos/switch.sy
===================================================================
--- uspace/dist/src/sysel/demos/switch.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/dist/src/sysel/demos/switch.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -0,0 +1,199 @@
+--
+-- Copyright (c) 2011 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+--- Switch statement demo.
+--
+-- This demonstrates the switch statement. The switch statement looks like:
+--
+-- switch <s_expr> is
+-- when <e1> [, <e2> ...] do
+--	<statements1>
+-- when <f1> [, <f2> ...] do
+--	<statements2>
+-- [...]
+-- [else do
+--	<statements3>]
+-- end
+--
+-- It is mostly equivalent to the pseudocode:
+--
+-- var v : <type of s_expr>;
+-- if v == <e1> [or v == <e2> ...] then
+--	<statements1>
+-- elif v == <f1> [ or v == <f2> ...] then
+--	<statements2>
+-- [...]
+-- [else
+--	<statements3>]
+-- end
+--
+-- This means there is no artificial limitation as to what you can switch
+-- on. The expressions don't have to be constant and they can be of any type
+-- as long as the switch expression (<s_expr>) can be compared with each
+-- of the when expressions (<e1>, <e2>, <f1>, <f2>, ...).
+--
+-- Note however, the 'or' here denotes short-circuit evaluation. (Currently
+-- the 'or' operation does not use short-circuit evaluation, but that's
+-- more of a bug than a feature.
+--
+class SwitchDemo is
+	class A is
+	end
+
+	var a1 : A, static;
+	var a2 : A, static;
+	var a3 : A, static;
+	var a4 : A, static;
+
+	enum MyEnum is
+		red;
+		green;
+		blue;
+		black;
+		cyan;
+	end
+
+	-- Switch on boolean value
+	fun SwitchBool(v : bool) : string, static is
+		switch v is
+		when false do
+			return "false";
+		when true do
+			return "true";
+		end
+	end
+
+	-- Switch on char value
+	fun SwitchChar(v : char) : string, static is
+		switch v is
+		when 'a', 'b' do
+			return "a/b";
+		when 'c', 'd' do
+			return "c/d";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on integer value
+	fun SwitchInt(v : int) : string, static is
+		switch v is
+		when 0, 1 do
+			return "0/1";
+		when 2, 3 do
+			return "2/3";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on string value
+	fun SwitchString(v : string) : string, static is
+		switch v is
+		when "foo", "bar"  do
+			return "foo/bar";
+		when "hello", "world" do
+			return "hello/world";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on object reference
+	fun SwitchObj(v : A) : string, static is
+		switch v is
+		when a1, a2 do
+			return "a1/a2";
+		when a3, a4 do
+			return "a3/a4";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on object reference
+	fun SwitchEnum(v : MyEnum) : string, static is
+		switch v is
+		when MyEnum.red, MyEnum.green do
+			return "red/green";
+		when MyEnum.blue, MyEnum.black do
+			return "blue/black";
+		else do
+			return "<other>";
+		end
+	end
+
+	fun Test(res : string; test_expr : string; expected : string), static is
+		Console.WriteLine(test_expr + " = '" + res + "' (expected '" +
+		    expected + "')");
+		if res != expected then
+			Console.WriteLine("Error: Got unexpected result.");
+			raise new Error.Base();
+		end
+	end
+
+	fun Main(), static is
+		a1 = new A();
+		a2 = new A();
+		a3 = new A();
+		a4 = new A();
+
+		Test(SwitchBool(false), "SwitchBool(false)", "false");
+		Test(SwitchBool(true), "SwitchBool(true)", "true");
+
+		Test(SwitchChar('a'), "SwitchChar('a')", "a/b");
+		Test(SwitchChar('b'), "SwitchChar('b')", "a/b");
+		Test(SwitchChar('c'), "SwitchChar('c')", "c/d");
+		Test(SwitchChar('d'), "SwitchChar('d')", "c/d");
+		Test(SwitchChar('e'), "SwitchChar('e')", "<other>");
+
+		Test(SwitchInt(0), "SwitchInt(0)", "0/1");
+		Test(SwitchInt(1), "SwitchInt(1)", "0/1");
+		Test(SwitchInt(2), "SwitchInt(2)", "2/3");
+		Test(SwitchInt(3), "SwitchInt(3)", "2/3");
+		Test(SwitchInt(4), "SwitchInt(4)", "<other>");
+
+		Test(SwitchString("foo"), "SwitchString('foo')", "foo/bar");
+		Test(SwitchString("bar"), "SwitchString('bar')", "foo/bar");
+		Test(SwitchString("hello"), "SwitchString('hello')", "hello/world");
+		Test(SwitchString("world"), "SwitchString('world')", "hello/world");
+		Test(SwitchString("boom"), "SwitchString('boom')", "<other>");
+
+		Test(SwitchObj(a1), "SwitchObj(a1)", "a1/a2");
+		Test(SwitchObj(a2), "SwitchObj(a2)", "a1/a2");
+		Test(SwitchObj(a3), "SwitchObj(a3)", "a3/a4");
+		Test(SwitchObj(a4), "SwitchObj(a4)", "a3/a4");
+		Test(SwitchObj(nil), "SwitchObj(nil)", "<other>");
+
+		Test(SwitchEnum(MyEnum.red), "SwitchEnum(MyEnum.red)", "red/green");
+		Test(SwitchEnum(MyEnum.green), "SwitchEnum(MyEnum.green)", "red/green");
+		Test(SwitchEnum(MyEnum.blue), "SwitchEnum(MyEnum.blue)", "blue/black");
+		Test(SwitchEnum(MyEnum.black), "SwitchEnum(MyEnum.black)", "blue/black");
+		Test(SwitchEnum(MyEnum.cyan), "SwitchEnum(MyEnum.cyan)", "<other>");
+	end
+end
Index: uspace/dist/src/sysel/demos/varargs.sy
===================================================================
--- uspace/dist/src/sysel/demos/varargs.sy	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/dist/src/sysel/demos/varargs.sy	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -44,5 +44,5 @@
 			-- implemented...
 			do
-				Builtin.WriteLine(args[i]);
+				Console.WriteLine(args[i]);
 			except e : Error.OutOfBounds do
 				error = true;
Index: uspace/drv/isa/isa.c
===================================================================
--- uspace/drv/isa/isa.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/isa/isa.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -43,4 +44,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <str_error.h>
 #include <ctype.h>
 #include <macros.h>
@@ -50,5 +52,5 @@
 #include <sys/stat.h>
 
-#include <driver.h>
+#include <ddf/driver.h>
 #include <ops/hw_res.h>
 
@@ -58,24 +60,25 @@
 
 #define NAME "isa"
-#define CHILD_DEV_CONF_PATH "/drv/isa/isa.dev"
+#define CHILD_FUN_CONF_PATH "/drv/isa/isa.dev"
+
+/** Obtain soft-state pointer from function node pointer */
+#define ISA_FUN(fnode) ((isa_fun_t *) ((fnode)->driver_data))
 
 #define ISA_MAX_HW_RES 4
 
-typedef struct isa_child_data {
+typedef struct isa_fun {
+	ddf_fun_t *fnode;
 	hw_resource_list_t hw_resources;
-} isa_child_data_t;
-
-static hw_resource_list_t *isa_get_child_resources(device_t *dev)
-{
-	isa_child_data_t *dev_data;
-
-	dev_data = (isa_child_data_t *)dev->driver_data;
-	if (dev_data == NULL)
-		return NULL;
-
-	return &dev_data->hw_resources;
-}
-
-static bool isa_enable_child_interrupt(device_t *dev)
+} isa_fun_t;
+
+static hw_resource_list_t *isa_get_fun_resources(ddf_fun_t *fnode)
+{
+	isa_fun_t *fun = ISA_FUN(fnode);
+	assert(fun != NULL);
+
+	return &fun->hw_resources;
+}
+
+static bool isa_enable_fun_interrupt(ddf_fun_t *fnode)
 {
 	// TODO
@@ -84,12 +87,12 @@
 }
 
-static hw_res_ops_t isa_child_hw_res_ops = {
-	&isa_get_child_resources,
-	&isa_enable_child_interrupt
+static hw_res_ops_t isa_fun_hw_res_ops = {
+	&isa_get_fun_resources,
+	&isa_enable_fun_interrupt
 };
 
-static device_ops_t isa_child_dev_ops;
-
-static int isa_add_device(device_t *dev);
+static ddf_dev_ops_t isa_fun_ops;
+
+static int isa_add_device(ddf_dev_t *dev);
 
 /** The isa device driver's standard operations */
@@ -104,33 +107,22 @@
 };
 
-
-static isa_child_data_t *create_isa_child_data() 
-{
-	isa_child_data_t *data;
-
-	data = (isa_child_data_t *) malloc(sizeof(isa_child_data_t));
-	if (data != NULL)
-		memset(data, 0, sizeof(isa_child_data_t));
-
-	return data;
-}
-
-static device_t *create_isa_child_dev()
-{
-	device_t *dev = create_device();
-	if (dev == NULL)
+static isa_fun_t *isa_fun_create(ddf_dev_t *dev, const char *name)
+{
+	isa_fun_t *fun = calloc(1, sizeof(isa_fun_t));
+	if (fun == NULL)
 		return NULL;
 
-	isa_child_data_t *data = create_isa_child_data();
-	if (data == NULL) {
-		delete_device(dev);
+	ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name);
+	if (fnode == NULL) {
+		free(fun);
 		return NULL;
 	}
 
-	dev->driver_data = data;
-	return dev;
-}
-
-static char *read_dev_conf(const char *conf_path)
+	fun->fnode = fnode;
+	fnode->driver_data = fun;
+	return fun;
+}
+
+static char *fun_conf_read(const char *conf_path)
 {
 	bool suc = false;
@@ -151,5 +143,5 @@
 	lseek(fd, 0, SEEK_SET);	
 	if (len == 0) {
-		printf(NAME ": read_dev_conf error: configuration file '%s' "
+		printf(NAME ": fun_conf_read error: configuration file '%s' "
 		    "is empty.\n", conf_path);
 		goto cleanup;
@@ -158,10 +150,10 @@
 	buf = malloc(len + 1);
 	if (buf == NULL) {
-		printf(NAME ": read_dev_conf error: memory allocation failed.\n");
+		printf(NAME ": fun_conf_read error: memory allocation failed.\n");
 		goto cleanup;
 	}
 
 	if (0 >= read(fd, buf, len)) {
-		printf(NAME ": read_dev_conf error: unable to read file '%s'.\n",
+		printf(NAME ": fun_conf_read error: unable to read file '%s'.\n",
 		    conf_path);
 		goto cleanup;
@@ -249,10 +241,8 @@
 }
 
-static void isa_child_set_irq(device_t *dev, int irq)
-{
-	isa_child_data_t *data = (isa_child_data_t *)dev->driver_data;
-
-	size_t count = data->hw_resources.count;
-	hw_resource_t *resources = data->hw_resources.resources;
+static void isa_fun_set_irq(isa_fun_t *fun, int irq)
+{
+	size_t count = fun->hw_resources.count;
+	hw_resource_t *resources = fun->hw_resources.resources;
 
 	if (count < ISA_MAX_HW_RES) {
@@ -260,16 +250,15 @@
 		resources[count].res.interrupt.irq = irq;
 
-		data->hw_resources.count++;
-
-		printf(NAME ": added irq 0x%x to device %s\n", irq, dev->name);
-	}
-}
-
-static void isa_child_set_io_range(device_t *dev, size_t addr, size_t len)
-{
-	isa_child_data_t *data = (isa_child_data_t *)dev->driver_data;
-
-	size_t count = data->hw_resources.count;
-	hw_resource_t *resources = data->hw_resources.resources;
+		fun->hw_resources.count++;
+
+		printf(NAME ": added irq 0x%x to function %s\n", irq,
+		    fun->fnode->name);
+	}
+}
+
+static void isa_fun_set_io_range(isa_fun_t *fun, size_t addr, size_t len)
+{
+	size_t count = fun->hw_resources.count;
+	hw_resource_t *resources = fun->hw_resources.resources;
 
 	if (count < ISA_MAX_HW_RES) {
@@ -279,30 +268,30 @@
 		resources[count].res.io_range.endianness = LITTLE_ENDIAN;
 
-		data->hw_resources.count++;
+		fun->hw_resources.count++;
 
 		printf(NAME ": added io range (addr=0x%x, size=0x%x) to "
-		    "device %s\n", (unsigned int) addr, (unsigned int) len,
-		    dev->name);
-	}
-}
-
-static void get_dev_irq(device_t *dev, char *val)
+		    "function %s\n", (unsigned int) addr, (unsigned int) len,
+		    fun->fnode->name);
+	}
+}
+
+static void fun_parse_irq(isa_fun_t *fun, char *val)
 {
 	int irq = 0;
 	char *end = NULL;
 
-	val = skip_spaces(val);	
+	val = skip_spaces(val);
 	irq = (int)strtol(val, &end, 0x10);
 
 	if (val != end)
-		isa_child_set_irq(dev, irq);
-}
-
-static void get_dev_io_range(device_t *dev, char *val)
+		isa_fun_set_irq(fun, irq);
+}
+
+static void fun_parse_io_range(isa_fun_t *fun, char *val)
 {
 	size_t addr, len;
 	char *end = NULL;
 
-	val = skip_spaces(val);	
+	val = skip_spaces(val);
 	addr = strtol(val, &end, 0x10);
 
@@ -310,5 +299,5 @@
 		return;
 
-	val = skip_spaces(end);	
+	val = skip_spaces(end);
 	len = strtol(val, &end, 0x10);
 
@@ -316,5 +305,5 @@
 		return;
 
-	isa_child_set_io_range(dev, addr, len);
+	isa_fun_set_io_range(fun, addr, len);
 }
 
@@ -331,45 +320,38 @@
 }
 
-static void get_dev_match_id(device_t *dev, char *val)
+static void fun_parse_match_id(isa_fun_t *fun, char *val)
 {
 	char *id = NULL;
 	int score = 0;
 	char *end = NULL;
-
-	val = skip_spaces(val);	
+	int rc;
+
+	val = skip_spaces(val);
 
 	score = (int)strtol(val, &end, 10);
 	if (val == end) {
 		printf(NAME " : error - could not read match score for "
-		    "device %s.\n", dev->name);
+		    "function %s.\n", fun->fnode->name);
 		return;
 	}
 
-	match_id_t *match_id = create_match_id();
-	if (match_id == NULL) {
-		printf(NAME " : failed to allocate match id for device %s.\n",
-		    dev->name);
-		return;
-	}
-
-	val = skip_spaces(end);	
+	val = skip_spaces(end);
 	get_match_id(&id, val);
 	if (id == NULL) {
 		printf(NAME " : error - could not read match id for "
-		    "device %s.\n", dev->name);
-		delete_match_id(match_id);
+		    "function %s.\n", fun->fnode->name);
 		return;
 	}
 
-	match_id->id = id;
-	match_id->score = score;
-
-	printf(NAME ": adding match id '%s' with score %d to device %s\n", id,
-	    score, dev->name);
-	add_match_id(&dev->match_ids, match_id);
-}
-
-static bool read_dev_prop(device_t *dev, char *line, const char *prop,
-    void (*read_fn)(device_t *, char *))
+	printf(NAME ": adding match id '%s' with score %d to function %s\n", id,
+	    score, fun->fnode->name);
+
+	rc = ddf_fun_add_match_id(fun->fnode, id, score);
+	if (rc != EOK)
+		printf(NAME ": error adding match ID: %s\n", str_error(rc));
+}
+
+static bool prop_parse(isa_fun_t *fun, char *line, const char *prop,
+    void (*read_fn)(isa_fun_t *, char *))
 {
 	size_t proplen = str_size(prop);
@@ -378,5 +360,5 @@
 		line += proplen;
 		line = skip_spaces(line);
-		(*read_fn)(dev, line);
+		(*read_fn)(fun, line);
 
 		return true;
@@ -386,12 +368,12 @@
 }
 
-static void get_dev_prop(device_t *dev, char *line)
+static void fun_prop_parse(isa_fun_t *fun, char *line)
 {
 	/* Skip leading spaces. */
 	line = skip_spaces(line);
 
-	if (!read_dev_prop(dev, line, "io_range", &get_dev_io_range) &&
-	    !read_dev_prop(dev, line, "irq", &get_dev_irq) &&
-	    !read_dev_prop(dev, line, "match", &get_dev_match_id))
+	if (!prop_parse(fun, line, "io_range", &fun_parse_io_range) &&
+	    !prop_parse(fun, line, "irq", &fun_parse_irq) &&
+	    !prop_parse(fun, line, "match", &fun_parse_match_id))
 	{
 	    printf(NAME " error undefined device property at line '%s'\n",
@@ -400,19 +382,18 @@
 }
 
-static void child_alloc_hw_res(device_t *dev)
-{
-	isa_child_data_t *data = (isa_child_data_t *)dev->driver_data;
-	data->hw_resources.resources = 
+static void fun_hw_res_alloc(isa_fun_t *fun)
+{
+	fun->hw_resources.resources = 
 	    (hw_resource_t *)malloc(sizeof(hw_resource_t) * ISA_MAX_HW_RES);
 }
 
-static char *read_isa_dev_info(char *dev_conf, device_t *parent)
+static char *isa_fun_read_info(char *fun_conf, ddf_dev_t *dev)
 {
 	char *line;
-	char *dev_name = NULL;
+	char *fun_name = NULL;
 
 	/* Skip empty lines. */
 	while (true) {
-		line = str_get_line(dev_conf, &dev_conf);
+		line = str_get_line(fun_conf, &fun_conf);
 
 		if (line == NULL) {
@@ -426,22 +407,20 @@
 
 	/* Get device name. */
-	dev_name = get_device_name(line);
-	if (dev_name == NULL)
+	fun_name = get_device_name(line);
+	if (fun_name == NULL)
 		return NULL;
 
-	device_t *dev = create_isa_child_dev();
-	if (dev == NULL) {
-		free(dev_name);
+	isa_fun_t *fun = isa_fun_create(dev, fun_name);
+	if (fun == NULL) {
+		free(fun_name);
 		return NULL;
 	}
 
-	dev->name = dev_name;
-
 	/* Allocate buffer for the list of hardware resources of the device. */
-	child_alloc_hw_res(dev);
+	fun_hw_res_alloc(fun);
 
 	/* Get properties of the device (match ids, irq and io range). */
 	while (true) {
-		line = str_get_line(dev_conf, &dev_conf);
+		line = str_get_line(fun_conf, &fun_conf);
 
 		if (line_empty(line)) {
@@ -454,46 +433,58 @@
 		 * and store it in the device structure.
 		 */
-		get_dev_prop(dev, line);
-
-		//printf(NAME ": next line ='%s'\n", dev_conf);
-		//printf(NAME ": current line ='%s'\n", line);
+		fun_prop_parse(fun, line);
 	}
 
 	/* Set device operations to the device. */
-	dev->ops = &isa_child_dev_ops;
-
-	printf(NAME ": child_device_register(dev, parent); device is %s.\n",
-	    dev->name);
-	child_device_register(dev, parent);
-
-	return dev_conf;
-}
-
-static void parse_dev_conf(char *conf, device_t *parent)
+	fun->fnode->ops = &isa_fun_ops;
+
+	printf(NAME ": Binding function %s.\n", fun->fnode->name);
+
+	/* XXX Handle error */
+	(void) ddf_fun_bind(fun->fnode);
+
+	return fun_conf;
+}
+
+static void fun_conf_parse(char *conf, ddf_dev_t *dev)
 {
 	while (conf != NULL && *conf != '\0') {
-		conf = read_isa_dev_info(conf, parent);
-	}
-}
-
-static void add_legacy_children(device_t *parent)
-{
-	char *dev_conf;
-
-	dev_conf = read_dev_conf(CHILD_DEV_CONF_PATH);
-	if (dev_conf != NULL) {
-		parse_dev_conf(dev_conf, parent);
-		free(dev_conf);
-	}
-}
-
-static int isa_add_device(device_t *dev)
+		conf = isa_fun_read_info(conf, dev);
+	}
+}
+
+static void isa_functions_add(ddf_dev_t *dev)
+{
+	char *fun_conf;
+
+	fun_conf = fun_conf_read(CHILD_FUN_CONF_PATH);
+	if (fun_conf != NULL) {
+		fun_conf_parse(fun_conf, dev);
+		free(fun_conf);
+	}
+}
+
+static int isa_add_device(ddf_dev_t *dev)
 {
 	printf(NAME ": isa_add_device, device handle = %d\n",
 	    (int) dev->handle);
 
-	/* Add child devices. */
-	add_legacy_children(dev);
-	printf(NAME ": finished the enumeration of legacy devices\n");
+	/* Make the bus device more visible. Does not do anything. */
+	printf(NAME ": adding a 'ctl' function\n");
+
+	ddf_fun_t *ctl = ddf_fun_create(dev, fun_exposed, "ctl");
+	if (ctl == NULL) {
+		printf(NAME ": Error creating control function.\n");
+		return EXDEV;
+	}
+
+	if (ddf_fun_bind(ctl) != EOK) {
+		printf(NAME ": Error binding control function.\n");
+		return EXDEV;
+	}
+
+	/* Add functions as specified in the configuration file. */
+	isa_functions_add(dev);
+	printf(NAME ": finished the enumeration of legacy functions\n");
 
 	return EOK;
@@ -502,5 +493,5 @@
 static void isa_init() 
 {
-	isa_child_dev_ops.interfaces[HW_RES_DEV_IFACE] = &isa_child_hw_res_ops;
+	isa_fun_ops.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops;
 }
 
@@ -509,5 +500,5 @@
 	printf(NAME ": HelenOS ISA bus driver\n");
 	isa_init();
-	return driver_main(&isa_driver);
+	return ddf_driver_main(&isa_driver);
 }
 
@@ -515,3 +506,2 @@
  * @}
  */
- 
Index: uspace/drv/ns8250/ns8250.c
===================================================================
--- uspace/drv/ns8250/ns8250.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/ns8250/ns8250.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -52,5 +53,6 @@
 #include <libarch/ddi.h>
 
-#include <driver.h>
+#include <ddf/driver.h>
+#include <ddf/interrupt.h>
 #include <ops/char_dev.h>
 
@@ -67,4 +69,10 @@
 #define MAX_BAUD_RATE 115200
 #define DLAB_MASK (1 << 7)
+
+/** Obtain soft-state structure from function node */
+#define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data))
+
+/** Obtain soft-state structure from device node */
+#define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data))
 
 /** The number of bits of one data unit send by the serial port. */
@@ -85,5 +93,9 @@
 
 /** The driver data for the serial port devices. */
-typedef struct ns8250_dev_data {
+typedef struct ns8250 {
+	/** DDF device node */
+	ddf_dev_t *dev;
+	/** DDF function node */
+	ddf_fun_t *fun;
 	/** Is there any client conntected to the device? */
 	bool client_connected;
@@ -98,30 +110,30 @@
 	/** The fibril mutex for synchronizing the access to the device. */
 	fibril_mutex_t mutex;
-} ns8250_dev_data_t;
-
-/** Create driver data for a device.
- *
- * @return		The driver data.
- */
-static ns8250_dev_data_t *create_ns8250_dev_data(void)
-{
-	ns8250_dev_data_t *data;
-	
-	data = (ns8250_dev_data_t *) malloc(sizeof(ns8250_dev_data_t));
-	if (NULL != data) {
-		memset(data, 0, sizeof(ns8250_dev_data_t));
-		fibril_mutex_initialize(&data->mutex);
-	}
-	return data;
-}
-
-/** Delete driver data.
- *
- * @param data		The driver data structure.
- */
-static void delete_ns8250_dev_data(ns8250_dev_data_t *data)
-{
-	if (data != NULL)
-		free(data);
+} ns8250_t;
+
+/** Create per-device soft-state structure.
+ *
+ * @return	Pointer to soft-state structure.
+ */
+static ns8250_t *ns8250_new(void)
+{
+	ns8250_t *ns;
+	
+	ns = (ns8250_t *) calloc(1, sizeof(ns8250_t));
+	if (ns == NULL)
+		return NULL;
+	
+	fibril_mutex_initialize(&ns->mutex);
+	return ns;
+}
+
+/** Delete soft-state structure.
+ *
+ * @param ns	The driver data structure.
+ */
+static void ns8250_delete(ns8250_t *ns)
+{
+	assert(ns != NULL);
+	free(ns);
 }
 
@@ -171,5 +183,5 @@
 /** Read data from the serial port device.
  *
- * @param dev		The serial port device.
+ * @param fun		The serial port function
  * @param buf		The ouput buffer for read data.
  * @param count		The number of bytes to be read.
@@ -178,15 +190,15 @@
  *			error number otherwise.
  */
-static int ns8250_read(device_t *dev, char *buf, size_t count)
-{
+static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count)
+{
+	ns8250_t *ns = NS8250(fun);
 	int ret = EOK;
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
-	
-	fibril_mutex_lock(&data->mutex);
-	while (!buf_is_empty(&data->input_buffer) && (size_t)ret < count) {
-		buf[ret] = (char)buf_pop_front(&data->input_buffer);
+	
+	fibril_mutex_lock(&ns->mutex);
+	while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
+		buf[ret] = (char)buf_pop_front(&ns->input_buffer);
 		ret++;
 	}
-	fibril_mutex_unlock(&data->mutex);
+	fibril_mutex_unlock(&ns->mutex);
 	
 	return ret;
@@ -195,33 +207,33 @@
 /** Write a character to the serial port.
  *
- * @param data		The serial port device's driver data.
- * @param c		The character to be written.
- */
-static inline void ns8250_putchar(ns8250_dev_data_t *data, uint8_t c)
-{
-	fibril_mutex_lock(&data->mutex);
-	ns8250_write_8(data->port, c);
-	fibril_mutex_unlock(&data->mutex);
+ * @param ns		Serial port device
+ * @param c		The character to be written
+ */
+static inline void ns8250_putchar(ns8250_t *ns, uint8_t c)
+{
+	fibril_mutex_lock(&ns->mutex);
+	ns8250_write_8(ns->port, c);
+	fibril_mutex_unlock(&ns->mutex);
 }
 
 /** Write data to the serial port.
  *
- * @param dev		The serial port device.
- * @param buf		The data to be written.
- * @param count		The number of bytes to be written.
- * @return		Zero on success.
- */
-static int ns8250_write(device_t *dev, char *buf, size_t count) 
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
+ * @param fun		The serial port function
+ * @param buf		The data to be written
+ * @param count		The number of bytes to be written
+ * @return		Zero on success
+ */
+static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count)
+{
+	ns8250_t *ns = NS8250(fun);
 	size_t idx;
 	
 	for (idx = 0; idx < count; idx++)
-		ns8250_putchar(data, (uint8_t) buf[idx]);
+		ns8250_putchar(ns, (uint8_t) buf[idx]);
 	
 	return 0;
 }
 
-static device_ops_t ns8250_dev_ops;
+static ddf_dev_ops_t ns8250_dev_ops;
 
 /** The character interface's callbacks. */
@@ -231,5 +243,5 @@
 };
 
-static int ns8250_add_device(device_t *dev);
+static int ns8250_add_device(ddf_dev_t *dev);
 
 /** The serial port device driver's standard operations. */
@@ -244,18 +256,13 @@
 };
 
-/** Clean up the serial port device structure.
- *
- * @param dev		The device structure.
- */
-static void ns8250_dev_cleanup(device_t *dev)
-{
-	if (dev->driver_data != NULL) {
-		delete_ns8250_dev_data((ns8250_dev_data_t*) dev->driver_data);
-		dev->driver_data = NULL;
-	}
-	
-	if (dev->parent_phone > 0) {
-		async_hangup(dev->parent_phone);
-		dev->parent_phone = 0;
+/** Clean up the serial port soft-state
+ *
+ * @param ns		Serial port device
+ */
+static void ns8250_dev_cleanup(ns8250_t *ns)
+{
+	if (ns->dev->parent_phone > 0) {
+		async_hangup(ns->dev->parent_phone);
+		ns->dev->parent_phone = 0;
 	}
 }
@@ -263,18 +270,16 @@
 /** Enable the i/o ports of the device.
  *
- * @param dev		The serial port device.
- * @return		True on success, false otherwise.
- */
-static bool ns8250_pio_enable(device_t *dev)
-{
-	printf(NAME ": ns8250_pio_enable %s\n", dev->name);
-	
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;
+ * @param ns		Serial port device
+ * @return		True on success, false otherwise
+ */
+static bool ns8250_pio_enable(ns8250_t *ns)
+{
+	printf(NAME ": ns8250_pio_enable %s\n", ns->dev->name);
 	
 	/* Gain control over port's registers. */
-	if (pio_enable((void *)(uintptr_t) data->io_addr, REG_COUNT,
-	    (void **) &data->port)) {
+	if (pio_enable((void *)(uintptr_t) ns->io_addr, REG_COUNT,
+	    (void **) &ns->port)) {
 		printf(NAME ": error - cannot gain the port %#" PRIx32 " for device "
-		    "%s.\n", data->io_addr, dev->name);
+		    "%s.\n", ns->io_addr, ns->dev->name);
 		return false;
 	}
@@ -285,13 +290,12 @@
 /** Probe the serial port device for its presence.
  *
- * @param dev		The serial port device.
- * @return		True if the device is present, false otherwise.
- */
-static bool ns8250_dev_probe(device_t *dev)
-{
-	printf(NAME ": ns8250_dev_probe %s\n", dev->name);
-	
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
-	ioport8_t *port_addr = data->port;
+ * @param ns		Serial port device
+ * @return		True if the device is present, false otherwise
+ */
+static bool ns8250_dev_probe(ns8250_t *ns)
+{
+	printf(NAME ": ns8250_dev_probe %s\n", ns->dev->name);
+	
+	ioport8_t *port_addr = ns->port;
 	bool res = true;
 	uint8_t olddata;
@@ -310,5 +314,5 @@
 	
 	if (!res)
-		printf(NAME ": device %s is not present.\n", dev->name);
+		printf(NAME ": device %s is not present.\n", ns->dev->name);
 	
 	return res;
@@ -317,10 +321,10 @@
 /** Initialize serial port device.
  *
- * @param dev		The serial port device.
- * @return		Zero on success, negative error number otherwise.
- */
-static int ns8250_dev_initialize(device_t *dev)
-{
-	printf(NAME ": ns8250_dev_initialize %s\n", dev->name);
+ * @param ns		Serial port device
+ * @return		Zero on success, negative error number otherwise
+ */
+static int ns8250_dev_initialize(ns8250_t *ns)
+{
+	printf(NAME ": ns8250_dev_initialize %s\n", ns->dev->name);
 	
 	int ret = EOK;
@@ -329,25 +333,19 @@
 	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
 	
-	/* Allocate driver data for the device. */
-	ns8250_dev_data_t *data = create_ns8250_dev_data();
-	if (data == NULL)
-		return ENOMEM;
-	dev->driver_data = data;
-	
 	/* Connect to the parent's driver. */
-	dev->parent_phone = devman_parent_device_connect(dev->handle,
+	ns->dev->parent_phone = devman_parent_device_connect(ns->dev->handle,
 	    IPC_FLAG_BLOCKING);
-	if (dev->parent_phone < 0) {
+	if (ns->dev->parent_phone < 0) {
 		printf(NAME ": failed to connect to the parent driver of the "
-		    "device %s.\n", dev->name);
-		ret = dev->parent_phone;
+		    "device %s.\n", ns->dev->name);
+		ret = ns->dev->parent_phone;
 		goto failed;
 	}
 	
 	/* Get hw resources. */
-	ret = hw_res_get_resource_list(dev->parent_phone, &hw_resources);
+	ret = hw_res_get_resource_list(ns->dev->parent_phone, &hw_resources);
 	if (ret != EOK) {
 		printf(NAME ": failed to get hw resources for the device "
-		    "%s.\n", dev->name);
+		    "%s.\n", ns->dev->name);
 		goto failed;
 	}
@@ -362,15 +360,15 @@
 		switch (res->type) {
 		case INTERRUPT:
-			data->irq = res->res.interrupt.irq;
+			ns->irq = res->res.interrupt.irq;
 			irq = true;
 			printf(NAME ": the %s device was asigned irq = 0x%x.\n",
-			    dev->name, data->irq);
+			    ns->dev->name, ns->irq);
 			break;
 			
 		case IO_RANGE:
-			data->io_addr = res->res.io_range.address;
+			ns->io_addr = res->res.io_range.address;
 			if (res->res.io_range.size < REG_COUNT) {
 				printf(NAME ": i/o range assigned to the device "
-				    "%s is too small.\n", dev->name);
+				    "%s is too small.\n", ns->dev->name);
 				ret = ELIMIT;
 				goto failed;
@@ -378,5 +376,5 @@
 			ioport = true;
 			printf(NAME ": the %s device was asigned i/o address = "
-			    "0x%x.\n", dev->name, data->io_addr);
+			    "0x%x.\n", ns->dev->name, ns->io_addr);
 			break;
 			
@@ -388,5 +386,5 @@
 	if (!irq || !ioport) {
 		printf(NAME ": missing hw resource(s) for the device %s.\n",
-		    dev->name);
+		    ns->dev->name);
 		ret = ENOENT;
 		goto failed;
@@ -397,5 +395,5 @@
 	
 failed:
-	ns8250_dev_cleanup(dev);
+	ns8250_dev_cleanup(ns);
 	hw_res_clean_resource_list(&hw_resources);
 	return ret;
@@ -404,10 +402,10 @@
 /** Enable interrupts on the serial port device.
  *
- * Interrupt when data is received.
+ * Interrupt when data is received
  *
  * @param port		The base address of the serial port device's ports.
  */
 static inline void ns8250_port_interrupts_enable(ioport8_t *port)
-{	
+{
 	pio_write_8(port + 1, 0x1);	/* Interrupt when data received. */
 	pio_write_8(port + 4, 0xB);
@@ -416,5 +414,5 @@
 /** Disable interrupts on the serial port device.
  *
- * @param port		The base address of the serial port device's ports.
+ * @param port		The base address of the serial port device's ports
  */
 static inline void ns8250_port_interrupts_disable(ioport8_t *port)
@@ -425,13 +423,11 @@
 /** Enable interrupts for the serial port device.
  *
- * @param dev		The device.
- * @return		Zero on success, negative error number otherwise.
- */
-static int ns8250_interrupt_enable(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
-	
+ * @param ns		Serial port device
+ * @return		Zero on success, negative error number otherwise
+ */
+static int ns8250_interrupt_enable(ns8250_t *ns)
+{
 	/* Enable interrupt on the serial port. */
-	ns8250_port_interrupts_enable(data->port);
+	ns8250_port_interrupts_enable(ns->port);
 	
 	return EOK;
@@ -618,10 +614,9 @@
  * Set the default parameters of the serial communication.
  *
- * @param dev		The serial port device.
- */
-static void ns8250_initialize_port(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *)dev->driver_data;
-	ioport8_t *port = data->port;
+ * @param ns		Serial port device
+ */
+static void ns8250_initialize_port(ns8250_t *ns)
+{
+	ioport8_t *port = ns->port;
 	
 	/* Disable interrupts. */
@@ -643,14 +638,13 @@
  * buffer.
  *
- * @param dev		The serial port device.
- */
-static void ns8250_read_from_device(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
-	ioport8_t *port = data->port;
+ * @param ns		Serial port device
+ */
+static void ns8250_read_from_device(ns8250_t *ns)
+{
+	ioport8_t *port = ns->port;
 	bool cont = true;
 	
 	while (cont) {
-		fibril_mutex_lock(&data->mutex);
+		fibril_mutex_lock(&ns->mutex);
 		
 		cont = ns8250_received(port);
@@ -658,17 +652,17 @@
 			uint8_t val = ns8250_read_8(port);
 			
-			if (data->client_connected) {
-				if (!buf_push_back(&data->input_buffer, val)) {
+			if (ns->client_connected) {
+				if (!buf_push_back(&ns->input_buffer, val)) {
 					printf(NAME ": buffer overflow on "
-					    "%s.\n", dev->name);
+					    "%s.\n", ns->dev->name);
 				} else {
 					printf(NAME ": the character %c saved "
 					    "to the buffer of %s.\n",
-					    val, dev->name);
+					    val, ns->dev->name);
 				}
 			}
 		}
 		
-		fibril_mutex_unlock(&data->mutex);
+		fibril_mutex_unlock(&ns->mutex);
 		fibril_yield();
 	}
@@ -682,83 +676,107 @@
  * @param dev		The serial port device.
  */
-static inline void ns8250_interrupt_handler(device_t *dev, ipc_callid_t iid,
+static inline void ns8250_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
     ipc_call_t *icall)
 {
-	ns8250_read_from_device(dev);
+	ns8250_read_from_device(NS8250_FROM_DEV(dev));
 }
 
 /** Register the interrupt handler for the device.
  *
+ * @param ns		Serial port device
+ */
+static inline int ns8250_register_interrupt_handler(ns8250_t *ns)
+{
+	return register_interrupt_handler(ns->dev, ns->irq,
+	    ns8250_interrupt_handler, NULL);
+}
+
+/** Unregister the interrupt handler for the device.
+ *
+ * @param ns		Serial port device
+ */
+static inline int ns8250_unregister_interrupt_handler(ns8250_t *ns)
+{
+	return unregister_interrupt_handler(ns->dev, ns->irq);
+}
+
+/** The add_device callback method of the serial port driver.
+ *
+ * Probe and initialize the newly added device.
+ *
  * @param dev		The serial port device.
  */
-static inline int ns8250_register_interrupt_handler(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
-	
-	return register_interrupt_handler(dev, data->irq,
-	    ns8250_interrupt_handler, NULL);
-}
-
-/** Unregister the interrupt handler for the device.
- *
- * @param dev		The serial port device.
- */
-static inline int ns8250_unregister_interrupt_handler(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
-	
-	return unregister_interrupt_handler(dev, data->irq);
-}
-
-/** The add_device callback method of the serial port driver.
- *
- * Probe and initialize the newly added device.
- *
- * @param dev		The serial port device.
- */
-static int ns8250_add_device(device_t *dev)
-{
+static int ns8250_add_device(ddf_dev_t *dev)
+{
+	ns8250_t *ns = NULL;
+	ddf_fun_t *fun = NULL;
+	bool need_cleanup = false;
+	int rc;
+	
 	printf(NAME ": ns8250_add_device %s (handle = %d)\n",
 	    dev->name, (int) dev->handle);
 	
-	int res = ns8250_dev_initialize(dev);
-	if (res != EOK)
-		return res;
-	
-	if (!ns8250_pio_enable(dev)) {
-		ns8250_dev_cleanup(dev);
-		return EADDRNOTAVAIL;
+	/* Allocate soft-state for the device */
+	ns = ns8250_new();
+	if (ns == NULL) {
+		rc = ENOMEM;
+		goto fail;
+	}
+	
+	ns->dev = dev;
+	dev->driver_data = ns;
+	
+	rc = ns8250_dev_initialize(ns);
+	if (rc != EOK)
+		goto fail;
+	
+	need_cleanup = true;
+	
+	if (!ns8250_pio_enable(ns)) {
+		rc = EADDRNOTAVAIL;
+		goto fail;
 	}
 	
 	/* Find out whether the device is present. */
-	if (!ns8250_dev_probe(dev)) {
-		ns8250_dev_cleanup(dev);
-		return ENOENT;
+	if (!ns8250_dev_probe(ns)) {
+		rc = ENOENT;
+		goto fail;
 	}
 	
 	/* Serial port initialization (baud rate etc.). */
-	ns8250_initialize_port(dev);
+	ns8250_initialize_port(ns);
 	
 	/* Register interrupt handler. */
-	if (ns8250_register_interrupt_handler(dev) != EOK) {
+	if (ns8250_register_interrupt_handler(ns) != EOK) {
 		printf(NAME ": failed to register interrupt handler.\n");
-		ns8250_dev_cleanup(dev);
-		return res;
+		rc = EADDRNOTAVAIL;
+		goto fail;
 	}
 	
 	/* Enable interrupt. */
-	res = ns8250_interrupt_enable(dev);
-	if (res != EOK) {
+	rc = ns8250_interrupt_enable(ns);
+	if (rc != EOK) {
 		printf(NAME ": failed to enable the interrupt. Error code = "
-		    "%d.\n", res);
-		ns8250_dev_cleanup(dev);
-		ns8250_unregister_interrupt_handler(dev);
-		return res;
+		    "%d.\n", rc);
+		goto fail;
+	}
+	
+	fun = ddf_fun_create(dev, fun_exposed, "a");
+	if (fun == NULL) {
+		printf(NAME ": error creating function.\n");
+		goto fail;
 	}
 	
 	/* Set device operations. */
-	dev->ops = &ns8250_dev_ops;
-	
-	add_device_to_class(dev, "serial");
+	fun->ops = &ns8250_dev_ops;
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		printf(NAME ": error binding function.\n");
+		goto fail;
+	}
+
+	ns->fun = fun;
+	
+	ddf_fun_add_to_class(fun, "serial");
 	
 	printf(NAME ": the %s device has been successfully initialized.\n",
@@ -766,4 +784,12 @@
 	
 	return EOK;
+fail:
+	if (fun != NULL)
+		ddf_fun_destroy(fun);
+	if (need_cleanup)
+		ns8250_dev_cleanup(ns);
+	if (ns != NULL)
+		ns8250_delete(ns);
+	return rc;
 }
 
@@ -775,7 +801,7 @@
  * @param dev		The device.
  */
-static int ns8250_open(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
+static int ns8250_open(ddf_fun_t *fun)
+{
+	ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
 	int res;
 	
@@ -788,5 +814,5 @@
 	}
 	fibril_mutex_unlock(&data->mutex);
-
+	
 	return res;
 }
@@ -799,7 +825,7 @@
  * @param dev		The device.
  */
-static void ns8250_close(device_t *dev)
-{
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
+static void ns8250_close(ddf_fun_t *fun)
+{
+	ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
 	
 	fibril_mutex_lock(&data->mutex);
@@ -823,8 +849,8 @@
  */
 static void
-ns8250_get_props(device_t *dev, unsigned int *baud_rate, unsigned int *parity,
+ns8250_get_props(ddf_dev_t *dev, unsigned int *baud_rate, unsigned int *parity,
     unsigned int *word_length, unsigned int* stop_bits)
 {
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
+	ns8250_t *data = (ns8250_t *) dev->driver_data;
 	ioport8_t *port = data->port;
 	
@@ -850,5 +876,5 @@
  * @param stop_bits	The number of stop bits to be used.
  */
-static int ns8250_set_props(device_t *dev, unsigned int baud_rate,
+static int ns8250_set_props(ddf_dev_t *dev, unsigned int baud_rate,
     unsigned int parity, unsigned int word_length, unsigned int stop_bits)
 {
@@ -857,5 +883,5 @@
 	    stop_bits);
 	
-	ns8250_dev_data_t *data = (ns8250_dev_data_t *) dev->driver_data;
+	ns8250_t *data = (ns8250_t *) dev->driver_data;
 	ioport8_t *port = data->port;
 	int ret;
@@ -877,5 +903,5 @@
  * Configure the parameters of the serial communication.
  */
-static void ns8250_default_handler(device_t *dev, ipc_callid_t callid,
+static void ns8250_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
     ipc_call_t *call)
 {
@@ -886,5 +912,5 @@
 	switch (method) {
 	case SERIAL_GET_COM_PROPS:
-		ns8250_get_props(dev, &baud_rate, &parity, &word_length,
+		ns8250_get_props(fun->dev, &baud_rate, &parity, &word_length,
 		    &stop_bits);
 		async_answer_4(callid, EOK, baud_rate, parity, word_length,
@@ -897,5 +923,5 @@
 		word_length = IPC_GET_ARG3(*call);
 		stop_bits = IPC_GET_ARG4(*call);
-		ret = ns8250_set_props(dev, baud_rate, parity, word_length,
+		ret = ns8250_set_props(fun->dev, baud_rate, parity, word_length,
 		    stop_bits);
 		async_answer_0(callid, ret);
@@ -925,5 +951,5 @@
 	printf(NAME ": HelenOS serial port driver\n");
 	ns8250_init();
-	return driver_main(&ns8250_driver);
+	return ddf_driver_main(&ns8250_driver);
 }
 
Index: uspace/drv/pciintel/pci.c
===================================================================
--- uspace/drv/pciintel/pci.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/pciintel/pci.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -44,6 +45,7 @@
 #include <ctype.h>
 #include <macros.h>
-
-#include <driver.h>
+#include <str_error.h>
+
+#include <ddf/driver.h>
 #include <devman.h>
 #include <ipc/devman.h>
@@ -61,14 +63,23 @@
 	((1 << 31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
-static hw_resource_list_t *pciintel_get_child_resources(device_t *dev)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	
-	if (dev_data == NULL)
+/** Obtain PCI function soft-state from DDF function node */
+#define PCI_FUN(fnode) ((pci_fun_t *) (fnode)->driver_data)
+
+/** Obtain PCI bus soft-state from DDF device node */
+#define PCI_BUS(dnode) ((pci_bus_t *) (dnode)->driver_data)
+
+/** Obtain PCI bus soft-state from function soft-state */
+#define PCI_BUS_FROM_FUN(fun) ((fun)->busptr)
+
+static hw_resource_list_t *pciintel_get_resources(ddf_fun_t *fnode)
+{
+	pci_fun_t *fun = PCI_FUN(fnode);
+	
+	if (fun == NULL)
 		return NULL;
-	return &dev_data->hw_resources;
-}
-
-static bool pciintel_enable_child_interrupt(device_t *dev)
+	return &fun->hw_resources;
+}
+
+static bool pciintel_enable_interrupt(ddf_fun_t *fnode)
 {
 	/* TODO */
@@ -77,19 +88,19 @@
 }
 
-static hw_res_ops_t pciintel_child_hw_res_ops = {
-	&pciintel_get_child_resources,
-	&pciintel_enable_child_interrupt
+static hw_res_ops_t pciintel_hw_res_ops = {
+	&pciintel_get_resources,
+	&pciintel_enable_interrupt
 };
 
-static device_ops_t pci_child_ops;
-
-static int pci_add_device(device_t *);
-
-/** The pci bus driver's standard operations. */
+static ddf_dev_ops_t pci_fun_ops;
+
+static int pci_add_device(ddf_dev_t *);
+
+/** PCI bus driver standard operations */
 static driver_ops_t pci_ops = {
 	.add_device = &pci_add_device
 };
 
-/** The pci bus driver structure. */
+/** PCI bus driver structure */
 static driver_t pci_driver = {
 	.name = NAME,
@@ -97,43 +108,33 @@
 };
 
-typedef struct pciintel_bus_data {
-	uint32_t conf_io_addr;
-	void *conf_data_port;
-	void *conf_addr_port;
-	fibril_mutex_t conf_mutex;
-} pci_bus_data_t;
-
-static pci_bus_data_t *create_pci_bus_data(void)
-{
-	pci_bus_data_t *bus_data;
-	
-	bus_data = (pci_bus_data_t *) malloc(sizeof(pci_bus_data_t));
-	if (bus_data != NULL) {
-		memset(bus_data, 0, sizeof(pci_bus_data_t));
-		fibril_mutex_initialize(&bus_data->conf_mutex);
-	}
-
-	return bus_data;
-}
-
-static void delete_pci_bus_data(pci_bus_data_t *bus_data)
-{
-	free(bus_data);
-}
-
-static void pci_conf_read(device_t *dev, int reg, uint8_t *buf, size_t len)
-{
-	assert(dev->parent != NULL);
-	
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	pci_bus_data_t *bus_data = (pci_bus_data_t *) dev->parent->driver_data;
-	
-	fibril_mutex_lock(&bus_data->conf_mutex);
+static pci_bus_t *pci_bus_new(void)
+{
+	pci_bus_t *bus;
+	
+	bus = (pci_bus_t *) calloc(1, sizeof(pci_bus_t));
+	if (bus == NULL)
+		return NULL;
+	
+	fibril_mutex_initialize(&bus->conf_mutex);
+	return bus;
+}
+
+static void pci_bus_delete(pci_bus_t *bus)
+{
+	assert(bus != NULL);
+	free(bus);
+}
+
+static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
+{
+	pci_bus_t *bus = PCI_BUS_FROM_FUN(fun);
+	
+	fibril_mutex_lock(&bus->conf_mutex);
 	
 	uint32_t conf_addr;
-	conf_addr = CONF_ADDR(dev_data->bus, dev_data->dev, dev_data->fn, reg);
-	void *addr = bus_data->conf_data_port + (reg & 3);
-	
-	pio_write_32(bus_data->conf_addr_port, conf_addr);
+	conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
+	void *addr = bus->conf_data_port + (reg & 3);
+	
+	pio_write_32(bus->conf_addr_port, conf_addr);
 	
 	switch (len) {
@@ -149,21 +150,18 @@
 	}
 	
-	fibril_mutex_unlock(&bus_data->conf_mutex);
-}
-
-static void pci_conf_write(device_t *dev, int reg, uint8_t *buf, size_t len)
-{
-	assert(dev->parent != NULL);
-	
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	pci_bus_data_t *bus_data = (pci_bus_data_t *) dev->parent->driver_data;
-	
-	fibril_mutex_lock(&bus_data->conf_mutex);
+	fibril_mutex_unlock(&bus->conf_mutex);
+}
+
+static void pci_conf_write(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
+{
+	pci_bus_t *bus = PCI_BUS_FROM_FUN(fun);
+	
+	fibril_mutex_lock(&bus->conf_mutex);
 	
 	uint32_t conf_addr;
-	conf_addr = CONF_ADDR(dev_data->bus, dev_data->dev, dev_data->fn, reg);
-	void *addr = bus_data->conf_data_port + (reg & 3);
-	
-	pio_write_32(bus_data->conf_addr_port, conf_addr);
+	conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
+	void *addr = bus->conf_data_port + (reg & 3);
+	
+	pio_write_32(bus->conf_addr_port, conf_addr);
 	
 	switch (len) {
@@ -179,66 +177,69 @@
 	}
 	
-	fibril_mutex_unlock(&bus_data->conf_mutex);
-}
-
-uint8_t pci_conf_read_8(device_t *dev, int reg)
+	fibril_mutex_unlock(&bus->conf_mutex);
+}
+
+uint8_t pci_conf_read_8(pci_fun_t *fun, int reg)
 {
 	uint8_t res;
-	pci_conf_read(dev, reg, &res, 1);
+	pci_conf_read(fun, reg, &res, 1);
 	return res;
 }
 
-uint16_t pci_conf_read_16(device_t *dev, int reg)
+uint16_t pci_conf_read_16(pci_fun_t *fun, int reg)
 {
 	uint16_t res;
-	pci_conf_read(dev, reg, (uint8_t *) &res, 2);
+	pci_conf_read(fun, reg, (uint8_t *) &res, 2);
 	return res;
 }
 
-uint32_t pci_conf_read_32(device_t *dev, int reg)
+uint32_t pci_conf_read_32(pci_fun_t *fun, int reg)
 {
 	uint32_t res;
-	pci_conf_read(dev, reg, (uint8_t *) &res, 4);
+	pci_conf_read(fun, reg, (uint8_t *) &res, 4);
 	return res;
 }
 
-void pci_conf_write_8(device_t *dev, int reg, uint8_t val)
-{
-	pci_conf_write(dev, reg, (uint8_t *) &val, 1);
-}
-
-void pci_conf_write_16(device_t *dev, int reg, uint16_t val)
-{
-	pci_conf_write(dev, reg, (uint8_t *) &val, 2);
-}
-
-void pci_conf_write_32(device_t *dev, int reg, uint32_t val)
-{
-	pci_conf_write(dev, reg, (uint8_t *) &val, 4);
-}
-
-void create_pci_match_ids(device_t *dev)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	match_id_t *match_id = NULL;
+void pci_conf_write_8(pci_fun_t *fun, int reg, uint8_t val)
+{
+	pci_conf_write(fun, reg, (uint8_t *) &val, 1);
+}
+
+void pci_conf_write_16(pci_fun_t *fun, int reg, uint16_t val)
+{
+	pci_conf_write(fun, reg, (uint8_t *) &val, 2);
+}
+
+void pci_conf_write_32(pci_fun_t *fun, int reg, uint32_t val)
+{
+	pci_conf_write(fun, reg, (uint8_t *) &val, 4);
+}
+
+void pci_fun_create_match_ids(pci_fun_t *fun)
+{
 	char *match_id_str;
-	
-	match_id = create_match_id();
-	if (match_id != NULL) {
-		asprintf(&match_id_str, "pci/ven=%04x&dev=%04x",
-		    dev_data->vendor_id, dev_data->device_id);
-		match_id->id = match_id_str;
-		match_id->score = 90;
-		add_match_id(&dev->match_ids, match_id);
-	}
-
+	int rc;
+	
+	asprintf(&match_id_str, "pci/ven=%04x&dev=%04x",
+	    fun->vendor_id, fun->device_id);
+
+	if (match_id_str == NULL) {
+		printf(NAME ": out of memory creating match ID.\n");
+		return;
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
+	if (rc != EOK) {
+		printf(NAME ": error adding match ID: %s\n",
+		    str_error(rc));
+	}
+	
 	/* TODO add more ids (with subsys ids, using class id etc.) */
 }
 
-void
-pci_add_range(device_t *dev, uint64_t range_addr, size_t range_size, bool io)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	hw_resource_list_t *hw_res_list = &dev_data->hw_resources;
+void pci_add_range(pci_fun_t *fun, uint64_t range_addr, size_t range_size,
+    bool io)
+{
+	hw_resource_list_t *hw_res_list = &fun->hw_resources;
 	hw_resource_t *hw_resources =  hw_res_list->resources;
 	size_t count = hw_res_list->count;
@@ -265,11 +266,11 @@
  * address add it to the devices hw resource list.
  *
- * @param dev	The pci device.
+ * @param fun	PCI function
  * @param addr	The address of the BAR in the PCI configuration address space of
- *		the device.
- * @return	The addr the address of the BAR which should be read next.
+ *		the device
+ * @return	The addr the address of the BAR which should be read next
  */
-int pci_read_bar(device_t *dev, int addr)
-{	
+int pci_read_bar(pci_fun_t *fun, int addr)
+{
 	/* Value of the BAR */
 	uint32_t val, mask;
@@ -285,5 +286,5 @@
 	
 	/* Get the value of the BAR. */
-	val = pci_conf_read_32(dev, addr);
+	val = pci_conf_read_32(fun, addr);
 	
 	io = (bool) (val & 1);
@@ -305,15 +306,15 @@
 	
 	/* Get the address mask. */
-	pci_conf_write_32(dev, addr, 0xffffffff);
-	mask = pci_conf_read_32(dev, addr);
+	pci_conf_write_32(fun, addr, 0xffffffff);
+	mask = pci_conf_read_32(fun, addr);
 	
 	/* Restore the original value. */
-	pci_conf_write_32(dev, addr, val);
-	val = pci_conf_read_32(dev, addr);
+	pci_conf_write_32(fun, addr, val);
+	val = pci_conf_read_32(fun, addr);
 	
 	range_size = pci_bar_mask_to_size(mask);
 	
 	if (addrw64) {
-		range_addr = ((uint64_t)pci_conf_read_32(dev, addr + 4) << 32) |
+		range_addr = ((uint64_t)pci_conf_read_32(fun, addr + 4) << 32) |
 		    (val & 0xfffffff0);
 	} else {
@@ -322,10 +323,10 @@
 	
 	if (range_addr != 0) {
-		printf(NAME ": device %s : ", dev->name);
+		printf(NAME ": function %s : ", fun->fnode->name);
 		printf("address = %" PRIx64, range_addr);
 		printf(", size = %x\n", (unsigned int) range_size);
 	}
 	
-	pci_add_range(dev, range_addr, range_size, io);
+	pci_add_range(fun, range_addr, range_size, io);
 	
 	if (addrw64)
@@ -335,8 +336,7 @@
 }
 
-void pci_add_interrupt(device_t *dev, int irq)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	hw_resource_list_t *hw_res_list = &dev_data->hw_resources;
+void pci_add_interrupt(pci_fun_t *fun, int irq)
+{
+	hw_resource_list_t *hw_res_list = &fun->hw_resources;
 	hw_resource_t *hw_resources = hw_res_list->resources;
 	size_t count = hw_res_list->count;
@@ -350,40 +350,40 @@
 	hw_res_list->count++;
 	
-	printf(NAME ": device %s uses irq %x.\n", dev->name, irq);
-}
-
-void pci_read_interrupt(device_t *dev)
-{
-	uint8_t irq = pci_conf_read_8(dev, PCI_BRIDGE_INT_LINE);
+	printf(NAME ": function %s uses irq %x.\n", fun->fnode->name, irq);
+}
+
+void pci_read_interrupt(pci_fun_t *fun)
+{
+	uint8_t irq = pci_conf_read_8(fun, PCI_BRIDGE_INT_LINE);
 	if (irq != 0xff)
-		pci_add_interrupt(dev, irq);
+		pci_add_interrupt(fun, irq);
 }
 
 /** Enumerate (recursively) and register the devices connected to a pci bus.
  *
- * @param parent	The host-to-pci bridge device.
- * @param bus_num	The bus number.
+ * @param bus		Host-to-PCI bridge
+ * @param bus_num	Bus number
  */
-void pci_bus_scan(device_t *parent, int bus_num) 
-{
-	device_t *dev = create_device();
-	pci_dev_data_t *dev_data = create_pci_dev_data();
-	dev->driver_data = dev_data;
-	dev->parent = parent;
+void pci_bus_scan(pci_bus_t *bus, int bus_num) 
+{
+	ddf_fun_t *fnode;
+	pci_fun_t *fun;
 	
 	int child_bus = 0;
 	int dnum, fnum;
 	bool multi;
-	uint8_t header_type; 
+	uint8_t header_type;
+	
+	fun = pci_fun_new(bus);
 	
 	for (dnum = 0; dnum < 32; dnum++) {
 		multi = true;
 		for (fnum = 0; multi && fnum < 8; fnum++) {
-			init_pci_dev_data(dev_data, bus_num, dnum, fnum);
-			dev_data->vendor_id = pci_conf_read_16(dev,
+			pci_fun_init(fun, bus_num, dnum, fnum);
+			fun->vendor_id = pci_conf_read_16(fun,
 			    PCI_VENDOR_ID);
-			dev_data->device_id = pci_conf_read_16(dev,
+			fun->device_id = pci_conf_read_16(fun,
 			    PCI_DEVICE_ID);
-			if (dev_data->vendor_id == 0xffff) {
+			if (fun->vendor_id == 0xffff) {
 				/*
 				 * The device is not present, go on scanning the
@@ -396,5 +396,5 @@
 			}
 			
-			header_type = pci_conf_read_8(dev, PCI_HEADER_TYPE);
+			header_type = pci_conf_read_8(fun, PCI_HEADER_TYPE);
 			if (fnum == 0) {
 				/* Is the device multifunction? */
@@ -404,22 +404,36 @@
 			header_type = header_type & 0x7F;
 			
-			create_pci_dev_name(dev);
-			
-			pci_alloc_resource_list(dev);
-			pci_read_bars(dev);
-			pci_read_interrupt(dev);
-			
-			dev->ops = &pci_child_ops;
-			
-			printf(NAME ": adding new child device %s.\n",
-			    dev->name);
-			
-			create_pci_match_ids(dev);
-			
-			if (child_device_register(dev, parent) != EOK) {
-				pci_clean_resource_list(dev);
-				clean_match_ids(&dev->match_ids);
-				free((char *) dev->name);
-				dev->name = NULL;
+			char *fun_name = pci_fun_create_name(fun);
+			if (fun_name == NULL) {
+				printf(NAME ": out of memory.\n");
+				return;
+			}
+			
+			fnode = ddf_fun_create(bus->dnode, fun_inner, fun_name);
+			if (fnode == NULL) {
+				printf(NAME ": error creating function.\n");
+				return;
+			}
+			
+			free(fun_name);
+			fun->fnode = fnode;
+			
+			pci_alloc_resource_list(fun);
+			pci_read_bars(fun);
+			pci_read_interrupt(fun);
+			
+			fnode->ops = &pci_fun_ops;
+			fnode->driver_data = fun;
+			
+			printf(NAME ": adding new function %s.\n",
+			    fnode->name);
+			
+			pci_fun_create_match_ids(fun);
+			
+			if (ddf_fun_bind(fnode) != EOK) {
+				pci_clean_resource_list(fun);
+				clean_match_ids(&fnode->match_ids);
+				free((char *) fnode->name);
+				fnode->name = NULL;
 				continue;
 			}
@@ -427,58 +441,59 @@
 			if (header_type == PCI_HEADER_TYPE_BRIDGE ||
 			    header_type == PCI_HEADER_TYPE_CARDBUS) {
-				child_bus = pci_conf_read_8(dev,
+				child_bus = pci_conf_read_8(fun,
 				    PCI_BRIDGE_SEC_BUS_NUM);
 				printf(NAME ": device is pci-to-pci bridge, "
 				    "secondary bus number = %d.\n", bus_num);
 				if (child_bus > bus_num)
-					pci_bus_scan(parent, child_bus);
+					pci_bus_scan(bus, child_bus);
 			}
 			
-			/* Alloc new aux. dev. structure. */
-			dev = create_device();
-			dev_data = create_pci_dev_data();
-			dev->driver_data = dev_data;
-			dev->parent = parent;
+			fun = pci_fun_new(bus);
 		}
 	}
 	
-	if (dev_data->vendor_id == 0xffff) {
-		delete_device(dev);
-		/* Free the auxiliary device structure. */
-		delete_pci_dev_data(dev_data);
-	}
-}
-
-static int pci_add_device(device_t *dev)
-{
+	if (fun->vendor_id == 0xffff) {
+		/* Free the auxiliary function structure. */
+		pci_fun_delete(fun);
+	}
+}
+
+static int pci_add_device(ddf_dev_t *dnode)
+{
+	pci_bus_t *bus = NULL;
+	ddf_fun_t *ctl = NULL;
+	bool got_res = false;
 	int rc;
-
+	
 	printf(NAME ": pci_add_device\n");
-	
-	pci_bus_data_t *bus_data = create_pci_bus_data();
-	if (bus_data == NULL) {
+	dnode->parent_phone = -1;
+	
+	bus = pci_bus_new();
+	if (bus == NULL) {
 		printf(NAME ": pci_add_device allocation failed.\n");
-		return ENOMEM;
-	}
-	
-	dev->parent_phone = devman_parent_device_connect(dev->handle,
+		rc = ENOMEM;
+		goto fail;
+	}
+	bus->dnode = dnode;
+	dnode->driver_data = bus;
+	
+	dnode->parent_phone = devman_parent_device_connect(dnode->handle,
 	    IPC_FLAG_BLOCKING);
-	if (dev->parent_phone < 0) {
+	if (dnode->parent_phone < 0) {
 		printf(NAME ": pci_add_device failed to connect to the "
 		    "parent's driver.\n");
-		delete_pci_bus_data(bus_data);
-		return dev->parent_phone;
+		rc = dnode->parent_phone;
+		goto fail;
 	}
 	
 	hw_resource_list_t hw_resources;
 	
-	rc = hw_res_get_resource_list(dev->parent_phone, &hw_resources);
+	rc = hw_res_get_resource_list(dnode->parent_phone, &hw_resources);
 	if (rc != EOK) {
 		printf(NAME ": pci_add_device failed to get hw resources for "
 		    "the device.\n");
-		delete_pci_bus_data(bus_data);
-		async_hangup(dev->parent_phone);
-		return rc;
-	}	
+		goto fail;
+	}
+	got_res = true;
 	
 	printf(NAME ": conf_addr = %" PRIx64 ".\n",
@@ -489,92 +504,113 @@
 	assert(hw_resources.resources[0].res.io_range.size == 8);
 	
-	bus_data->conf_io_addr =
+	bus->conf_io_addr =
 	    (uint32_t) hw_resources.resources[0].res.io_range.address;
 	
-	if (pio_enable((void *)(uintptr_t)bus_data->conf_io_addr, 8,
-	    &bus_data->conf_addr_port)) {
+	if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 8,
+	    &bus->conf_addr_port)) {
 		printf(NAME ": failed to enable configuration ports.\n");
-		delete_pci_bus_data(bus_data);
-		async_hangup(dev->parent_phone);
+		rc = EADDRNOTAVAIL;
+		goto fail;
+	}
+	bus->conf_data_port = (char *) bus->conf_addr_port + 4;
+	
+	/* Make the bus device more visible. It has no use yet. */
+	printf(NAME ": adding a 'ctl' function\n");
+	
+	ctl = ddf_fun_create(bus->dnode, fun_exposed, "ctl");
+	if (ctl == NULL) {
+		printf(NAME ": error creating control function.\n");
+		rc = ENOMEM;
+		goto fail;
+	}
+	
+	rc = ddf_fun_bind(ctl);
+	if (rc != EOK) {
+		printf(NAME ": error binding control function.\n");
+		goto fail;
+	}
+	
+	/* Enumerate functions. */
+	printf(NAME ": scanning the bus\n");
+	pci_bus_scan(bus, 0);
+	
+	hw_res_clean_resource_list(&hw_resources);
+	
+	return EOK;
+	
+fail:
+	if (bus != NULL)
+		pci_bus_delete(bus);
+	if (dnode->parent_phone >= 0)
+		async_hangup(dnode->parent_phone);
+	if (got_res)
 		hw_res_clean_resource_list(&hw_resources);
-		return EADDRNOTAVAIL;
-	}
-	bus_data->conf_data_port = (char *) bus_data->conf_addr_port + 4;
-	
-	dev->driver_data = bus_data;
-	
-	/* Enumerate child devices. */
-	printf(NAME ": scanning the bus\n");
-	pci_bus_scan(dev, 0);
-	
-	hw_res_clean_resource_list(&hw_resources);
-	
-	return EOK;
+	if (ctl != NULL)
+		ddf_fun_destroy(ctl);
+
+	return rc;
 }
 
 static void pciintel_init(void)
 {
-	pci_child_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_child_hw_res_ops;
-}
-
-pci_dev_data_t *create_pci_dev_data(void)
-{
-	pci_dev_data_t *res = (pci_dev_data_t *) malloc(sizeof(pci_dev_data_t));
-	
-	if (res != NULL)
-		memset(res, 0, sizeof(pci_dev_data_t));
-	return res;
-}
-
-void init_pci_dev_data(pci_dev_data_t *dev_data, int bus, int dev, int fn)
-{
-	dev_data->bus = bus;
-	dev_data->dev = dev;
-	dev_data->fn = fn;
-}
-
-void delete_pci_dev_data(pci_dev_data_t *dev_data)
-{
-	if (dev_data != NULL) {
-		hw_res_clean_resource_list(&dev_data->hw_resources);
-		free(dev_data);
-	}
-}
-
-void create_pci_dev_name(device_t *dev)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
+	pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
+}
+
+pci_fun_t *pci_fun_new(pci_bus_t *bus)
+{
+	pci_fun_t *fun;
+	
+	fun = (pci_fun_t *) calloc(1, sizeof(pci_fun_t));
+	if (fun == NULL)
+		return NULL;
+
+	fun->busptr = bus;
+	return fun;
+}
+
+void pci_fun_init(pci_fun_t *fun, int bus, int dev, int fn)
+{
+	fun->bus = bus;
+	fun->dev = dev;
+	fun->fn = fn;
+}
+
+void pci_fun_delete(pci_fun_t *fun)
+{
+	assert(fun != NULL);
+	hw_res_clean_resource_list(&fun->hw_resources);
+	free(fun);
+}
+
+char *pci_fun_create_name(pci_fun_t *fun)
+{
 	char *name = NULL;
 	
-	asprintf(&name, "%02x:%02x.%01x", dev_data->bus, dev_data->dev,
-	    dev_data->fn);
-	dev->name = name;
-}
-
-bool pci_alloc_resource_list(device_t *dev)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *)dev->driver_data;
-	
-	dev_data->hw_resources.resources =
+	asprintf(&name, "%02x:%02x.%01x", fun->bus, fun->dev,
+	    fun->fn);
+	return name;
+}
+
+bool pci_alloc_resource_list(pci_fun_t *fun)
+{
+	fun->hw_resources.resources =
 	    (hw_resource_t *) malloc(PCI_MAX_HW_RES * sizeof(hw_resource_t));
-	return dev_data->hw_resources.resources != NULL;
-}
-
-void pci_clean_resource_list(device_t *dev)
-{
-	pci_dev_data_t *dev_data = (pci_dev_data_t *) dev->driver_data;
-	
-	if (dev_data->hw_resources.resources != NULL) {
-		free(dev_data->hw_resources.resources);
-		dev_data->hw_resources.resources = NULL;
-	}
-}
-
-/** Read the base address registers (BARs) of the device and adds the addresses
- * to its hw resource list.
+	return fun->hw_resources.resources != NULL;
+}
+
+void pci_clean_resource_list(pci_fun_t *fun)
+{
+	if (fun->hw_resources.resources != NULL) {
+		free(fun->hw_resources.resources);
+		fun->hw_resources.resources = NULL;
+	}
+}
+
+/** Read the base address registers (BARs) of the function and add the addresses
+ * to its HW resource list.
  *
- * @param dev the pci device.
+ * @param fun	PCI function
  */
-void pci_read_bars(device_t *dev)
+void pci_read_bars(pci_fun_t *fun)
 {
 	/*
@@ -585,5 +621,5 @@
 	
 	while (addr <= PCI_BASE_ADDR_5)
-		addr = pci_read_bar(dev, addr);
+		addr = pci_read_bar(fun, addr);
 }
 
@@ -597,5 +633,5 @@
 	printf(NAME ": HelenOS pci bus driver (intel method 1).\n");
 	pciintel_init();
-	return driver_main(&pci_driver);
+	return ddf_driver_main(&pci_driver);
 }
 
Index: uspace/drv/pciintel/pci.h
===================================================================
--- uspace/drv/pciintel/pci.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/pciintel/pci.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -36,13 +37,22 @@
 #define PCI_H_
 
-#include <stdlib.h>
-#include <driver.h>
-#include <malloc.h>
-
+#include <ddf/driver.h>
 #include "pci_regs.h"
 
 #define PCI_MAX_HW_RES 8
 
-typedef struct pci_dev_data {
+typedef struct pciintel_bus {
+	/** DDF device node */
+	ddf_dev_t *dnode;
+	uint32_t conf_io_addr;
+	void *conf_data_port;
+	void *conf_addr_port;
+	fibril_mutex_t conf_mutex;
+} pci_bus_t;
+
+typedef struct pci_fun_data {
+	pci_bus_t *busptr;
+	ddf_fun_t *fnode;
+
 	int bus;
 	int dev;
@@ -51,31 +61,31 @@
 	int device_id;
 	hw_resource_list_t hw_resources;
-} pci_dev_data_t;
+} pci_fun_t;
 
-extern void create_pci_match_ids(device_t *);
+extern void pci_fun_create_match_ids(pci_fun_t *);
 
-extern uint8_t pci_conf_read_8(device_t *, int);
-extern uint16_t pci_conf_read_16(device_t *, int);
-extern uint32_t pci_conf_read_32(device_t *, int);
-extern void pci_conf_write_8(device_t *, int, uint8_t);
-extern void pci_conf_write_16(device_t *, int, uint16_t);
-extern void pci_conf_write_32(device_t *, int, uint32_t);
+extern uint8_t pci_conf_read_8(pci_fun_t *, int);
+extern uint16_t pci_conf_read_16(pci_fun_t *, int);
+extern uint32_t pci_conf_read_32(pci_fun_t *, int);
+extern void pci_conf_write_8(pci_fun_t *, int, uint8_t);
+extern void pci_conf_write_16(pci_fun_t *, int, uint16_t);
+extern void pci_conf_write_32(pci_fun_t *, int, uint32_t);
 
-extern void pci_add_range(device_t *, uint64_t, size_t, bool);
-extern int pci_read_bar(device_t *, int);
-extern void pci_read_interrupt(device_t *);
-extern void pci_add_interrupt(device_t *, int);
+extern void pci_add_range(pci_fun_t *, uint64_t, size_t, bool);
+extern int pci_read_bar(pci_fun_t *, int);
+extern void pci_read_interrupt(pci_fun_t *);
+extern void pci_add_interrupt(pci_fun_t *, int);
 
-extern void pci_bus_scan(device_t *, int);
+extern pci_fun_t *pci_fun_new(pci_bus_t *);
+extern void pci_fun_init(pci_fun_t *, int, int, int);
+extern void pci_fun_delete(pci_fun_t *);
+extern char *pci_fun_create_name(pci_fun_t *);
 
-extern pci_dev_data_t *create_pci_dev_data(void);
-extern void init_pci_dev_data(pci_dev_data_t *, int, int, int);
-extern void delete_pci_dev_data(pci_dev_data_t *);
-extern void create_pci_dev_name(device_t *);
+extern void pci_bus_scan(pci_bus_t *, int);
 
-extern bool pci_alloc_resource_list(device_t *);
-extern void pci_clean_resource_list(device_t *);
+extern bool pci_alloc_resource_list(pci_fun_t *);
+extern void pci_clean_resource_list(pci_fun_t *);
 
-extern void pci_read_bars(device_t *);
+extern void pci_read_bars(pci_fun_t *);
 extern size_t pci_bar_mask_to_size(uint32_t);
 
Index: uspace/drv/root/root.c
===================================================================
--- uspace/drv/root/root.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/root/root.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -2,4 +2,5 @@
  * Copyright (c) 2010 Lenka Trochtova
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -44,4 +45,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <str_error.h>
 #include <ctype.h>
 #include <macros.h>
@@ -49,5 +51,5 @@
 #include <sysinfo.h>
 
-#include <driver.h>
+#include <ddf/driver.h>
 #include <devman.h>
 #include <ipc/devman.h>
@@ -55,13 +57,13 @@
 #define NAME "root"
 
-#define PLATFORM_DEVICE_NAME "hw"
-#define PLATFORM_DEVICE_MATCH_ID_FMT "platform/%s"
-#define PLATFORM_DEVICE_MATCH_SCORE 100
-
-#define VIRTUAL_DEVICE_NAME "virt"
-#define VIRTUAL_DEVICE_MATCH_ID "rootvirt"
-#define VIRTUAL_DEVICE_MATCH_SCORE 100
-
-static int root_add_device(device_t *dev);
+#define PLATFORM_FUN_NAME "hw"
+#define PLATFORM_FUN_MATCH_ID_FMT "platform/%s"
+#define PLATFORM_FUN_MATCH_SCORE 100
+
+#define VIRTUAL_FUN_NAME "virt"
+#define VIRTUAL_FUN_MATCH_ID "rootvirt"
+#define VIRTUAL_FUN_MATCH_SCORE 100
+
+static int root_add_device(ddf_dev_t *dev);
 
 /** The root device driver's standard operations. */
@@ -76,35 +78,60 @@
 };
 
-/** Create the device which represents the root of virtual device tree.
- *
- * @param parent Parent of the newly created device.
- * @return Error code.
- */
-static int add_virtual_root_child(device_t *parent)
-{
-	printf(NAME ": adding new child for virtual devices.\n");
-	printf(NAME ":   device node is `%s' (%d %s)\n", VIRTUAL_DEVICE_NAME,
-	    VIRTUAL_DEVICE_MATCH_SCORE, VIRTUAL_DEVICE_MATCH_ID);
-
-	int res = child_device_register_wrapper(parent, VIRTUAL_DEVICE_NAME,
-	    VIRTUAL_DEVICE_MATCH_ID, VIRTUAL_DEVICE_MATCH_SCORE);
-
-	return res;
-}
-
-/** Create the device which represents the root of HW device tree.
- *
- * @param parent	Parent of the newly created device.
- * @return 0 on success, negative error number otherwise.
- */
-static int add_platform_child(device_t *parent)
+/** Create the function which represents the root of virtual device tree.
+ *
+ * @param dev	Device
+ * @return	EOK on success or negative error code
+ */
+static int add_virtual_root_fun(ddf_dev_t *dev)
+{
+	const char *name = VIRTUAL_FUN_NAME;
+	ddf_fun_t *fun;
+	int rc;
+
+	printf(NAME ": adding new function for virtual devices.\n");
+	printf(NAME ":   function node is `%s' (%d %s)\n", name,
+	    VIRTUAL_FUN_MATCH_SCORE, VIRTUAL_FUN_MATCH_ID);
+
+	fun = ddf_fun_create(dev, fun_inner, name);
+	if (fun == NULL) {
+		printf(NAME ": error creating function %s\n", name);
+		return ENOMEM;
+	}
+
+	rc = ddf_fun_add_match_id(fun, VIRTUAL_FUN_MATCH_ID,
+	    VIRTUAL_FUN_MATCH_SCORE);
+	if (rc != EOK) {
+		printf(NAME ": error adding match IDs to function %s\n", name);
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		printf(NAME ": error binding function %s: %s\n", name,
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	return EOK;
+}
+
+/** Create the function which represents the root of HW device tree.
+ *
+ * @param dev	Device
+ * @return	EOK on success or negative error code
+ */
+static int add_platform_fun(ddf_dev_t *dev)
 {
 	char *match_id;
 	char *platform;
 	size_t platform_size;
-	int res;
+
+	const char *name = PLATFORM_FUN_NAME;
+	ddf_fun_t *fun;
+	int rc;
 
 	/* Get platform name from sysinfo. */
-
 	platform = sysinfo_get_data("platform", &platform_size);
 	if (platform == NULL) {
@@ -123,20 +150,36 @@
 
 	/* Construct match ID. */
-
-	if (asprintf(&match_id, PLATFORM_DEVICE_MATCH_ID_FMT, platform) == -1) {
+	if (asprintf(&match_id, PLATFORM_FUN_MATCH_ID_FMT, platform) == -1) {
 		printf(NAME ": Memory allocation failed.\n");
 		return ENOMEM;
 	}
 
-	/* Add child. */
-
-	printf(NAME ": adding new child for platform device.\n");
-	printf(NAME ":   device node is `%s' (%d %s)\n", PLATFORM_DEVICE_NAME,
-	    PLATFORM_DEVICE_MATCH_SCORE, match_id);
-
-	res = child_device_register_wrapper(parent, PLATFORM_DEVICE_NAME,
-	    match_id, PLATFORM_DEVICE_MATCH_SCORE);
-
-	return res;
+	/* Add function. */
+	printf(NAME ": adding platform function\n");
+	printf(NAME ":   function node is `%s' (%d %s)\n", PLATFORM_FUN_NAME,
+	    PLATFORM_FUN_MATCH_SCORE, match_id);
+
+	fun = ddf_fun_create(dev, fun_inner, name);
+	if (fun == NULL) {
+		printf(NAME ": error creating function %s\n", name);
+		return ENOMEM;
+	}
+
+	rc = ddf_fun_add_match_id(fun, match_id, PLATFORM_FUN_MATCH_SCORE);
+	if (rc != EOK) {
+		printf(NAME ": error adding match IDs to function %s\n", name);
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		printf(NAME ": error binding function %s: %s\n", name,
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	return EOK;
 }
 
@@ -146,9 +189,9 @@
  *			of HW and pseudo devices).
  */
-static int root_add_device(device_t *dev)
+static int root_add_device(ddf_dev_t *dev)
 {
 	printf(NAME ": root_add_device, device handle=%" PRIun "\n",
 	    dev->handle);
-	
+
 	/*
 	 * Register virtual devices root.
@@ -156,11 +199,11 @@
 	 * vital for the system.
 	 */
-	add_virtual_root_child(dev);
+	add_virtual_root_fun(dev);
 
 	/* Register root device's children. */
-	int res = add_platform_child(dev);
+	int res = add_platform_fun(dev);
 	if (EOK != res)
 		printf(NAME ": failed to add child device for platform.\n");
-	
+
 	return res;
 }
@@ -169,5 +212,5 @@
 {
 	printf(NAME ": HelenOS root device driver\n");
-	return driver_main(&root_driver);
+	return ddf_driver_main(&root_driver);
 }
 
Index: uspace/drv/rootpc/rootpc.c
===================================================================
--- uspace/drv/rootpc/rootpc.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/rootpc/rootpc.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -46,5 +46,5 @@
 #include <macros.h>
 
-#include <driver.h>
+#include <ddf/driver.h>
 #include <devman.h>
 #include <ipc/devman.h>
@@ -55,9 +55,12 @@
 #define NAME "rootpc"
 
-typedef struct rootpc_child_dev_data {
+/** Obtain function soft-state from DDF function node */
+#define ROOTPC_FUN(fnode) ((rootpc_fun_t *) (fnode)->driver_data)
+
+typedef struct rootpc_fun {
 	hw_resource_list_t hw_resources;
-} rootpc_child_dev_data_t;
-
-static int rootpc_add_device(device_t *dev);
+} rootpc_fun_t;
+
+static int rootpc_add_device(ddf_dev_t *dev);
 static void root_pc_init(void);
 
@@ -82,5 +85,5 @@
 };
 
-static rootpc_child_dev_data_t pci_data = {
+static rootpc_fun_t pci_data = {
 	.hw_resources = {
 		1,
@@ -89,16 +92,13 @@
 };
 
-static hw_resource_list_t *rootpc_get_child_resources(device_t *dev)
-{
-	rootpc_child_dev_data_t *data;
-	
-	data = (rootpc_child_dev_data_t *) dev->driver_data;
-	if (NULL == data)
-		return NULL;
-	
-	return &data->hw_resources;
-}
-
-static bool rootpc_enable_child_interrupt(device_t *dev)
+static hw_resource_list_t *rootpc_get_resources(ddf_fun_t *fnode)
+{
+	rootpc_fun_t *fun = ROOTPC_FUN(fnode);
+	
+	assert(fun != NULL);
+	return &fun->hw_resources;
+}
+
+static bool rootpc_enable_interrupt(ddf_fun_t *fun)
 {
 	/* TODO */
@@ -107,64 +107,63 @@
 }
 
-static hw_res_ops_t child_hw_res_ops = {
-	&rootpc_get_child_resources,
-	&rootpc_enable_child_interrupt
+static hw_res_ops_t fun_hw_res_ops = {
+	&rootpc_get_resources,
+	&rootpc_enable_interrupt
 };
 
 /* Initialized in root_pc_init() function. */
-static device_ops_t rootpc_child_ops;
+static ddf_dev_ops_t rootpc_fun_ops;
 
 static bool
-rootpc_add_child(device_t *parent, const char *name, const char *str_match_id,
-    rootpc_child_dev_data_t *drv_data)
-{
-	printf(NAME ": adding new child device '%s'.\n", name);
-	
-	device_t *child = NULL;
+rootpc_add_fun(ddf_dev_t *dev, const char *name, const char *str_match_id,
+    rootpc_fun_t *fun)
+{
+	printf(NAME ": adding new function '%s'.\n", name);
+	
+	ddf_fun_t *fnode = NULL;
 	match_id_t *match_id = NULL;
 	
 	/* Create new device. */
-	child = create_device();
-	if (NULL == child)
+	fnode = ddf_fun_create(dev, fun_inner, name);
+	if (fnode == NULL)
 		goto failure;
 	
-	child->name = name;
-	child->driver_data = drv_data;
+	fnode->driver_data = fun;
 	
 	/* Initialize match id list */
 	match_id = create_match_id();
-	if (NULL == match_id)
+	if (match_id == NULL)
 		goto failure;
 	
 	match_id->id = str_match_id;
 	match_id->score = 100;
-	add_match_id(&child->match_ids, match_id);
+	add_match_id(&fnode->match_ids, match_id);
 	
 	/* Set provided operations to the device. */
-	child->ops = &rootpc_child_ops;
-	
-	/* Register child device. */
-	if (EOK != child_device_register(child, parent))
+	fnode->ops = &rootpc_fun_ops;
+	
+	/* Register function. */
+	if (ddf_fun_bind(fnode) != EOK) {
+		printf(NAME ": error binding function %s.\n", name);
 		goto failure;
+	}
 	
 	return true;
 	
 failure:
-	if (NULL != match_id)
+	if (match_id != NULL)
 		match_id->id = NULL;
 	
-	if (NULL != child) {
-		child->name = NULL;
-		delete_device(child);
-	}
-	
-	printf(NAME ": failed to add child device '%s'.\n", name);
+	if (fnode != NULL)
+		ddf_fun_destroy(fnode);
+	
+	printf(NAME ": failed to add function '%s'.\n", name);
 	
 	return false;
 }
 
-static bool rootpc_add_children(device_t *dev)
-{
-	return rootpc_add_child(dev, "pci0", "intel_pci", &pci_data);
+static bool rootpc_add_functions(ddf_dev_t *dev)
+{
+	return rootpc_add_fun(dev, "pci0", "intel_pci", &pci_data);
 }
 
@@ -175,12 +174,12 @@
  * @return		Zero on success, negative error number otherwise.
  */
-static int rootpc_add_device(device_t *dev)
+static int rootpc_add_device(ddf_dev_t *dev)
 {
 	printf(NAME ": rootpc_add_device, device handle = %d\n",
 	    (int)dev->handle);
 	
-	/* Register child devices. */
-	if (!rootpc_add_children(dev)) {
-		printf(NAME ": failed to add child devices for PC platform.\n");
+	/* Register functions. */
+	if (!rootpc_add_functions(dev)) {
+		printf(NAME ": failed to add functions for PC platform.\n");
 	}
 	
@@ -190,5 +189,5 @@
 static void root_pc_init(void)
 {
-	rootpc_child_ops.interfaces[HW_RES_DEV_IFACE] = &child_hw_res_ops;
+	rootpc_fun_ops.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops;
 }
 
@@ -197,5 +196,5 @@
 	printf(NAME ": HelenOS PC platform driver\n");
 	root_pc_init();
-	return driver_main(&rootpc_driver);
+	return ddf_driver_main(&rootpc_driver);
 }
 
Index: uspace/drv/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/rootvirt/rootvirt.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/rootvirt/rootvirt.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -39,20 +39,20 @@
 #include <errno.h>
 #include <str_error.h>
-#include <driver.h>
+#include <ddf/driver.h>
 
 #define NAME "rootvirt"
 
-/** Virtual device entry. */
+/** Virtual function entry */
 typedef struct {
-	/** Device name. */
+	/** Function name */
 	const char *name;
-	/** Device match id. */
+	/** Function match ID */
 	const char *match_id;
-} virtual_device_t;
+} virtual_function_t;
 
-/** List of existing virtual devices. */
-virtual_device_t virtual_devices[] = {
+/** List of existing virtual functions */
+virtual_function_t virtual_functions[] = {
 #include "devices.def"
-	/* Terminating item. */
+	/* Terminating item */
 	{
 		.name = NULL,
@@ -61,8 +61,8 @@
 };
 
-static int add_device(device_t *dev);
+static int rootvirt_add_device(ddf_dev_t *dev);
 
 static driver_ops_t rootvirt_ops = {
-	.add_device = &add_device
+	.add_device = &rootvirt_add_device
 };
 
@@ -72,30 +72,45 @@
 };
 
-/** Add child device.
+/** Add function to the virtual device.
  *
- * @param parent Parent device.
- * @param virt_dev Virtual device to add.
- * @return Error code.
+ * @param vdev		The virtual device
+ * @param vfun		Virtual function description
+ * @return		EOK on success or negative error code.
  */
-static int add_child(device_t *parent, virtual_device_t *virt_dev)
+static int rootvirt_add_fun(ddf_dev_t *vdev, virtual_function_t *vfun)
 {
-	printf(NAME ": registering child device `%s' (match \"%s\")\n",
-	    virt_dev->name, virt_dev->match_id);
+	ddf_fun_t *fun;
+	int rc;
 
-	int rc = child_device_register_wrapper(parent, virt_dev->name,
-	    virt_dev->match_id, 10);
+	printf(NAME ": registering function `%s' (match \"%s\")\n",
+	    vfun->name, vfun->match_id);
 
-	if (rc == EOK) {
-		printf(NAME ": registered child device `%s'\n",
-		    virt_dev->name);
-	} else {
-		printf(NAME ": failed to register child device `%s': %s\n",
-		    virt_dev->name, str_error(rc));
+	fun = ddf_fun_create(vdev, fun_inner, vfun->name);
+	if (fun == NULL) {
+		printf(NAME ": error creating function %s\n", vfun->name);
+		return ENOMEM;
 	}
 
-	return rc;
+	rc = ddf_fun_add_match_id(fun, vfun->match_id, 10);
+	if (rc != EOK) {
+		printf(NAME ": error adding match IDs to function %s\n",
+		    vfun->name);
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		printf(NAME ": error binding function %s: %s\n", vfun->name,
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	printf(NAME ": registered child device `%s'\n", vfun->name);
+	return EOK;
 }
 
-static int add_device(device_t *dev)
+static int rootvirt_add_device(ddf_dev_t *dev)
 {
 	static int instances = 0;
@@ -109,15 +124,14 @@
 	}
 
-	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
-	    dev->name, (int)dev->handle);
-	
+	printf(NAME ": add_device(handle=%d)\n", (int)dev->handle);
+
 	/*
-	 * Go through all virtual devices and try to add them.
+	 * Go through all virtual functions and try to add them.
 	 * We silently ignore failures.
 	 */
-	virtual_device_t *virt_dev = virtual_devices;
-	while (virt_dev->name != NULL) {
-		(void) add_child(dev, virt_dev);
-		virt_dev++;
+	virtual_function_t *vfun = virtual_functions;
+	while (vfun->name != NULL) {
+		(void) rootvirt_add_fun(dev, vfun);
+		vfun++;
 	}
 
@@ -128,5 +142,5 @@
 {
 	printf(NAME ": HelenOS virtual devices root driver\n");
-	return driver_main(&rootvirt_driver);
+	return ddf_driver_main(&rootvirt_driver);
 }
 
Index: uspace/drv/test1/char.c
===================================================================
--- uspace/drv/test1/char.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/test1/char.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -37,10 +37,10 @@
 #include "test1.h"
 
-static int impl_char_read(device_t *dev, char *buf, size_t count) {
+static int impl_char_read(ddf_fun_t *fun, char *buf, size_t count) {
 	memset(buf, 0, count);
 	return count;
 }
 
-static int imp_char_write(device_t *dev, char *buf, size_t count) {
+static int imp_char_write(ddf_fun_t *fun, char *buf, size_t count) {
 	return count;
 }
@@ -51,5 +51,5 @@
 };
 
-device_ops_t char_device_ops = {
+ddf_dev_ops_t char_device_ops = {
 	.interfaces[CHAR_DEV_IFACE] = &char_dev_ops
 };
Index: uspace/drv/test1/test1.c
===================================================================
--- uspace/drv/test1/test1.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/test1/test1.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -34,13 +34,15 @@
 #include <errno.h>
 #include <str_error.h>
+#include <ddf/driver.h>
+
 #include "test1.h"
 
-static int add_device(device_t *dev);
+static int test1_add_device(ddf_dev_t *dev);
 
 static driver_ops_t driver_ops = {
-	.add_device = &add_device
+	.add_device = &test1_add_device
 };
 
-static driver_t the_driver = {
+static driver_t test1_driver = {
 	.name = NAME,
 	.driver_ops = &driver_ops
@@ -55,19 +57,35 @@
  * @param score Device match score.
  */
-static void register_child_verbose(device_t *parent, const char *message,
+static int register_fun_verbose(ddf_dev_t *parent, const char *message,
     const char *name, const char *match_id, int match_score)
 {
-	printf(NAME ": registering child device `%s': %s.\n",
-	   name, message);
+	ddf_fun_t *fun;
+	int rc;
 
-	int rc = child_device_register_wrapper(parent, name,
-	    match_id, match_score);
+	printf(NAME ": registering function `%s': %s.\n", name, message);
 
-	if (rc == EOK) {
-		printf(NAME ": registered child device `%s'.\n", name);
-	} else {
-		printf(NAME ": failed to register child `%s' (%s).\n",
-		    name, str_error(rc));
+	fun = ddf_fun_create(parent, fun_inner, name);
+	if (fun == NULL) {
+		printf(NAME ": error creating function %s\n", name);
+		return ENOMEM;
 	}
+
+	rc = ddf_fun_add_match_id(fun, match_id, match_score);
+	if (rc != EOK) {
+		printf(NAME ": error adding match IDs to function %s\n", name);
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		printf(NAME ": error binding function %s: %s\n", name,
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	printf(NAME ": registered child device `%s'\n", name);
+	return EOK;
 }
 
@@ -89,19 +107,34 @@
  * @return Error code reporting success of the operation.
  */
-static int add_device(device_t *dev)
+static int test1_add_device(ddf_dev_t *dev)
 {
+	ddf_fun_t *fun_a;
+	int rc;
+
 	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
 	    dev->name, (int) dev->handle);
 
-	add_device_to_class(dev, "virtual");
+	fun_a = ddf_fun_create(dev, fun_exposed, "a");
+	if (fun_a == NULL) {
+		printf(NAME ": error creating function 'a'.\n");
+		return ENOMEM;
+	}
+
+	rc = ddf_fun_bind(fun_a);
+	if (rc != EOK) {
+		printf(NAME ": error binding function 'a'.\n");
+		return rc;
+	}
+
+	ddf_fun_add_to_class(fun_a, "virtual");
 
 	if (str_cmp(dev->name, "null") == 0) {
-		dev->ops = &char_device_ops;
-		add_device_to_class(dev, "virt-null");
-	} else if (dev->parent == NULL) {
-		register_child_verbose(dev, "cloning myself ;-)", "clone",
+		fun_a->ops = &char_device_ops;
+		ddf_fun_add_to_class(fun_a, "virt-null");
+	} else if (str_cmp(dev->name, "test1") == 0) {
+		(void) register_fun_verbose(dev, "cloning myself ;-)", "clone",
 		    "virtual&test1", 10);
 	} else if (str_cmp(dev->name, "clone") == 0) {
-		register_child_verbose(dev, "run by the same task", "child",
+		(void) register_fun_verbose(dev, "run by the same task", "child",
 		    "virtual&test1&child", 10);
 	}
@@ -115,5 +148,5 @@
 {
 	printf(NAME ": HelenOS test1 virtual device driver\n");
-	return driver_main(&the_driver);
+	return ddf_driver_main(&test1_driver);
 }
 
Index: uspace/drv/test1/test1.h
===================================================================
--- uspace/drv/test1/test1.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/test1/test1.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -32,9 +32,9 @@
 #define DRV_TEST1_TEST1_H_
 
-#include <driver.h>
+#include <ddf/driver.h>
 
 #define NAME "test1"
 
-extern device_ops_t char_device_ops;
+extern ddf_dev_ops_t char_device_ops;
 
 #endif
Index: uspace/drv/test2/test2.c
===================================================================
--- uspace/drv/test2/test2.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/drv/test2/test2.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -31,18 +31,19 @@
 
 #include <assert.h>
+#include <async.h>
 #include <stdio.h>
 #include <errno.h>
 #include <str_error.h>
-#include <driver.h>
+#include <ddf/driver.h>
 
 #define NAME "test2"
 
-static int add_device(device_t *dev);
+static int test2_add_device(ddf_dev_t *dev);
 
 static driver_ops_t driver_ops = {
-	.add_device = &add_device
+	.add_device = &test2_add_device
 };
 
-static driver_t the_driver = {
+static driver_t test2_driver = {
 	.name = NAME,
 	.driver_ops = &driver_ops
@@ -57,53 +58,86 @@
  * @param score Device match score.
  */
-static void register_child_verbose(device_t *parent, const char *message,
+static int register_fun_verbose(ddf_dev_t *parent, const char *message,
     const char *name, const char *match_id, int match_score)
 {
-	printf(NAME ": registering child device `%s': %s.\n",
-	   name, message);
+	ddf_fun_t *fun;
+	int rc;
 
-	int rc = child_device_register_wrapper(parent, name,
-	    match_id, match_score);
+	printf(NAME ": registering function `%s': %s.\n", name, message);
 
-	if (rc == EOK) {
-		printf(NAME ": registered child device `%s'.\n", name);
-	} else {
-		printf(NAME ": failed to register child `%s' (%s).\n",
-		    name, str_error(rc));
+	fun = ddf_fun_create(parent, fun_inner, name);
+	if (fun == NULL) {
+		printf(NAME ": error creating function %s\n", name);
+		return ENOMEM;
 	}
+
+	rc = ddf_fun_add_match_id(fun, match_id, match_score);
+	if (rc != EOK) {
+		printf(NAME ": error adding match IDs to function %s\n", name);
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		printf(NAME ": error binding function %s: %s\n", name,
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	printf(NAME ": registered child device `%s'\n", name);
+	return EOK;
 }
 
 /** Add child devices after some sleep.
  *
- * @param arg Parent device structure (device_t *).
+ * @param arg Parent device structure (ddf_dev_t *).
  * @return Always EOK.
  */
 static int postponed_birth(void *arg)
 {
-	device_t *dev = (device_t *) arg;
+	ddf_dev_t *dev = (ddf_dev_t *) arg;
+	ddf_fun_t *fun_a;
+	int rc;
 
 	async_usleep(1000);
 
-	register_child_verbose(dev, "child driven by the same task",
+	(void) register_fun_verbose(dev, "child driven by the same task",
 	    "child", "virtual&test2", 10);
-	register_child_verbose(dev, "child driven by test1",
+	(void) register_fun_verbose(dev, "child driven by test1",
 	    "test1", "virtual&test1", 10);
 
-	add_device_to_class(dev, "virtual");
+	fun_a = ddf_fun_create(dev, fun_exposed, "a");
+	if (fun_a == NULL) {
+		printf(NAME ": error creating function 'a'.\n");
+		return ENOMEM;
+	}
+
+	rc = ddf_fun_bind(fun_a);
+	if (rc != EOK) {
+		printf(NAME ": error binding function 'a'.\n");
+		return rc;
+	}
+
+	ddf_fun_add_to_class(fun_a, "virtual");
 
 	return EOK;
 }
 
-
-static int add_device(device_t *dev)
+static int test2_add_device(ddf_dev_t *dev)
 {
-	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	printf(NAME ": test2_add_device(name=\"%s\", handle=%d)\n",
 	    dev->name, (int) dev->handle);
 
-	if (dev->parent == NULL) {
+	if (str_cmp(dev->name, "child") != 0) {
 		fid_t postpone = fibril_create(postponed_birth, dev);
+		if (postpone == 0) {
+			printf(NAME ": fibril_create() error\n");
+			return ENOMEM;
+		}
 		fibril_add_ready(postpone);
 	} else {
-		register_child_verbose(dev, "child without available driver",
+		(void) register_fun_verbose(dev, "child without available driver",
 		    "ERROR", "non-existent.match.id", 10);
 	}
@@ -115,5 +149,5 @@
 {
 	printf(NAME ": HelenOS test2 virtual device driver\n");
-	return driver_main(&the_driver);
+	return ddf_driver_main(&test2_driver);
 }
 
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/Makefile	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -91,6 +91,6 @@
 	generic/loader.c \
 	generic/getopt.c \
-	generic/adt/list.o \
-	generic/adt/hash_table.o \
+	generic/adt/list.c \
+	generic/adt/hash_table.c \
 	generic/adt/dynamic_fifo.c \
 	generic/adt/measured_strings.c \
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -44,8 +44,4 @@
 	} :data
 	
-	. = ALIGN(0x1000);
-	
-	_heap = .;
-	
 	/DISCARD/ : {
 		*(*);
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -5,4 +5,5 @@
 	text PT_LOAD FLAGS(5);
 	data PT_LOAD FLAGS(6);
+	debug PT_NOTE;
 }
 
@@ -13,14 +14,16 @@
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x1000;
-
+	
 	.data : {
 		*(.data);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -31,16 +34,27 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = ALIGNOF(.tdata);
+	
 	.bss : {
 		*(COMMON);
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x1000);
-	_heap = .;
+	
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -9,15 +9,16 @@
 SECTIONS {
 	. = 0x1000 + SIZEOF_HEADERS;
-
+	
 	.init : {
 		*(.init);
-	} : text
+	} :text
+	
 	.text : {
 		*(.text);
-        *(.rodata*);
+		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x1000;
-
+	
 	.data : {
 		*(.opd);
@@ -25,4 +26,5 @@
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -33,18 +35,16 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = ALIGNOF(.tdata);
+	
 	.bss : {
 		*(.sbss);
 		*(.scommon);
-        *(COMMON);
-        *(.bss);
+		*(COMMON);
+		*(.bss);
 	} :data
-	
-	. = ALIGN(0x1000);
-	_heap = .;
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -5,4 +5,5 @@
 	text PT_LOAD FLAGS(5);
 	data PT_LOAD FLAGS(6);
+	debug PT_NOTE;
 }
 
@@ -42,7 +43,16 @@
 	} :data
 	
-	. = ALIGN(0x1000);
-	
-	_heap = .;
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
 	
 	/DISCARD/ : {
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -9,19 +9,21 @@
 SECTIONS {
 	. = 0x4000 + SIZEOF_HEADERS;
-
+	
 	.init : {
 		*(.init);
-	} : text
+	} :text
+	
 	.text : {
 		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x4000;
-
+	
 	.got : {
 		_gp = .;
 		*(.got*);
-	} :data	
+	} :data
+	
 	.data : {
 		*(.opd);
@@ -29,4 +31,5 @@
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -37,5 +40,7 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = ALIGNOF(.tdata);
+	
 	.bss : {
 		*(.sbss);
@@ -44,10 +49,7 @@
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x4000);
-	_heap = .;
- 
+	
 	/DISCARD/ : {
 		*(*);
-        }
+	}
 }
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -13,43 +13,46 @@
 		*(.init);
 	} :text
+	
 	.text : {
-	        *(.text);
+		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x4000;
-
+	
 	.data : {
 		*(.data);
 		*(.data.rel*);
 	} :data
-
+	
 	.got : {
 		_gp = .;
 		*(.got);
 	} :data
-
+	
 	.tdata : {
 		_tdata_start = .;
 		*(.tdata);
 		_tdata_end = .;
+	} :data
+	
+	.tbss : {
 		_tbss_start = .;
 		*(.tbss);
 		_tbss_end = .;
 	} :data
-	_tls_alignment = ALIGNOF(.tdata);
-
+	
+	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.sbss : {
 		*(.scommon);
 		*(.sbss);
-	}	
+	}
+	
 	.bss : {
 		*(.bss);
 		*(COMMON);
 	} :data
-
-	. = ALIGN(0x4000);
-	_heap = .;
-
+	
 	/DISCARD/ : {
 		*(*);
Index: uspace/lib/c/arch/mips32/src/entry.s
===================================================================
--- uspace/lib/c/arch/mips32/src/entry.s	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/mips32/src/entry.s	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -29,6 +29,7 @@
 .text
 .section .init, "ax"
+
 .global __entry
-.global __entry_driver
+
 .set noreorder
 .option pic2
@@ -57,6 +58,2 @@
 	nop
 .end
-
-# Alignment of output section data to 0x4000
-.section .data
-.align 14
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -9,19 +9,21 @@
 SECTIONS {
 	. = 0x1000 + SIZEOF_HEADERS;
-
+	
 	.init : {
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x1000;
-
+	
 	.data : {
 		*(.data);
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -32,5 +34,7 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = ALIGNOF(.tdata);
+	
 	.bss : {
 		*(.sbss);
@@ -38,11 +42,7 @@
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x1000);
-	_heap = .;
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -9,23 +9,26 @@
 SECTIONS {
 	. = 0x4000 + SIZEOF_HEADERS;
-
+	
 	.init : {
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x4000;
-
+	
 	.got : {
 		 _gp = .;
 		 *(.got*);
 	} :data
+	
 	.data : {
 		*(.data);
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -36,5 +39,7 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = ALIGNOF(.tdata);
+	
 	.bss : {
 		*(.sbss);
@@ -42,11 +47,7 @@
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x4000);
-	_heap = .;
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/as.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -40,7 +40,5 @@
 #include <bitops.h>
 #include <malloc.h>
-
-/** Last position allocated by as_get_mappable_page */
-static uintptr_t last_allocated = 0;
+#include "private/libc.h"
 
 /** Create address space area.
@@ -103,27 +101,15 @@
 }
 
-/** Return pointer to some unmapped area, where fits new as_area
+/** Return pointer to unmapped address space area
  *
  * @param size Requested size of the allocation.
  *
- * @return pointer to the beginning
+ * @return Pointer to the beginning of unmapped address space area.
  *
  */
 void *as_get_mappable_page(size_t size)
 {
-	if (size == 0)
-		return NULL;
-	
-	size_t sz = 1 << (fnzb(size - 1) + 1);
-	if (last_allocated == 0)
-		last_allocated = get_max_heap_addr();
-	
-	/*
-	 * Make sure we allocate from naturally aligned address.
-	 */
-	uintptr_t res = ALIGN_UP(last_allocated, sz);
-	last_allocated = res + ALIGN_UP(size, PAGE_SIZE);
-	
-	return ((void *) res);
+	return (void *) __SYSCALL2(SYS_AS_GET_UNMAPPED_AREA,
+	    (sysarg_t) __entry, (sysarg_t) size);
 }
 
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/async.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -430,4 +430,10 @@
 	
 	fid_t fid = fibril_create(notification_fibril, msg);
+	if (fid == 0) {
+		free(msg);
+		futex_up(&async_futex);
+		return false;
+	}
+	
 	fibril_add_ready(fid);
 	
@@ -681,8 +687,10 @@
 	conn->wdata.fid = fibril_create(connection_fibril, conn);
 	
-	if (!conn->wdata.fid) {
+	if (conn->wdata.fid == 0) {
 		free(conn);
+		
 		if (callid)
 			ipc_answer_0(callid, ENOMEM);
+		
 		return (uintptr_t) NULL;
 	}
@@ -853,5 +861,6 @@
 {
 	fid_t fid = fibril_create(async_manager_fibril, NULL);
-	fibril_add_manager(fid);
+	if (fid != 0)
+		fibril_add_manager(fid);
 }
 
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/devman.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -123,9 +123,13 @@
 }
 
-static int devman_send_match_id(int phone, match_id_t *match_id) \
-{
-	ipc_call_t answer;
-	aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score, &answer);
-	int retval = async_data_write_start(phone, match_id->id, str_size(match_id->id));
+static int devman_send_match_id(int phone, match_id_t *match_id)
+{
+	ipc_call_t answer;
+
+	aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score,
+	    &answer);
+	int retval = async_data_write_start(phone, match_id->id,
+	    str_size(match_id->id));
+
 	async_wait_for(req, NULL);
 	return retval;
@@ -133,26 +137,43 @@
 
 
-static int devman_send_match_ids(int phone, match_id_list_t *match_ids) 
+static int devman_send_match_ids(int phone, match_id_list_t *match_ids)
 {
 	link_t *link = match_ids->ids.next;
 	match_id_t *match_id = NULL;
 	int ret = EOK;
-	
+
 	while (link != &match_ids->ids) {
 		match_id = list_get_instance(link, match_id_t, link); 
-		if (EOK != (ret = devman_send_match_id(phone, match_id))) 
-		{
-			printf("Driver failed to send match id, error number = %d\n", ret);
-			return ret;			
-		}
+		ret = devman_send_match_id(phone, match_id);
+		if (ret != EOK) {
+			printf("Driver failed to send match id, error %d\n",
+			    ret);
+			return ret;
+		}
+
 		link = link->next;
 	}
-	return ret;	
-}
-
-int devman_child_device_register(
-	const char *name, match_id_list_t *match_ids, devman_handle_t parent_handle, devman_handle_t *handle)
-{		
+
+	return ret;
+}
+
+/** Add function to a device.
+ *
+ * Request devman to add a new function to the specified device owned by
+ * this driver task.
+ *
+ * @param name		Name of the new function
+ * @param ftype		Function type, fun_inner or fun_exposed
+ * @param match_ids	Match IDs (should be empty for fun_exposed)
+ * @param devh		Devman handle of the device
+ * @param funh		Place to store handle of the new function
+ *
+ * @return		EOK on success or negative error code.
+ */
+int devman_add_function(const char *name, fun_type_t ftype,
+    match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
+{
 	int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
+	int fun_handle;
 	
 	if (phone < 0)
@@ -161,7 +182,9 @@
 	async_serialize_start();
 	
-	int match_count = list_count(&match_ids->ids);	
-	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAN_ADD_CHILD_DEVICE, parent_handle, match_count, &answer);
+	int match_count = list_count(&match_ids->ids);
+	ipc_call_t answer;
+
+	aid_t req = async_send_3(phone, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
+	    devh, match_count, &answer);
 
 	sysarg_t retval = async_data_write_start(phone, name, str_size(name));
@@ -178,18 +201,16 @@
 	async_serialize_end();
 	
-	if (retval != EOK) {
-		if (handle != NULL) {
-			*handle = -1;
-		}
-		return retval;
-	}	
-	
-	if (handle != NULL)
-		*handle = (int) IPC_GET_ARG1(answer);	
-		
-	return retval;
-}
-
-int devman_add_device_to_class(devman_handle_t devman_handle, const char *class_name)
+	if (retval == EOK)
+		fun_handle = (int) IPC_GET_ARG1(answer);
+	else
+		fun_handle = -1;
+	
+	*funh = fun_handle;
+
+	return retval;
+}
+
+int devman_add_device_to_class(devman_handle_t devman_handle,
+    const char *class_name)
 {
 	int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
@@ -200,7 +221,9 @@
 	async_serialize_start();
 	ipc_call_t answer;
-	aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS, devman_handle, &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, class_name, str_size(class_name));
+	aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS,
+	    devman_handle, &answer);
+	
+	sysarg_t retval = async_data_write_start(phone, class_name,
+	    str_size(class_name));
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
@@ -212,5 +235,5 @@
 	async_serialize_end();
 	
-	return retval;	
+	return retval;
 }
 
@@ -265,5 +288,6 @@
 }
 
-int devman_device_get_handle(const char *pathname, devman_handle_t *handle, unsigned int flags)
+int devman_device_get_handle(const char *pathname, devman_handle_t *handle,
+    unsigned int flags)
 {
 	int phone = devman_get_phone(DEVMAN_CLIENT, flags);
@@ -278,5 +302,6 @@
 	    &answer);
 	
-	sysarg_t retval = async_data_write_start(phone, pathname, str_size(pathname));
+	sysarg_t retval = async_data_write_start(phone, pathname,
+	    str_size(pathname));
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
Index: uspace/lib/c/generic/fibril.c
===================================================================
--- uspace/lib/c/generic/fibril.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/fibril.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -115,4 +115,6 @@
 	fibril->retval = 0;
 	fibril->flags = 0;
+	
+	fibril->waits_for = NULL;
 	
 	return fibril;
@@ -276,6 +278,4 @@
 	fibril->arg = arg;
 
-	fibril->waits_for = NULL;
-	
 	context_save(&fibril->ctx);
 	context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack,
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/loader.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -160,4 +160,5 @@
 	int rc = async_data_write_start(ldr->phone_id, (void *) pa, pa_len);
 	if (rc != EOK) {
+		free(pa);
 		async_wait_for(req, NULL);
 		return rc;
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/malloc.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -47,33 +47,77 @@
 #include "private/malloc.h"
 
-/* Magic used in heap headers. */
-#define HEAP_BLOCK_HEAD_MAGIC  0xBEEF0101
-
-/* Magic used in heap footers. */
-#define HEAP_BLOCK_FOOT_MAGIC  0xBEEF0202
-
-/** Allocation alignment (this also covers the alignment of fields
-    in the heap header and footer) */
+/** Magic used in heap headers. */
+#define HEAP_BLOCK_HEAD_MAGIC  UINT32_C(0xBEEF0101)
+
+/** Magic used in heap footers. */
+#define HEAP_BLOCK_FOOT_MAGIC  UINT32_C(0xBEEF0202)
+
+/** Magic used in heap descriptor. */
+#define HEAP_AREA_MAGIC  UINT32_C(0xBEEFCAFE)
+
+/** Allocation alignment.
+ *
+ * This also covers the alignment of fields
+ * in the heap header and footer.
+ *
+ */
 #define BASE_ALIGN  16
 
-/**
- * Either 4 * 256M on 32-bit architecures or 16 * 256M on 64-bit architectures
- */
-#define MAX_HEAP_SIZE  (sizeof(uintptr_t) << 28)
-
-/**
- *
- */
-#define STRUCT_OVERHEAD  (sizeof(heap_block_head_t) + sizeof(heap_block_foot_t))
-
-/**
- * Calculate real size of a heap block (with header and footer)
+/** Overhead of each heap block. */
+#define STRUCT_OVERHEAD \
+	(sizeof(heap_block_head_t) + sizeof(heap_block_foot_t))
+
+/** Calculate real size of a heap block.
+ *
+ * Add header and footer size.
+ *
  */
 #define GROSS_SIZE(size)  ((size) + STRUCT_OVERHEAD)
 
-/**
- * Calculate net size of a heap block (without header and footer)
+/** Calculate net size of a heap block.
+ *
+ * Subtract header and footer size.
+ *
  */
 #define NET_SIZE(size)  ((size) - STRUCT_OVERHEAD)
+
+/** Get first block in heap area.
+ *
+ */
+#define AREA_FIRST_BLOCK(area) \
+	(ALIGN_UP(((uintptr_t) (area)) + sizeof(heap_area_t), BASE_ALIGN))
+
+/** Get footer in heap block.
+ *
+ */
+#define BLOCK_FOOT(head) \
+	((heap_block_foot_t *) \
+	    (((uintptr_t) head) + head->size - sizeof(heap_block_foot_t)))
+
+/** Heap area.
+ *
+ * The memory managed by the heap allocator is divided into
+ * multiple discontinuous heaps. Each heap is represented
+ * by a separate address space area which has this structure
+ * at its very beginning.
+ *
+ */
+typedef struct heap_area {
+	/** Start of the heap area (including this structure)
+	 *
+	 * Aligned on page boundary.
+	 *
+	 */
+	void *start;
+	
+	/** End of the heap area (aligned on page boundary) */
+	void *end;
+	
+	/** Next heap area */
+	struct heap_area *next;
+	
+	/** A magic value */
+	uint32_t magic;
+} heap_area_t;
 
 /** Header of a heap block
@@ -87,4 +131,7 @@
 	bool free;
 	
+	/** Heap area this block belongs to */
+	heap_area_t *area;
+	
 	/* A magic value to detect overwrite of heap header */
 	uint32_t magic;
@@ -102,25 +149,19 @@
 } heap_block_foot_t;
 
-/** Linker heap symbol */
-extern char _heap;
+/** First heap area */
+static heap_area_t *first_heap_area = NULL;
+
+/** Last heap area */
+static heap_area_t *last_heap_area = NULL;
+
+/** Next heap block to examine (next fit algorithm) */
+static heap_block_head_t *next = NULL;
 
 /** Futex for thread-safe heap manipulation */
 static futex_t malloc_futex = FUTEX_INITIALIZER;
 
-/** Address of heap start */
-static void *heap_start = 0;
-
-/** Address of heap end */
-static void *heap_end = 0;
-
-/** Maximum heap size */
-static size_t max_heap_size = (size_t) -1;
-
-/** Current number of pages of heap area */
-static size_t heap_pages = 0;
-
 /** Initialize a heap block
  *
- * Fills in the structures related to a heap block.
+ * Fill in the structures related to a heap block.
  * Should be called only inside the critical section.
  *
@@ -128,16 +169,18 @@
  * @param size Size of the block including the header and the footer.
  * @param free Indication of a free block.
- *
- */
-static void block_init(void *addr, size_t size, bool free)
+ * @param area Heap area the block belongs to.
+ *
+ */
+static void block_init(void *addr, size_t size, bool free, heap_area_t *area)
 {
 	/* Calculate the position of the header and the footer */
 	heap_block_head_t *head = (heap_block_head_t *) addr;
-	heap_block_foot_t *foot =
-	    (heap_block_foot_t *) (addr + size - sizeof(heap_block_foot_t));
 	
 	head->size = size;
 	head->free = free;
+	head->area = area;
 	head->magic = HEAP_BLOCK_HEAD_MAGIC;
+	
+	heap_block_foot_t *foot = BLOCK_FOOT(head);
 	
 	foot->size = size;
@@ -160,6 +203,5 @@
 	assert(head->magic == HEAP_BLOCK_HEAD_MAGIC);
 	
-	heap_block_foot_t *foot =
-	    (heap_block_foot_t *) (addr + head->size - sizeof(heap_block_foot_t));
+	heap_block_foot_t *foot = BLOCK_FOOT(head);
 	
 	assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC);
@@ -167,49 +209,130 @@
 }
 
-/** Increase the heap area size
- *
- * Should be called only inside the critical section.
- *
- * @param size Number of bytes to grow the heap by.
- *
- */
-static bool grow_heap(size_t size)
+/** Check a heap area structure
+ *
+ * @param addr Address of the heap area.
+ *
+ */
+static void area_check(void *addr)
+{
+	heap_area_t *area = (heap_area_t *) addr;
+	
+	assert(area->magic == HEAP_AREA_MAGIC);
+	assert(area->start < area->end);
+	assert(((uintptr_t) area->start % PAGE_SIZE) == 0);
+	assert(((uintptr_t) area->end % PAGE_SIZE) == 0);
+}
+
+/** Create new heap area
+ *
+ * @param start Preffered starting address of the new area.
+ * @param size  Size of the area.
+ *
+ */
+static bool area_create(size_t size)
+{
+	void *start = as_get_mappable_page(size);
+	if (start == NULL)
+		return false;
+	
+	/* Align the heap area on page boundary */
+	void *astart = (void *) ALIGN_UP((uintptr_t) start, PAGE_SIZE);
+	size_t asize = ALIGN_UP(size, PAGE_SIZE);
+	
+	astart = as_area_create(astart, asize, AS_AREA_WRITE | AS_AREA_READ);
+	if (astart == (void *) -1)
+		return false;
+	
+	heap_area_t *area = (heap_area_t *) astart;
+	
+	area->start = astart;
+	area->end = (void *)
+	    ALIGN_DOWN((uintptr_t) astart + asize, BASE_ALIGN);
+	area->next = NULL;
+	area->magic = HEAP_AREA_MAGIC;
+	
+	void *block = (void *) AREA_FIRST_BLOCK(area);
+	size_t bsize = (size_t) (area->end - block);
+	
+	block_init(block, bsize, true, area);
+	
+	if (last_heap_area == NULL) {
+		first_heap_area = area;
+		last_heap_area = area;
+	} else {
+		last_heap_area->next = area;
+		last_heap_area = area;
+	}
+	
+	return true;
+}
+
+/** Try to enlarge a heap area
+ *
+ * @param area Heap area to grow.
+ * @param size Gross size of item to allocate (bytes).
+ *
+ */
+static bool area_grow(heap_area_t *area, size_t size)
 {
 	if (size == 0)
+		return true;
+	
+	area_check(area);
+	
+	size_t asize = ALIGN_UP((size_t) (area->end - area->start) + size,
+	    PAGE_SIZE);
+	
+	/* New heap area size */
+	void *end = (void *)
+	    ALIGN_DOWN((uintptr_t) area->start + asize, BASE_ALIGN);
+	
+	/* Check for overflow */
+	if (end < area->start)
 		return false;
-
-	if ((heap_start + size < heap_start) || (heap_end + size < heap_end))
+	
+	/* Resize the address space area */
+	int ret = as_area_resize(area->start, asize, 0);
+	if (ret != EOK)
 		return false;
 	
-	size_t heap_size = (size_t) (heap_end - heap_start);
-	
-	if ((max_heap_size != (size_t) -1) && (heap_size + size > max_heap_size))
-		return false;
-	
-	size_t pages = (size - 1) / PAGE_SIZE + 1;
-	
-	if (as_area_resize((void *) &_heap, (heap_pages + pages) * PAGE_SIZE, 0)
-	    == EOK) {
-		void *end = (void *) ALIGN_DOWN(((uintptr_t) &_heap) +
-		    (heap_pages + pages) * PAGE_SIZE, BASE_ALIGN);
-		block_init(heap_end, end - heap_end, true);
-		heap_pages += pages;
-		heap_end = end;
+	/* Add new free block */
+	block_init(area->end, (size_t) (end - area->end), true, area);
+	
+	/* Update heap area parameters */
+	area->end = end;
+	
+	return true;
+}
+
+/** Try to enlarge any of the heap areas
+ *
+ * @param size Gross size of item to allocate (bytes).
+ *
+ */
+static bool heap_grow(size_t size)
+{
+	if (size == 0)
 		return true;
-	}
-	
-	return false;
-}
-
-/** Decrease the heap area
- *
- * Should be called only inside the critical section.
- *
- * @param size Number of bytes to shrink the heap by.
- *
- */
-static void shrink_heap(void)
-{
-	// TODO
+	
+	/* First try to enlarge some existing area */
+	heap_area_t *area;
+	for (area = first_heap_area; area != NULL; area = area->next) {
+		if (area_grow(area, size))
+			return true;
+	}
+	
+	/* Eventually try to create a new area */
+	return area_create(AREA_FIRST_BLOCK(size));
+}
+
+/** Try to shrink heap space
+ *
+ * In all cases the next pointer is reset.
+ *
+ */
+static void heap_shrink(void)
+{
+	next = NULL;
 }
 
@@ -223,33 +346,6 @@
 void __malloc_init(void)
 {
-	if (!as_area_create((void *) &_heap, PAGE_SIZE,
-	    AS_AREA_WRITE | AS_AREA_READ))
+	if (!area_create(PAGE_SIZE))
 		abort();
-	
-	heap_pages = 1;
-	heap_start = (void *) ALIGN_UP((uintptr_t) &_heap, BASE_ALIGN);
-	heap_end =
-	    (void *) ALIGN_DOWN(((uintptr_t) &_heap) + PAGE_SIZE, BASE_ALIGN);
-	
-	/* Make the entire area one large block. */
-	block_init(heap_start, heap_end - heap_start, true);
-}
-
-/** Get maximum heap address
- *
- */
-uintptr_t get_max_heap_addr(void)
-{
-	futex_down(&malloc_futex);
-	
-	if (max_heap_size == (size_t) -1)
-		max_heap_size =
-		    max((size_t) (heap_end - heap_start), MAX_HEAP_SIZE);
-	
-	uintptr_t max_heap_addr = (uintptr_t) heap_start + max_heap_size;
-	
-	futex_up(&malloc_futex);
-	
-	return max_heap_addr;
 }
 
@@ -273,6 +369,6 @@
 		/* Block big enough -> split. */
 		void *next = ((void *) cur) + size;
-		block_init(next, cur->size - size, true);
-		block_init(cur, size, false);
+		block_init(next, cur->size - size, true, cur->area);
+		block_init(cur, size, false, cur->area);
 	} else {
 		/* Block too small -> use as is. */
@@ -281,43 +377,53 @@
 }
 
-/** Allocate a memory block
+/** Allocate memory from heap area starting from given block
  *
  * Should be called only inside the critical section.
- *
- * @param size  The size of the block to allocate.
- * @param align Memory address alignment.
- *
- * @return the address of the block or NULL when not enough memory.
- *
- */
-static void *malloc_internal(const size_t size, const size_t align)
-{
-	if (align == 0)
-		return NULL;
-	
-	size_t falign = lcm(align, BASE_ALIGN);
-	size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign));
-	
-	bool grown = false;
-	void *result;
-	
-loop:
-	result = NULL;
-	heap_block_head_t *cur = (heap_block_head_t *) heap_start;
-	
-	while ((result == NULL) && ((void *) cur < heap_end)) {
+ * As a side effect this function also sets the current
+ * pointer on successful allocation.
+ *
+ * @param area        Heap area where to allocate from.
+ * @param first_block Starting heap block.
+ * @param final_block Heap block where to finish the search
+ *                    (may be NULL).
+ * @param real_size   Gross number of bytes to allocate.
+ * @param falign      Physical alignment of the block.
+ *
+ * @return Address of the allocated block or NULL on not enough memory.
+ *
+ */
+static void *malloc_area(heap_area_t *area, heap_block_head_t *first_block,
+    heap_block_head_t *final_block, size_t real_size, size_t falign)
+{
+	area_check((void *) area);
+	assert((void *) first_block >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) first_block < area->end);
+	
+	heap_block_head_t *cur;
+	for (cur = first_block; (void *) cur < area->end;
+	    cur = (heap_block_head_t *) (((void *) cur) + cur->size)) {
 		block_check(cur);
+		
+		/* Finish searching on the final block */
+		if ((final_block != NULL) && (cur == final_block))
+			break;
 		
 		/* Try to find a block that is free and large enough. */
 		if ((cur->free) && (cur->size >= real_size)) {
-			/* We have found a suitable block.
-			   Check for alignment properties. */
-			void *addr = ((void *) cur) + sizeof(heap_block_head_t);
-			void *aligned = (void *) ALIGN_UP(addr, falign);
+			/*
+			 * We have found a suitable block.
+			 * Check for alignment properties.
+			 */
+			void *addr = (void *)
+			    ((uintptr_t) cur + sizeof(heap_block_head_t));
+			void *aligned = (void *)
+			    ALIGN_UP((uintptr_t) addr, falign);
 			
 			if (addr == aligned) {
 				/* Exact block start including alignment. */
 				split_mark(cur, real_size);
-				result = addr;
+				
+				next = cur;
+				return addr;
 			} else {
 				/* Block start has to be aligned */
@@ -325,15 +431,19 @@
 				
 				if (cur->size >= real_size + excess) {
-					/* The current block is large enough to fit
-					   data in including alignment */
-					if ((void *) cur > heap_start) {
-						/* There is a block before the current block.
-						   This previous block can be enlarged to compensate
-						   for the alignment excess */
-						heap_block_foot_t *prev_foot =
-						    ((void *) cur) - sizeof(heap_block_foot_t);
+					/*
+					 * The current block is large enough to fit
+					 * data in (including alignment).
+					 */
+					if ((void *) cur > (void *) AREA_FIRST_BLOCK(area)) {
+						/*
+						 * There is a block before the current block.
+						 * This previous block can be enlarged to
+						 * compensate for the alignment excess.
+						 */
+						heap_block_foot_t *prev_foot = (heap_block_foot_t *)
+						    ((void *) cur - sizeof(heap_block_foot_t));
 						
-						heap_block_head_t *prev_head =
-						    (heap_block_head_t *) (((void *) cur) - prev_foot->size);
+						heap_block_head_t *prev_head = (heap_block_head_t *)
+						    ((void *) cur - prev_foot->size);
 						
 						block_check(prev_head);
@@ -342,25 +452,38 @@
 						heap_block_head_t *next_head = ((void *) cur) + excess;
 						
-						if ((!prev_head->free) && (excess >= STRUCT_OVERHEAD)) {
-							/* The previous block is not free and there is enough
-							   space to fill in a new free block between the previous
-							   and current block */
-							block_init(cur, excess, true);
+						if ((!prev_head->free) &&
+						    (excess >= STRUCT_OVERHEAD)) {
+							/*
+							 * The previous block is not free and there
+							 * is enough free space left to fill in
+							 * a new free block between the previous
+							 * and current block.
+							 */
+							block_init(cur, excess, true, area);
 						} else {
-							/* The previous block is free (thus there is no need to
-							   induce additional fragmentation to the heap) or the
-							   excess is small, thus just enlarge the previous block */
-							block_init(prev_head, prev_head->size + excess, prev_head->free);
+							/*
+							 * The previous block is free (thus there
+							 * is no need to induce additional
+							 * fragmentation to the heap) or the
+							 * excess is small. Therefore just enlarge
+							 * the previous block.
+							 */
+							block_init(prev_head, prev_head->size + excess,
+							    prev_head->free, area);
 						}
 						
-						block_init(next_head, reduced_size, true);
+						block_init(next_head, reduced_size, true, area);
 						split_mark(next_head, real_size);
-						result = aligned;
-						cur = next_head;
+						
+						next = next_head;
+						return aligned;
 					} else {
-						/* The current block is the first block on the heap.
-						   We have to make sure that the alignment excess
-						   is large enough to fit a new free block just
-						   before the current block */
+						/*
+						 * The current block is the first block
+						 * in the heap area. We have to make sure
+						 * that the alignment excess is large enough
+						 * to fit a new free block just before the
+						 * current block.
+						 */
 						while (excess < STRUCT_OVERHEAD) {
 							aligned += falign;
@@ -371,10 +494,14 @@
 						if (cur->size >= real_size + excess) {
 							size_t reduced_size = cur->size - excess;
-							cur = (heap_block_head_t *) (heap_start + excess);
+							cur = (heap_block_head_t *)
+							    (AREA_FIRST_BLOCK(area) + excess);
 							
-							block_init(heap_start, excess, true);
-							block_init(cur, reduced_size, true);
+							block_init((void *) AREA_FIRST_BLOCK(area), excess,
+							    true, area);
+							block_init(cur, reduced_size, true, area);
 							split_mark(cur, real_size);
-							result = aligned;
+							
+							next = cur;
+							return aligned;
 						}
 					}
@@ -382,17 +509,67 @@
 			}
 		}
-		
-		/* Advance to the next block. */
-		cur = (heap_block_head_t *) (((void *) cur) + cur->size);
-	}
-	
-	if ((result == NULL) && (!grown)) {
-		if (grow_heap(real_size)) {
-			grown = true;
+	}
+	
+	return NULL;
+}
+
+/** Allocate a memory block
+ *
+ * Should be called only inside the critical section.
+ *
+ * @param size  The size of the block to allocate.
+ * @param align Memory address alignment.
+ *
+ * @return Address of the allocated block or NULL on not enough memory.
+ *
+ */
+static void *malloc_internal(const size_t size, const size_t align)
+{
+	assert(first_heap_area != NULL);
+	
+	if (align == 0)
+		return NULL;
+	
+	size_t falign = lcm(align, BASE_ALIGN);
+	size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign));
+	
+	bool retry = false;
+	heap_block_head_t *split;
+	
+loop:
+	
+	/* Try the next fit approach */
+	split = next;
+	
+	if (split != NULL) {
+		void *addr = malloc_area(split->area, split, NULL, real_size,
+		    falign);
+		
+		if (addr != NULL)
+			return addr;
+	}
+	
+	/* Search the entire heap */
+	heap_area_t *area;
+	for (area = first_heap_area; area != NULL; area = area->next) {
+		heap_block_head_t *first = (heap_block_head_t *)
+		    AREA_FIRST_BLOCK(area);
+		
+		void *addr = malloc_area(area, first, split, real_size,
+		    falign);
+		
+		if (addr != NULL)
+			return addr;
+	}
+	
+	if (!retry) {
+		/* Try to grow the heap space */
+		if (heap_grow(real_size)) {
+			retry = true;
 			goto loop;
 		}
 	}
 	
-	return result;
+	return NULL;
 }
 
@@ -473,9 +650,12 @@
 	    (heap_block_head_t *) (addr - sizeof(heap_block_head_t));
 	
-	assert((void *) head >= heap_start);
-	assert((void *) head < heap_end);
-	
 	block_check(head);
 	assert(!head->free);
+	
+	heap_area_t *area = head->area;
+	
+	area_check(area);
+	assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) head < area->end);
 	
 	void *ptr = NULL;
@@ -487,29 +667,34 @@
 		/* Shrink */
 		if (orig_size - real_size >= STRUCT_OVERHEAD) {
-			/* Split the original block to a full block
-			   and a trailing free block */
-			block_init((void *) head, real_size, false);
+			/*
+			 * Split the original block to a full block
+			 * and a trailing free block.
+			 */
+			block_init((void *) head, real_size, false, area);
 			block_init((void *) head + real_size,
-			    orig_size - real_size, true);
-			shrink_heap();
+			    orig_size - real_size, true, area);
+			heap_shrink();
 		}
 		
 		ptr = ((void *) head) + sizeof(heap_block_head_t);
 	} else {
-		/* Look at the next block. If it is free and the size is
-		   sufficient then merge the two. Otherwise just allocate
-		   a new block, copy the original data into it and
-		   free the original block. */
+		/*
+		 * Look at the next block. If it is free and the size is
+		 * sufficient then merge the two. Otherwise just allocate
+		 * a new block, copy the original data into it and
+		 * free the original block.
+		 */
 		heap_block_head_t *next_head =
 		    (heap_block_head_t *) (((void *) head) + head->size);
 		
-		if (((void *) next_head < heap_end) &&
+		if (((void *) next_head < area->end) &&
 		    (head->size + next_head->size >= real_size) &&
 		    (next_head->free)) {
 			block_check(next_head);
-			block_init(head, head->size + next_head->size, false);
+			block_init(head, head->size + next_head->size, false, area);
 			split_mark(head, real_size);
 			
 			ptr = ((void *) head) + sizeof(heap_block_head_t);
+			next = NULL;
 		} else
 			reloc = true;
@@ -542,9 +727,12 @@
 	    = (heap_block_head_t *) (addr - sizeof(heap_block_head_t));
 	
-	assert((void *) head >= heap_start);
-	assert((void *) head < heap_end);
-	
 	block_check(head);
 	assert(!head->free);
+	
+	heap_area_t *area = head->area;
+	
+	area_check(area);
+	assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) head < area->end);
 	
 	/* Mark the block itself as free. */
@@ -555,12 +743,12 @@
 	    = (heap_block_head_t *) (((void *) head) + head->size);
 	
-	if ((void *) next_head < heap_end) {
+	if ((void *) next_head < area->end) {
 		block_check(next_head);
 		if (next_head->free)
-			block_init(head, head->size + next_head->size, true);
+			block_init(head, head->size + next_head->size, true, area);
 	}
 	
 	/* Look at the previous block. If it is free, merge the two. */
-	if ((void *) head > heap_start) {
+	if ((void *) head > (void *) AREA_FIRST_BLOCK(area)) {
 		heap_block_foot_t *prev_foot =
 		    (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t));
@@ -572,8 +760,9 @@
 		
 		if (prev_head->free)
-			block_init(prev_head, prev_head->size + head->size, true);
-	}
-	
-	shrink_heap();
+			block_init(prev_head, prev_head->size + head->size, true,
+			    area);
+	}
+	
+	heap_shrink();
 	
 	futex_up(&malloc_futex);
Index: uspace/lib/c/generic/private/libc.h
===================================================================
--- uspace/lib/c/generic/private/libc.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/generic/private/libc.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -36,6 +36,7 @@
 #define LIBC_PRIVATE_LIBC_H_
 
+extern void __entry(void);
+extern void __main(void *) __attribute__((noreturn));
 extern int main(int, char *[]);
-extern void __main(void *) __attribute__((noreturn));
 
 #endif
Index: uspace/lib/c/include/as.h
===================================================================
--- uspace/lib/c/include/as.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/include/as.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -41,4 +41,17 @@
 #include <libarch/config.h>
 
+static inline size_t SIZE2PAGES(size_t size)
+{
+	if (size == 0)
+		return 0;
+	
+	return (size_t) ((size - 1) >> PAGE_WIDTH) + 1;
+}
+
+static inline size_t PAGES2SIZE(size_t pages)
+{
+	return (size_t) (pages << PAGE_WIDTH);
+}
+
 extern void *as_area_create(void *address, size_t size, int flags);
 extern int as_area_resize(void *address, size_t size, int flags);
Index: uspace/lib/c/include/devman.h
===================================================================
--- uspace/lib/c/include/devman.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/include/devman.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -45,5 +45,5 @@
 
 extern int devman_driver_register(const char *, async_client_conn_t);
-extern int devman_child_device_register(const char *, match_id_list_t *,
+extern int devman_add_function(const char *, fun_type_t, match_id_list_t *,
     devman_handle_t, devman_handle_t *);
 
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/include/ipc/devman.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -42,4 +42,13 @@
 
 typedef sysarg_t devman_handle_t;
+
+typedef enum {
+	/** Invalid value for debugging purposes */
+	fun_invalid = 0,
+	/** Function to which child devices attach */
+	fun_inner,
+	/** Fuction exported to external clients (leaf function) */
+	fun_exposed
+} fun_type_t;
 
 /** Ids of device models used for device-to-driver matching.
@@ -127,5 +136,5 @@
 typedef enum {
 	DEVMAN_DRIVER_REGISTER = IPC_FIRST_USER_METHOD,
-	DEVMAN_ADD_CHILD_DEVICE,
+	DEVMAN_ADD_FUNCTION,
 	DEVMAN_ADD_MATCH_ID,
 	DEVMAN_ADD_DEVICE_TO_CLASS
Index: uspace/lib/c/include/malloc.h
===================================================================
--- uspace/lib/c/include/malloc.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/include/malloc.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -38,6 +38,4 @@
 #include <sys/types.h>
 
-extern uintptr_t get_max_heap_addr(void);
-
 extern void *malloc(const size_t size)
     __attribute__((malloc));
Index: uspace/lib/c/include/unistd.h
===================================================================
--- uspace/lib/c/include/unistd.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/c/include/unistd.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -44,6 +44,4 @@
 #endif
 
-#define getpagesize()  (PAGE_SIZE)
-
 #ifndef SEEK_SET
 	#define SEEK_SET  0
@@ -57,4 +55,6 @@
 	#define SEEK_END  2
 #endif
+
+#define getpagesize()  (PAGE_SIZE)
 
 extern int dup2(int oldfd, int newfd);
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/drv/generic/driver.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,9 +50,11 @@
 #include <errno.h>
 #include <inttypes.h>
+#include <devman.h>
 
 #include <ipc/driver.h>
 
 #include "dev_iface.h"
-#include "driver.h"
+#include "ddf/driver.h"
+#include "ddf/interrupt.h"
 
 /** Driver structure */
@@ -59,6 +62,6 @@
 
 /** Devices */
-LIST_INITIALIZE(devices);
-FIBRIL_MUTEX_INITIALIZE(devices_mutex);
+LIST_INITIALIZE(functions);
+FIBRIL_MUTEX_INITIALIZE(functions_mutex);
 
 /** Interrupts */
@@ -76,4 +79,8 @@
 };
 
+static ddf_dev_t *create_device(void);
+static void delete_device(ddf_dev_t *);
+static remote_handler_t *function_get_default_handler(ddf_fun_t *);
+static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
 
 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
@@ -150,5 +157,5 @@
 
 interrupt_context_t *
-find_interrupt_context(interrupt_context_list_t *list, device_t *dev, int irq)
+find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
 {
 	fibril_mutex_lock(&list->mutex);
@@ -172,5 +179,5 @@
 
 int
-register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler,
+register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
     irq_code_t *pseudocode)
 {
@@ -195,5 +202,5 @@
 }
 
-int unregister_interrupt_handler(device_t *dev, int irq)
+int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
 {
 	interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
@@ -209,35 +216,36 @@
 }
 
-static void add_to_devices_list(device_t *dev)
-{
-	fibril_mutex_lock(&devices_mutex);
-	list_append(&dev->link, &devices);
-	fibril_mutex_unlock(&devices_mutex);
-}
-
-static void remove_from_devices_list(device_t *dev)
-{
-	fibril_mutex_lock(&devices_mutex);
-	list_remove(&dev->link);
-	fibril_mutex_unlock(&devices_mutex);
-}
-
-static device_t *driver_get_device(link_t *devices, devman_handle_t handle)
-{
-	device_t *dev = NULL;
-	
-	fibril_mutex_lock(&devices_mutex);
-	link_t *link = devices->next;
-	
-	while (link != devices) {
-		dev = list_get_instance(link, device_t, link);
-		if (dev->handle == handle) {
-			fibril_mutex_unlock(&devices_mutex);
-			return dev;
+static void add_to_functions_list(ddf_fun_t *fun)
+{
+	fibril_mutex_lock(&functions_mutex);
+	list_append(&fun->link, &functions);
+	fibril_mutex_unlock(&functions_mutex);
+}
+
+static void remove_from_functions_list(ddf_fun_t *fun)
+{
+	fibril_mutex_lock(&functions_mutex);
+	list_remove(&fun->link);
+	fibril_mutex_unlock(&functions_mutex);
+}
+
+static ddf_fun_t *driver_get_function(link_t *functions, devman_handle_t handle)
+{
+	ddf_fun_t *fun = NULL;
+	
+	fibril_mutex_lock(&functions_mutex);
+	link_t *link = functions->next;
+	
+	while (link != functions) {
+		fun = list_get_instance(link, ddf_fun_t, link);
+		if (fun->handle == handle) {
+			fibril_mutex_unlock(&functions_mutex);
+			return fun;
 		}
+		
 		link = link->next;
 	}
 	
-	fibril_mutex_unlock(&devices_mutex);
+	fibril_mutex_unlock(&functions_mutex);
 	
 	return NULL;
@@ -250,14 +258,17 @@
 	
 	devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
-    	devman_handle_t parent_dev_handle = IPC_GET_ARG2(*icall);
-	
-	device_t *dev = create_device();
+    	devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
+	
+	ddf_dev_t *dev = create_device();
 	dev->handle = dev_handle;
-	
+
 	async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
 	dev->name = dev_name;
-	
-	add_to_devices_list(dev);
-	dev->parent = driver_get_device(&devices, parent_dev_handle);
+
+	/*
+	 * Currently not used, parent fun handle is stored in context
+	 * of the connection to the parent device driver.
+	 */
+	(void) parent_fun_handle;
 	
 	res = driver->driver_ops->add_device(dev);
@@ -268,5 +279,4 @@
 		printf("%s: failed to add a new device with handle = %" PRIun ".\n",
 		    driver->name, dev_handle);
-		remove_from_devices_list(dev);
 		delete_device(dev);
 	}
@@ -311,8 +321,8 @@
 	 */
 	devman_handle_t handle = IPC_GET_ARG2(*icall);
-	device_t *dev = driver_get_device(&devices, handle);
-
-	if (dev == NULL) {
-		printf("%s: driver_connection_gen error - no device with handle"
+	ddf_fun_t *fun = driver_get_function(&functions, handle);
+
+	if (fun == NULL) {
+		printf("%s: driver_connection_gen error - no function with handle"
 		    " %" PRIun " was found.\n", driver->name, handle);
 		async_answer_0(iid, ENOENT);
@@ -327,7 +337,7 @@
 	
 	int ret = EOK;
-	/* open the device */
-	if (dev->ops != NULL && dev->ops->open != NULL)
-		ret = (*dev->ops->open)(dev);
+	/* Open device function */
+	if (fun->ops != NULL && fun->ops->open != NULL)
+		ret = (*fun->ops->open)(fun);
 	
 	async_answer_0(iid, ret);
@@ -344,7 +354,7 @@
 		switch  (method) {
 		case IPC_M_PHONE_HUNGUP:
-			/* close the device */
-			if (dev->ops != NULL && dev->ops->close != NULL)
-				(*dev->ops->close)(dev);
+			/* Close device function */
+			if (fun->ops != NULL && fun->ops->close != NULL)
+				(*fun->ops->close)(fun);
 			async_answer_0(callid, EOK);
 			return;
@@ -356,11 +366,12 @@
 			if (!is_valid_iface_idx(iface_idx)) {
 				remote_handler_t *default_handler =
-				    device_get_default_handler(dev);
+				    function_get_default_handler(fun);
 				if (default_handler != NULL) {
-					(*default_handler)(dev, callid, &call);
+					(*default_handler)(fun, callid, &call);
 					break;
 				}
+				
 				/*
-				 * This is not device's interface and the
+				 * Function has no such interface and
 				 * default handler is not provided.
 				 */
@@ -372,12 +383,12 @@
 			}
 			
-			/* calling one of the device's interfaces */
+			/* calling one of the function's interfaces */
 			
 			/* Get the interface ops structure. */
-			void *ops = device_get_ops(dev, iface_idx);
+			void *ops = function_get_ops(fun, iface_idx);
 			if (ops == NULL) {
 				printf("%s: driver_connection_gen error - ",
 				    driver->name);
-				printf("device with handle %" PRIun " has no interface "
+				printf("Function with handle %" PRIun " has no interface "
 				    "with id %d.\n", handle, iface_idx);
 				async_answer_0(callid, ENOTSUP);
@@ -408,7 +419,7 @@
 			 * receive parameters from the remote client and it will
 			 * pass it to the corresponding local interface method
-			 * associated with the device by its driver.
+			 * associated with the function by its driver.
 			 */
-			(*iface_method_ptr)(dev, ops, callid, &call);
+			(*iface_method_ptr)(fun, ops, callid, &call);
 			break;
 		}
@@ -425,5 +436,4 @@
 	driver_connection_gen(iid, icall, false);
 }
-
 
 /** Function for handling connections to device driver. */
@@ -454,120 +464,200 @@
  * @return		The device structure.
  */
-device_t *create_device(void)
-{
-	device_t *dev = malloc(sizeof(device_t));
-
-	if (dev != NULL) {
-		memset(dev, 0, sizeof(device_t));
-		init_match_ids(&dev->match_ids);
-	}
-
+static ddf_dev_t *create_device(void)
+{
+	ddf_dev_t *dev;
+
+	dev = malloc(sizeof(ddf_dev_t));
+	if (dev == NULL)
+		return NULL;
+
+	memset(dev, 0, sizeof(ddf_dev_t));
 	return dev;
 }
 
+/** Create new function structure.
+ *
+ * @return		The device structure.
+ */
+static ddf_fun_t *create_function(void)
+{
+	ddf_fun_t *fun;
+
+	fun = calloc(1, sizeof(ddf_fun_t));
+	if (fun == NULL)
+		return NULL;
+
+	init_match_ids(&fun->match_ids);
+	link_initialize(&fun->link);
+
+	return fun;
+}
+
 /** Delete device structure.
  *
  * @param dev		The device structure.
  */
-void delete_device(device_t *dev)
-{
-	clean_match_ids(&dev->match_ids);
-	if (dev->name != NULL)
-		free(dev->name);
+static void delete_device(ddf_dev_t *dev)
+{
 	free(dev);
 }
 
-void *device_get_ops(device_t *dev, dev_inferface_idx_t idx)
+/** Delete device structure.
+ *
+ * @param dev		The device structure.
+ */
+static void delete_function(ddf_fun_t *fun)
+{
+	clean_match_ids(&fun->match_ids);
+	if (fun->name != NULL)
+		free(fun->name);
+	free(fun);
+}
+
+/** Create a DDF function node.
+ *
+ * Create a DDF function (in memory). Both child devices and external clients
+ * communicate with a device via its functions.
+ *
+ * The created function node is fully formed, but only exists in the memory
+ * of the client task. In order to be visible to the system, the function
+ * must be bound using ddf_fun_bind().
+ *
+ * This function should only fail if there is not enough free memory.
+ * Specifically, this function succeeds even if @a dev already has
+ * a (bound) function with the same name.
+ *
+ * Type: A function of type fun_inner indicates that DDF should attempt
+ * to attach child devices to the function. fun_exposed means that
+ * the function should be exported to external clients (applications).
+ *
+ * @param dev		Device to which we are adding function
+ * @param ftype		Type of function (fun_inner or fun_exposed)
+ * @param name		Name of function
+ *
+ * @return		New function or @c NULL if memory is not available
+ */
+ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name)
+{
+	ddf_fun_t *fun;
+
+	fun = create_function();
+	if (fun == NULL)
+		return NULL;
+
+	fun->bound = false;
+	fun->dev = dev;
+	fun->ftype = ftype;
+
+	fun->name = str_dup(name);
+	if (fun->name == NULL) {
+		delete_function(fun);
+		return NULL;
+	}
+
+	return fun;
+}
+
+/** Destroy DDF function node.
+ *
+ * Destroy a function previously created with ddf_fun_create(). The function
+ * must not be bound.
+ *
+ * @param fun		Function to destroy
+ */
+void ddf_fun_destroy(ddf_fun_t *fun)
+{
+	assert(fun->bound == false);
+	delete_function(fun);
+}
+
+static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx)
 {
 	assert(is_valid_iface_idx(idx));
-	if (dev->ops == NULL)
+	if (fun->ops == NULL)
 		return NULL;
-	return dev->ops->interfaces[idx];
-}
-
-int child_device_register(device_t *child, device_t *parent)
-{
-	assert(child->name != NULL);
+	return fun->ops->interfaces[idx];
+}
+
+/** Bind a function node.
+ *
+ * Bind the specified function to the system. This effectively makes
+ * the function visible to the system (uploads it to the server).
+ *
+ * This function can fail for several reasons. Specifically,
+ * it will fail if the device already has a bound function of
+ * the same name.
+ *
+ * @param fun		Function to bind
+ * @return		EOK on success or negative error code
+ */
+int ddf_fun_bind(ddf_fun_t *fun)
+{
+	assert(fun->name != NULL);
 	
 	int res;
 	
-	add_to_devices_list(child);
-	res = devman_child_device_register(child->name, &child->match_ids,
-	    parent->handle, &child->handle);
+	add_to_functions_list(fun);
+	res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
+	    fun->dev->handle, &fun->handle);
 	if (res != EOK) {
-		remove_from_devices_list(child);
+		remove_from_functions_list(fun);
 		return res;
 	}
 	
+	fun->bound = true;
 	return res;
 }
 
-/** Wrapper for child_device_register for devices with single match id.
- *
- * @param parent Parent device.
- * @param child_name Child device name.
- * @param child_match_id Child device match id.
- * @param child_match_score Child device match score.
- * @return Error code.
- */
-int child_device_register_wrapper(device_t *parent, const char *child_name,
-    const char *child_match_id, int child_match_score)
-{
-	device_t *child = NULL;
-	match_id_t *match_id = NULL;
-	int rc;
-	
-	child = create_device();
-	if (child == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-	
-	child->name = child_name;
+/** Add single match ID to inner function.
+ *
+ * Construct and add a single match ID to the specified function.
+ * Cannot be called when the function node is bound.
+ *
+ * @param fun			Function
+ * @param match_id_str		Match string
+ * @param match_score		Match score
+ * @return			EOK on success, ENOMEM if out of memory.
+ */
+int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str,
+    int match_score)
+{
+	match_id_t *match_id;
+	
+	assert(fun->bound == false);
+	assert(fun->ftype == fun_inner);
 	
 	match_id = create_match_id();
-	if (match_id == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-	
-	match_id->id = child_match_id;
-	match_id->score = child_match_score;
-	add_match_id(&child->match_ids, match_id);
-	
-	rc = child_device_register(child, parent);
-	if (rc != EOK)
-		goto failure;
-	
+	if (match_id == NULL)
+		return ENOMEM;
+	
+	match_id->id = match_id_str;
+	match_id->score = 90;
+	
+	add_match_id(&fun->match_ids, match_id);
 	return EOK;
-	
-failure:
-	if (match_id != NULL) {
-		match_id->id = NULL;
-		delete_match_id(match_id);
-	}
-	
-	if (child != NULL) {
-		child->name = NULL;
-		delete_device(child);
-	}
-	
-	return rc;
 }
 
 /** Get default handler for client requests */
-remote_handler_t *device_get_default_handler(device_t *dev)
-{
-	if (dev->ops == NULL)
+static remote_handler_t *function_get_default_handler(ddf_fun_t *fun)
+{
+	if (fun->ops == NULL)
 		return NULL;
-	return dev->ops->default_handler;
-}
-
-int add_device_to_class(device_t *dev, const char *class_name)
-{
-	return devman_add_device_to_class(dev->handle, class_name);
-}
-
-int driver_main(driver_t *drv)
+	return fun->ops->default_handler;
+}
+
+/** Add exposed function to class.
+ *
+ * Must only be called when the function is bound.
+ */
+int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
+{
+	assert(fun->bound == true);
+	assert(fun->ftype == fun_exposed);
+	
+	return devman_add_device_to_class(fun->handle, class_name);
+}
+
+int ddf_driver_main(driver_t *drv)
 {
 	/*
Index: uspace/lib/drv/generic/remote_char_dev.c
===================================================================
--- uspace/lib/drv/generic/remote_char_dev.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/drv/generic/remote_char_dev.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -37,10 +37,10 @@
 
 #include "ops/char_dev.h"
-#include "driver.h"
+#include "ddf/driver.h"
 
 #define MAX_CHAR_RW_COUNT 256
 
-static void remote_char_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_char_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_char_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_char_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 
 /** Remote character interface operations. */
@@ -67,9 +67,9 @@
  * local interface to the remote client.
  *
- * @param dev		The device from which the data are read.
+ * @param fun		The function from which the data are read.
  * @param ops		The local ops structure.
  */
 static void
-remote_char_read(device_t *dev, void *ops, ipc_callid_t callid,
+remote_char_read(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
     ipc_call_t *call)
 {
@@ -94,5 +94,5 @@
 	
 	char buf[MAX_CHAR_RW_COUNT];
-	int ret = (*char_dev_ops->read)(dev, buf, len);
+	int ret = (*char_dev_ops->read)(fun, buf, len);
 	
 	if (ret < 0) {
@@ -114,9 +114,9 @@
  * local interface to the remote client.
  *
- * @param dev		The device to which the data are written.
+ * @param fun		The function to which the data are written.
  * @param ops		The local ops structure.
  */
 static void
-remote_char_write(device_t *dev, void *ops, ipc_callid_t callid,
+remote_char_write(ddf_fun_t *fun, void *ops, ipc_callid_t callid,
     ipc_call_t *call)
 {
@@ -144,5 +144,5 @@
 	async_data_write_finalize(cid, buf, len);
 	
-	int ret = (*char_dev_ops->write)(dev, buf, len);
+	int ret = (*char_dev_ops->write)(fun, buf, len);
 	if (ret < 0) {
 		/* Some error occured. */
Index: uspace/lib/drv/generic/remote_hw_res.c
===================================================================
--- uspace/lib/drv/generic/remote_hw_res.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/drv/generic/remote_hw_res.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -37,9 +37,9 @@
 
 #include "ops/hw_res.h"
-#include "driver.h"
+#include "ddf/driver.h"
 
-static void remote_hw_res_get_resource_list(device_t *, void *, ipc_callid_t,
+static void remote_hw_res_get_resource_list(ddf_fun_t *, void *, ipc_callid_t,
     ipc_call_t *);
-static void remote_hw_res_enable_interrupt(device_t *, void *, ipc_callid_t,
+static void remote_hw_res_enable_interrupt(ddf_fun_t *, void *, ipc_callid_t,
     ipc_call_t *);
 
@@ -55,5 +55,5 @@
 };
 
-static void remote_hw_res_enable_interrupt(device_t *dev, void *ops,
+static void remote_hw_res_enable_interrupt(ddf_fun_t *fun, void *ops,
     ipc_callid_t callid, ipc_call_t *call)
 {
@@ -62,5 +62,5 @@
 	if (hw_res_ops->enable_interrupt == NULL)
 		async_answer_0(callid, ENOTSUP);
-	else if (hw_res_ops->enable_interrupt(dev))
+	else if (hw_res_ops->enable_interrupt(fun))
 		async_answer_0(callid, EOK);
 	else
@@ -68,5 +68,5 @@
 }
 
-static void remote_hw_res_get_resource_list(device_t *dev, void *ops,
+static void remote_hw_res_get_resource_list(ddf_fun_t *fun, void *ops,
     ipc_callid_t callid, ipc_call_t *call)
 {
@@ -78,5 +78,5 @@
 	}
 	
-	hw_resource_list_t *hw_resources = hw_res_ops->get_resource_list(dev);
+	hw_resource_list_t *hw_resources = hw_res_ops->get_resource_list(fun);
 	if (hw_resources == NULL){
 		async_answer_0(callid, ENOENT);
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef DDF_DRIVER_H_
+#define DDF_DRIVER_H_
+
+#include <ipc/devman.h>
+#include <ipc/dev_iface.h>
+
+#include "../dev_iface.h"
+
+typedef struct ddf_dev ddf_dev_t;
+typedef struct ddf_fun ddf_fun_t;
+
+/*
+ * Device
+ */
+
+/** Devices operations */
+typedef struct ddf_dev_ops {
+	/**
+	 * Optional callback function called when a client is connecting to the
+	 * device.
+	 */
+	int (*open)(ddf_fun_t *);
+	
+	/**
+	 * Optional callback function called when a client is disconnecting from
+	 * the device.
+	 */
+	void (*close)(ddf_fun_t *);
+	
+	/** The table of standard interfaces implemented by the device. */
+	void *interfaces[DEV_IFACE_COUNT];
+	
+	/**
+	 * The default handler of remote client requests. If the client's remote
+	 * request cannot be handled by any of the standard interfaces, the
+	 * default handler is used.
+	 */
+	remote_handler_t *default_handler;
+} ddf_dev_ops_t;
+
+/** Device structure */
+struct ddf_dev {
+	/**
+	 * Globally unique device identifier (assigned to the device by the
+	 * device manager).
+	 */
+	devman_handle_t handle;
+	
+	/**
+	 * Phone to the parent device driver (if it is different from this
+	 * driver)
+	 */
+	int parent_phone;
+	
+	/** Device name */
+	const char *name;
+	
+	/** Driver-specific data associated with this device */
+	void *driver_data;
+	
+	/** Link in the list of devices handled by the driver */
+	link_t link;
+};
+
+/** Function structure */
+struct ddf_fun {
+	/** True if bound to the device manager */
+	bool bound;
+	/** Function indentifier (asigned by device manager) */
+	devman_handle_t handle;
+	
+	/** Device which this function belogs to */
+	ddf_dev_t *dev;
+	
+	/** Function type */
+	fun_type_t ftype;
+	/** Function name */
+	const char *name;
+	/** List of device ids for driver matching */
+	match_id_list_t match_ids;
+	/** Driver-specific data associated with this function */
+	void *driver_data;
+	/** Implementation of operations provided by this function */
+	ddf_dev_ops_t *ops;
+	
+	/** Link in the list of functions handled by the driver */
+	link_t link;
+};
+
+/*
+ * Driver
+ */
+
+/** Generic device driver operations */
+typedef struct driver_ops {
+	/** Callback method for passing a new device to the device driver */
+	int (*add_device)(ddf_dev_t *dev);
+	/* TODO: add other generic driver operations */
+} driver_ops_t;
+
+/** Driver structure */
+typedef struct driver {
+	/** Name of the device driver */
+	const char *name;
+	/** Generic device driver operations */
+	driver_ops_t *driver_ops;
+} driver_t;
+
+extern int ddf_driver_main(driver_t *);
+
+extern ddf_fun_t *ddf_fun_create(ddf_dev_t *, fun_type_t, const char *);
+extern void ddf_fun_destroy(ddf_fun_t *);
+extern int ddf_fun_bind(ddf_fun_t *);
+extern int ddf_fun_add_match_id(ddf_fun_t *, const char *, int);
+
+extern int ddf_fun_add_to_class(ddf_fun_t *, const char *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/ddf/interrupt.h
===================================================================
--- uspace/lib/drv/include/ddf/interrupt.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
+++ uspace/lib/drv/include/ddf/interrupt.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef DDF_INTERRUPT_H_
+#define DDF_INTERRUPT_H_
+
+#include <kernel/ddi/irq.h>
+#include <adt/list.h>
+#include <ddi.h>
+#include <fibril_synch.h>
+
+#include "driver.h"
+#include "../dev_iface.h"
+
+/*
+ * Interrupts
+ */
+
+typedef void interrupt_handler_t(ddf_dev_t *, ipc_callid_t, ipc_call_t *);
+
+typedef struct interrupt_context {
+	int id;
+	ddf_dev_t *dev;
+	int irq;
+	interrupt_handler_t *handler;
+	link_t link;
+} interrupt_context_t;
+
+typedef struct interrupt_context_list {
+	int curr_id;
+	link_t contexts;
+	fibril_mutex_t mutex;
+} interrupt_context_list_t;
+
+extern interrupt_context_t *create_interrupt_context(void);
+extern void delete_interrupt_context(interrupt_context_t *);
+extern void init_interrupt_context_list(interrupt_context_list_t *);
+extern void add_interrupt_context(interrupt_context_list_t *,
+    interrupt_context_t *);
+extern void remove_interrupt_context(interrupt_context_list_t *,
+    interrupt_context_t *);
+extern interrupt_context_t *find_interrupt_context_by_id(
+    interrupt_context_list_t *, int);
+extern interrupt_context_t *find_interrupt_context(
+    interrupt_context_list_t *, ddf_dev_t *, int);
+
+extern int register_interrupt_handler(ddf_dev_t *, int, interrupt_handler_t *,
+    irq_code_t *);
+extern int unregister_interrupt_handler(ddf_dev_t *, int);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/dev_iface.h
===================================================================
--- uspace/lib/drv/include/dev_iface.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/drv/include/dev_iface.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -43,5 +43,5 @@
  */
 
-struct device;
+struct ddf_fun;
 
 /*
@@ -49,8 +49,8 @@
  * devices driver.
  */
-typedef void remote_iface_func_t(struct device *, void *, ipc_callid_t,
+typedef void remote_iface_func_t(struct ddf_fun *, void *, ipc_callid_t,
     ipc_call_t *);
 typedef remote_iface_func_t *remote_iface_func_ptr_t;
-typedef void remote_handler_t(struct device *, ipc_callid_t, ipc_call_t *);
+typedef void remote_handler_t(struct ddf_fun *, ipc_callid_t, ipc_call_t *);
 
 typedef struct {
Index: pace/lib/drv/include/driver.h
===================================================================
--- uspace/lib/drv/include/driver.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ 	(revision )
@@ -1,193 +1,0 @@
-/*
- * Copyright (c) 2010 Lenka Trochtova
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libdrv
- * @{
- */
-/** @file
- */
-
-#ifndef LIBDRV_DRIVER_H_
-#define LIBDRV_DRIVER_H_
-
-#include <kernel/ddi/irq.h>
-#include <adt/list.h>
-#include <devman.h>
-#include <ipc/devman.h>
-#include <ipc/dev_iface.h>
-#include <assert.h>
-#include <ddi.h>
-#include <libarch/ddi.h>
-#include <fibril_synch.h>
-#include <malloc.h>
-
-#include "dev_iface.h"
-
-struct device;
-typedef struct device device_t;
-
-/*
- * Device class
- */
-
-/** Devices operations */
-typedef struct device_ops {
-	/**
-	 * Optional callback function called when a client is connecting to the
-	 * device.
-	 */
-	int (*open)(device_t *);
-	
-	/**
-	 * Optional callback function called when a client is disconnecting from
-	 * the device.
-	 */
-	void (*close)(device_t *);
-	
-	/** The table of standard interfaces implemented by the device. */
-	void *interfaces[DEV_IFACE_COUNT];
-	
-	/**
-	 * The default handler of remote client requests. If the client's remote
-	 * request cannot be handled by any of the standard interfaces, the
-	 * default handler is used.
-	 */
-	remote_handler_t *default_handler;
-} device_ops_t;
-
-
-/*
- * Device
- */
-
-/** Device structure */
-struct device {
-	/**
-	 * Globally unique device identifier (assigned to the device by the
-	 * device manager).
-	 */
-	devman_handle_t handle;
-	
-	/**
-	 * Phone to the parent device driver (if it is different from this
-	 * driver)
-	 */
-	int parent_phone;
-	
-	/** Parent device if handled by this driver, NULL otherwise */
-	device_t *parent;
-	/** Device name */
-	const char *name;
-	/** List of device ids for device-to-driver matching */
-	match_id_list_t match_ids;
-	/** Driver-specific data associated with this device */
-	void *driver_data;
-	/** The implementation of operations provided by this device */
-	device_ops_t *ops;
-	
-	/** Link in the list of devices handled by the driver */
-	link_t link;
-};
-
-/*
- * Driver
- */
-
-/** Generic device driver operations */
-typedef struct driver_ops {
-	/** Callback method for passing a new device to the device driver */
-	int (*add_device)(device_t *dev);
-	/* TODO: add other generic driver operations */
-} driver_ops_t;
-
-/** Driver structure */
-typedef struct driver {
-	/** Name of the device driver */
-	const char *name;
-	/** Generic device driver operations */
-	driver_ops_t *driver_ops;
-} driver_t;
-
-int driver_main(driver_t *);
-
-/** Create new device structure.
- *
- * @return		The device structure.
- */
-extern device_t *create_device(void);
-extern void delete_device(device_t *);
-extern void *device_get_ops(device_t *, dev_inferface_idx_t);
-
-extern int child_device_register(device_t *, device_t *);
-extern int child_device_register_wrapper(device_t *, const char *, const char *,
-    int);
-
-/*
- * Interrupts
- */
-
-typedef void interrupt_handler_t(device_t *, ipc_callid_t, ipc_call_t *);
-
-typedef struct interrupt_context {
-	int id;
-	device_t *dev;
-	int irq;
-	interrupt_handler_t *handler;
-	link_t link;
-} interrupt_context_t;
-
-typedef struct interrupt_context_list {
-	int curr_id;
-	link_t contexts;
-	fibril_mutex_t mutex;
-} interrupt_context_list_t;
-
-extern interrupt_context_t *create_interrupt_context(void);
-extern void delete_interrupt_context(interrupt_context_t *);
-extern void init_interrupt_context_list(interrupt_context_list_t *);
-extern void add_interrupt_context(interrupt_context_list_t *,
-    interrupt_context_t *);
-extern void remove_interrupt_context(interrupt_context_list_t *,
-    interrupt_context_t *);
-extern interrupt_context_t *find_interrupt_context_by_id(
-    interrupt_context_list_t *, int);
-extern interrupt_context_t *find_interrupt_context(
-    interrupt_context_list_t *, device_t *, int);
-
-extern int register_interrupt_handler(device_t *, int, interrupt_handler_t *,
-    irq_code_t *);
-extern int unregister_interrupt_handler(device_t *, int);
-
-extern remote_handler_t *device_get_default_handler(device_t *);
-extern int add_device_to_class(device_t *, const char *);
-
-#endif
-
-/**
- * @}
- */
Index: uspace/lib/drv/include/ops/char_dev.h
===================================================================
--- uspace/lib/drv/include/ops/char_dev.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/drv/include/ops/char_dev.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -36,9 +36,9 @@
 #define LIBDRV_OPS_CHAR_DEV_H_
 
-#include "../driver.h"
+#include "../ddf/driver.h"
 
 typedef struct {
-	int (*read)(device_t *, char *, size_t);
-	int (*write)(device_t *, char *, size_t);
+	int (*read)(ddf_fun_t *, char *, size_t);
+	int (*write)(ddf_fun_t *, char *, size_t);
 } char_dev_ops_t;
 
Index: uspace/lib/drv/include/ops/hw_res.h
===================================================================
--- uspace/lib/drv/include/ops/hw_res.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/lib/drv/include/ops/hw_res.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -39,9 +39,9 @@
 #include <sys/types.h>
 
-#include "../driver.h"
+#include "../ddf/driver.h"
 
 typedef struct {
-	 hw_resource_list_t *(*get_resource_list)(device_t *);
-	 bool (*enable_interrupt)(device_t *);
+	 hw_resource_list_t *(*get_resource_list)(ddf_fun_t *);
+	 bool (*enable_interrupt)(ddf_fun_t *);
 } hw_res_ops_t;
 
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -55,4 +55,5 @@
 #include <as.h>
 #include <fibril_synch.h>
+#include <stdint.h>
 #include <str.h>
 #include <devmap.h>
@@ -61,4 +62,5 @@
 #include <errno.h>
 #include <bool.h>
+#include <byteorder.h>
 #include <task.h>
 #include <macros.h>
@@ -73,6 +75,9 @@
 #define LEGACY_CTLS 4
 
-/** Physical block size. Should be always 512. */
-static const size_t block_size = 512;
+/**
+ * Size of data returned from Identify Device or Identify Packet Device
+ * command.
+ */
+static const size_t identify_data_size = 512;
 
 /** Size of the communication area. */
@@ -105,10 +110,16 @@
 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
     const void *buf);
-static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
+static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
     void *buf);
-static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
+static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
     const void *buf);
 static int disk_init(disk_t *d, int disk_id);
 static int drive_identify(int drive_id, void *buf);
+static int identify_pkt_dev(int dev_idx, void *buf);
+static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
+    void *obuf, size_t obuf_size);
+static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size);
+static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
+    void *obuf, size_t obuf_size);
 static void disk_print_summary(disk_t *d);
 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
@@ -203,15 +214,20 @@
 	printf("%s: ", d->model);
 
-	switch (d->amode) {
-	case am_chs:
-		printf("CHS %u cylinders, %u heads, %u sectors",
-		    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
-		break;
-	case am_lba28:
-		printf("LBA-28");
-		break;
-	case am_lba48:
-		printf("LBA-48");
-		break;
+	if (d->dev_type == ata_reg_dev) {
+		switch (d->amode) {
+		case am_chs:
+			printf("CHS %u cylinders, %u heads, %u sectors",
+			    disk->geom.cylinders, disk->geom.heads,
+			    disk->geom.sectors);
+			break;
+		case am_lba28:
+			printf("LBA-28");
+			break;
+		case am_lba48:
+			printf("LBA-48");
+			break;
+		}
+	} else {
+		printf("PACKET");
 	}
 
@@ -313,5 +329,5 @@
 			    IPC_GET_ARG2(call));
 			cnt = IPC_GET_ARG3(call);
-			if (cnt * block_size > comm_size) {
+			if (cnt * disk[disk_id].block_size > comm_size) {
 				retval = ELIMIT;
 				break;
@@ -323,5 +339,5 @@
 			    IPC_GET_ARG2(call));
 			cnt = IPC_GET_ARG3(call);
-			if (cnt * block_size > comm_size) {
+			if (cnt * disk[disk_id].block_size > comm_size) {
 				retval = ELIMIT;
 				break;
@@ -330,5 +346,5 @@
 			break;
 		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, block_size);
+			async_answer_1(callid, EOK, disk[disk_id].block_size);
 			continue;
 		case BD_GET_NUM_BLOCKS:
@@ -353,4 +369,5 @@
 	identify_data_t idata;
 	uint8_t model[40];
+	ata_inquiry_data_t inq_data;
 	uint16_t w;
 	uint8_t c;
@@ -359,11 +376,42 @@
 	unsigned i;
 
+	d->present = false;
+	fibril_mutex_initialize(&d->lock);
+
+	/* Try identify command. */
 	rc = drive_identify(disk_id, &idata);
-	if (rc != EOK) {
-		d->present = false;
-		return rc;
-	}
-
-	if ((idata.caps & cap_lba) == 0) {
+	if (rc == EOK) {
+		/* Success. It's a register (non-packet) device. */
+		printf("ATA register-only device found.\n");
+		d->dev_type = ata_reg_dev;
+	} else if (rc == EIO) {
+		/*
+		 * There is something, but not a register device.
+		 * It could be a packet device.
+		 */
+		rc = identify_pkt_dev(disk_id, &idata);
+		if (rc == EOK) {
+			/* We have a packet device. */
+			d->dev_type = ata_pkt_dev;
+		} else {
+			/* Nope. Something's there, but not recognized. */
+			return EIO;
+		}
+	} else {
+		/* Operation timed out. That means there is no device there. */
+		return EIO;
+	}
+
+	printf("device caps: 0x%04x\n", idata.caps);
+	if (d->dev_type == ata_pkt_dev) {
+		/* Packet device */
+		d->amode = 0;
+
+		d->geom.cylinders = 0;
+		d->geom.heads = 0;
+		d->geom.sectors = 0;
+
+		d->blocks = 0;
+	} else if ((idata.caps & rd_cap_lba) == 0) {
 		/* Device only supports CHS addressing. */
 		d->amode = am_chs;
@@ -422,7 +470,25 @@
 	d->model[pos] = '\0';
 
+	if (d->dev_type == ata_pkt_dev) {
+		/* Send inquiry. */
+		rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data));
+		if (rc != EOK) {
+			printf("Device inquiry failed.\n");
+			d->present = false;
+			return EIO;
+		}
+
+		/* Check device type. */
+		if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM)
+			printf("Warning: Peripheral device type is not CD-ROM.\n");
+
+		/* Assume 2k block size for now. */
+		d->block_size = 2048;
+	} else {
+		/* Assume register Read always uses 512-byte blocks. */
+		d->block_size = 512;
+	}
+
 	d->present = true;
-	fibril_mutex_initialize(&d->lock);
-
 	return EOK;
 }
@@ -435,5 +501,10 @@
 
 	while (cnt > 0) {
-		rc = ata_bd_read_block(disk_id, ba, 1, buf);
+		if (disk[disk_id].dev_type == ata_reg_dev)
+			rc = ata_rcmd_read(disk_id, ba, 1, buf);
+		else
+			rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
+			    disk[disk_id].block_size);
+
 		if (rc != EOK)
 			return rc;
@@ -441,5 +512,5 @@
 		++ba;
 		--cnt;
-		buf += block_size;
+		buf += disk[disk_id].block_size;
 	}
 
@@ -453,6 +524,9 @@
 	int rc;
 
+	if (disk[disk_id].dev_type != ata_reg_dev)
+		return ENOTSUP;
+
 	while (cnt > 0) {
-		rc = ata_bd_write_block(disk_id, ba, 1, buf);
+		rc = ata_rcmd_write(disk_id, ba, 1, buf);
 		if (rc != EOK)
 			return rc;
@@ -460,5 +534,5 @@
 		++ba;
 		--cnt;
-		buf += block_size;
+		buf += disk[disk_id].block_size;
 	}
 
@@ -473,4 +547,7 @@
  * @param disk_id	Device ID, 0 or 1.
  * @param buf		Pointer to a 512-byte buffer.
+ *
+ * @return		ETIMEOUT on timeout (this can mean the device is
+ *			not present). EIO if device responds with error.
  */
 static int drive_identify(int disk_id, void *buf)
@@ -484,5 +561,5 @@
 
 	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
-		return EIO;
+		return ETIMEOUT;
 
 	pio_write_8(&cmd->drive_head, drv_head);
@@ -493,15 +570,15 @@
 	 */
 	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
-		return EIO;
+		return ETIMEOUT;
 
 	pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
 
 	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
-		return EIO;
+		return ETIMEOUT;
 
 	/* Read data from the disk buffer. */
 
 	if ((status & SR_DRQ) != 0) {
-		for (i = 0; i < block_size / 2; i++) {
+		for (i = 0; i < identify_data_size / 2; i++) {
 			data = pio_read_16(&cmd->data_port);
 			((uint16_t *) buf)[i] = data;
@@ -509,6 +586,204 @@
 	}
 
+	if ((status & SR_ERR) != 0) {
+		return EIO;
+	}
+
+	return EOK;
+}
+
+/** Issue Identify Packet Device command.
+ *
+ * Reads @c identify data into the provided buffer. This is used to detect
+ * whether an ATAPI device is present and if so, to determine its parameters.
+ *
+ * @param dev_idx	Device index, 0 or 1.
+ * @param buf		Pointer to a 512-byte buffer.
+ */
+static int identify_pkt_dev(int dev_idx, void *buf)
+{
+	uint16_t data;
+	uint8_t status;
+	uint8_t drv_head;
+	size_t i;
+
+	drv_head = ((dev_idx != 0) ? DHR_DRV : 0);
+
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
+		return EIO;
+
+	pio_write_8(&cmd->drive_head, drv_head);
+
+	/* For ATAPI commands we do not need to wait for DRDY. */
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
+		return EIO;
+
+	pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV);
+
+	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
+		return EIO;
+
+	/* Read data from the device buffer. */
+
+	if ((status & SR_DRQ) != 0) {
+		for (i = 0; i < identify_data_size / 2; i++) {
+			data = pio_read_16(&cmd->data_port);
+			((uint16_t *) buf)[i] = data;
+		}
+	}
+
 	if ((status & SR_ERR) != 0)
 		return EIO;
+
+	return EOK;
+}
+
+/** Issue packet command (i. e. write a command packet to the device).
+ *
+ * Only data-in commands are supported (e.g. inquiry, read).
+ *
+ * @param dev_idx	Device index (0 or 1)
+ * @param obuf		Buffer for storing data read from device
+ * @param obuf_size	Size of obuf in bytes
+ *
+ * @return EOK on success, EIO on error.
+ */
+static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
+    void *obuf, size_t obuf_size)
+{
+	size_t i;
+	uint8_t status;
+	uint8_t drv_head;
+	disk_t *d;
+	size_t data_size;
+	uint16_t val;
+
+	d = &disk[dev_idx];
+	fibril_mutex_lock(&d->lock);
+
+	/* New value for Drive/Head register */
+	drv_head =
+	    ((dev_idx != 0) ? DHR_DRV : 0);
+
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	pio_write_8(&cmd->drive_head, drv_head);
+
+	if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	/* Byte count <- max. number of bytes we can read in one transfer. */
+	pio_write_8(&cmd->cylinder_low, 0xfe);
+	pio_write_8(&cmd->cylinder_high, 0xff);
+
+	pio_write_8(&cmd->command, CMD_PACKET);
+
+	if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	/* Write command packet. */
+	for (i = 0; i < (cpkt_size + 1) / 2; i++)
+		pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]);
+
+	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	if ((status & SR_DRQ) == 0) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	/* Read byte count. */
+	data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) +
+	    ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8);
+
+	/* Check whether data fits into output buffer. */
+	if (data_size > obuf_size) {
+		/* Output buffer is too small to store data. */
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	/* Read data from the device buffer. */
+	for (i = 0; i < (data_size + 1) / 2; i++) {
+		val = pio_read_16(&cmd->data_port);
+		((uint16_t *) obuf)[i] = val;
+	}
+
+	if (status & SR_ERR) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	fibril_mutex_unlock(&d->lock);
+
+	return EOK;
+}
+
+/** Issue ATAPI Inquiry.
+ *
+ * @param dev_idx	Device index (0 or 1)
+ * @param obuf		Buffer for storing inquiry data read from device
+ * @param obuf_size	Size of obuf in bytes
+ *
+ * @return EOK on success, EIO on error.
+ */
+static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size)
+{
+	ata_pcmd_inquiry_t cp;
+	int rc;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.opcode = PCMD_INQUIRY;
+	cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */
+
+	rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+/** Issue ATAPI read(12) command.
+ *
+ * Output buffer must be large enough to hold the data, otherwise the
+ * function will fail.
+ *
+ * @param dev_idx	Device index (0 or 1)
+ * @param ba		Starting block address
+ * @param cnt		Number of blocks to read
+ * @param obuf		Buffer for storing inquiry data read from device
+ * @param obuf_size	Size of obuf in bytes
+ *
+ * @return EOK on success, EIO on error.
+ */
+static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
+    void *obuf, size_t obuf_size)
+{
+	ata_pcmd_read_12_t cp;
+	int rc;
+
+	if (ba > UINT32_MAX)
+		return EINVAL;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.opcode = PCMD_READ_12;
+	cp.ba = host2uint32_t_be(ba);
+	cp.nblocks = host2uint32_t_be(cnt);
+
+	rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
+	if (rc != EOK)
+		return rc;
 
 	return EOK;
@@ -524,5 +799,5 @@
  * @return EOK on success, EIO on error.
  */
-static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
+static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
     void *buf)
 {
@@ -579,5 +854,5 @@
 		/* Read data from the device buffer. */
 
-		for (i = 0; i < block_size / 2; i++) {
+		for (i = 0; i < disk[disk_id].block_size / 2; i++) {
 			data = pio_read_16(&cmd->data_port);
 			((uint16_t *) buf)[i] = data;
@@ -601,5 +876,5 @@
  * @return EOK on success, EIO on error.
  */
-static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
+static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
     const void *buf)
 {
@@ -655,5 +930,5 @@
 		/* Write data to the device buffer. */
 
-		for (i = 0; i < block_size / 2; i++) {
+		for (i = 0; i < disk[disk_id].block_size / 2; i++) {
 			pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
 		}
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -53,6 +53,11 @@
 };
 
-/** Block addressing mode. */
-enum addr_mode {
+enum ata_dev_type {
+	ata_reg_dev,	/* Register device (no packet feature set support) */
+	ata_pkt_dev	/* Packet device (supports packet feature set). */
+};
+
+/** Register device block addressing mode. */
+enum rd_addr_mode {
 	am_chs,		/**< CHS block addressing */
 	am_lba28,	/**< LBA-28 block addressing */
@@ -62,6 +67,5 @@
 /** Block coordinates */
 typedef struct {
-	/** Addressing mode used */
-	enum addr_mode amode;
+	enum rd_addr_mode amode;
 
 	union {
@@ -90,5 +94,10 @@
 typedef struct {
 	bool present;
-	enum addr_mode amode;
+
+	/** Device type */
+	enum ata_dev_type dev_type;
+
+	/** Addressing mode to use (if register device) */
+	enum rd_addr_mode amode;
 
 	/*
@@ -102,4 +111,5 @@
 
 	uint64_t blocks;
+	size_t block_size;
 
 	char model[STR_BOUNDS(40) + 1];
Index: uspace/srv/bd/ata_bd/ata_hw.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_hw.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/bd/ata_bd/ata_hw.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -134,8 +134,10 @@
 	CMD_WRITE_SECTORS	= 0x30,
 	CMD_WRITE_SECTORS_EXT	= 0x34,
+	CMD_PACKET		= 0xA0,
+	CMD_IDENTIFY_PKT_DEV	= 0xA1,
 	CMD_IDENTIFY_DRIVE	= 0xEC
 };
 
-/** Data returned from @c identify command. */
+/** Data returned from identify device and identify packet device command. */
 typedef struct {
 	uint16_t gen_conf;
@@ -159,5 +161,5 @@
 	uint16_t max_rw_multiple;
 	uint16_t _res48;
-	uint16_t caps;
+	uint16_t caps;		/* Different meaning for packet device */
 	uint16_t _res50;
 	uint16_t pio_timing;
@@ -214,9 +216,22 @@
 } identify_data_t;
 
-enum ata_caps {
-	cap_iordy	= 0x0800,
-	cap_iordy_cbd	= 0x0400,
-	cap_lba		= 0x0200,
-	cap_dma		= 0x0100
+/** Capability bits for register device. */
+enum ata_regdev_caps {
+	rd_cap_iordy		= 0x0800,
+	rd_cap_iordy_cbd	= 0x0400,
+	rd_cap_lba		= 0x0200,
+	rd_cap_dma		= 0x0100
+};
+
+/** Capability bits for packet device. */
+enum ata_pktdev_caps {
+	pd_cap_ildma		= 0x8000,
+	pd_cap_cmdqueue		= 0x4000,
+	pd_cap_overlap		= 0x2000,
+	pd_cap_need_softreset	= 0x1000,	/* Obsolete (ATAPI-6) */
+	pd_cap_iordy		= 0x0800,
+	pd_cap_iordy_dis	= 0x0400,
+	pd_cap_lba		= 0x0200,	/* Must be on */
+	pd_cap_dma		= 0x0100
 };
 
@@ -226,4 +241,56 @@
 };
 
+/** ATA packet command codes. */
+enum ata_pkt_command {
+	PCMD_INQUIRY		= 0x12,
+	PCMD_READ_12		= 0xa8
+};
+
+/** ATAPI Inquiry command */
+typedef struct {
+	uint8_t opcode;		/**< Operation code (PCMD_INQUIRY) */
+	uint8_t _res0;
+	uint8_t _res1;
+	uint8_t _res2;
+	uint8_t alloc_len;	/**< Allocation length */
+	uint8_t _res3;
+	uint8_t _res4;
+	uint8_t _res5;
+	uint32_t _res6;
+} __attribute__ ((packed)) ata_pcmd_inquiry_t;
+
+/** ATAPI Read(12) command */
+typedef struct {
+	uint8_t opcode;		/**< Operation code (PCMD_READ_12) */
+	uint8_t _res0;
+	uint32_t ba;		/**< Starting block address */
+	uint32_t nblocks;	/**< Number of blocks to transfer */
+	uint8_t _res1;
+	uint8_t _res2;
+} __attribute__ ((packed)) ata_pcmd_read_12_t;
+
+/** Data returned from Inquiry command (mandatory part) */
+typedef struct {
+	uint8_t pdev_type;	/** Reserved, Peripheral device type */
+	uint8_t rmb;		/** RMB, Reserved */
+	uint8_t std_version;	/** ISO version, ECMA version, ANSI version */
+	uint8_t atapi_ver_rdf;	/** ATAPI version, Response data format */
+	uint8_t additional_len;	/** Additional length */
+	uint8_t _res0;
+	uint8_t _res1;
+	uint8_t _res2;
+	uint8_t vendor_id[8];	/** Vendor ID */
+	uint8_t product_id[8];	/** Product ID */
+	uint8_t product_rev[4];	/** Product revision level */
+} ata_inquiry_data_t;
+
+/** Extract value of ata_inquiry_data_t.pdev_type */
+#define INQUIRY_PDEV_TYPE(val) ((val) & 0x1f)
+
+/** Values for ata_inquiry_data_t.pdev_type */
+enum ata_pdev_type {
+	PDEV_TYPE_CDROM		= 0x05
+};
+
 #endif
 
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/devman/devman.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -41,4 +41,6 @@
 #include "devman.h"
 
+fun_node_t *find_node_child(fun_node_t *parent, const char *name);
+
 /* hash table operations */
 
@@ -51,13 +53,20 @@
     link_t *item)
 {
-	node_t *dev = hash_table_get_instance(item, node_t, devman_link);
+	dev_node_t *dev = hash_table_get_instance(item, dev_node_t, devman_dev);
 	return (dev->handle == (devman_handle_t) key[0]);
 }
 
-static int devmap_devices_compare(unsigned long key[], hash_count_t keys,
+static int devman_functions_compare(unsigned long key[], hash_count_t keys,
     link_t *item)
 {
-	node_t *dev = hash_table_get_instance(item, node_t, devmap_link);
-	return (dev->devmap_handle == (devmap_handle_t) key[0]);
+	fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devman_fun);
+	return (fun->handle == (devman_handle_t) key[0]);
+}
+
+static int devmap_functions_compare(unsigned long key[], hash_count_t keys,
+    link_t *item)
+{
+	fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devmap_fun);
+	return (fun->devmap_handle == (devmap_handle_t) key[0]);
 }
 
@@ -82,7 +91,13 @@
 };
 
+static hash_table_operations_t devman_functions_ops = {
+	.hash = devices_hash,
+	.compare = devman_functions_compare,
+	.remove_callback = devices_remove_callback
+};
+
 static hash_table_operations_t devmap_devices_ops = {
 	.hash = devices_hash,
-	.compare = devmap_devices_compare,
+	.compare = devmap_functions_compare,
 	.remove_callback = devices_remove_callback
 };
@@ -373,28 +388,52 @@
 }
 
-/** Create root device node in the device tree.
+/** Create root device and function node in the device tree.
  *
  * @param tree	The device tree.
  * @return	True on success, false otherwise.
  */
-bool create_root_node(dev_tree_t *tree)
-{
-	node_t *node;
-
-	printf(NAME ": create_root_node\n");
-
+bool create_root_nodes(dev_tree_t *tree)
+{
+	fun_node_t *fun;
+	dev_node_t *dev;
+	
+	printf(NAME ": create_root_nodes\n");
+	
 	fibril_rwlock_write_lock(&tree->rwlock);
-	node = create_dev_node();
-	if (node != NULL) {
-		insert_dev_node(tree, node, clone_string(""), NULL);
-		match_id_t *id = create_match_id();
-		id->id = clone_string("root");
-		id->score = 100;
-		add_match_id(&node->match_ids, id);
-		tree->root_node = node;
-	}
+	
+	/*
+	 * Create root function. This is a pseudo function to which
+	 * the root device node is attached. It allows us to match
+	 * the root device driver in a standard manner, i.e. against
+	 * the parent function.
+	 */
+	
+	fun = create_fun_node();
+	if (fun == NULL) {
+		fibril_rwlock_write_unlock(&tree->rwlock);
+		return false;
+	}
+	
+	insert_fun_node(tree, fun, clone_string(""), NULL);
+	match_id_t *id = create_match_id();
+	id->id = clone_string("root");
+	id->score = 100;
+	add_match_id(&fun->match_ids, id);
+	tree->root_node = fun;
+	
+	/*
+	 * Create root device node.
+	 */
+	dev = create_dev_node();
+	if (dev == NULL) {
+		fibril_rwlock_write_unlock(&tree->rwlock);
+		return false;
+	}
+	
+	insert_dev_node(tree, dev, fun);
+	
 	fibril_rwlock_write_unlock(&tree->rwlock);
-
-	return node != NULL;
+	
+	return dev != NULL;
 }
 
@@ -414,5 +453,5 @@
  *			is found.
  */
-driver_t *find_best_match_driver(driver_list_t *drivers_list, node_t *node)
+driver_t *find_best_match_driver(driver_list_t *drivers_list, dev_node_t *node)
 {
 	driver_t *best_drv = NULL, *drv = NULL;
@@ -442,13 +481,13 @@
  * @param drv		The driver.
  */
-void attach_driver(node_t *node, driver_t *drv)
+void attach_driver(dev_node_t *dev, driver_t *drv)
 {
 	printf(NAME ": attach_driver %s to device %s\n",
-	    drv->name, node->pathname);
+	    drv->name, dev->pfun->pathname);
 	
 	fibril_mutex_lock(&drv->driver_mutex);
 	
-	node->drv = drv;
-	list_append(&node->driver_devices, &drv->devices);
+	dev->drv = drv;
+	list_append(&dev->driver_devices, &drv->devices);
 	
 	fibril_mutex_unlock(&drv->driver_mutex);
@@ -530,5 +569,5 @@
 static void pass_devices_to_driver(driver_t *driver, dev_tree_t *tree)
 {
-	node_t *dev;
+	dev_node_t *dev;
 	link_t *link;
 	int phone;
@@ -551,5 +590,5 @@
 	link = driver->devices.next;
 	while (link != &driver->devices) {
-		dev = list_get_instance(link, node_t, driver_devices);
+		dev = list_get_instance(link, dev_node_t, driver_devices);
 		if (dev->passed_to_driver) {
 			link = link->next;
@@ -669,11 +708,11 @@
 }
 
-/** Create devmap path and name for the device. */
-static void devmap_register_tree_device(node_t *node, dev_tree_t *tree)
+/** Create devmap path and name for the function. */
+void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
 {
 	char *devmap_pathname = NULL;
 	char *devmap_name = NULL;
 	
-	asprintf(&devmap_name, "%s", node->pathname);
+	asprintf(&devmap_name, "%s", fun->pathname);
 	if (devmap_name == NULL)
 		return;
@@ -689,7 +728,7 @@
 	
 	devmap_device_register_with_iface(devmap_pathname,
-	    &node->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
-	
-	tree_add_devmap_device(tree, node);
+	    &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
+	
+	tree_add_devmap_function(tree, fun);
 	
 	free(devmap_name);
@@ -702,5 +741,5 @@
  * @param node		The device's node in the device tree.
  */
-void add_device(int phone, driver_t *drv, node_t *node, dev_tree_t *tree)
+void add_device(int phone, driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
 {
 	/*
@@ -709,5 +748,5 @@
 	 */
 	printf(NAME ": add_device (driver `%s', device `%s')\n", drv->name,
-	    node->name);
+	    dev->pfun->name);
 	
 	sysarg_t rc;
@@ -716,16 +755,16 @@
 	/* Send the device to the driver. */
 	devman_handle_t parent_handle;
-	if (node->parent) {
-		parent_handle = node->parent->handle;
+	if (dev->pfun) {
+		parent_handle = dev->pfun->handle;
 	} else {
 		parent_handle = 0;
 	}
 
-	aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, node->handle,
+	aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, dev->handle,
 	    parent_handle, &answer);
 	
 	/* Send the device's name to the driver. */
-	rc = async_data_write_start(phone, node->name,
-	    str_size(node->name) + 1);
+	rc = async_data_write_start(phone, dev->pfun->name,
+	    str_size(dev->pfun->name) + 1);
 	if (rc != EOK) {
 		/* TODO handle error */
@@ -737,15 +776,14 @@
 	switch(rc) {
 	case EOK:
-		node->state = DEVICE_USABLE;
-		devmap_register_tree_device(node, tree);
+		dev->state = DEVICE_USABLE;
 		break;
 	case ENOENT:
-		node->state = DEVICE_NOT_PRESENT;
+		dev->state = DEVICE_NOT_PRESENT;
 		break;
 	default:
-		node->state = DEVICE_INVALID;
-	}
-	
-	node->passed_to_driver = true;
+		dev->state = DEVICE_INVALID;
+	}
+	
+	dev->passed_to_driver = true;
 
 	return;
@@ -759,18 +797,23 @@
  *			successfully assigned to the device, false otherwise.
  */
-bool assign_driver(node_t *node, driver_list_t *drivers_list, dev_tree_t *tree)
-{
+bool assign_driver(dev_node_t *dev, driver_list_t *drivers_list,
+    dev_tree_t *tree)
+{
+	assert(dev != NULL);
+	assert(drivers_list != NULL);
+	assert(tree != NULL);
+	
 	/*
 	 * Find the driver which is the most suitable for handling this device.
 	 */
-	driver_t *drv = find_best_match_driver(drivers_list, node);
+	driver_t *drv = find_best_match_driver(drivers_list, dev);
 	if (drv == NULL) {
 		printf(NAME ": no driver found for device '%s'.\n",
-		    node->pathname);
+		    dev->pfun->pathname);
 		return false;
 	}
 	
 	/* Attach the driver to the device. */
-	attach_driver(node, drv);
+	attach_driver(dev, drv);
 	
 	fibril_mutex_lock(&drv->driver_mutex);
@@ -786,5 +829,5 @@
 		int phone = async_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
 		if (phone >= 0) {
-			add_device(phone, drv, node, tree);
+			add_device(phone, drv, dev, tree);
 			async_hangup(phone);
 		}
@@ -810,15 +853,17 @@
 	hash_table_create(&tree->devman_devices, DEVICE_BUCKETS, 1,
 	    &devman_devices_ops);
-	hash_table_create(&tree->devmap_devices, DEVICE_BUCKETS, 1,
+	hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
+	    &devman_functions_ops);
+	hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
 	    &devmap_devices_ops);
 	
 	fibril_rwlock_initialize(&tree->rwlock);
 	
-	/* Create root node and add it to the device tree. */
-	if (!create_root_node(tree))
+	/* Create root function and root device and add them to the device tree. */
+	if (!create_root_nodes(tree))
 		return false;
 
 	/* Find suitable driver and start it. */
-	return assign_driver(tree->root_node, drivers_list, tree);
+	return assign_driver(tree->root_node->child, drivers_list, tree);
 }
 
@@ -829,13 +874,13 @@
  * @return		A device node structure.
  */
-node_t *create_dev_node(void)
-{
-	node_t *res = malloc(sizeof(node_t));
+dev_node_t *create_dev_node(void)
+{
+	dev_node_t *res = malloc(sizeof(dev_node_t));
 	
 	if (res != NULL) {
-		memset(res, 0, sizeof(node_t));
-		list_initialize(&res->children);
-		list_initialize(&res->match_ids.ids);
-		list_initialize(&res->classes);
+		memset(res, 0, sizeof(dev_node_t));
+		list_initialize(&res->functions);
+		link_initialize(&res->driver_devices);
+		link_initialize(&res->devman_dev);
 	}
 	
@@ -847,14 +892,11 @@
  * @param node		The device node structure.
  */
-void delete_dev_node(node_t *node)
-{
-	assert(list_empty(&node->children));
-	assert(node->parent == NULL);
-	assert(node->drv == NULL);
-	
-	clean_match_ids(&node->match_ids);
-	free_not_null(node->name);
-	free_not_null(node->pathname);
-	free(node);
+void delete_dev_node(dev_node_t *dev)
+{
+	assert(list_empty(&dev->functions));
+	assert(dev->pfun == NULL);
+	assert(dev->drv == NULL);
+	
+	free(dev);
 }
 
@@ -865,5 +907,5 @@
  * @return		The device node.
  */
-node_t *find_dev_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
+dev_node_t *find_dev_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
 {
 	unsigned long key = handle;
@@ -873,5 +915,5 @@
 	
 	link = hash_table_find(&tree->devman_devices, &key);
-	return hash_table_get_instance(link, node_t, devman_link);
+	return hash_table_get_instance(link, dev_node_t, devman_dev);
 }
 
@@ -882,15 +924,88 @@
  * @return		The device node.
  */
-node_t *find_dev_node(dev_tree_t *tree, devman_handle_t handle)
-{
-	node_t *node = NULL;
+dev_node_t *find_dev_node(dev_tree_t *tree, devman_handle_t handle)
+{
+	dev_node_t *dev = NULL;
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
-	node = find_dev_node_no_lock(tree, handle);
+	dev = find_dev_node_no_lock(tree, handle);
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
-	return node;
-}
-
+	return dev;
+}
+
+/* Function nodes */
+
+/** Create a new function node.
+ *
+ * @return		A function node structure.
+ */
+fun_node_t *create_fun_node(void)
+{
+	fun_node_t *res = malloc(sizeof(fun_node_t));
+	
+	if (res != NULL) {
+		memset(res, 0, sizeof(fun_node_t));
+		link_initialize(&res->dev_functions);
+		list_initialize(&res->match_ids.ids);
+		list_initialize(&res->classes);
+		link_initialize(&res->devman_fun);
+		link_initialize(&res->devmap_fun);
+	}
+	
+	return res;
+}
+
+/** Delete a function node.
+ *
+ * @param fun		The device node structure.
+ */
+void delete_fun_node(fun_node_t *fun)
+{
+	assert(fun->dev == NULL);
+	assert(fun->child == NULL);
+	
+	clean_match_ids(&fun->match_ids);
+	free_not_null(fun->name);
+	free_not_null(fun->pathname);
+	free(fun);
+}
+
+/** Find the function node with the specified handle.
+ *
+ * @param tree		The device tree where we look for the device node.
+ * @param handle	The handle of the function.
+ * @return		The function node.
+ */
+fun_node_t *find_fun_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
+{
+	unsigned long key = handle;
+	link_t *link;
+	
+	assert(fibril_rwlock_is_locked(&tree->rwlock));
+	
+	link = hash_table_find(&tree->devman_functions, &key);
+	if (link == NULL)
+		return NULL;
+	
+	return hash_table_get_instance(link, fun_node_t, devman_fun);
+}
+
+/** Find the function node with the specified handle.
+ *
+ * @param tree		The device tree where we look for the device node.
+ * @param handle	The handle of the function.
+ * @return		The function node.
+ */
+fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle)
+{
+	fun_node_t *fun = NULL;
+	
+	fibril_rwlock_read_lock(&tree->rwlock);
+	fun = find_fun_node_no_lock(tree, handle);
+	fibril_rwlock_read_unlock(&tree->rwlock);
+	
+	return fun;
+}
 
 /** Create and set device's full path in device tree.
@@ -901,14 +1016,14 @@
  *			resources etc.).
  */
-static bool set_dev_path(node_t *node, node_t *parent)
-{
-	assert(node->name != NULL);
-	
-	size_t pathsize = (str_size(node->name) + 1);
+static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
+{
+	assert(fun->name != NULL);
+	
+	size_t pathsize = (str_size(fun->name) + 1);
 	if (parent != NULL)
 		pathsize += str_size(parent->pathname) + 1;
 	
-	node->pathname = (char *) malloc(pathsize);
-	if (node->pathname == NULL) {
+	fun->pathname = (char *) malloc(pathsize);
+	if (fun->pathname == NULL) {
 		printf(NAME ": failed to allocate device path.\n");
 		return false;
@@ -916,9 +1031,9 @@
 	
 	if (parent != NULL) {
-		str_cpy(node->pathname, pathsize, parent->pathname);
-		str_append(node->pathname, pathsize, "/");
-		str_append(node->pathname, pathsize, node->name);
+		str_cpy(fun->pathname, pathsize, parent->pathname);
+		str_append(fun->pathname, pathsize, "/");
+		str_append(fun->pathname, pathsize, fun->name);
 	} else {
-		str_cpy(node->pathname, pathsize, node->name);
+		str_cpy(fun->pathname, pathsize, fun->name);
 	}
 	
@@ -936,44 +1051,81 @@
  *			etc.).
  */
-bool insert_dev_node(dev_tree_t *tree, node_t *node, char *dev_name,
-    node_t *parent)
-{
-	assert(node != NULL);
+bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
+{
+	assert(dev != NULL);
 	assert(tree != NULL);
-	assert(dev_name != NULL);
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
-	node->name = dev_name;
-	if (!set_dev_path(node, parent)) {
+	/* Add the node to the handle-to-node map. */
+	dev->handle = ++tree->current_handle;
+	unsigned long key = dev->handle;
+	hash_table_insert(&tree->devman_devices, &key, &dev->devman_dev);
+
+	/* Add the node to the list of its parent's children. */
+	printf("insert_dev_node: dev=%p, dev->pfun := %p\n", dev, pfun);
+	dev->pfun = pfun;
+	pfun->child = dev;
+	
+	return true;
+}
+
+/** Insert new function into device tree.
+ *
+ * @param tree		The device tree.
+ * @param node		The newly added function node. 
+ * @param dev_name	The name of the newly added function.
+ * @param parent	Owning device node.
+ *
+ * @return		True on success, false otherwise (insufficient resources
+ *			etc.).
+ */
+bool insert_fun_node(dev_tree_t *tree, fun_node_t *fun, char *fun_name,
+    dev_node_t *dev)
+{
+	fun_node_t *pfun;
+	
+	assert(fun != NULL);
+	assert(tree != NULL);
+	assert(fun_name != NULL);
+	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
+	
+	/*
+	 * The root function is a special case, it does not belong to any
+	 * device so for the root function dev == NULL.
+	 */
+	pfun = (dev != NULL) ? dev->pfun : NULL;
+	
+	fun->name = fun_name;
+	if (!set_fun_path(fun, pfun)) {
 		return false;
 	}
 	
 	/* Add the node to the handle-to-node map. */
-	node->handle = ++tree->current_handle;
-	unsigned long key = node->handle;
-	hash_table_insert(&tree->devman_devices, &key, &node->devman_link);
+	fun->handle = ++tree->current_handle;
+	unsigned long key = fun->handle;
+	hash_table_insert(&tree->devman_functions, &key, &fun->devman_fun);
 
 	/* Add the node to the list of its parent's children. */
-	node->parent = parent;
-	if (parent != NULL)
-		list_append(&node->sibling, &parent->children);
+	fun->dev = dev;
+	if (dev != NULL)
+		list_append(&fun->dev_functions, &dev->functions);
 	
 	return true;
 }
 
-/** Find device node with a specified path in the device tree.
+/** Find function node with a specified path in the device tree.
  * 
- * @param path		The path of the device node in the device tree.
+ * @param path		The path of the function node in the device tree.
  * @param tree		The device tree.
- * @return		The device node if it is present in the tree, NULL
+ * @return		The function node if it is present in the tree, NULL
  *			otherwise.
  */
-node_t *find_dev_node_by_path(dev_tree_t *tree, char *path)
+fun_node_t *find_fun_node_by_path(dev_tree_t *tree, char *path)
 {
 	fibril_rwlock_read_lock(&tree->rwlock);
 	
-	node_t *dev = tree->root_node;
+	fun_node_t *fun = tree->root_node;
 	/*
-	 * Relative path to the device from its parent (but with '/' at the
+	 * Relative path to the function from its parent (but with '/' at the
 	 * beginning)
 	 */
@@ -982,5 +1134,5 @@
 	bool cont = (rel_path[0] == '/');
 	
-	while (cont && dev != NULL) {
+	while (cont && fun != NULL) {
 		next_path_elem  = get_path_elem_end(rel_path + 1);
 		if (next_path_elem[0] == '/') {
@@ -991,5 +1143,5 @@
 		}
 		
-		dev = find_node_child(dev, rel_path + 1);
+		fun = find_node_child(fun, rel_path + 1);
 		
 		if (cont) {
@@ -1002,27 +1154,27 @@
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
-	return dev;
-}
-
-/** Find child device node with a specified name.
+	return fun;
+}
+
+/** Find child function node with a specified name.
  *
  * Device tree rwlock should be held at least for reading.
  *
- * @param parent	The parent device node.
- * @param name		The name of the child device node.
- * @return		The child device node.
- */
-node_t *find_node_child(node_t *parent, const char *name)
-{
-	node_t *dev;
+ * @param parent	The parent function node.
+ * @param name		The name of the child function.
+ * @return		The child function node.
+ */
+fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
+{
+	fun_node_t *fun;
 	link_t *link;
 	
-	link = parent->children.next;
-	
-	while (link != &parent->children) {
-		dev = list_get_instance(link, node_t, sibling);
+	link = pfun->child->functions.next;
+	
+	while (link != &pfun->child->functions) {
+		fun = list_get_instance(link, fun_node_t, dev_functions);
 		
-		if (str_cmp(name, dev->name) == 0)
-			return dev;
+		if (str_cmp(name, fun->name) == 0)
+			return fun;
 		
 		link = link->next;
@@ -1107,5 +1259,5 @@
 }
 
-/** Add the device to the class.
+/** Add the device function to the class.
  *
  * The device may be added to multiple classes and a class may contain multiple
@@ -1120,12 +1272,18 @@
  *			with the class.
  */
-dev_class_info_t *add_device_to_class(node_t *dev, dev_class_t *cl,
+dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
     const char *base_dev_name)
 {
-	dev_class_info_t *info = create_dev_class_info();
+	dev_class_info_t *info;
+
+	assert(fun != NULL);
+	assert(cl != NULL);
+
+	info = create_dev_class_info();
+
 	
 	if (info != NULL) {
 		info->dev_class = cl;
-		info->dev = dev;
+		info->fun = fun;
 		
 		/* Add the device to the class. */
@@ -1135,5 +1293,5 @@
 		
 		/* Add the class to the device. */
-		list_append(&info->dev_classes, &dev->classes);
+		list_append(&info->dev_classes, &fun->classes);
 		
 		/* Create unique name for the device within the class. */
@@ -1189,5 +1347,5 @@
 	list_initialize(&class_list->classes);
 	fibril_rwlock_initialize(&class_list->rwlock);
-	hash_table_create(&class_list->devmap_devices, DEVICE_BUCKETS, 1,
+	hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
 	    &devmap_devices_class_ops);
 }
@@ -1196,23 +1354,23 @@
 /* Devmap devices */
 
-node_t *find_devmap_tree_device(dev_tree_t *tree, devmap_handle_t devmap_handle)
-{
-	node_t *dev = NULL;
+fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
+{
+	fun_node_t *fun = NULL;
 	link_t *link;
 	unsigned long key = (unsigned long) devmap_handle;
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
-	link = hash_table_find(&tree->devmap_devices, &key);
+	link = hash_table_find(&tree->devmap_functions, &key);
 	if (link != NULL)
-		dev = hash_table_get_instance(link, node_t, devmap_link);
+		fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
-	return dev;
-}
-
-node_t *find_devmap_class_device(class_list_t *classes,
+	return fun;
+}
+
+fun_node_t *find_devmap_class_function(class_list_t *classes,
     devmap_handle_t devmap_handle)
 {
-	node_t *dev = NULL;
+	fun_node_t *fun = NULL;
 	dev_class_info_t *cli;
 	link_t *link;
@@ -1220,31 +1378,31 @@
 	
 	fibril_rwlock_read_lock(&classes->rwlock);
-	link = hash_table_find(&classes->devmap_devices, &key);
+	link = hash_table_find(&classes->devmap_functions, &key);
 	if (link != NULL) {
 		cli = hash_table_get_instance(link, dev_class_info_t,
 		    devmap_link);
-		dev = cli->dev;
+		fun = cli->fun;
 	}
 	fibril_rwlock_read_unlock(&classes->rwlock);
 	
-	return dev;
-}
-
-void class_add_devmap_device(class_list_t *class_list, dev_class_info_t *cli)
+	return fun;
+}
+
+void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
 {
 	unsigned long key = (unsigned long) cli->devmap_handle;
 	
 	fibril_rwlock_write_lock(&class_list->rwlock);
-	hash_table_insert(&class_list->devmap_devices, &key, &cli->devmap_link);
+	hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
 	fibril_rwlock_write_unlock(&class_list->rwlock);
 
-	assert(find_devmap_class_device(class_list, cli->devmap_handle) != NULL);
-}
-
-void tree_add_devmap_device(dev_tree_t *tree, node_t *node)
-{
-	unsigned long key = (unsigned long) node->devmap_handle;
+	assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
+}
+
+void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
+{
+	unsigned long key = (unsigned long) fun->devmap_handle;
 	fibril_rwlock_write_lock(&tree->rwlock);
-	hash_table_insert(&tree->devmap_devices, &key, &node->devmap_link);
+	hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
 	fibril_rwlock_write_unlock(&tree->rwlock);
 }
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/devman/devman.h	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -56,6 +56,9 @@
 #define DEVMAP_SEPARATOR '\\'
 
-struct node;
-typedef struct node node_t;
+struct dev_node;
+typedef struct dev_node dev_node_t;
+
+struct fun_node;
+typedef struct fun_node fun_node_t;
 
 typedef enum {
@@ -117,55 +120,26 @@
 } device_state_t;
 
-/** Representation of a node in the device tree. */
-struct node {
+/** Device node in the device tree. */
+struct dev_node {
 	/** The global unique identifier of the device. */
 	devman_handle_t handle;
-	/** The name of the device specified by its parent. */
-	char *name;
-	
-	/**
-	 * Full path and name of the device in device hierarchi (i. e. in full
-	 * path in device tree).
-	 */
-	char *pathname;
-	
-	/** The node of the parent device. */
-	node_t *parent;
-	
-	/**
-	 * Pointers to previous and next child devices in the linked list of
-	 * parent device's node.
-	 */
-	link_t sibling;
-	
-	/** List of child device nodes. */
-	link_t children;
-	/** List of device ids for device-to-driver matching. */
-	match_id_list_t match_ids;
+	
+	/** (Parent) function the device is attached to. */
+	fun_node_t *pfun;
+	
+	/** List of device functions. */
+	link_t functions;
 	/** Driver of this device. */
 	driver_t *drv;
 	/** The state of the device. */
 	device_state_t state;
-	/**
-	 * Pointer to the previous and next device in the list of devices
-	 * owned by one driver.
-	 */
+	/** Link to list of devices owned by driver (driver_t.devices) */
 	link_t driver_devices;
 	
-	/** The list of device classes to which this device belongs. */
-	link_t classes;
-	/** Devmap handle if the device is registered by devmapper. */
-	devmap_handle_t devmap_handle;
-	
 	/**
 	 * Used by the hash table of devices indexed by devman device handles.
 	 */
-	link_t devman_link;
-	
-	/**
-	 * Used by the hash table of devices indexed by devmap device handles.
-	 */
-	link_t devmap_link;
-
+	link_t devman_dev;
+	
 	/**
 	 * Whether this device was already passed to the driver.
@@ -173,9 +147,47 @@
 	bool passed_to_driver;
 };
+
+/** Function node in the device tree. */
+struct fun_node {
+	/** The global unique identifier of the function */
+	devman_handle_t handle;
+	/** Name of the function, assigned by the device driver */
+	char *name;
+	
+	/** Full path and name of the device in device hierarchy */
+	char *pathname;
+	
+	/** Device which this function belongs to */
+	dev_node_t *dev;
+	
+	/** Link to list of functions in the device (ddf_dev_t.functions) */
+	link_t dev_functions;
+	
+	/** Child device node (if any attached). */
+	dev_node_t *child;
+	/** List of device ids for device-to-driver matching. */
+	match_id_list_t match_ids;
+	
+	/** The list of device classes to which this device function belongs. */
+	link_t classes;
+	/** Devmap handle if the device function is registered by devmap. */
+	devmap_handle_t devmap_handle;
+	
+	/**
+	 * Used by the hash table of functions indexed by devman device handles.
+	 */
+	link_t devman_fun;
+	
+	/**
+	 * Used by the hash table of functions indexed by devmap device handles.
+	 */
+	link_t devmap_fun;
+};
+
 
 /** Represents device tree. */
 typedef struct dev_tree {
 	/** Root device node. */
-	node_t *root_node;
+	fun_node_t *root_node;
 	
 	/**
@@ -191,9 +203,12 @@
 	hash_table_t devman_devices;
 	
+	/** Hash table of all devices indexed by devman handles. */
+	hash_table_t devman_functions;
+	
 	/**
 	 * Hash table of devices registered by devmapper, indexed by devmap
 	 * handles.
 	 */
-	hash_table_t devmap_devices;
+	hash_table_t devmap_functions;
 } dev_tree_t;
 
@@ -227,7 +242,7 @@
 
 /**
- * Provides n-to-m mapping between device nodes and classes - each device may
- * be register to the arbitrary number of classes and each class may contain
- * the arbitrary number of devices.
+ * Provides n-to-m mapping between function nodes and classes - each function
+ * can register in an arbitrary number of classes and each class can contain
+ * an arbitrary number of device functions.
  */
 typedef struct dev_class_info {
@@ -235,5 +250,5 @@
 	dev_class_t *dev_class;
 	/** The device. */
-	node_t *dev;
+	fun_node_t *fun;
 	
 	/**
@@ -249,5 +264,5 @@
 	link_t dev_classes;
 	
-	/** The name of the device within the class. */
+	/** The name of the device function within the class. */
 	char *dev_name;
 	/** The handle of the device by device mapper in the class namespace. */
@@ -270,5 +285,5 @@
 	 * indexed by devmap handles.
 	 */
-	hash_table_t devmap_devices;
+	hash_table_t devmap_functions;
 	
 	/** Fibril mutex for list of classes. */
@@ -278,5 +293,5 @@
 /* Match ids and scores */
 
-extern int get_match_score(driver_t *, node_t *);
+extern int get_match_score(driver_t *, dev_node_t *);
 
 extern bool parse_match_ids(char *, match_id_list_t *);
@@ -292,10 +307,10 @@
 extern int lookup_available_drivers(driver_list_t *, const char *);
 
-extern driver_t *find_best_match_driver(driver_list_t *, node_t *);
-extern bool assign_driver(node_t *, driver_list_t *, dev_tree_t *);
+extern driver_t *find_best_match_driver(driver_list_t *, dev_node_t *);
+extern bool assign_driver(dev_node_t *, driver_list_t *, dev_tree_t *);
 
 extern void add_driver(driver_list_t *, driver_t *);
-extern void attach_driver(node_t *, driver_t *);
-extern void add_device(int, driver_t *, node_t *, dev_tree_t *);
+extern void attach_driver(dev_node_t *, driver_t *);
+extern void add_device(int, driver_t *, dev_node_t *, dev_tree_t *);
 extern bool start_driver(driver_t *);
 
@@ -310,17 +325,24 @@
 /* Device nodes */
 
-extern node_t *create_dev_node(void);
-extern void delete_dev_node(node_t *node);
-extern node_t *find_dev_node_no_lock(dev_tree_t *tree,
+extern dev_node_t *create_dev_node(void);
+extern void delete_dev_node(dev_node_t *node);
+extern dev_node_t *find_dev_node_no_lock(dev_tree_t *tree,
     devman_handle_t handle);
-extern node_t *find_dev_node(dev_tree_t *tree, devman_handle_t handle);
-extern node_t *find_dev_node_by_path(dev_tree_t *, char *);
-extern node_t *find_node_child(node_t *, const char *);
+extern dev_node_t *find_dev_node(dev_tree_t *tree, devman_handle_t handle);
+extern dev_node_t *find_dev_function(dev_node_t *, const char *);
+
+extern fun_node_t *create_fun_node(void);
+extern void delete_fun_node(fun_node_t *);
+extern fun_node_t *find_fun_node_no_lock(dev_tree_t *tree,
+    devman_handle_t handle);
+extern fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle);
+extern fun_node_t *find_fun_node_by_path(dev_tree_t *, char *);
 
 /* Device tree */
 
 extern bool init_device_tree(dev_tree_t *, driver_list_t *);
-extern bool create_root_node(dev_tree_t *);
-extern bool insert_dev_node(dev_tree_t *, node_t *, char *, node_t *);
+extern bool create_root_nodes(dev_tree_t *);
+extern bool insert_dev_node(dev_tree_t *, dev_node_t *, fun_node_t *);
+extern bool insert_fun_node(dev_tree_t *, fun_node_t *, char *, dev_node_t *);
 
 /* Device classes */
@@ -330,5 +352,5 @@
 extern size_t get_new_class_dev_idx(dev_class_t *);
 extern char *create_dev_name_for_class(dev_class_t *, const char *);
-extern dev_class_info_t *add_device_to_class(node_t *, dev_class_t *,
+extern dev_class_info_t *add_function_to_class(fun_node_t *, dev_class_t *,
     const char *);
 
@@ -341,9 +363,11 @@
 /* Devmap devices */
 
-extern node_t *find_devmap_tree_device(dev_tree_t *, devmap_handle_t);
-extern node_t *find_devmap_class_device(class_list_t *, devmap_handle_t);
-
-extern void class_add_devmap_device(class_list_t *, dev_class_info_t *);
-extern void tree_add_devmap_device(dev_tree_t *, node_t *);
+extern void devmap_register_tree_function(fun_node_t *, dev_tree_t *);
+
+extern fun_node_t *find_devmap_tree_function(dev_tree_t *, devmap_handle_t);
+extern fun_node_t *find_devmap_class_function(class_list_t *, devmap_handle_t);
+
+extern void class_add_devmap_function(class_list_t *, dev_class_info_t *);
+extern void tree_add_devmap_function(dev_tree_t *, fun_node_t *);
 
 #endif
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/devman/main.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -199,23 +199,26 @@
 static int assign_driver_fibril(void *arg)
 {
-	node_t *node = (node_t *) arg;
-	assign_driver(node, &drivers_list, &device_tree);
+	dev_node_t *dev_node = (dev_node_t *) arg;
+	assign_driver(dev_node, &drivers_list, &device_tree);
 	return EOK;
 }
 
-/** Handle child device registration.
+/** Handle function registration.
  *
  * Child devices are registered by their parent's device driver.
  */
-static void devman_add_child(ipc_callid_t callid, ipc_call_t *call)
-{
-	devman_handle_t parent_handle = IPC_GET_ARG1(*call);
-	sysarg_t match_count = IPC_GET_ARG2(*call);
+static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
+{
+	fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
+	devman_handle_t dev_handle = IPC_GET_ARG2(*call);
+	sysarg_t match_count = IPC_GET_ARG3(*call);
 	dev_tree_t *tree = &device_tree;
 	
 	fibril_rwlock_write_lock(&tree->rwlock);
-	node_t *parent = find_dev_node_no_lock(&device_tree, parent_handle);
-	
-	if (parent == NULL) {
+
+	dev_node_t *dev = NULL;
+	dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
+	
+	if (pdev == NULL) {
 		fibril_rwlock_write_unlock(&tree->rwlock);
 		async_answer_0(callid, ENOENT);
@@ -223,6 +226,15 @@
 	}
 	
-	char *dev_name = NULL;
-	int rc = async_data_write_accept((void **)&dev_name, true, 0, 0, 0, 0);
+	if (ftype != fun_inner && ftype != fun_exposed) {
+		/* Unknown function type */
+		printf(NAME ": Error, unknown function type provided by driver!\n");
+
+		fibril_rwlock_write_unlock(&tree->rwlock);
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+	
+	char *fun_name = NULL;
+	int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
 	if (rc != EOK) {
 		fibril_rwlock_write_unlock(&tree->rwlock);
@@ -231,38 +243,55 @@
 	}
 	
-	node_t *node = create_dev_node();
-	if (!insert_dev_node(&device_tree, node, dev_name, parent)) {
+	fun_node_t *fun = create_fun_node();
+	if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
 		fibril_rwlock_write_unlock(&tree->rwlock);
-		delete_dev_node(node);
+		delete_fun_node(fun);
 		async_answer_0(callid, ENOMEM);
 		return;
 	}
 
+	if (ftype == fun_inner) {
+		dev = create_dev_node();
+		if (dev == NULL) {
+			fibril_rwlock_write_unlock(&tree->rwlock);
+			delete_fun_node(fun);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+
+		insert_dev_node(tree, dev, fun);
+	}
+
 	fibril_rwlock_write_unlock(&tree->rwlock);
 	
-	printf(NAME ": devman_add_child %s\n", node->pathname);
-	
-	devman_receive_match_ids(match_count, &node->match_ids);
-
-	/*
-	 * Try to find a suitable driver and assign it to the device.  We do
-	 * not want to block the current fibril that is used for processing
-	 * incoming calls: we will launch a separate fibril to handle the
-	 * driver assigning. That is because assign_driver can actually include
-	 * task spawning which could take some time.
-	 */
-	fid_t assign_fibril = fibril_create(assign_driver_fibril, node);
-	if (assign_fibril == 0) {
+	printf(NAME ": devman_add_function %s\n", fun->pathname);
+	
+	devman_receive_match_ids(match_count, &fun->match_ids);
+
+	if (ftype == fun_inner) {
+		assert(dev != NULL);
 		/*
-		 * Fallback in case we are out of memory.
-		 * Probably not needed as we will die soon anyway ;-).
+		 * Try to find a suitable driver and assign it to the device.  We do
+		 * not want to block the current fibril that is used for processing
+		 * incoming calls: we will launch a separate fibril to handle the
+		 * driver assigning. That is because assign_driver can actually include
+		 * task spawning which could take some time.
 		 */
-		(void) assign_driver_fibril(node);
+		fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
+		if (assign_fibril == 0) {
+			/*
+			 * Fallback in case we are out of memory.
+			 * Probably not needed as we will die soon anyway ;-).
+			 */
+			(void) assign_driver_fibril(fun);
+		} else {
+			fibril_add_ready(assign_fibril);
+		}
 	} else {
-		fibril_add_ready(assign_fibril);
-	}
-
+		devmap_register_tree_function(fun, tree);
+	}
+	
 	/* Return device handle to parent's driver. */
-	async_answer_1(callid, EOK, node->handle);
+	async_answer_1(callid, EOK, fun->handle);
 }
 
@@ -288,10 +317,10 @@
 	 * mapper.
 	 */
-	class_add_devmap_device(&class_list, cli);
+	class_add_devmap_function(&class_list, cli);
 	
 	free(devmap_pathname);
 }
 
-static void devman_add_device_to_class(ipc_callid_t callid, ipc_call_t *call)
+static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
 {
 	devman_handle_t handle = IPC_GET_ARG1(*call);
@@ -306,6 +335,6 @@
 	}	
 	
-	node_t *dev = find_dev_node(&device_tree, handle);
-	if (dev == NULL) {
+	fun_node_t *fun = find_fun_node(&device_tree, handle);
+	if (fun == NULL) {
 		async_answer_0(callid, ENOENT);
 		return;
@@ -313,11 +342,11 @@
 	
 	dev_class_t *cl = get_dev_class(&class_list, class_name);
-	dev_class_info_t *class_info = add_device_to_class(dev, cl, NULL);
+	dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
 	
 	/* Register the device's class alias by devmapper. */
 	devmap_register_class_dev(class_info);
 	
-	printf(NAME ": device '%s' added to class '%s', class name '%s' was "
-	    "asigned to it\n", dev->pathname, class_name, class_info->dev_name);
+	printf(NAME ": function'%s' added to class '%s', class name '%s' was "
+	    "asigned to it\n", fun->pathname, class_name, class_info->dev_name);
 
 	async_answer_0(callid, EOK);
@@ -372,9 +401,9 @@
 			cont = false;
 			continue;
-		case DEVMAN_ADD_CHILD_DEVICE:
-			devman_add_child(callid, &call);
+		case DEVMAN_ADD_FUNCTION:
+			devman_add_function(callid, &call);
 			break;
 		case DEVMAN_ADD_DEVICE_TO_CLASS:
-			devman_add_device_to_class(callid, &call);
+			devman_add_function_to_class(callid, &call);
 			break;
 		default:
@@ -387,5 +416,5 @@
 /** Find handle for the device instance identified by the device's path in the
  * device tree. */
-static void devman_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
+static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
 {
 	char *pathname;
@@ -397,14 +426,14 @@
 	}
 	
-	node_t * dev = find_dev_node_by_path(&device_tree, pathname);
+	fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
 	
 	free(pathname);
 
-	if (dev == NULL) {
+	if (fun == NULL) {
 		async_answer_0(iid, ENOENT);
 		return;
 	}
-	
-	async_answer_1(iid, EOK, dev->handle);
+
+	async_answer_1(iid, EOK, fun->handle);
 }
 
@@ -426,5 +455,5 @@
 			continue;
 		case DEVMAN_DEVICE_GET_HANDLE:
-			devman_device_get_handle(callid, &call);
+			devman_function_get_handle(callid, &call);
 			break;
 		default:
@@ -438,21 +467,41 @@
 {
 	devman_handle_t handle = IPC_GET_ARG2(*icall);
-	
-	node_t *dev = find_dev_node(&device_tree, handle);
-	if (dev == NULL) {
-		printf(NAME ": devman_forward error - no device with handle %" PRIun
-		    " was found.\n", handle);
+	devman_handle_t fwd_h;
+	fun_node_t *fun = NULL;
+	dev_node_t *dev = NULL;
+	
+	fun = find_fun_node(&device_tree, handle);
+	if (fun == NULL)
+		dev = find_dev_node(&device_tree, handle);
+	else
+		dev = fun->dev;
+
+	if (fun == NULL && dev == NULL) {
+		printf(NAME ": devman_forward error - no device or function with "
+		    "handle %" PRIun " was found.\n", handle);
 		async_answer_0(iid, ENOENT);
 		return;
 	}
+
+	if (fun == NULL && !drv_to_parent) {
+		printf(NAME ": devman_forward error - cannot connect to "
+		    "handle %" PRIun ", refers to a device.\n", handle);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
 	
 	driver_t *driver = NULL;
 	
 	if (drv_to_parent) {
-		if (dev->parent != NULL)
-			driver = dev->parent->drv;
+		/* Connect to parent function of a device (or device function). */
+		if (dev->pfun->dev != NULL)
+			driver = dev->pfun->dev->drv;
+		fwd_h = dev->pfun->handle;
 	} else if (dev->state == DEVICE_USABLE) {
+		/* Connect to the specified function */
 		driver = dev->drv;
 		assert(driver != NULL);
+
+		fwd_h = handle;
 	}
 	
@@ -478,7 +527,13 @@
 	}
 
-	printf(NAME ": devman_forward: forward connection to device %s to "
-	    "driver %s.\n", dev->pathname, driver->name);
-	async_forward_fast(iid, driver->phone, method, dev->handle, 0, IPC_FF_NONE);
+	if (fun != NULL) {
+		printf(NAME ": devman_forward: forward connection to function %s to "
+		    "driver %s.\n", fun->pathname, driver->name);
+	} else {
+		printf(NAME ": devman_forward: forward connection to device %s to "
+		    "driver %s.\n", dev->pfun->pathname, driver->name);
+	}
+
+	async_forward_fast(iid, driver->phone, method, fwd_h, 0, IPC_FF_NONE);
 }
 
@@ -488,14 +543,17 @@
 {
 	devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
-	node_t *dev;
-
-	dev = find_devmap_tree_device(&device_tree, devmap_handle);
-	if (dev == NULL)
-		dev = find_devmap_class_device(&class_list, devmap_handle);
-	
-	if (dev == NULL || dev->drv == NULL) {
+	fun_node_t *fun;
+	dev_node_t *dev;
+
+	fun = find_devmap_tree_function(&device_tree, devmap_handle);
+	if (fun == NULL)
+		fun = find_devmap_class_function(&class_list, devmap_handle);
+	
+	if (fun == NULL || fun->dev->drv == NULL) {
 		async_answer_0(iid, ENOENT);
 		return;
 	}
+	
+	dev = fun->dev;
 	
 	if (dev->state != DEVICE_USABLE || dev->drv->phone <= 0) {
@@ -504,8 +562,8 @@
 	}
 	
-	async_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, dev->handle, 0,
+	async_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, fun->handle, 0,
 	    IPC_FF_NONE);
 	printf(NAME ": devman_connection_devmapper: forwarded connection to "
-	    "device %s to driver %s.\n", dev->pathname, dev->drv->name);
+	    "device %s to driver %s.\n", fun->pathname, dev->drv->name);
 }
 
Index: uspace/srv/devman/match.c
===================================================================
--- uspace/srv/devman/match.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/devman/match.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -57,8 +57,8 @@
 }
 
-int get_match_score(driver_t *drv, node_t *dev)
+int get_match_score(driver_t *drv, dev_node_t *dev)
 {
 	link_t *drv_head = &drv->match_ids.ids;
-	link_t *dev_head = &dev->match_ids.ids;
+	link_t *dev_head = &dev->pfun->match_ids.ids;
 	
 	if (list_empty(drv_head) || list_empty(dev_head))
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/devmap/devmap.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -123,4 +123,10 @@
 static devmap_handle_t last_handle = 0;
 static devmap_device_t *null_devices[NULL_DEVICES];
+
+/*
+ * Dummy list for null devices. This is necessary so that null devices can
+ * be used just as any other devices, e.g. in devmap_device_unregister_core().
+ */
+static LIST_INITIALIZE(dummy_null_driver_devices);
 
 static devmap_handle_t devmap_create_handle(void)
@@ -953,7 +959,11 @@
 	device->name = dev_name;
 	
-	/* Insert device into list of all devices
-	   and into null devices array */
+	/*
+	 * Insert device into list of all devices and into null devices array.
+	 * Insert device into a dummy list of null driver's devices so that it
+	 * can be safely removed later.
+	 */
 	list_append(&device->devices, &devices_list);
+	list_append(&device->driver_devices, &dummy_null_driver_devices);
 	null_devices[i] = device;
 	
Index: uspace/srv/hid/console/gcons.c
===================================================================
--- uspace/srv/hid/console/gcons.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/hid/console/gcons.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -285,6 +285,7 @@
 	ssize_t nx = (ssize_t) mouse_x + dx;
 	ssize_t ny = (ssize_t) mouse_y + dy;
-
-	if (!use_gcons)
+	
+	/* Until gcons is initalized we don't have the screen resolution */
+	if (xres == 0 || yres == 0)
 		return;
 	
Index: uspace/srv/hid/kbd/Makefile
===================================================================
--- uspace/srv/hid/kbd/Makefile	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/hid/kbd/Makefile	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -78,5 +78,5 @@
 		SOURCES += \
 			port/pl050.c \
-			ctl/pl050.c
+			ctl/pc.c
 	endif
 endif
Index: pace/srv/hid/kbd/ctl/pl050.c
===================================================================
--- uspace/srv/hid/kbd/ctl/pl050.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ 	(revision )
@@ -1,267 +1,0 @@
-/*
- * Copyright (c) 2009 Vineeth Pillai
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING 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_ctl
- * @ingroup kbd
- * @{
- */
-/**
- * @file
- * @brief PL050 keyboard controller driver.
- */
-
-#include <kbd.h>
-#include <io/console.h>
-#include <io/keycode.h>
-#include <kbd_ctl.h>
-#include <gsp.h>
-#include <stdio.h>
-
-#define PL050_CAPS_SCAN_CODE 0x58
-#define PL050_NUM_SCAN_CODE 0x77
-#define PL050_SCROLL_SCAN_CODE 0x7E
-
-static bool is_lock_key(int);
-enum dec_state {
-	ds_s,
-	ds_e
-};
-
-static enum dec_state ds;
-
-static int scanmap_simple[] = {
-
-	[0x0e] = KC_BACKTICK,
-
-	[0x16] = KC_1,
-	[0x1e] = KC_2,
-	[0x26] = KC_3,
-	[0x25] = KC_4,
-	[0x2e] = KC_5,
-	[0x36] = KC_6,
-	[0x3d] = KC_7,
-	[0x3e] = KC_8,
-	[0x46] = KC_9,
-	[0x45] = KC_0,
-
-	[0x4e] = KC_MINUS,
-	[0x55] = KC_EQUALS,
-	[0x66] = KC_BACKSPACE,
-
-	[0x0d] = KC_TAB,
-
-	[0x15] = KC_Q,
-	[0x1d] = KC_W,
-	[0x24] = KC_E,
-	[0x2d] = KC_R,
-	[0x2c] = KC_T,
-	[0x35] = KC_Y,
-	[0x3c] = KC_U,
-	[0x43] = KC_I,
-	[0x44] = KC_O,
-	[0x4d] = KC_P,
-
-	[0x54] = KC_LBRACKET,
-	[0x5b] = KC_RBRACKET,
-
-	[0x58] = KC_CAPS_LOCK,
-
-	[0x1c] = KC_A,
-	[0x1b] = KC_S,
-	[0x23] = KC_D,
-	[0x2b] = KC_F,
-	[0x34] = KC_G,
-	[0x33] = KC_H,
-	[0x3b] = KC_J,
-	[0x42] = KC_K,
-	[0x4b] = KC_L,
-
-	[0x4c] = KC_SEMICOLON,
-	[0x52] = KC_QUOTE,
-	[0x5d] = KC_BACKSLASH,
-
-	[0x12] = KC_LSHIFT,
-
-	[0x1a] = KC_Z,
-	[0x22] = KC_X,
-	[0x21] = KC_C,
-	[0x2a] = KC_V,
-	[0x32] = KC_B,
-	[0x31] = KC_N,
-	[0x3a] = KC_M,
-
-	[0x41] = KC_COMMA,
-	[0x49] = KC_PERIOD,
-	[0x4a] = KC_SLASH,
-
-	[0x59] = KC_RSHIFT,
-
-	[0x14] = KC_LCTRL,
-	[0x11] = KC_LALT,
-	[0x29] = KC_SPACE,
-
-	[0x76] = KC_ESCAPE,
-
-	[0x05] = KC_F1,
-	[0x06] = KC_F2,
-	[0x04] = KC_F3,
-	[0x0c] = KC_F4,
-	[0x03] = KC_F5,
-	[0x0b] = KC_F6,
-	[0x02] = KC_F7,
-
-	[0x0a] = KC_F8,
-	[0x01] = KC_F9,
-	[0x09] = KC_F10,
-
-	[0x78] = KC_F11,
-	[0x07] = KC_F12,
-
-	[0x60] = KC_SCROLL_LOCK,
-
-	[0x5a] = KC_ENTER,
-
-	[0x77] = KC_NUM_LOCK,
-	[0x7c] = KC_NTIMES,
-	[0x7b] = KC_NMINUS,
-	[0x79] = KC_NPLUS,
-	[0x6c] = KC_N7,
-	[0x75] = KC_N8,
-	[0x7d] = KC_N9,
-	[0x6b] = KC_N4,
-	[0x73] = KC_N5,
-	[0x74] = KC_N6,
-	[0x69] = KC_N1,
-	[0x72] = KC_N2,
-	[0x7a] = KC_N3,
-	[0x70] = KC_N0,
-	[0x71] = KC_NPERIOD
-};
-
-static int scanmap_e0[] = {
-	[0x65] = KC_RALT,
-	[0x59] = KC_RSHIFT,
-
-	[0x64] = KC_PRTSCR,
-
-	[0x70] = KC_INSERT,
-	[0x6c] = KC_HOME,
-	[0x7d] = KC_PAGE_UP,
-
-	[0x71] = KC_DELETE,
-	[0x69] = KC_END,
-	[0x7a] = KC_PAGE_DOWN,
-
-	[0x75] = KC_UP,
-	[0x6b] = KC_LEFT,
-	[0x72] = KC_DOWN,
-	[0x74] = KC_RIGHT,
-
-	[0x4a] = KC_NSLASH,
-	[0x5a] = KC_NENTER
-};
-
-int kbd_ctl_init(void)
-{
-	ds = ds_s;
-	return 0;
-}
-
-void kbd_ctl_parse_scancode(int scancode)
-{
-	static int key_release_flag = 0;
-	static int is_locked = 0;
-	console_ev_type_t type;
-	unsigned int key;
-	int *map;
-	size_t map_length;
-
-	if (scancode == 0xe0) {
-		ds = ds_e;
-		return;
-	}
-
-	switch (ds) {
-	case ds_s:
-		map = scanmap_simple;
-		map_length = sizeof(scanmap_simple) / sizeof(int);
-		break;
-	case ds_e:
-		map = scanmap_e0;
-		map_length = sizeof(scanmap_e0) / sizeof(int);
-		break;
-	default:
-		map = NULL;
-		map_length = 0;
-	}
-
-	ds = ds_s;
-	if (scancode == 0xf0) {
-		key_release_flag = 1;
-		return;
-	} else {
-		if (key_release_flag) {
-			type = KEY_RELEASE;
-			key_release_flag = 0;
-			if (is_lock_key(scancode)) {
-				if (!is_locked) {
-					is_locked = 1;
-				} else {
-					is_locked = 0;
-					return;
-				}
-			}
-		} else {
-			if (is_lock_key(scancode) && is_locked)
-				return;
-			type = KEY_PRESS;
-		}
-	}
-
-	if (scancode < 0)
-		return;
-
-	key = map[scancode];
-	if (key != 0)
-		kbd_push_ev(type, key);
-}
-
-static bool is_lock_key(int sc)
-{
-	return ((sc == PL050_CAPS_SCAN_CODE) || (sc == PL050_NUM_SCAN_CODE) ||
-	    (sc == PL050_SCROLL_SCAN_CODE));
-}
-
-void kbd_ctl_set_ind(unsigned mods)
-{
-	(void) mods;
-}
-
-/**
- * @}
- */ 
Index: uspace/srv/loader/arch/abs32le/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/abs32le/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/abs32le/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -3,4 +3,5 @@
  * is the base address and the special interp section.
  */
+
 STARTUP(LIBC_PREFIX/arch/UARCH/src/entry.o)
 ENTRY(__entry)
@@ -54,8 +55,4 @@
 	} :data
 	
-	. = ALIGN(0x1000);
-	
-	_heap = .;
-	
 	/DISCARD/ : {
 		*(*);
Index: uspace/srv/loader/arch/amd64/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/amd64/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/amd64/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -1,2 +1,7 @@
+/*
+ * The difference from _link.ld.in for regular statically-linked apps
+ * is the base address and the special interp section.
+ */
+
 STARTUP(LIBC_PREFIX/arch/UARCH/src/entry.o)
 ENTRY(__entry)
@@ -6,4 +11,5 @@
 	text PT_LOAD FLAGS(5);
 	data PT_LOAD FLAGS(6);
+	debug PT_NOTE;
 }
 
@@ -11,7 +17,7 @@
 	.interp : {
 		*(.interp);
-	} : interp
-
-	/* . = 0x0000700000001000;*/
+	} :interp
+	
+	/* . = 0x0000700000001000; */
 	. = 0x70001000;
 	
@@ -19,4 +25,5 @@
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
@@ -27,4 +34,5 @@
 		*(.data);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -32,4 +40,5 @@
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -37,16 +46,27 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.bss : {
 		*(COMMON);
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x1000);
-	_heap = .;
+	
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/srv/loader/arch/arm32/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/arm32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/arm32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -3,4 +3,5 @@
  * is the base address.
  */
+
 STARTUP(LIBC_PREFIX/arch/UARCH/src/entry.o)
 ENTRY(__entry)
@@ -16,13 +17,14 @@
 		*(.interp);
 	} : interp
-
+	
 	. = 0x70001000;
-
+	
 	.init ALIGN(0x1000): SUBALIGN(0x1000) {
 		*(.init);
-	} : text
+	} :text
+	
 	.text : {
 		*(.text);
-        *(.rodata*);
+		*(.rodata*);
 	} :text
 	
@@ -32,4 +34,5 @@
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -37,4 +40,5 @@
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -42,18 +46,16 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.bss : {
 		*(.sbss);
 		*(.scommon);
-        *(COMMON);
-        *(.bss);
+		*(COMMON);
+		*(.bss);
 	} :data
-	
-	. = ALIGN(0x1000);
-	_heap = .;
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/srv/loader/arch/ia32/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/ia32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/ia32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -3,4 +3,5 @@
  * is the base address and the special interp section.
  */
+
 STARTUP(LIBC_PREFIX/arch/UARCH/src/entry.o)
 ENTRY(__entry)
@@ -10,4 +11,5 @@
 	text PT_LOAD FILEHDR PHDRS FLAGS(5);
 	data PT_LOAD FLAGS(6);
+	debug PT_NOTE;
 }
 
@@ -52,7 +54,16 @@
 	} :data
 	
-	. = ALIGN(0x1000);
-	
-	_heap = .;
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
 	
 	/DISCARD/ : {
Index: uspace/srv/loader/arch/ia64/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/ia64/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/ia64/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -12,22 +12,24 @@
 		*(.interp);
 	} :interp
-
+	
 	/* On Itanium code sections must be aligned to 16 bytes. */
 	. = ALIGN(0x800000000 + SIZEOF_HEADERS, 16);
-
+	
 	.init : {
 		*(.init);
-	} : text
+	} :text
+	
 	.text : {
 		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x4000;
-
+	
 	.got : {
 		_gp = .;
 		*(.got*);
-	} :data	
+	} :data
+	
 	.data : {
 		*(.opd);
@@ -35,4 +37,5 @@
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -40,4 +43,5 @@
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -45,5 +49,7 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.bss : {
 		*(.sbss);
@@ -52,10 +58,7 @@
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x4000);
-	_heap = .;
- 
+	
 	/DISCARD/ : {
 		*(*);
-        }
+	}
 }
Index: uspace/srv/loader/arch/mips32/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/mips32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/mips32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -3,4 +3,5 @@
  * is the base address.
  */
+
 STARTUP(LIBC_PREFIX/arch/UARCH/src/entry.o)
 ENTRY(__entry)
@@ -16,5 +17,5 @@
 		*(.interp);
 	} :interp
-
+	
 	. = 0x70004000;
 	
@@ -22,19 +23,22 @@
 		*(.init);
 	} :text
+	
 	.text : {
-	        *(.text);
+		*(.text);
 		*(.rodata*);
 	} :text
-
+	
+	. = . + 0x4000;
+	
 	.data : {
 		*(.data);
 		*(.data.rel*);
 	} :data
-
+	
 	.got : {
 		_gp = .;
 		*(.got);
 	} :data
-
+	
 	.tdata : {
 		_tdata_start = .;
@@ -42,4 +46,5 @@
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -47,18 +52,17 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
-
+	
 	.sbss : {
 		*(.scommon);
 		*(.sbss);
-	}	
+	}
+	
 	.bss : {
 		*(.bss);
 		*(COMMON);
 	} :data
-
-	. = ALIGN(0x4000);
-	_heap = .;
-
+	
 	/DISCARD/ : {
 		*(*);
Index: uspace/srv/loader/arch/ppc32/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/ppc32/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/ppc32/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -3,4 +3,5 @@
  * is the base address.
  */
+
 STARTUP(LIBC_PREFIX/arch/UARCH/src/entry.o)
 ENTRY(__entry)
@@ -16,10 +17,11 @@
 		*(.interp);
 	} :interp
-
+	
 	. = 0x70001000;
-
+	
 	.init ALIGN(0x1000) : SUBALIGN(0x1000) {
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
@@ -31,4 +33,5 @@
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -36,4 +39,5 @@
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -41,5 +45,7 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.bss : {
 		*(.sbss);
@@ -47,11 +53,7 @@
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x1000);
-	_heap = .;
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/srv/loader/arch/sparc64/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/sparc64/_link.ld.in	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/arch/sparc64/_link.ld.in	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -12,25 +12,28 @@
 		*(.interp);
 	} :interp
-
+	
 	. = 0x70004000 + SIZEOF_HEADERS;
-
+	
 	.init : {
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
 		*(.rodata*);
 	} :text
-
+	
 	. = . + 0x4000;
-
+	
 	.got : {
 		 _gp = .;
 		 *(.got*);
 	} :data
+	
 	.data : {
 		*(.data);
 		*(.sdata);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
@@ -38,4 +41,5 @@
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -43,5 +47,7 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.bss : {
 		*(.sbss);
@@ -49,11 +55,7 @@
 		*(.bss);
 	} :data
-
-	. = ALIGN(0x4000);
-	_heap = .;
 	
 	/DISCARD/ : {
 		*(*);
 	}
-
 }
Index: uspace/srv/loader/elf_load.c
===================================================================
--- uspace/srv/loader/elf_load.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/loader/elf_load.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -109,5 +109,5 @@
 	int fd;
 	int rc;
-
+	
 	fd = open(file_name, O_RDONLY);
 	if (fd < 0) {
@@ -300,4 +300,5 @@
 	case PT_NULL:
 	case PT_PHDR:
+	case PT_NOTE:
 		break;
 	case PT_LOAD:
@@ -310,5 +311,4 @@
 	case PT_DYNAMIC:
 	case PT_SHLIB:
-	case PT_NOTE:
 	case PT_LOPROC:
 	case PT_HIPROC:
@@ -344,5 +344,5 @@
 	seg_ptr = (void *) seg_addr;
 
-	DPRINTF("Load segment at addr %p, size 0x%x\n", seg_addr,
+	DPRINTF("Load segment at addr %p, size 0x%x\n", (void *) seg_addr,
 		entry->p_memsz);
 
@@ -372,6 +372,7 @@
 	mem_sz = entry->p_memsz + (entry->p_vaddr - base);
 
-	DPRINTF("Map to seg_addr=%p-%p.\n", seg_addr,
-	entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE));
+	DPRINTF("Map to seg_addr=%p-%p.\n", (void *) seg_addr,
+	    (void *) (entry->p_vaddr + bias +
+	    ALIGN_UP(entry->p_memsz, PAGE_SIZE)));
 
 	/*
@@ -386,6 +387,6 @@
 	}
 
-	DPRINTF("as_area_create(%p, 0x%x, %d) -> 0x%lx\n",
-		base + bias, mem_sz, flags, (uintptr_t)a);
+	DPRINTF("as_area_create(%p, %#zx, %d) -> %p\n",
+	    (void *) (base + bias), mem_sz, flags, (void *) a);
 
 	/*
@@ -464,5 +465,5 @@
 		    (void *)((uint8_t *)entry->sh_addr + elf->bias);
 		DPRINTF("Dynamic section found at %p.\n",
-			(uintptr_t)elf->info->dynamic);
+		    (void *) elf->info->dynamic);
 		break;
 	default:
Index: uspace/srv/net/tl/udp/udp.c
===================================================================
--- uspace/srv/net/tl/udp/udp.c	(revision 5716e9afd07b8c8ac4e5fb6977a879035c2ffe10)
+++ uspace/srv/net/tl/udp/udp.c	(revision 76b5a95cdf127e6bca3c36046fa6af8e0e443f48)
@@ -740,5 +740,5 @@
 	int socket_id;
 	size_t addrlen;
-	size_t size;
+	size_t size = 0;
 	ipc_call_t answer;
 	size_t answer_count;
